Claude-code-plugins-plus-skills exa-policy-guardrails
install
source · Clone the upstream repo
git clone https://github.com/jeremylongshore/claude-code-plugins-plus-skills
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/jeremylongshore/claude-code-plugins-plus-skills "$T" && mkdir -p ~/.claude/skills && cp -r "$T/plugins/saas-packs/exa-pack/skills/exa-policy-guardrails" ~/.claude/skills/jeremylongshore-claude-code-plugins-plus-skills-exa-policy-guardrails && rm -rf "$T"
manifest:
plugins/saas-packs/exa-pack/skills/exa-policy-guardrails/SKILL.mdsource content
Exa Policy Guardrails
Overview
Policy enforcement for Exa neural search integrations. Exa searches the open web, so results may include unreliable sources, competitor content, or inappropriate material. This skill covers domain allowlists/blocklists (via Exa's
includeDomains/excludeDomains), content moderation, query sanitization, freshness policies, and per-user budget enforcement.
Prerequisites
installed and configuredexa-js- Content policy requirements defined
- Redis for per-user quota tracking (optional)
Instructions
Step 1: Domain Filtering (Built-in Exa Feature)
import Exa from "exa-js"; const exa = new Exa(process.env.EXA_API_KEY); // Exa supports up to 1200 domains in includeDomains/excludeDomains const TRUSTED_SOURCES = { medical: [ "pubmed.ncbi.nlm.nih.gov", "who.int", "cdc.gov", "nejm.org", "nature.com", "thelancet.com", ], technical: [ "github.com", "stackoverflow.com", "developer.mozilla.org", "docs.python.org", "nodejs.org", "arxiv.org", ], news: [ "reuters.com", "apnews.com", "bbc.com", "techcrunch.com", "arstechnica.com", ], }; const BLOCKED_DOMAINS = [ "competitor1.com", "competitor2.io", "spam-farm.com", "content-mill.net", ]; async function policySearch( query: string, category: keyof typeof TRUSTED_SOURCES | "general" ) { const opts: any = { type: "auto", numResults: 10, text: { maxCharacters: 1000 }, moderation: true, // Exa's built-in content moderation }; if (category !== "general" && TRUSTED_SOURCES[category]) { opts.includeDomains = TRUSTED_SOURCES[category]; } else { opts.excludeDomains = BLOCKED_DOMAINS; } return exa.searchAndContents(query, opts); }
Step 2: Query Content Policy
const BLOCKED_PATTERNS = [ /how to (hack|exploit|attack|ddos)/i, /(buy|purchase|order)\s+(drugs|weapons|firearms)/i, /personal.*(address|phone|ssn|social security)/i, /generate.*(malware|ransomware|virus)/i, ]; function validateQuery(input: string): string { for (const pattern of BLOCKED_PATTERNS) { if (pattern.test(input)) { throw new PolicyViolation("Query blocked by content policy"); } } // Sanitize return input .replace(/[<>{}]/g, "") // strip HTML/template chars .replace(/\0/g, "") // remove null bytes .trim() .substring(0, 500); // cap query length } class PolicyViolation extends Error { constructor(message: string) { super(message); this.name = "PolicyViolation"; } }
Step 3: Freshness Policy
// Enforce minimum recency for time-sensitive use cases function applyFreshnessPolicy( opts: any, maxAgeDays: number ): any { const cutoff = new Date(Date.now() - maxAgeDays * 24 * 60 * 60 * 1000); return { ...opts, startPublishedDate: cutoff.toISOString(), }; } // Usage: only return results from the last 90 days const results = await exa.searchAndContents("AI regulation updates", applyFreshnessPolicy( { type: "neural", numResults: 10, text: true }, 90 // max 90 days old ) );
Step 4: Per-User Budget Enforcement
class ExaUsagePolicy { private usage = new Map<string, { count: number; resetAt: number }>(); private limits: Record<string, number>; constructor(limits: Record<string, number> = { "free": 10, "pro": 100, "enterprise": 1000, }) { this.limits = limits; } checkQuota(userId: string, tier: string): void { const limit = this.limits[tier] || this.limits["free"] || 10; const now = Date.now(); const hourKey = `${userId}:${new Date().toISOString().substring(0, 13)}`; let entry = this.usage.get(hourKey); if (!entry || entry.resetAt < now) { entry = { count: 0, resetAt: now + 3600 * 1000 }; } if (entry.count >= limit) { throw new PolicyViolation( `Hourly search quota exceeded: ${entry.count}/${limit}` ); } entry.count++; this.usage.set(hourKey, entry); } } const usagePolicy = new ExaUsagePolicy();
Step 5: Combined Policy Enforcement
async function enforcedSearch( userId: string, userTier: string, rawQuery: string, category: keyof typeof TRUSTED_SOURCES | "general" = "general", maxAgeDays?: number ) { // 1. Check quota usagePolicy.checkQuota(userId, userTier); // 2. Validate and sanitize query const query = validateQuery(rawQuery); // 3. Build options with domain policy let opts: any = { type: "auto", numResults: 10, text: { maxCharacters: 1000 }, moderation: true, }; if (category !== "general" && TRUSTED_SOURCES[category]) { opts.includeDomains = TRUSTED_SOURCES[category]; } else { opts.excludeDomains = BLOCKED_DOMAINS; } // 4. Apply freshness policy if (maxAgeDays) { opts = applyFreshnessPolicy(opts, maxAgeDays); } // 5. Execute search return exa.searchAndContents(query, opts); }
Error Handling
| Issue | Cause | Solution |
|---|---|---|
| Competitor content in results | No domain filtering | Apply blocklist |
| Harmful query accepted | No content policy | Validate queries against blocked patterns |
| Stale results displayed | No freshness check | Apply filter |
| API cost overrun | No usage limits | Implement per-user/tier quotas |
| Blocked policy query | False positive | Review and adjust |
Resources
Next Steps
For architecture decisions, see
exa-architecture-variants. For cost control, see exa-cost-tuning.