| name | exa-lead-gen |
| description | Generate enriched lead lists using Exa deep search. Finds companies matching an ICP, enriches with signals/news/scores, and outputs CSV. Use when generating leads, building prospect lists, finding companies to sell to, doing outbound research, or ICP-based company discovery. Triggers on "leads", "lead gen", "prospect list", "find companies", "ICP", "outbound list". |
| context | fork |
MCP server note (this workspace): Exa tools come from the exa-search MCP server — mcp__exa-search__web_search_advanced_exa and mcp__exa-search__deep_search_exa. Load them via ToolSearch if not already available.
Lead Generation with Exa Deep Search
Generate large, enriched lead lists by running parallel Exa deep searches across micro-verticals derived from an Ideal Customer Profile (ICP).
See reference.md for the full ICP-research outputSchema, the three-param deep dive and 400-error constraints, the enrichment-field catalog, and the subagent + systemPrompt templates. Run scripts/compile_leads_csv.py (after editing its CONFIG header) for the Step 5 CSV compile.
Prerequisites
This skill requires the exa-search MCP server with the deep_search_exa tool (including outputSchema and systemPrompt support).
If mcp__exa-search__deep_search_exa is unavailable, tell the user:
You need the Exa MCP server installed with your API key.
Instructions: https://docs.exa.ai/reference/exa-mcp
Then stop.
Tool Restriction
ONLY use mcp__exa-search__deep_search_exa, the Task tool (to spawn batch subagents), Write, and Bash (for the Python CSV compile). Do NOT use web search, file reads of raw lead JSON, or other Exa tools.
Architecture: Subagent-Driven Lead Gen
The main agent (you) never touches raw lead data. This keeps your context lean and prevents token bloat.
Main Agent (orchestrator — lean context)
├── Step 1: ICP research (1 exa call, user confirms/refines)
├── Step 2: Generate micro-verticals (LLM reasoning, no API)
├── Step 3: Design outputSchema (LLM reasoning, no API)
├── Step 4: Spawn batch subagents ──┐
│ Each batch subagent: │
│ - Receives 5 micro-verticals │
│ - Runs 5 exa deep calls │
│ - Writes JSON to /tmp files │
│ - Reports back ONLY the count │
├── Step 5: Python CSV compiler (reads JSON files, dedupes, outputs CSV)
└── Step 6: Summary
Why subagents? Each exa deep call returns ~45 companies as structured JSON (5-15K tokens). For 1000 leads (~30 calls), that's 150-450K tokens of raw data. The main agent doesn't need any of it — the Python script handles dedup/sort/CSV. Subagents process the data, write to files, dispose their context, and report back just the count.
Why batches of 5? Each subagent runs 5 exa calls in parallel (the practical max). For 30 micro-verticals: 6 batch subagents. Less overhead than 1-per-call (30 spawns), avoids the context bloat of one giant subagent.
The Three Params (in brief)
Each deep_search_exa call has three distinct params: objective (the query — keywords that place it in Exa's embedding space), systemPrompt (the brain — how to score, what to exclude, how many results), and outputSchema (the structure — exact fields and enrichment level).
REQUIRED on every deep_search_exa call — no exceptions: structuredOutput: true, numResults: 50 (matching the systemPrompt's "exactly 50" target), highlightMaxCharacters: 1, type: "deep". Always use type: "deep" — deep-reasoning is for single complex research questions, not bulk lead gen.
Every string field in any outputSchema MUST include a length constraint in its description (e.g. "in 12 words or less"). Never leave a string field unconstrained.
See reference.md for the full 400-error / schema-constraint set (max 10 properties across all nesting, flat-primitive array items only, root type: object required, null silently ignored, supported field types) and the numResults/systemPrompt alignment rationale.
Step 1: Research the Target Company
When the user says "Make a list of 1000 leads for {company}", first run a single deep_search_exa call to understand the company's product and ICP. This call is small enough to run in the main context. Use the ICP-research outputSchema in reference.md (with numResults: 10).
Present the results and ask the user to confirm or refine:
- Is the ICP description accurate?
- Any sub-verticals to add/remove?
- Any companies to exclude (competitors, existing customers)?
- How many leads do they want? (default 200)
- Any specific enrichment columns they care about?
Step 2: Generate Micro-Verticals (Query Expansion)
Using the confirmed ICP and sub-verticals as seeds, expand into micro-verticals — highly specific, keyword-rich queries that each cover distinct territory in Exa's embedding space. You do this expansion yourself (no Exa call needed — LLMs are great at query expansion).
Generate MORE queries than you need: each call returns ~35-48 companies (avg ~42), and dedupe will trim some. Better to overshoot than undershoot.
Target: ceil(requested_leads / 35) micro-verticals — /35 (not /45) is intentional overshoot to absorb dedupe loss.
Query Expansion Patterns
- Competitor mining — "companies similar to {existing_customer} building {product_type}" or "alternatives to {existing_customer} in {space}". Highest-signal pattern — it directly targets the core ICP.
- Geographic breakdown — "US-based", "European", "Asia-Pacific", "Latin American" + the vertical keywords.
- Company stage breakdown — "seed-stage startups building...", "growth-stage companies building...", "enterprise companies using...".
- Technology stack — "companies using {relevant_tech} for {use_case}" (e.g. "companies using LangChain for document processing").
- Use-case decomposition — break a sub-vertical into specific use cases: instead of "AI healthcare companies", try "clinical trial matching platforms", "medical imaging AI diagnostics", "EHR data analytics tools".
- Buyer persona targeting — "companies with VP of Data Science building...", "engineering-led organizations using...".
Micro-Vertical Quality Checklist
Each micro-vertical should be:
- 4-8 descriptive keywords that place it precisely in embedding space
- Non-overlapping with other micro-verticals (minimize dedupe waste)
- Specific enough to return relevant companies (not "AI companies" — too broad)
- Broad enough to return 20+ results (not "Series B AI radiology startups in Boston" — too narrow)
Example Expansion
Sub-vertical: "Sales intelligence and data enrichment platforms" →
- "B2B sales intelligence platforms using web scraping and contact data enrichment"
- "Revenue intelligence startups analyzing call recordings and CRM data"
- "Account-based marketing platforms with intent data and buyer signals"
- "Companies similar to ZoomInfo building business contact databases"
- "European sales enablement startups with AI-powered prospecting tools"
- "Seed-stage startups building outbound sales automation and email sequencing"
Step 3: Design the Output Schema
Based on the user's prompt, the ICP research (especially useful_enrichments), and what makes sense for this campaign, craft a custom outputSchema for the lead-gen calls.
See reference.md for the full field catalog — the "always include" core fields (company_name, website, product_description, icp_fit_score, icp_fit_reasoning) plus the common enrichment fields (employee count, funding stage, key technologies, recent signals, hiring signals, competitor overlap, etc.).
Reminders: max 9 item-level fields (the companies wrapper counts as 1 of the 10-property limit), all item fields flat primitives, every string field carries a word limit. More fields = more latency — warn the user if the schema is heavy.
Step 4: Spawn Batch Subagents
Group the micro-verticals into batches of 5. For each batch, spawn a Task subagent with all the context it needs to work independently. See reference.md for the subagent prompt template and the systemPrompt template the subagent uses inside each exa call.
Spawn batch subagents in parallel via multiple Task tool calls in a single message. In practice, MCP call overhead naturally staggers requests enough to stay under Exa deep's QPS limits — 6 parallel subagents is tested-safe. For very large runs (10+ subagents), launch in waves of ~6 (Exa deep has a lower QPS limit than standard search); reduce wave size if you hit rate limits. After each wave, update the user.
Step 5: Compile CSV with Python
After all batch subagents complete, the main agent runs scripts/compile_leads_csv.py via Bash. The main agent NEVER reads the raw JSON files directly — only the script does.
Edit just the CONFIG header at the top of scripts/compile_leads_csv.py — OUTPUT_FILE, COLUMNS (matching your Step-3 outputSchema field names), and ARRAY_COLUMNS (which columns hold arrays, joined with |) — then run it. The script reads all /tmp/exa_leads_batch_*.json files, dedupes by normalized company name (case-insensitive, strips Inc/Ltd/etc.), keeps the higher icp_fit_score on collision, sorts by score descending, writes the CSV, prints summary stats, and cleans up the batch files.
Step 6: Summary
After the CSV is written, print:
## Lead Generation Complete
- Total leads: {count}
- Duplicates removed: {count}
- ICP score distribution: 8-10: {N} | 5-7: {N} | 1-4: {N}
- Exa deep calls made: {count}
- Batch subagents used: {count}
- Output: {filename}
Next step (optional): propose the high-fit rows into the workspace CRM via round investors add — proposal-only, never --yes, never write round.db directly. Otherwise the CSV stands as a standalone export.
Handling Partial Failures
- If a subagent reports failed calls, note it but continue — the micro-vertical overshoot absorbs occasional losses.
- If more than 50% of total calls fail, inform the user and suggest fewer leads.
- Never retry the exact same query — adjust the micro-vertical wording instead.
- If the Python script fails to parse a batch file, it logs a warning and skips it.
Performance Notes
- Each
deep_search_exa call takes 4-12s (longer with complex schemas). Multiple subagents run in parallel without issues.
- Yield per call: ~35-48 companies (avg ~42) when requesting 50. Budget micro-verticals via
ceil(requested_leads / 35).
- For large lists (500+), confirm before starting: "This will require ~{N} Exa deep search calls in {M} batch subagents. Proceed?"
- Subagent architecture keeps main context under ~50K tokens even for 1000+ lead runs.