Fractal exploration of any question through recursive AI agents.
A question spawns angles. Each angle spawns deeper angles. The tree grows until questions become atomic — then everything synthesizes back up into one comprehensive answer.
Question: "Why do smart people make bad decisions?"
│
├── What cognitive biases affect intelligent people?
│ ├── How does overconfidence manifest in experts?
│ ├── What is the curse of knowledge?
│ └── ... (each can branch further)
│
├── How does expertise create blind spots?
│ └── ...
│
└── What role does emotional reasoning play?
└── ...
↓ ALL BRANCHES EXPLORED IN PARALLEL ↓
↓ SYNTHESIZE BACK UP THE TREE ↓
[Comprehensive Answer]
Fan-out is unbounded, and it spends your money.
There is no cap on how many sub-questions a decomposition may produce, and no cap
on how many child agents get spawned. The orchestrator parses every Q: line
the model emits and launches one agent per line, then recurses. -p/--parallel
limits how many run at the same time; it does not limit how many run in total.
A single run of the first command in this README decomposed one question into 69 sub-questions and began spawning 69 child agents. At the default depth of 5, a modest 8-way branch is ~4,000 leaf calls.
It happens with no API key set, which is the part that surprises people: the
default provider shells out to your locally installed claude binary, so it
inherits whatever session that binary is already logged into. Nothing prompts
you, and nothing warns you at runtime.
Start with -d 1, on a cheap model, and watch what it does:
deep-research research -d 1 -m haiku -r haiku "A small question"Interrupting a run is safe but unrecoverable — there is no resume. See Checkpoints and resume.
The default path does not use an API key. It drives CLI tools you have already installed and logged into.
| You want to use | You need |
|---|---|
opus, sonnet, haiku (the default) |
The claude CLI on your PATH, already logged in: npm install -g @anthropic-ai/claude-code then claude |
gemini:pro, gemini:flash |
The gemini CLI on your PATH, already logged in |
gpt5-mini |
GPT5_MINI_API_KEY + GPT5_MINI_ENDPOINT (your own Azure OpenAI resource) |
grok, grok-3, grok-4 |
OPENROUTER_API_KEY |
kimi |
KIMI_API_KEY + KIMI_ENDPOINT (your own Azure AI Services resource) |
Python 3.10+.
ANTHROPIC_API_KEYis not used for authentication anywhere in this project. It appears only as a label indeep-research validateoutput. Claude access comes from theclaudeCLI's own session. The same is true ofGEMINI_API_KEYand thegeminiCLI.
git clone https://github.com/Cranot/deep-research.git
cd deep-research
pip install -e .
# Or with development dependencies
pip install -e ".[dev]"Only needed for the three key-based providers. Create a .env in the project
root (it is gitignored):
# Azure OpenAI — bring your own resource
GPT5_MINI_API_KEY=your-key
GPT5_MINI_ENDPOINT=https://<your-resource>.openai.azure.com
GPT5_MINI_DEPLOYMENT=gpt-5-mini # optional
GPT5_MINI_API_VERSION=2024-02-01 # optional
# OpenRouter (Grok)
OPENROUTER_API_KEY=your-key
OPENROUTER_MODEL=x-ai/grok-4.1-fast:free # optional
# Kimi via Azure AI Services — bring your own resource
KIMI_API_KEY=your-key
KIMI_ENDPOINT=https://<your-resource>.services.ai.azure.com/openai/v1/
KIMI_MODEL=Kimi-K2-Thinking # optionalNo endpoint defaults ship with this project. If you do not set the endpoint, the provider raises a clear error rather than pointing at someone else's resource.
Behaviour can also be tuned through DEEP_RESEARCH_* variables — see
deep-research config for the full list and current values.
deep-research requires a subcommand. There are six: research,
perspectives, socratic, cache, config, validate.
# Basic research (start shallow — see the cost warning above)
deep-research research -d 1 "What makes startups successful?"
# Socratic mode — improve the question before researching it
deep-research socratic "How do I become more productive?"
# Perspective expansion — multi-angle analysis
deep-research perspectives "What makes good leadership?"
# Check what is configured and reachable
deep-research config
deep-research validate "Your question"The four strategies are reachable only from the Python API. There is no
--strategy CLI flag.
import asyncio
from pathlib import Path
from deep_research.core import MasterChef
async def main():
chef = MasterChef(
output_dir=Path("reports/my-research"),
max_parallel=10,
)
result = await chef.cook(
"What makes startups successful?",
"recursive_research", # or "socratic" / "perspective_expander" / "grounded_research"
context={"model": "haiku"},
)
print(result.final_synthesis.content)
asyncio.run(main())chef.cook() also accepts a strategy object, which is how you change its
parameters:
from deep_research.core import grounded_research_strategy
result = await chef.cook(
"Current state of AI",
grounded_research_strategy(max_depth=1),
context={"model": "haiku"},
)
MasterChefand the CLI are two separate execution paths. The CLI runsOrchestrator; strategies, the knowledge graph andgraph.jsonbelong toMasterChef. Features are not shared between them — the table below says which is which.
./deep-research.sh "Your question"
./deep-research.sh -d 2 -m opus -r haiku "Your question"The bash script is the original implementation and is not flag-compatible
with the Python CLI: it has no -o, no -v and no perspective options, its
-w/--web genuinely works, and its -d 0 genuinely means unlimited. It is the
only thing in this repo that writes SYNTHESIS.md.
| Strategy | Description | Best For |
|---|---|---|
recursive_research |
Decompose → Answer → Synthesize | General research |
socratic |
Challenge assumptions, find better questions | Unclear problems |
perspective_expander |
Multi-angle analysis with blind spot detection | Complex topics |
grounded_research |
Web-verified answers (runs live web searches) | Fact-checking, current events |
All four are addressable by name through MasterChef.cook():
from deep_research.core.strategy import StrategyRegistry, register_builtin_strategies
register_builtin_strategies()
print(sorted(StrategyRegistry.instance().available()))
# ['grounded_research', 'perspective_expander', 'recursive_research', 'socratic']provider:model → gemini:flash, claude:opus
model → defaults to Claude (haiku = claude:haiku)
Five providers ship with the project:
| Provider | Models | Auth | Notes |
|---|---|---|---|
| Claude | opus, sonnet, haiku |
local claude CLI |
Default. Best orchestrator (opus) |
| Gemini | flash, pro |
local gemini CLI |
Fast, cost-effective leaves |
| OpenAI/Azure | gpt5-mini |
API key + your endpoint | Requires temperature=1.0 |
| OpenRouter | grok, grok-3, grok-4 |
API key | Via x-ai |
| Kimi | kimi |
API key + your endpoint | Strong merger in our testing |
# Quality-focused
deep-research research -m opus -r haiku -d 2 "Your question"
# Cost-optimized with ensemble
deep-research research -l "haiku,gemini:flash" --merger kimi:kimi -d 2 "Your question"
# All-Gemini
deep-research research -m gemini:pro -r gemini:flash -d 2 "Your question"deep-research research [OPTIONS] "Your question"| Flag | Default | Description |
|---|---|---|
-m, --model |
opus |
Orchestrator model |
-r, --researcher |
haiku |
Researcher model for child agents |
-l, --leaves |
(use -r) |
Leaf ensemble, comma-separated |
--merger |
(use -m) |
Model for merging ensemble results |
-d, --depth |
0 |
Max recursion depth. 0 means "use the configured default", currently 5 — it does not mean unlimited. Hard ceiling 20 |
-p, --parallel |
10 |
Max concurrent agents (not a total cap) |
-o, --output |
auto | Output directory |
-w, --web |
off | Accepted but not yet wired on this command — it has no effect. The CLI prints a note if you pass it. Web grounding lives in the grounded_research strategy (Python API) and in the bash script |
-v, --verbose |
off | Accepted but not yet wired on this command — it has no effect |
--perspectives |
— | Perspective models, comma-separated |
--perspective-picker |
sonnet |
Model that selects the best perspectives |
--all-perspectives |
off | Use all available models for perspective expansion |
--perspective-depth |
1 |
1 = flat, 2+ = recursive sub-perspectives |
--no-blind-spot |
off | Disable blind spot detection |
--no-perspective-cache |
off | Disable perspective caching |
There is no --strategy flag. Strategy selection is Python-API only.
src/deep_research/
├── core/ # MasterChef framework (Python API path)
│ ├── node.py # Typed nodes, epistemic states
│ ├── graph.py # Knowledge graphs with checkpointing
│ ├── operation.py # Operation protocol
│ ├── strategy.py # Declarative strategies + registry
│ ├── chef.py # MasterChef orchestrator
│ └── operations/ # Concrete operations
│ ├── decompose.py # DECOMPOSE: Question → Sub-questions
│ ├── answer.py # ANSWER: Question → Answer
│ ├── synthesize.py # SYNTHESIZE: Findings → Synthesis
│ ├── detect.py # DETECT: Blind spots, tensions
│ └── ground.py # GROUND: Web-verified claims
├── providers/ # LLM integrations
│ ├── claude.py # Local `claude` CLI (subprocess)
│ ├── gemini.py # Local `gemini` CLI (subprocess)
│ ├── openai_azure.py # Azure OpenAI
│ ├── openrouter.py # OpenRouter
│ └── kimi.py # Kimi (Azure AI Services)
├── recipes/ # Research methodologies
│ ├── perspective.py # Perspective expansion
│ └── socratic.py # Socratic questioning
├── orchestrator.py # Recursive agent tree (CLI path)
└── cli.py # Typer CLI
Nodes: Typed content units (Question, Answer, Insight, BlindSpot, …) with epistemic status (Unknown → Explored → Validated → Synthesized)
Operations: Epistemic transitions (DECOMPOSE, ANSWER, SYNTHESIZE, GROUND, …)
Strategies: Declarative recipes that orchestrate operations
MasterChef: Executes strategies on knowledge graphs
deep-research research writes:
reports/YYYY-MM-DD-your-question-slug/
├── agents/ # Individual agent outputs
│ ├── d0-001-opus.md # ← the root agent's file IS the final report
│ ├── d1-002-haiku.md
│ └── ...
├── research.log # JSONL event log
└── metrics.json # Run metrics
deep-research perspectives adds PERSPECTIVES.md; deep-research socratic
writes SOCRATIC.md.
There is deliberately no separate SYNTHESIS.md on the Python path — the
root agent's file under agents/ is the synthesized report. SYNTHESIS.md is
written by the legacy deep-research.sh only.
graph.json is written by the Python API path (MasterChef) when an
output_dir is given. The CLI does not produce it.
MasterChef checkpoints the knowledge graph to graph.json after each phase,
and KnowledgeGraph.load() can read one back. There is no resume path wired
up — no --resume flag, and nothing in the CLI or MasterChef restarts from
a checkpoint. The CLI path does not checkpoint at all; it writes per-agent
markdown as it goes, so an interrupted run leaves partial files you can read but
cannot continue. Treat graph.json as an inspectable artifact, not a resume
point.
pip install -e ".[dev]"
pytest tests/ -v # 114 tests, no network, no spend
ruff check src/ tests/
ruff format --check src/ tests/tests/test_masterchef.py contains two live integration tests that really do
invoke a model. They are skipped unless a claude binary is on PATH and
DEEP_RESEARCH_LIVE_TESTS=1 is set:
DEEP_RESEARCH_LIVE_TESTS=1 pytest tests/test_masterchef.py- Multi-model merges beat single models — ensembling 4+ diverse outputs produces higher quality than any single model
- Kimi-K2-Thinking is a strong merger — 9.5/10 quality in our own side-by-side testing
- Cheap models ensemble well — haiku + flash as leaves, kimi as merger = best cost/quality
- Every question contains hidden angles — recursive exploration surfaces what you'd never think to ask
These are observations from the authors' own runs, not a benchmark.
- RECIPES.md — 156 research patterns
- docs/API.md — Python API reference
- docs/TROUBLESHOOTING.md — Common problems
- AgentsKB — Pre-researched knowledge for AI agents
MIT — see LICENSE.
Deep Research - Fractal exploration through recursive AI agents
Made by Dimitris Mitsos & AgentsKB.com