Skip to main content 홈 크리에이터 comeonoliver skillshub clay-policy-guardrails
clay-policy-guardrails Implement credit spending limits, data privacy enforcement, and input validation guardrails for Clay pipelines.
Use when enforcing spending caps, blocking PII enrichment,
or adding pre-enrichment validation rules.
Trigger with phrases like "clay policy", "clay guardrails", "clay spending limit",
"clay data privacy rules", "clay validation", "clay controls".
설치로 이동 Skills Marketplace 커뮤니티가 만든 AI 스킬을 발견하고 탐색하세요.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
직접 명령은 검토 Prompt를 거치지 않습니다. 실행하기 전에 소스를 확인하세요.
npx skills add https://github.com/ComeOnOliver/skillshub --skill clay-policy-guardrails명령은 한 줄로 유지됩니다. 복사하기 전에 가로로 스크롤해 전체 내용을 확인하세요.
로컬 사본을 원하시나요? SkillsMP에서 현재 제공할 수 있는 파일을 다운로드하세요.
Zip 다운로드 다운로드 중... 이 저장소의 다른 Skills Review product and feature risk before an AI coding agent starts implementation.
Use Xquik for X data and confirmation-gated X actions: tweet search, user lookup, follower export, media download, monitors, webhooks, MCP, and SDK workflows.
Canton Network open-source ecosystem guide covering DAML SDK, Canton runtime, and Splice applications. Use when working with Canton Network, DAML smart contracts, or building decentralized applications.
name clay-policy-guardrails description Implement credit spending limits, data privacy enforcement, and input validation guardrails for Clay pipelines.
Use when enforcing spending caps, blocking PII enrichment,
or adding pre-enrichment validation rules.
Trigger with phrases like "clay policy", "clay guardrails", "clay spending limit",
"clay data privacy rules", "clay validation", "clay controls".
allowed-tools Read, Write, Edit, Bash(node:*) version 1.0.0 license MIT author Jeremy Longshore <jeremy@intentsolutions.io> compatible-with claude-code, codex, openclaw tags ["saas","clay","clay-policy"]
Clay Policy Guardrails
Overview
Policy enforcement and guardrails for Clay data enrichment pipelines. Clay processes personal and business data at scale, requiring strict controls around credit spending, data privacy compliance, input validation, and export restrictions.
Prerequisites
Clay integration in production or pre-production
Understanding of GDPR/CCPA requirements
Credit budget defined by management
Data classification policy for your organization
Instructions
Step 1: Credit Spending Guardrails
interface CreditPolicy {
dailyLimit : number ;
perTableLimit : number ;
perBatchLimit : number ;
alertThresholdPct : number ;
hardStopEnabled : boolean ;
}
const CREDIT_POLICIES : Record <string , CreditPolicy > = {
conservative : {
dailyLimit : 200 ,
perTableLimit : 500 ,
perBatchLimit : 100 ,
alertThresholdPct : 70 ,
hardStopEnabled : true ,
},
standard : {
dailyLimit : 500 ,
perTableLimit : 2000 ,
perBatchLimit : 500 ,
alertThresholdPct : 80 ,
hardStopEnabled : true ,
},
: {
: ,
: ,
: ,
: ,
: ,
},
};
{
dailyUsed = ;
tableUsage = < , >();
( ) {}
( : , : , : ): {
: ;
?: ;
} {
estimated = rowCount * creditsPerRow;
(estimated > . . ) {
{
: ,
: ,
};
}
( . + estimated > . . ) {
( . . ) {
{
: ,
: ,
};
}
. ( );
}
tableTotal = ( . . (tableId) || ) + estimated;
(tableTotal > . . ) {
{
: ,
: ,
};
}
dailyPct = (( . + estimated) / . . ) * ;
(dailyPct > . . ) {
. ( );
}
{ : };
}
( ) {
. += credits;
. . (tableId, ( . . (tableId) || ) + credits);
}
}
aggressive
dailyLimit
2000
perTableLimit
10000
perBatchLimit
2000
alertThresholdPct
90
hardStopEnabled
false
class
CreditPolicyEnforcer
private
0
private
new
Map
string
number
constructor
private policy : CreditPolicy
checkBatch
tableId
string
rowCount
number
creditsPerRow
number
allowed
boolean
reason
string
const
if
this
policy
perBatchLimit
return
allowed
false
reason
`Batch (${estimated} credits) exceeds per-batch limit (${this .policy.perBatchLimit} ). Split into smaller batches.`
if
this
dailyUsed
this
policy
dailyLimit
if
this
policy
hardStopEnabled
return
allowed
false
reason
`Would exceed daily limit: ${this .dailyUsed} + ${estimated} > ${this .policy.dailyLimit} `
console
warn
`WARNING: Exceeding daily limit (${this .dailyUsed + estimated} /${this .policy.dailyLimit} )`
const
this
tableUsage
get
0
if
this
policy
perTableLimit
return
allowed
false
reason
`Table ${tableId} would exceed limit: ${tableTotal} > ${this .policy.perTableLimit} `
const
this
dailyUsed
this
policy
dailyLimit
100
if
this
policy
alertThresholdPct
console
warn
`Credit alert: ${dailyPct.toFixed(0 )} % of daily limit used`
return
allowed
true
recordUsage
tableId : string , credits : number
this
dailyUsed
this
tableUsage
set
this
tableUsage
get
0
Step 2: Data Privacy Guardrails
const BLOCKED_ENRICHMENT_FIELDS = new Set ([
'ssn' , 'social_security' , 'tax_id' ,
'date_of_birth' , 'dob' , 'birthday' ,
'home_address' , 'home_phone' ,
'personal_phone' , 'personal_mobile' ,
'bank_account' , 'credit_card' ,
'medical_history' , 'health_records' ,
'salary' , 'compensation' ,
'political_affiliation' , 'religion' ,
'ethnic_origin' , 'sexual_orientation' ,
]);
const CONSENT_REQUIRED_FIELDS = new Set ([
'personal_email' , 'phone_number' , 'mobile_phone' ,
]);
interface PrivacyCheckResult {
allowed : boolean ;
violations : string [];
warnings : string [];
}
function checkPrivacy (
fieldsToEnrich : string [],
hasExplicitConsent : boolean = false ,
): PrivacyCheckResult {
const violations : string [] = [];
const warnings : string [] = [];
for (const field of fieldsToEnrich) {
const normalized = field.toLowerCase ().replace (/[\s-]/g , '_' );
if (BLOCKED_ENRICHMENT_FIELDS .has (normalized)) {
violations.push (`BLOCKED: "${field} " is a restricted field (never enrich)` );
}
if (CONSENT_REQUIRED_FIELDS .has (normalized) && !hasExplicitConsent) {
warnings.push (`CONSENT: "${field} " requires explicit consent to enrich` );
}
}
return {
allowed : violations.length === 0 ,
violations,
warnings,
};
}
Step 3: Input Validation Guardrails
const PERSONAL_EMAIL_DOMAINS = new Set ([
'gmail.com' , 'yahoo.com' , 'hotmail.com' , 'outlook.com' , 'icloud.com' ,
'aol.com' , 'protonmail.com' , 'mail.com' , 'yandex.com' , 'gmx.com' ,
]);
const DISPOSABLE_EMAIL_DOMAINS = new Set ([
'tempmail.com' , 'guerrillamail.com' , 'throwaway.email' , 'yopmail.com' ,
'mailinator.com' , '10minutemail.com' , 'trashmail.com' ,
]);
interface ValidationResult {
valid : Record <string , unknown >[];
rejected : { row : Record <string , unknown >; reason : string }[];
stats : {
total : number ;
valid : number ;
invalidDomain : number ;
personalDomain : number ;
disposableDomain : number ;
missingRequiredField : number ;
duplicates : number ;
};
}
function validateBatch (
rows : Record <string , unknown >[],
requiredFields : string [] = ['domain' ],
): ValidationResult {
const seen = new Set <string >();
const stats = {
total : rows.length , valid : 0 , invalidDomain : 0 ,
personalDomain : 0 , disposableDomain : 0 , missingRequiredField : 0 , duplicates : 0 ,
};
const valid : Record <string , unknown >[] = [];
const rejected : { row : Record <string , unknown >; reason : string }[] = [];
for (const row of rows) {
const missing = requiredFields.filter (f => !row[f]);
if (missing.length > 0 ) {
rejected.push ({ row, reason : `Missing required: ${missing.join(', ' )} ` });
stats.missingRequiredField ++;
continue ;
}
const domain = String (row.domain || '' ).toLowerCase ().trim ();
if (!domain.includes ('.' ) || domain.length < 4 ) {
rejected.push ({ row, reason : `Invalid domain: "${domain} "` });
stats.invalidDomain ++;
continue ;
}
if (PERSONAL_EMAIL_DOMAINS .has (domain)) {
rejected.push ({ row, reason : `Personal email domain: ${domain} ` });
stats.personalDomain ++;
continue ;
}
if (DISPOSABLE_EMAIL_DOMAINS .has (domain)) {
rejected.push ({ row, reason : `Disposable email domain: ${domain} ` });
stats.disposableDomain ++;
continue ;
}
const key = `${domain} :${String (row.first_name || '' ).toLowerCase()} :${String (row.last_name || '' ).toLowerCase()} ` ;
if (seen.has (key)) {
stats.duplicates ++;
continue ;
}
seen.add (key);
valid.push ({ ...row, domain });
stats.valid ++;
}
return { valid, rejected, stats };
}
Step 4: Export Restrictions
type ExportDestination = 'crm' | 'outreach' | 'analytics' | 'csv' ;
const EXPORT_RULES : Record <ExportDestination , {
allowedFields : string [];
blockedFields : string [];
requiresApproval : boolean ;
}> = {
crm : {
allowedFields : ['email' , 'first_name' , 'last_name' , 'company_name' , 'job_title' , 'icp_score' ],
blockedFields : ['personal_email' , 'home_address' ],
requiresApproval : false ,
},
outreach : {
allowedFields : ['email' , 'first_name' , 'company_name' , 'personalized_opener' ],
blockedFields : ['phone_number' , 'linkedin_url' , 'personal_email' ],
requiresApproval : false ,
},
analytics : {
allowedFields : ['company_name' , 'industry' , 'employee_count' , 'icp_score' ],
blockedFields : ['email' , 'first_name' , 'last_name' , 'phone_number' ],
requiresApproval : false ,
},
csv : {
allowedFields : ['*' ],
blockedFields : ['personal_email' , 'home_address' , 'ssn' ],
requiresApproval : true ,
},
};
function filterForExport (
rows : Record <string , unknown >[],
destination : ExportDestination ,
): Record <string , unknown >[] {
const rules = EXPORT_RULES [destination];
return rows.map (row => {
const filtered : Record <string , unknown > = {};
for (const [key, value] of Object .entries (row)) {
if (rules.blockedFields .includes (key)) continue ;
if (rules.allowedFields [0 ] !== '*' && !rules.allowedFields .includes (key)) continue ;
filtered[key] = value;
}
return filtered;
});
}
Error Handling Issue Cause Solution Credit overrun No spending limits enforced Implement credit policy enforcer PII enrichment violation No privacy checks Add blocked field validation Wasted credits on bad data No input validation Pre-validate all batches Unauthorized data export No export restrictions Implement per-destination field filtering
Resources
Next Steps For architecture patterns at scale, see clay-architecture-variants.