agentleFS
exa-labsexa-labs/agent-skills/skills/build-with-exa/SKILL.md

build-with-exa

Skill67 starsChanged 2 months agoMITView on GitHub

Build applications and agents with Exa's API: search, contents extraction, answer, Agent API, monitors, websets, OpenAI-compatible endpoints, and exa-py/exa-js SDKs. Use when choosing Exa endpoints, writing Exa API calls, integrating semantic web search or research into products, or debugging Exa request shapes.

  • Reads credentials
  • Installs packages
  • Sends data out

2 other projects use a version of this, 1 of them edited.

Adopted by

Most recently taken up by

  • Other versions2 projects use a version of this.

    Word for word · 0

    None found.

    Edited · 1

    1. MoizIbnYousaf/marketing-cli★ 3359% same

    Wrote their own version · 1

    1. jackmazac/exa-cli★ 1same name

    How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.

  • In this repository4 other files it gives its agents.

The file

We split this skill into the rules it gives an agent

8 rules. About 0 are common, 1 is distinctive, and 7 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈1

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 7

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    Before picking an endpoint, decide which workflow shape fits:

    line 68
  2. Very specific:

    Default to the search endpoint: Use the search endpoint (/search) for most new integrations, then move to a more specialized Exa surface …

    line 75
  3. Very specific:

    If you define the tool yourself, make objective a required string parameter next to query, give it this description verbatim, and pass the …

    line 172
  4. Very specific:

    Do not give an LLM a search tool that takes only query.

    line 182
  5. Very specific:

    Do not decorate the recommended request without reason.

    line 183
  6. Very specific:

    Never invent category values like github, documentation, qa, or pdf.

    line 191
  7. Very specific:

    Do not treat /agent as a drop-in replacement for /search.

    line 193
  8. Very specific:

    Treat /findSimilar as deprecated.

    line 195

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Build with Exa

Scope

Included by default:

  • Core retrieval APIs: search endpoint, contents endpoint, answer endpoint
  • Long-running research workflows: Agent API (/agent)
  • Async and recurring workflows: Monitors API
  • Legacy surface: Websets API (existing integrations only; new collection-building work uses the Agent API)
  • Historical content: Exa Snapshot (snapshotAsOf on search and contents)
  • SDK guidance: Python exa-py, TypeScript exa-js

Note on data retention: /search, /contents, /answer, and /agent offer Zero Data Retention (ZDR). Websets and the Monitors API (/monitors) are not ZDR. If a use case requires ZDR, stay on the ZDR surfaces or contact Exa.

Installation

# Python
pip install exa-py

# TypeScript / JavaScript
npm install exa-js

Install the latest SDK release with the package manager so it resolves the latest release and all SDK surfaces will be available.

Authentication

export EXA_API_KEY="your_api_key_here"

Exa accepts either the x-api-key header or Authorization: Bearer <key>.

The recommended Exa search request is the query plus token-efficient content extraction, and nothing else. Content extraction is a recommendation, not a server default: omit contents and results carry only metadata (title, URL, dates), no page content.

{
  "query": "latest developments in LLMs",
  "type": "auto",
  "contents": { "highlights": true }
}

Every other request field except objective is gated: add it only when the user's task explicitly requires it. Do not restate server defaults, and do not add controls because they seem plausibly useful. In particular:

  • type defaults to auto; stating type: "auto" explicitly is fine, but do not send another mode unless the task requires it (for example a latency-critical UX or deep synthesis).
  • numResults defaults to 10; omit numResults unless the task requires a different number of results. Set it only as an intentional product decision, not as boilerplate.
  • Omit category. Use it only when the user explicitly asks for category-constrained retrieval.
  • includeDomains and excludeDomains should be set only when the user explicitly requests a hard allowlist or blocklist and supplies or approves its contents. Express source preferences through query phrasing or systemPrompt instead.
  • maxAgeHours should be set only when extracted page content must be current. It caps cache age before a live crawl; it is not a publication-recency filter.
  • For "recent stories" tasks, put the recency in the query ("latest", "recent"). startPublishedDate / endPublishedDate are hard filters that drop undated and misdated pages; add them only when the task states a bounded window that must be enforced ("from the last seven days", "published in 2026"). Do not reach for maxAgeHours.
  • highlights should be set to true by default for all tasks unless otherwise specified. Do not add maxCharacters or other highlight options without an explicit budget requirement in the task.
  • objective belongs on every search that is one step of a larger task, such as a search an LLM agent calls as a tool, a query a model writes, or one step of a multi-step pipeline. Set it to the goal that search serves. Say which documents should rank first, which to exclude, and which facts or figures to pull. When an LLM calls search as a tool, the model writes objective alongside query. See Search as an LLM Tool.

API Decision Workflow

Before picking an endpoint, decide which workflow shape fits:

  • Raw web content for your own LLM or agent: use /search with the recommended request above
  • Web search as a tool your LLM or agent calls: use the SDK tool helpers, which ask the model for query and objective on every call. See Search as an LLM Tool.
  • A specific output shape, or fields that have to be extracted or synthesized from the pages: use /search and add outputSchema (and systemPrompt if behavior guidance is needed). The user does not have to say "JSON" or "schema": "the funding amount each article reports", "name, title, and company for each person", or a field the result must carry that result metadata only sometimes has (a required author) are all structured-output requests. Fields every result already carries (title, URL, published date) are not: "10 articles with title and URL" is the recommended request with numResults. A compact schema (author and URL per article) stays on auto; type: "deep" when the schema is wide or its fields take more than one search to fill, since it runs several. See Structured Output in references/search.md.
  • Long-running multi-step research, list-building, or enrichment with structured output: use the Agent API (/agent), with the same outputSchema rule for its fields

Default to the search endpoint. Use the search endpoint (/search) for most new integrations, then move to a more specialized Exa surface only when the task shape clearly calls for it.

  1. Need general semantic web retrieval, synthesized output, or content extraction from search results: use the search endpoint (/search)
  2. Already know the URLs and need clean page extraction or freshness controls: use the contents endpoint (/contents)
  3. Need pages related to a known seed URL: use the search endpoint (/search) with a query derived from the page (for example title, topic, or text from /contents)
  4. Need a grounded answer with citations and no LLM of your own doing generation: use the answer endpoint (/answer). If the product already has a chat LLM, give it /search as a tool instead.
  5. Need code-focused retrieval from repos, docs, and Stack Overflow: use the search endpoint (/search)
  6. Need OpenAI SDK drop-in compatibility for chat or responses clients: use the OpenAI-compatible endpoints (/chat/completions, /responses)
  7. Need asynchronous multi-step research, list-building, enrichment, or follow-up questions over prior research: use the Agent API (/agent)
  8. Need scheduled recurring search with webhook delivery: use the Monitors API (/monitors)
  9. Maintaining an existing Websets integration: see the migration guide (references/migrate-websets-to-agent.md) and transition to the Agent API (references/agent.md). Do not use Websets for new work; use the Agent API instead.
  10. Need page content as it was at a past datetime (backtesting agents, reproducible evals, comparing earlier versions of docs, pricing pages, policies, or filings): use Exa Snapshot, the snapshotAsOf field on /contents (top level) or /search (inside contents). See references/snapshot.md.

Quick Start

For more complete examples, see the relevant reference file in the table below.

Python (/search):

from exa_py import Exa

exa = Exa(api_key="YOUR_EXA_API_KEY")
result = exa.search(
    "latest developments in LLMs",
    type="auto",
    contents={"highlights": True}
)

for item in result.results:
    print(item.title, item.url)

TypeScript (/search):

import Exa from "exa-js";

const exa = new Exa();
const result = await exa.search("latest developments in LLMs", {
  type: "auto",
  contents: { highlights: true }
});

for (const item of result.results) {
  console.log(item.title, item.url);
}

Raw HTTP (/search):

curl -X POST "https://api.exa.ai/search" \
  -H "Content-Type: application/json" \
  -H "x-api-key: $EXA_API_KEY" \
  -d '{
    "query": "latest developments in LLMs",
    "type": "auto",
    "contents": {
      "highlights": true
    }
  }'

Search as an LLM Tool

When an LLM decides when to search, give it Exa search as a tool. The SDK helpers build the tool definition, run the model's calls and format the results. The search tool asks the model for query and objective on every call and runs the recommended request.

Python (OpenAI Chat Completions):

from exa_py import Exa
from openai import OpenAI

exa = Exa()  # reads EXA_API_KEY from the environment
openai_client = OpenAI()
messages = [{"role": "user", "content": "What's the latest on AI chips?"}]

completion = openai_client.chat.completions.create(
    model="gpt-5.6",
    messages=messages,
    tools=[exa.openai.web_search(), exa.openai.get_contents()],
)
message = completion.choices[0].message
messages.append(message)
messages += exa.openai.handle_tool_calls(message)

Repeat the request and handler step until the model replies without tool calls.

ProviderPythonTypeScript
OpenAI Chat Completionsexa.openai.web_search(), exa.openai.handle_tool_calls(message)exa.openai.webSearch(), exa.openai.handleToolCalls(message)
OpenAI Responsesexa.openai.responses.web_search(), exa.openai.responses.handle_tool_calls(response)exa.openai.responses.webSearch(), exa.openai.responses.handleToolCalls(response)
Anthropic Messagesexa.anthropic.web_search(), exa.anthropic.handle_tool_use(response)exa.anthropic.webSearch(), exa.anthropic.handleToolUse(response)
Any other frameworkexa.tools.web_search(), a provider-neutral spec with a run methodexa.tools.webSearch(), a provider-neutral spec with a run method

If you define the tool yourself, make objective a required string parameter next to query, give it this description verbatim, and pass the model's value to search unchanged:

Goal for this search turn; say which documents should rank first, which should be excluded, and what specific facts or figures to pull from them.

Full hand-written tool definitions for OpenAI and Anthropic are in references/prompting-and-patterns.md.

Critical Pitfalls

  • Do not give an LLM a search tool that takes only query. Use the SDK tool helpers, or add objective as a required parameter with the recommended description and pass it to search unchanged.
  • Do not decorate the recommended request without reason. Adding category, domain filters, boilerplate numResults, or freshness controls without an explicit task requirement is the most common integration mistake.
  • Do not answer an extraction request with a bare search. A field that has to come out of the page, or a metadata field the user requires on every result, goes in outputSchema; keep/drop rules go in systemPrompt; query is retrieval intent only. If a clause of the query says only, include, exclude, drop, or return, it is in the wrong field. Do not add outputSchema for fields every result already carries (title, URL, published date).
  • On the search endpoint, text, highlights, and summary belong inside contents, not at the top level.
  • On the contents endpoint, text, highlights, and summary are top-level fields, not nested inside contents.
  • Pick one of highlights, text, or summary. Do not stack them. summary requires an explicit user request for Exa-side per-result synthesis.
  • Almost all tasks should use bare highlights: true. numSentences and highlightsPerUrl are deprecated, and maxCharacters needs an explicit budget requirement.
  • List-building and enrichment workflows belong on the Agent API (/agent), not on /search with category: "people" or category: "company". Those categories are only for retrieving raw people or company documents.
  • maxAgeHours controls crawl/cache freshness (how old extracted page content may be before a live crawl), not publication recency. Do not use it as a "recent results" control; recency belongs in query phrasing. startPublishedDate / endPublishedDate are for task-stated bounded windows ("the last seven days", "in 2026") that must be enforced, not for "recent" or "latest" alone.
  • Never invent category values like github, documentation, qa, or pdf. When a user does request category-constrained retrieval, check the search reference first: specialized categories such as people and company restrict which filters are valid.
  • OpenAI-compatible endpoints are for compatibility-first use cases. Prefer native Exa endpoints for new integrations when you want clearer request semantics.
  • Do not treat /agent as a drop-in replacement for /search. It is higher-latency and async, so use the dedicated Agent reference when that workflow shape is the real fit. Prefer it over Websets for new collection-building work.
  • Agent requests should always set effort explicitly, wait for a terminal status via polling or SSE and check how the run ended before reading output, and expose output.grounding when relevant in a product.
  • Treat /findSimilar as deprecated. Prefer /search (optionally after /contents on the seed URL) for related-page discovery.

Reference Files

FileTopics
references/search.mdSearch endpoint request/response shape, search types, filters, nested contents, structured output
references/contents.mdContents endpoint extraction, freshness, statuses, top-level content fields
references/snapshot.mdExa Snapshot: snapshotAsOf historical page versions on /contents and /search, limits, snapshot vs freshness
references/answer.mdGrounded answer generation with citations and structured output
references/agent.mdAgent API for async multi-step research, enrichment, structured output, polling, and events
references/openai-compat.mdOpenAI-compatible endpoints, model routing, extra_body usage
references/monitors.mdStandalone Monitors API for scheduled recurring search
references/migrate-websets-to-agent.mdMigrate Websets to the Agent API: call-site classification, request mapping, delivery rewrite, verification
references/sdks.mdPython and TypeScript SDK naming, methods, and shape differences
references/http-requests.mdMinimal raw HTTP examples across major Exa surfaces
references/models-and-modes.mdSearch type selection, answer/research model routing, latency tradeoffs
references/prompting-and-patterns.mdDurable query, prompting, freshness, and output-schema patterns
references/common-mistakes.mdOver-specification and parameter-shape corrections

Canonical Docs

  • Docs home: https://exa.ai/docs
  • Documentation index: https://exa.ai/docs/llms.txt
  • Search reference: https://exa.ai/docs/reference/search
  • Agent API guide: https://exa.ai/docs/agent/quickstart
  • Exa Snapshot: https://exa.ai/docs/search/snapshot
  • Exa Connect overview: https://exa.ai/docs/agent/connect/overview
  • Python SDK spec: https://exa.ai/docs/sdks/quickstart
  • TypeScript SDK spec: https://exa.ai/docs/sdks/quickstart

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.