exa-search · diff
git:20260427.a3e615e to git:20261019.6849eaf
70 added, 211 removed. Audit A to A.
---
name: exa-search
- description: Search the web with Exa AI — neural search, content extraction, similar page discovery, quick research with citations, and async pro research with structured output. Covers all Exa endpoints (/search, /contents, /findSimilar, /answer, /research/v0/tasks). Triggers on web search, find pages, similar pages, research with citations, Exa, neural search.
- ---
-
- # Exa Search Skill
-
- 5 specialized scripts for Exa AI search API—neural search, content extraction, similar pages, research with citations, and async pro research.
-
- **Prerequisite:** `EXA_API_KEY` environment variable. Get key at https://dashboard.exa.ai
-
- ## Token-Efficient Search
-
- Inspired by Anthropic's [dynamic filtering](https://claude.com/blog/improved-web-search-with-dynamic-filtering)—always filter before reasoning. ~24% fewer tokens, ~11% better accuracy.
-
- ### The Principle: Search Cheaply → Filter → Extract Selectively → Reason
-
- **DO:**
- ```bash
- # Step 1: Search with --no-text (titles/URLs only — cheapest)
- python3 ~/.claude/skills/exa-search/scripts/exa_search.py "query" -n 20 --no-text
-
- # Step 2: Evaluate titles, pick best 3-5 URLs
-
- # Step 3: Extract only those URLs with bounded content
- python3 ~/.claude/skills/exa-search/scripts/exa_contents.py URL1 URL2 --highlights --max-chars 3000
- ```
-
- **DON'T:** Search with full text for 50 results, then reason over all of it.
-
- ### Use API-Level Filters First (Free Filtering)
-
- These reduce results at the API level before you ever see them:
-
- - `--must-include "term"` — results must contain this string
- - `--must-exclude "term"` — removes irrelevant results
- - `--domains site1.com site2.com` — restrict to authoritative sources
- - `--category "research paper"` — eliminate irrelevant content types
- - `--after 2025-01-01` / `--before` — temporal filtering
-
- ### Use Summaries Over Full Text
-
- When you need the gist, not raw content:
- ```bash
- # AI-distilled summaries — much smaller than full text
- python3 ~/.claude/skills/exa-search/scripts/exa_search.py "query" --summary "Key findings" -n 5
- ```
-
- ### Use Bounded Context for RAG
-
- ```bash
- # Capped context string — prevents unbounded token usage
- python3 ~/.claude/skills/exa-search/scripts/exa_search.py "query" --context --context-chars 5000
- ```
-
- ### Post-Process with filter_web_results.py
-
- Pipe Exa JSON output through the Firecrawl filter script for additional reduction:
- ```bash
- python3 ~/.claude/skills/exa-search/scripts/exa_search.py "query" --json | \
- python3 ~/.claude/skills/firecrawl/scripts/filter_web_results.py \
- --fields "title,url,text" --max-chars 3000
- ```
-
- ### Cost Tiers — Match to Task
-
- | Type | Latency | Cost/1k | When |
- |------|---------|---------|------|
- | `--instant` | <150ms | Cheapest | Real-time lookups, autocomplete |
- | `--fast` | ~500ms | Low | Quick checks, confirmations |
- | `auto` (default) | -- | Medium | General search |
- | `--deep` | 4-12s | $12 | Comprehensive research |
- | `--deep-reasoning` | 12-50s | $15 | Maximum depth + synthesis |
-
- ### Structured Deep Search (Exa Deep)
-
- Deep and deep-reasoning searches support structured JSON output via `outputSchema`. The API returns parsed content in `output.content` with per-field grounding citations and confidence scores.
-
- | Quick Example | Purpose |
- |---------------|---------|
- | `... --deep --text-output "Short answer"` | Simple text answer |
- | `... --deep-reasoning --schema-preset company` | Structured company research |
- | `... --deep --output-schema '{"type":"object","properties":{"answer":{"type":"string"}}}'` | Custom schema |
- | `... --deep --schema-file ~/schemas/analysis.json` | Schema from file |
-
- Presets: `company`, `paper-survey`, `competitor-analysis`, `person`, `news-digest`
-
- Output includes field-level grounding: per-field citations with [H]igh/[M]edium/[L]ow confidence.
-
+ description: Searches the web through Exa 3.0 with six Python scripts—lite/auto/deep search with category, domain, and date filters, Dynamic Highlights, structured output with field-level citations, clean extraction from known URLs, cited answers, and the async Agent API for list building, enrichment, and multi-hop research. This skill should be used for any web search, fact lookup, current events, finding papers, companies, people, or news, reading known URLs, questions that need cited answers, building lists of entities that match criteria, or enriching records with web data. It is the default web search tool (built-in WebSearch is blocked). Triggers on search the web, look up, find pages, research with citations, Exa, list of companies, enrich.
---
- ## Available Scripts
-
- ### 1. exa_search.py — Neural Web Search
-
- ```bash
- python3 ~/.claude/skills/exa-search/scripts/exa_search.py "query" [options]
- ```
-
- | Quick Example | Purpose |
- |---------------|---------|
- | `... exa_search.py "AI frameworks"` | Basic search |
- | `... exa_search.py "transformers" --category "research paper" -n 20` | Academic papers |
- | `... exa_search.py "query" --deep --additional-queries "alt query"` | Deep search |
- | `... exa_search.py "query" --domains docs.python.org` | Domain-filtered |
- | `... exa_search.py "query" --after 2025-01-01 --category news` | Recent news |
- | `... exa_search.py "query" --context --context-chars 10000` | RAG context |
- | `... exa_search.py "query" --instant -n 5` | Sub-150ms lookup |
- | `... exa_search.py "Top AI startups" --deep-reasoning --schema-preset company` | Structured company research |
- | `... exa_search.py "Who is CEO of Stripe?" --deep --text-output "Short answer"` | Quick factual answer |
-
- **Categories:** company, research paper, news, pdf, github, personal site, people, financial report
-
- ### 2. exa_contents.py — URL Content Extraction
-
- ```bash
- python3 ~/.claude/skills/exa-search/scripts/exa_contents.py URL [URL2...] [options]
- ```
-
- | Quick Example | Purpose |
- |---------------|---------|
- | `... exa_contents.py "https://arxiv.org/abs/2307.06435"` | Extract paper |
- | `... exa_contents.py URL --summary "Key methods" --highlights` | Summarized extraction |
- | `... exa_contents.py URL --livecrawl always` | Fresh content |
- | `... exa_contents.py URL --max-chars 5000` | Bounded extraction |
-
- ### 3. exa_similar.py — Find Similar Pages
+ # Exa Search
- ```bash
- python3 ~/.claude/skills/exa-search/scripts/exa_similar.py URL [options]
- ```
+ Six scripts over Exa 3.0 (API spec 2.0.0, synced 2026-10-19). `S=~/.claude/skills/exa-search/scripts`.
- | Quick Example | Purpose |
- |---------------|---------|
- | `... exa_similar.py "https://stripe.com" --category company --exclude-source` | Find competitors |
- | `... exa_similar.py "https://arxiv.org/abs/..." -n 15` | Related papers |
- | `... exa_similar.py URL --summary "How different?"` | Comparison summaries |
+ **Prerequisite:** `EXA_API_KEY` (https://dashboard.exa.ai).
- ### 4. exa_research.py — AI-Powered Research
+ ## Pick the Script
- ```bash
- python3 ~/.claude/skills/exa-search/scripts/exa_research.py "question" [options]
- ```
+ | Task | Command |
+ |---|---|
+ | Quick lookup, cheapest | `python3 $S/exa_search.py "query" --lite --highlights --no-text` |
+ | General web search | `python3 $S/exa_search.py "query" --highlights --no-text` |
+ | Papers / companies / people / news | `... exa_search.py "query" --category publication` (or `company`, `people`, `news`) |
+ | Read known URLs | `python3 $S/exa_contents.py URL1 URL2 --highlights --no-text` |
+ | Cited answer | `python3 $S/exa_research.py "question" --sources` |
+ | Cited answer from specific sites/dates | `... exa_research.py "question" --domains a.org --after 2026-01-01` (routes to /search) |
+ | One synthesized answer or JSON from a search | `... exa_search.py "question" --text-output "Short answer"` / `--schema-preset company` |
+ | Multi-step research, lists, enrichment | `python3 $S/exa_agent.py run "task" --effort medium` (see `references/agent-api.md`) |
+ | Pages like a URL | `python3 $S/exa_similar.py URL` (deprecated endpoint; prefer a descriptive `exa_search.py` query) |
- | Quick Example | Purpose |
- |---------------|---------|
- | `... exa_research.py "React vs Vue differences?" --sources` | Research with citations |
- | `... exa_research.py "query" --stream` | Real-time streaming |
- | `... exa_research.py "query" --domains docs.python.org` | Authoritative sources |
- | `... exa_research.py "query" --markdown` | Markdown with citations |
- | `... exa_research.py "query" --answer-only` | Pipe-friendly output |
+ ## Token-Efficient Recipe
- ### 5. exa_research_async.py — Async Pro Research
+ Search cheaply → pick URLs → extract selectively → reason.
```bash
- python3 ~/.claude/skills/exa-search/scripts/exa_research_async.py "question" [options]
+ python3 $S/exa_search.py "query" --lite --highlights --no-text -n 10 # ranked excerpts, no full text
+ python3 $S/exa_contents.py URL1 URL2 --highlights-query "what I need" --no-text
+ python3 $S/exa_contents.py URL1 --max-chars 5000 # full text only when needed
```
- | Quick Example | Purpose |
- |---------------|---------|
- | `... exa_research_async.py "Compare AI frameworks" --pro --wait` | Pro model |
- | `... exa_research_async.py "Quick overview" --fast` | Fast model |
- | `... exa_research_async.py "query" --schema '{...}'` | Structured output |
- | `... exa_research_async.py status r_abc123` | Check job |
- | `... exa_research_async.py list` | List jobs |
-
- ---
-
- ## Script Selection Guide
-
- | Task | Best Script |
- |------|-------------|
- | Web search with filters | `exa_search.py` |
- | Research papers | `exa_search.py --category "research paper"` |
- | Company/startup info | `exa_search.py --category company` |
- | GitHub repos/code | `exa_search.py --category github` |
- | Extract known URL content | `exa_contents.py` |
- | Find competitors | `exa_similar.py --exclude-source` |
- | Quick answers with citations | `exa_research.py --sources` |
- | Complex structured research | `exa_research_async.py --pro` |
- | Real-time search | `exa_search.py --instant` |
- | RAG context building | `exa_search.py --context` |
- | Structured research with grounding | `exa_search.py --deep-reasoning --schema-preset company` |
- | Quick factual answer | `exa_search.py --deep --text-output "Short answer"` |
+ - Highlights beat full text: 500 chars of highlights match 8,000 chars of text on SimpleQA.
+ - Text is **on by default** in `exa_search.py`; `--no-text` saves context, not dollars (lite and auto bundle contents for 10 results).
+ - `--dynamic` (Dynamic Highlights) shares one budget across all results—use it when the results feed one context.
+ - Filter at the API: `--domains`, `--exclude-domains`, `--category`, `--after/--before`.
+ - Post-filter JSON: `... --json | python3 ~/.claude/skills/firecrawl/scripts/filter_web_results.py --fields "title,url,highlights" --max-chars 3000`.
- ## Exa vs Firecrawl vs Native Claude Tools
+ ## Search Types and Cost
- | Need | Best Tool | Why |
- |------|-----------|-----|
- | Semantic/neural search | Exa `exa_search.py` | AI-powered relevance |
- | Find research papers | Exa `--category "research paper"` | Academic index |
- | Quick research answer | Exa `exa_research.py` | Citations + synthesis |
- | Find similar pages | Exa `exa_similar.py` | Semantic similarity |
- | Single page → markdown | Firecrawl `scrape --only-main-content` | Cleanest output |
- | Crawl entire site | Firecrawl `crawl --wait --progress` | Link following |
- | Autonomous data finding | Firecrawl `agent` | No URLs needed |
- | Search + scrape combined | Firecrawl `search --scrape` | One operation |
- | Claude API agent building | Native `web_search_20260209` | Built-in dynamic filtering |
- | Twitter/X content | `jina URL` | Only tool that works |
+ | Flag | Latency | $/1k requests | Notes |
+ |---|---|---|---|
+ | `--lite` | ~450ms | $4 | Cache only. Accepts query, `--objective`, category, `-n`, domains, dates, text, highlights, `--snapshot-as-of`, `--location`, `--safe`—nothing else |
+ | (default `auto`) | ~1s | $7 | Best balance; full parameter set |
+ | `--deep-lite` | ~4s | $12 | Lightweight synthesis; `--additional-queries` |
+ | `--deep` | 4–15s | $12 | Multi-step search and synthesis |
+ | legacy `--fast` / `--instant` / `--deep-reasoning` / `--neural` | — | $7 / $4 / $15 / — | Still accepted with a stderr hint |
- ---
+ Extras: results above 10 add $1/1k; `--summary` adds $1/1k pages; `exa_contents.py` is $1/1k pages per content type; `exa_research.py` is $5/1k. Agent runs: `medium` $0.10 (script default), `auto` metered ≤$5, `ultra` metered ≤$20; full effort table in `references/agent-api.md`.
- ## Common Workflows
+ ## Structured Output
- ### Research a Topic
- ```bash
- python3 ~/.claude/skills/exa-search/scripts/exa_research.py "How does RAG work?" --sources --markdown
- ```
+ `--text-output "desc"`, `--output-schema JSON`, `--schema-file F`, or `--schema-preset` (`company`, `paper-survey`, `competitor-analysis`, `person`, `news-digest`) work on **every type except lite**, within **10 properties in total** (nested and array-item properties count) and 2 levels; every array needs `items`. The answer arrives in `output.content`; `output.grounding` gives per-field citations with `[H]/[M]/[L]` confidence. Add `--system-prompt` for format or tone.
- ### Literature Review
- ```bash
- # Find papers, then find similar to best hit
- python3 ~/.claude/skills/exa-search/scripts/exa_search.py "transformer optimization" --category "research paper" -n 20 --summary "Key contributions"
- python3 ~/.claude/skills/exa-search/scripts/exa_similar.py "https://arxiv.org/abs/1706.03762" --category "research paper" -n 15
- ```
+ ## Gotchas
- ### Documentation Research
- ```bash
- python3 ~/.claude/skills/exa-search/scripts/exa_search.py "React useEffect cleanup" --domains react.dev developer.mozilla.org --context
- ```
+ - **`/answer` has no source filters.** `exa_research.py` sends `--domains`, `--exclude-domains`, `--after`, `--before`, and `-n` to `/search` (auto + text schema, $7/1k) and says so on stderr. Without them it uses `/answer`, where `--model exa|exa-pro|exa-fast|exa-research` and `--stream` apply.
+ - **Lite rejects** summary, schemas, system prompts, freshness, context, subpages, and extras with a 400 that names the field. Drop `--lite`.
+ - **Lite drops uncached pages** when text or highlights are requested, so fewer than `-n` results is normal; rerun without `--lite` when coverage matters.
+ - **`/search` object schemas cap at 10 properties in total and 2 nesting levels.** Larger shapes go to `exa_agent.py`. Never add citation or confidence fields—grounding has them.
+ - **`--dynamic`** sends the `Exa-Beta: dynamic-highlights-2026-08-28` header and cannot combine with `--highlights-max-chars`.
+ - **`--category company`/`people`** reject `--after/--before`; `people` also rejects `--exclude-domains`.
+ - **Categories:** `research paper` is now `publication` (auto-mapped); `pdf`/`github` were deprecated in Exa's 2026-07-23 changelog and now pass as soft hints; `tweet` is rejected.
+ - **Warnings vs notices:** warnings (ignored or deprecated fields) go to stderr; notices (e.g. restrictions relaxed) print with the results—read them before trusting the results.
+ - **Repeated list flags accumulate:** `--domains a.com --domains b.com` and `--domains a.com,b.com` both send both domains.
+ - **Freshness:** `--max-age-hours 0` always fetches fresh, `-1` is cache only. `--livecrawl` still works but is mapped (always→0, preferred→1, never→-1). `--snapshot-as-of DATE` returns historical versions: pay-as-you-go gets a 100-request trial, a rolling 5-month window, and 10 results or 1 contents URL per request; Free gets 403. It excludes freshness flags, `--subpages`, `--category`, and `--deep`.
+ - **Deprecated but sent:** `--must-include/--must-exclude` (approximate word matching), `--context`, and `--subpages` on search (use `exa_contents.py --subpages`).
+ - **Retired:** `exa_research_async.py` (Research API returns 410, probed 2026-10-19) prints the `exa_agent.py` equivalent and exits 2.
+ - **Agent runs are async and cost money:** the script always sends `--effort` (default `medium`) and polls to completion. Pair `--effort auto`/`ultra` with `--max-cost` (otherwise the cap is $5/$20); fixed efforts reject it. If polling is lost, the run continues and the script prints `status RUN_ID --wait` (exit 3).
+ - **Exit codes:** 0 ok; 1 API, network, or failed/cancelled run; 2 usage; 3 agent run still going; 4 `exa_research.py` got no answer. `exa_contents.py` exits 1 when every URL failed.
- ### Build RAG Context
- ```bash
- python3 ~/.claude/skills/exa-search/scripts/exa_search.py "Python async patterns" --context --context-chars 15000 --domains docs.python.org
- ```
+ ## Exa vs Other Tools
- ---
+ | Need | Tool |
+ |---|---|
+ | Semantic search, papers, companies, people | Exa `exa_search.py` |
+ | Researched lists, enrichment, multi-hop | Exa `exa_agent.py` |
+ | Single page → clean markdown | Firecrawl `scrape --only-main-content` |
+ | Crawl an entire site | Firecrawl `crawl` |
+ | Twitter/X content | `jina URL` |
+ | Exa inside an MCP client | `https://mcp.exa.ai/mcp` (`web_search_exa`, `web_fetch_exa`, `web_search_advanced_exa`, `agent_run`) |
- ## Reference Documentation
+ ## References
| File | Contents |
- |------|----------|
- | `references/exa-scripts-reference.md` | Full parameter reference for all 5 scripts, cost table, MCP comparison, test suite |
+ |---|---|
+ | `references/exa-scripts-reference.md` | Every flag of every script, legacy-flag map, output shapes, tests |
+ | `references/agent-api.md` | Agent API: effort choice, task writing, schemas, budgets, run lifecycle |
+ | `references/exa-docs-2026-10-19/` | Exa docs and OpenAPI spec snapshot (source of truth for this sync) |
- ## Test Suite
+ ## Tests
```bash
- python3 ~/.claude/skills/exa-search/scripts/test_exa.py --quick # Quick validation
- python3 ~/.claude/skills/exa-search/scripts/test_exa.py # Full suite
- python3 ~/.claude/skills/exa-search/scripts/test_exa.py --endpoint search # Specific endpoint
+ python3 $S/test_exa.py --quick # offline: no key, no network
+ python3 $S/test_exa.py # offline + live (~$0.15)
+ python3 $S/test_exa.py --endpoint agent # live, one endpoint
```