Use when the user mentions Exa research OR when the workflow benefits from complex, multi-step research and other exa-ai approaches are not yielding satisfactory results.
Manage asynchronous research tasks with exa-ai for complex, multi-step research workflows.
Use --help to see available commands and verify usage before running:
exa-ai <command> --help
When using the Bash tool with complex shell syntax, follow these best practices for reliability:
jq to parse output in a follow-up command if needed$(...) can be fragile; break into sequential stepsExample:
# Less reliable: nested command substitution
results=$(exa-ai research-start --instructions "query" | jq -r '.result')
# More reliable: run directly, then parse
exa-ai research-start --instructions "query"
# Then in a follow-up command if needed:
exa-ai research-get research_id | jq -r '.result'
Research is the most expensive Exa endpoint:
Cost strategy:
search, answer, or get-contents insteadexa-research (standard) instead of exa-research-pro unless you need the higher qualityResearch tasks are asynchronous operations that allow you to:
Use research-start when:
Use search (from exa-core) when:
Initiate a new research task with instructions.
exa-ai research-start --instructions "Find the top 10 Ruby performance optimization techniques"
For detailed options and examples, consult REFERENCE.md.
Check status and retrieve results of a research task.
exa-ai research-get research_abc123
For detailed options and examples, consult REFERENCE.md.
List all your research tasks with pagination.
exa-ai research-list --limit 10
For detailed options and examples, consult REFERENCE.md.
exa-ai research-start \
--instructions "Find the latest breakthroughs in quantum computing"
exa-ai research-start \
--instructions "Compare TypeScript vs Flow for type checking" \
--output-schema '{
"type":"object",
"properties":{
"typescript":{
"type":"object",
"properties":{
"pros":{"type":"array","items":{"type":"string"}},
"cons":{"type":"array","items":{"type":"string"}}
}
},
"flow":{
"type":"object",
"properties":{
"pros":{"type":"array","items":{"type":"string"}},
"cons":{"type":"array","items":{"type":"string"}}
}
}
}
}'
# Start research
research_id=$(exa-ai research-start \
--instructions "Analyze competitor landscape for project management tools" | jq -r '.research_id')
# Check status later
status=$(exa-ai research-get $research_id | jq -r '.status')
# Get results when complete
if [ "$status" = "completed" ]; then
exa-ai research-get $research_id | jq -r '.result'
fi
exa-ai research-start \
--instructions "Comprehensive analysis of microservices vs monolithic architecture with case studies" \
--model exa-research-pro \
--events
Applies to: answer, search, find-similar, get-contents
When using schema parameters (--output-schema or --summary-schema), always wrap properties in an object:
{"type":"object","properties":{"field_name":{"type":"string"}}}
DO NOT use bare properties without the object wrapper:
{"properties":{"field_name":{"type":"string"}}} // ❌ Missing "type":"object"
Why: The Exa API requires a valid JSON Schema with an object type at the root level. Omitting this causes validation errors.
Examples:
# ✅ CORRECT - object wrapper included
exa-ai search "AI news" \
--summary-schema '{"type":"object","properties":{"headline":{"type":"string"}}}'
# ❌ WRONG - missing object wrapper
exa-ai search "AI news" \
--summary-schema '{"properties":{"headline":{"type":"string"}}}'
Applies to: answer, context, search, find-similar, get-contents
toon format produces YAML-like output, not JSON. DO NOT pipe toon output to jq for parsing:
# ❌ WRONG - toon is not JSON
exa-ai search "query" --output-format toon | jq -r '.results'
# ✅ CORRECT - use JSON (default) with jq
exa-ai search "query" | jq -r '.results[].title'
# ✅ CORRECT - use toon for direct reading only
exa-ai search "query" --output-format toon
Why: jq expects valid JSON input. toon format is designed for human readability and produces YAML-like output that jq cannot parse.
Applies to: answer, context, search, find-similar, get-contents
Pick one strategy and stick with it throughout your workflow:
Approach 1: toon only - Compact YAML-like output for direct reading
exa-ai search "query" --output-format toonApproach 2: JSON + jq - Extract specific fields programmatically
exa-ai search "query" | jq -r '.results[].title'Approach 3: Schemas + jq - Structured data extraction with validation
exa-ai search "query" --summary-schema '{...}' | jq -r '.results[].summary | fromjson'Why: Mixing approaches increases complexity and token usage. Choosing one approach optimizes for your use case.
Applies to: monitor, search (websets), research, and all skills using complex commands
When using the Bash tool with complex shell syntax, run commands directly and parse output in separate steps:
# ❌ WRONG - nested command substitution
webset_id=$(exa-ai webset-create --search '{"query":"..."}' | jq -r '.webset_id')
# ✅ CORRECT - run directly, then parse
exa-ai webset-create --search '{"query":"..."}'
# Then in a follow-up command:
webset_id=$(cat output.json | jq -r '.webset_id')
Why: Complex nested $(...) command substitutions can fail unpredictably in shell environments. Running commands directly and parsing separately improves reliability and makes debugging easier.
Applies to: All skills when using complex multi-step operations
Avoid nesting multiple levels of command substitution:
# ❌ WRONG - deeply nested
result=$(exa-ai search "$(cat query.txt | tr '\n' ' ')" --num-results $(cat config.json | jq -r '.count'))
# ✅ CORRECT - sequential steps
query=$(cat query.txt | tr '\n' ' ')
count=$(cat config.json | jq -r '.count')
exa-ai search "$query" --num-results $count
Why: Nested command substitutions are fragile and hard to debug when they fail. Sequential steps make each operation explicit and easier to troubleshoot.
Applies to: All skills when working with multi-step workflows
For readability and reliability, break complex operations into clear sequential steps:
# ❌ Less maintainable - everything in one line
exa-ai webset-create --search '{"query":"startups","count":1}' | jq -r '.webset_id' | xargs -I {} exa-ai webset-search-create {} --query "AI" --behavior override
# ✅ More maintainable - clear steps
exa-ai webset-create --search '{"query":"startups","count":1}'
webset_id=$(jq -r '.webset_id' < output.json)
exa-ai webset-search-create $webset_id --query "AI" --behavior override
Why: Sequential steps are easier to understand, debug, and modify. Each step can be verified independently.