Best practices for handling data with Lindy AI. Use when managing sensitive data, implementing data privacy, or ensuring data compliance. Trigger with phrases like "lindy data", "lindy privacy", "lindy PII", "lindy data handling", "lindy GDPR".
/plugin marketplace add jeremylongshore/claude-code-plugins-plus-skills/plugin install lindy-pack@claude-code-plugins-plusThis skill is limited to using the following tools:
Best practices for secure and compliant data handling with Lindy AI.
// data/classification.ts
enum DataClassification {
PUBLIC = 'public',
INTERNAL = 'internal',
CONFIDENTIAL = 'confidential',
RESTRICTED = 'restricted', // PII, PHI, etc.
}
interface DataPolicy {
classification: DataClassification;
canSendToLindy: boolean;
requiresRedaction: boolean;
retentionDays: number;
}
const policies: Record<DataClassification, DataPolicy> = {
[DataClassification.PUBLIC]: {
classification: DataClassification.PUBLIC,
canSendToLindy: true,
requiresRedaction: false,
retentionDays: 365,
},
[DataClassification.INTERNAL]: {
classification: DataClassification.INTERNAL,
canSendToLindy: true,
requiresRedaction: false,
retentionDays: 90,
},
[DataClassification.CONFIDENTIAL]: {
classification: DataClassification.CONFIDENTIAL,
canSendToLindy: true,
requiresRedaction: true,
retentionDays: 30,
},
[DataClassification.RESTRICTED]: {
classification: DataClassification.RESTRICTED,
canSendToLindy: false,
requiresRedaction: true,
retentionDays: 7,
},
};
// data/pii-redactor.ts
interface PIIPattern {
name: string;
pattern: RegExp;
replacement: string;
}
const piiPatterns: PIIPattern[] = [
{
name: 'email',
pattern: /[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/g,
replacement: '[EMAIL REDACTED]',
},
{
name: 'phone',
pattern: /(\+\d{1,3}[-.]?)?\(?\d{3}\)?[-.]?\d{3}[-.]?\d{4}/g,
replacement: '[PHONE REDACTED]',
},
{
name: 'ssn',
pattern: /\d{3}-\d{2}-\d{4}/g,
replacement: '[SSN REDACTED]',
},
{
name: 'credit_card',
pattern: /\d{4}[-\s]?\d{4}[-\s]?\d{4}[-\s]?\d{4}/g,
replacement: '[CREDIT CARD REDACTED]',
},
{
name: 'ip_address',
pattern: /\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/g,
replacement: '[IP REDACTED]',
},
];
export function redactPII(text: string): { redacted: string; found: string[] } {
let redacted = text;
const found: string[] = [];
for (const pattern of piiPatterns) {
const matches = text.match(pattern.pattern);
if (matches) {
found.push(pattern.name);
redacted = redacted.replace(pattern.pattern, pattern.replacement);
}
}
return { redacted, found };
}
// lib/secure-lindy.ts
import { Lindy } from '@lindy-ai/sdk';
import { redactPII } from '../data/pii-redactor';
export class SecureLindy {
private lindy: Lindy;
constructor() {
this.lindy = new Lindy({ apiKey: process.env.LINDY_API_KEY });
}
async runSecure(agentId: string, input: string, options: {
classification: DataClassification;
redactPII?: boolean;
}) {
// Check if data can be sent to Lindy
const policy = policies[options.classification];
if (!policy.canSendToLindy) {
throw new Error(`Data classification ${options.classification} cannot be sent to Lindy`);
}
// Redact PII if required
let processedInput = input;
let redactionLog: string[] = [];
if (policy.requiresRedaction || options.redactPII) {
const result = redactPII(input);
processedInput = result.redacted;
redactionLog = result.found;
if (redactionLog.length > 0) {
console.log('PII redacted:', redactionLog);
}
}
// Run agent
const result = await this.lindy.agents.run(agentId, { input: processedInput });
// Log for compliance
await this.logDataAccess({
agentId,
classification: options.classification,
piiRedacted: redactionLog,
timestamp: new Date(),
});
return result;
}
private async logDataAccess(log: any): Promise<void> {
// Store audit log
console.log('Data access log:', JSON.stringify(log));
}
}
// data/retention.ts
import { Lindy } from '@lindy-ai/sdk';
interface RetentionPolicy {
maxAgeDays: number;
autoDelete: boolean;
}
async function enforceRetention(policy: RetentionPolicy) {
const lindy = new Lindy({ apiKey: process.env.LINDY_API_KEY });
const cutoffDate = new Date();
cutoffDate.setDate(cutoffDate.getDate() - policy.maxAgeDays);
// Get old runs
const runs = await lindy.runs.list({
before: cutoffDate.toISOString(),
});
console.log(`Found ${runs.length} runs older than ${policy.maxAgeDays} days`);
if (policy.autoDelete) {
for (const run of runs) {
await lindy.runs.delete(run.id);
console.log(`Deleted run: ${run.id}`);
}
}
}
// compliance/gdpr.ts
import { Lindy } from '@lindy-ai/sdk';
class GDPRHandler {
private lindy: Lindy;
constructor() {
this.lindy = new Lindy({ apiKey: process.env.LINDY_API_KEY });
}
// Right to Access
async exportUserData(userId: string): Promise<any> {
const runs = await this.lindy.runs.list({ userId });
const agents = await this.lindy.agents.list({ userId });
return {
exportDate: new Date().toISOString(),
userId,
runs: runs.map(r => ({
id: r.id,
agentId: r.agentId,
createdAt: r.createdAt,
// Don't include input/output for security
})),
agents: agents.map(a => ({
id: a.id,
name: a.name,
createdAt: a.createdAt,
})),
};
}
// Right to Erasure
async deleteUserData(userId: string): Promise<void> {
// Delete all runs
const runs = await this.lindy.runs.list({ userId });
for (const run of runs) {
await this.lindy.runs.delete(run.id);
}
// Delete all agents
const agents = await this.lindy.agents.list({ userId });
for (const agent of agents) {
await this.lindy.agents.delete(agent.id);
}
console.log(`Deleted all data for user: ${userId}`);
}
}
[ ] Data classification scheme defined
[ ] PII detection implemented
[ ] Redaction applied before sending to Lindy
[ ] Audit logging enabled
[ ] Retention policies defined
[ ] GDPR/CCPA handlers implemented
[ ] Data access controls configured
[ ] Encryption in transit (HTTPS)
[ ] Regular data audits scheduled
| Issue | Cause | Solution |
|---|---|---|
| PII leaked | Missing redaction | Enable auto-redaction |
| Retention exceeded | No cleanup | Schedule retention job |
| Classification missing | No policy | Default to restricted |
Proceed to lindy-enterprise-rbac for access control.
Creating algorithmic art using p5.js with seeded randomness and interactive parameter exploration. Use this when users request creating art using code, generative art, algorithmic art, flow fields, or particle systems. Create original algorithmic art rather than copying existing artists' work to avoid copyright violations.
Applies Anthropic's official brand colors and typography to any sort of artifact that may benefit from having Anthropic's look-and-feel. Use it when brand colors or style guidelines, visual formatting, or company design standards apply.
Create beautiful visual art in .png and .pdf documents using design philosophy. You should use this skill when the user asks to create a poster, piece of art, design, or other static piece. Create original visual designs, never copying existing artists' work to avoid copyright violations.