Clay Data HandlingSAFE
Model-agnostic agent-skills platform with a harness-free canonical layer, verified adapters, and the ccpi package manager. Explore at tonsofskills.com.
Overview
Model-agnostic agent-skills platform with a harness-free canonical layer, verified adapters, and the ccpi package manager. Explore at tonsofskills.com.
4f83675ca38aOBSERVED · 2026-10-08Host compatibility
What the documentation claims. We have not run a compatibility test.
| Host | Status | Notes |
|---|---|---|
| claude-code | mentioned |
What it tells the agent
The instruction file, verbatim from the audited commit — this is the text the model reads, and the surface the audit's instruction layer examines. Quoted here so you can judge it without cloning anything.
--- name: clay-data-handling description: 'Implement GDPR/CCPA-compliant data handling for Clay enrichment pipelines. Use when handling PII from enrichments, implementing data retention policies, or ensuring regulatory compliance for Clay-enriched lead data. Trigger with phrases like "clay data", "clay PII", "clay GDPR", "clay data retention", "clay privacy", "clay CCPA", "clay compliance". ' allowed-tools: Read, Write, Edit, Grep version: 1.14.0 license: MIT author: Jeremy Longshore <[email protected]> tags: - saas - clay - compliance compatibility: Designed for Claude Code --- # Clay Data Handling ## Overview Manage lead data through Clay enrichment pipelines in compliance with GDPR, CCPA, and data privacy best practices. Clay enriches records with PII (emails, phone numbers, LinkedIn profiles, job titles), requiring careful handling of consent, retention, and export controls. ## Prerequisites - Clay account with enriched tables - Understanding of GDPR/CCPA requirements for B2B data - Data retention policy defined by your legal team - CRM or database for enriched data storage ## Instructions ### Step 1: Classify Enriched Data by Sensitivity ```typescript // src/clay/data-classification.ts enum DataSensitivity { PUBLIC = 'public', // Company name, industry, employee count BUSINESS = 'business', // Work email, job title, LinkedIn URL PERSONAL = 'personal', // Phone number, personal email RESTRICTED = 'restricted' // Home address, personal phone } const FIELD_CLASSIFICATION: Record<string, DataSensitivity> = { company_name: DataSensitivity.PUBLIC, industry: DataSensitivity.PUBLIC, employee_count: DataSensitivity.PUBLIC, domain: DataSensitivity.PUBLIC, work_email: DataSensitivity.BUSINESS, job_title: DataSensitivity.BUSINESS, linkedin_url: DataSensitivity.BUSINESS, first_name: DataSensitivity.BUSINESS, last_name: DataSensitivity.BUSINESS, phone_number: DataSensitivity.PERSONAL, personal_email: DataSensitivity.RESTRICTED, home_address: DataSensitivity.RESTRICTED, }; function classifyRow(row: Record<string, unknown>): Record<DataSensitivity, string[]> { const classified: Record<DataSensitivity, string[]> = { public: [], business: [], personal: [], restricted: [], }; for (const [field, value] of Object.entries(row)) { if (value == null) continue; const sensitivity = FIELD_CLASSIFICATION[field] || DataSensitivity.BUSINESS; classified[sensitivity].push(field); } return classified; } ``` ### Step 2: Validate Input Data Before Enrichment ```typescript // src/clay/data-validation.ts import { z } from 'zod'; const ClayInputSchema = z.object({ domain: z.string().min(3).refine(d => d.includes('.'), 'Invalid domain'), first_name: z.string().min(1).max(100), last_name: z.string().min(1).max(100), email: z.string().email().optional(), source: z.string().optional(), consent_basis: z.enum(['legitimate_interest', 'consent', 'contract']).optional(), }); function validateForEnrichment(rows: unknown[]): { valid: z.infer<typeof ClayInputSchema>[]; invalid: { row: unknown; errors: string[] }[]; } { const valid: z.infer<typeof ClayInputSchema>[] = []; const invalid: { row: unknown; errors: string[] }[] = []; for (const row of rows) { const result = ClayInputSchema.safeParse(row); if (result.success) { valid.push(result.data); } else { invalid.push({ row, errors: result.error.issues.map(i => `${i.path.join('.')}: ${i.message}`), }); } } return { valid, invalid }; } ``` ### Step 3: Deduplicate Before Enrichment ```typescript // src/clay/dedup.ts — prevent credit waste on duplicates function deduplicateLeads( rows: Record<string, unknown>[], keyFields: string[] = ['domain', 'first_name', 'last_name'], ): { unique: Record<string, unknown>[]; duplicates: number } { const seen = new Set<string>(); const unique: Record<string, unknown>[] = []; let duplicates = 0; for (const row of rows) { const key = keyFields .map(f => String(row[f] || '').toLowerCase().trim()) .join(':'); if (seen.has(key)) { duplicates++; continue; } seen.add(key); unique.push(row); } return { unique, duplicates }; } ``` ### Step 4: Add Retention Metadata to Enriched Data ```typescript // src/clay/retention.ts interface EnrichedRecordWithRetention { // Original enriched data [key: string]: unknown; // Retention metadata _enriched_at: string; // ISO timestamp _retention_expires: string; // ISO timestamp _enrichment_source: string; // 'clay' _consent_basis: string; // Legal basis for processing _data_subject_rights: string; // How to handle deletion requests } function addRetentionMetadata( enrichedRow: Record<string, unknown>, retentionDays: number = 365, consentBasis: string = 'legitimate_interest', ): EnrichedRecordWithRetention { const now = new Date(); const expires = new Date(now.getTime() + retentionDays * 24 * 60 * 60 * 1000); return { ...enrichedRow, _enriched_at: now.toISOString(), _retention_expires: expires.toISOString(), _enrichment_source: 'clay', _consent_basis: consentBasis, _data_subject_rights: 'Contact [email protected] for deletion/access requests', }; } ``` ### Step 5: GDPR-Compliant Export ```typescript // src/clay/export.ts /** Strip PII for analytics/reporting exports */ function anonymizeForAnalytics(row: Record<string, unknown>): Record<string, unknown> { const anonymized = { ...row }; // Hash identifiers instead of including plaintext if (anonymized.work_email) { anonymized.email_hash = crypto.createHash('sha256') .update(String(anonymized.work_email).toLowerCase()) .digest('hex'); delete anonymized.work_email; } // Remove all personal identifiers delete anonymized.first_name; delete anonymized.last_name; delete anonymized.phone_number; delete anonymized.linkedin_url;
Trust audit
SAFEgrade B · trust 89/100 Nothing in the source contradicts what it says it does. Grade A is reserved for packages that have also passed the behavioural sandbox.
| Layer | What it checks | Result |
|---|---|---|
| L0 | Provenance & inventory | PASS |
| L1 | Static analysis of the code | PASS |
| L2 | Instruction surface (what it tells the agent) | PASS |
| L3 | Class-specific surface | PASS |
| L4 | Behavioural (sandbox) | SKIPPED |
What the source does
- Filesystem
- none-observed
- Network
- none-observed
- Shell
- none-observed
- Dependencies
- pinned
- Secrets in source
- none-found
Findings (0)
No findings outside the package's declared scope.
Gates applied: no_behavioural_pass.
4f83675ca38afull audit observations/trust-audit/skill/jeremylongshore__clay-data-handling.json · Report an issue / request a re-scanAudit history
Every audit this skill has had.
| Date | Source | Verdict | Grade | Score | Change |
|---|---|---|---|---|---|
| 2026-10-08 | 4f83675ca38a | SAFE | B | 89 | first audit |
Questions
What does the Clay Data Handling skill do?
Model-agnostic agent-skills platform with a harness-free canonical layer, verified adapters, and the ccpi package manager. Explore at tonsofskills.com.
Is Clay Data Handling safe to install?
The audit found nothing in the source that contradicts what it says it does, and graded it B (89/100). Grade A is held back for packages that have also passed a sandboxed behavioural run, which is why a clean skill reads B.
What can Clay Data Handling access on my machine?
The audit observed no filesystem, network or shell use at all in its source.
Which assistants does Clay Data Handling work with?
Its documentation mentions claude-code. That is what the text claims, not a compatibility test we ran.
How current is this page?
The grade is for one exact copy of the source (4f83675ca38a), read on 2026-10-08. The repository is watched, and a new audit runs when it changes — this is the first audit.