A research agent that cites and checks its sources.
Ask a question; get back a cited Markdown report whose every claim has been re-fetched from its source and verified. Built end-to-end on the Pydantic stack: Pydantic AI Β· Logfire Β· Pydantic Evals Β· Pydantic AI Gateway. Anthropic models only, no other services.
Most open-source "deep research" tools stop at retrieve and summarize; deepresearch adds the step they skip: adversarial verification. It re-fetches every cited page and judges each claim against what the page actually says. Contradicted claims are dropped, unverifiable ones (paywalls, 403s) are kept but flagged, and the eval suite exists to prove that step earns its cost.
Clarifier (-i) ββ 0-3 plan-changing questions βββΊ editable plan gate (pre-spend)
β
ββββββββββββΊ Gap Analyst ββββ follow-ups βββββ iterate until saturated /
β (sees the compressed workspace digest) βΌ capped / unaffordable
Planner βββΊ Researchers (parallel, server-side web search + fetch) βββΊ next wave β¦
(acceptance β (wave β₯2 gets the ALREADY-ESTABLISHED brief)
criteria) βΌ
Verifier ββ re-fetches every cited source, judges every claim βββΊ
β
βΌ
Synthesizer ββ outline β sections, code-numbered [n] citations βββ
β β
βΌ β revise (β€2Γ,
Critic ββ grades vs the plan's acceptance criteria β ship | revise β guidance-driven)
β
βΌ ship every stage checkpoints β --resume
report.md (+ report.html) + run.json
- π¬ Claim-level verification: each claim is re-checked against its source, and its verdict (
supported/partial/unsupported/unverifiable) drives what reaches the report. - π Iterative with a compressed workspace: a gap analyst reviews each wave through a code-built digest (per-branch summaries,
NEW THIS WAVEdeltas, semantic dedup, per-domain caps) and asks follow-ups until marginal value runs out. - π§ββοΈ Human-in-the-loop when you want it:
--interactiveasks 0β3 clarifying questions only when the answer would change the plan, then lets you edit sub-questions before any money is spent. - β―οΈ Interruptible: every stage checkpoints, and
--resume runs/<id>continues where a run stopped with prior spend still counted against the original cap. - βοΈ Critic gate: the planner sets acceptance criteria and a post-synthesis critic drives bounded revise passes (
--max-revise,0= cheapest) while the outline and citation numbering stay fixed. - π§Ύ Typed end to end: every hop is a Pydantic model with validators, and code owns the citation numbers so they can't drift (
py.typed, pyright-clean). - πΈ Deterministic cost control: structural caps, per-call
UsageLimits, priced checkpoints, and a predictive wave-affordability gate keep spend bounded, with the Gateway spend cap as backstop. - π Observable: one
logfire.instrument_pydantic_ai()turns a whole run into a single trace tree, and eachrun.jsoncarries its Logfire trace id. - π Measured: a Pydantic Evals suite pairs objective metrics with FACT-style citation accuracy, RACE-style judges, a verifier on/off A/B, and behavioral span evals that run offline in CI.
- π Not just a CLI: an importable library (
from deepresearch import run_research) and an MCP server of itself (deepresearch-mcp) for Claude Desktop/Code.
uv sync
cp .env.example .env # add your keys (see Requirements)
uv run deepresearch "What are the main approaches to LLM hallucination detection?"(After the first PyPI release this becomes uvx deepresearch "question", no clone needed.)
You get a live progress view, then a run folder:
runs/20260719-...-llm-hallucination-detection/
βββ report.md # cited report: TL;DR, sections, limitations, references
βββ run.json # full audit trail: plan, claims, verdicts, usage, cost, timings
β¦and a summary:
run 20260719-...-llm-hallucination-detection
claims 34
verdicts supported: 22 Β· partial: 6 Β· unverifiable: 6 (79% of judged supported)
waves 2 (saturated)
searches 18
est. cost $0.71
duration 94s
report runs/β¦/report.md
| Variable | Purpose | Needed? |
|---|---|---|
PYDANTIC_AI_GATEWAY_API_KEY |
Route all calls through the Gateway (BYOK = free) for spend caps + cost tracking | default routing |
ANTHROPIC_API_KEY |
Direct Anthropic access (--routing direct or split) |
fallback |
LOGFIRE_TOKEN |
Full tracing in Logfire (free tier: 10M spans/mo) | optional, recommended |
Python β₯ 3.11 Β· uv. Costs real money: web search is $10/1k searches; a standard run β $0.55β0.90.
deepresearch "your question" [--depth quick|standard|deep] [--max-cost USD] [--no-verify] [--max-revise N]| Depth | Waves | Synthesis model | Default cap |
|---|---|---|---|
quick |
1 | Sonnet 4.6 | $0.50 |
standard |
2 | Sonnet 5 | $2.00 |
deep |
up to 4 | Opus 4.8 | $8.00 |
Exit codes: 0 ok Β· 1 fatal Β· 2 synthesis fell back to a claims dump Β· 3 spend refusal Β· 130 interrupted.
Minimum-cost run (~$0.24, still a real cited report): --depth quick --no-verify --max-revise 0. At the quick tier the search cost is the floor (9 searches Γ $0.01 = $0.09); the revise loop is the biggest saveable lever, so --max-revise 0 is where most of the savings come from.
Interrupted? Every run checkpoints after each stage: deepresearch --resume runs/<id> continues where it stopped, with the money already spent still counted against the original cap.
| Flag | Effect |
|---|---|
-d, --depth |
quick Β· standard Β· deep (default standard) |
-o, --output |
output directory (default runs/) |
--max-cost |
USD cap for this run (overrides the profile default) |
--routing |
gateway Β· direct Β· split (server-tool roles direct, rest via gateway) |
--no-verify |
skip claim verification |
--max-revise |
critic-driven revise passes (default 2; 0 disables the critic loop, cheapest) |
--resume |
continue an interrupted run from its runs/<id> directory (omit QUESTION) |
-i, --interactive |
clarifying questions + editable plan gate before any money is spent |
--html |
also render a standalone report.html (inline CSS, dark-mode aware) |
--json |
print run.json to stdout (scriptable) |
--plain |
line-based progress, no live UI |
-q, --quiet |
no progress output |
Per-role model overrides are env vars, e.g. DEEPRESEARCH_MODELS__SYNTHESIZER=claude-opus-4-8.
deepresearch ships an MCP server of itself: one deep_research(question, depth, max_cost) tool
returning the cited report. Install the extra (uv sync --extra mcp) and register the stdio
command in Claude Desktop / Claude Code:
{
"mcpServers": {
"deepresearch": {
"command": "uv",
"args": ["run", "--extra", "mcp", "deepresearch-mcp"],
"cwd": "/path/to/deep-research"
}
}
}| deepresearch | gpt-researcher | open_deep_research | DeerFlow | |
|---|---|---|---|---|
| Per-claim source re-verification | β dedicated stage | β | β | β |
| Deterministic $ budget + predictive gating | β | β | β | β |
| Offline CI incl. behavioral span evals | β | β | β | partial |
| Checkpoint / resume | β | β | β | β |
| Editable plan gate / clarify | β | partial | partial | β |
| Compressed research workspace | β | β | β | partial |
| Eval suite in-repo | β | β | partial | β |
| MCP server of itself | β | β | β | β |
| Providers | Anthropic only (by design) | many | many | many |
Verified against each project's default branch on 2026-07-21 (fast-moving repos, so check
before quoting). DeerFlow's classic deep-research pipeline (plan-review gate, code-assembled
citations, src/eval/) lives on its main-1.x branch; the 2.0 main default is a broader
agent harness. gpt-researcher's MCP server is a separate repo (gptr-mcp).
Per-claim source re-verification means a live pipeline stage that re-fetches the source
behind each claim and returns a per-claim supported/contradicted/unverifiable verdict. It is
not a whole-draft consistency review (gpt-researcher's multi_agents FactCheckerAgent reviews
the assembled draft against in-memory notes without re-fetching sources), nor an offline
hallucination eval, nor consensus-across-sources reading. Those exist elsewhere; a per-claim
re-fetch-and-adjudicate stage is what the β marks the absence of.
The bet this project makes: verification and measurement beat breadth. Not every row here is ours alone (resume, eval suites and compressed context are increasingly table stakes), but per-claim source re-verification, a deterministic dollar budget with predictive gating, and behavioral evals wired into offline CI are. One provider, one stack, every claim re-checked against its source, and the eval harness in-repo so the numbers can be measured, not implied.
uv run python -m evals.run_evals # 8-case suite (~$2.50) + judges
uv run python -m evals.run_evals --depth standard # evaluate the depth users actually run
uv run python -m evals.experiments.verifier_ab # the flagship: verifier on vs off (~$5)
uv run python -m evals.experiments.pairwise A B # win/tie/loss between two run dirsEight question categories cover factual, multi-hop, time-sensitive, numeric, contested, niche-technical, survey, and false-premise. Objective evaluators (citation coverage + sentence-level density, citation integrity, URL resolution, verified-claim rate, unverifiable rate, unsupported-leakage, duration) run alongside LLM judges for completeness, faithfulness, premise-handling, and a RACE-style rubric (comprehensiveness/insight/readability).
FACT-style citation accuracy samples cited sentences and judges entailment against the claims' verbatim quotes, the metric where even top products only reach 78β90%. With LOGFIRE_TOKEN set, every run lands as a named experiment in Logfire.
Everything in this repo was built and tested offline ($0). To validate live behavior and fill the results placeholder above, run in order. Stop at any budget line:
uv run python scripts/spike_gateway_server_tools.pythenRUN_LIVE_TESTS=1 uv run pytest -m live: environment sanity (~$0.05).- One standard run:
uv run deepresearch "your question" --depth standard, then check the cache-hit row in the summary, thinking behavior in the Logfire trace, and wave gating (~$1). uv run python -m evals.run_evals: full suite incl. citation accuracy (~$3).uv run python -m evals.experiments.verifier_ab: the A/B (~$5).- Paste the A/B table over the placeholder above; add the citation-accuracy number and cache-hit rate to Highlights. Optionally render the demo GIF:
vhs docs/demo.tape(one more quick run).
uv run pytest # 91 offline tests, hermetic: no API calls, no keys, no cost
uv run pyright && uv run ruff check . # CI runs these on 3.11β3.13
RUN_LIVE_TESTS=1 uv run pytest -m live # ~$0.05 live smoke (also answers the gateway question)
uv run python scripts/spike_gateway_server_tools.py # run once per new environmentRepo rules, commands, and architecture invariants live in AGENTS.md (agent- and human-readable; llms.txt has the source map). The honest build log (every learning, dead end, and stack dev-ex note, from the origin story onward) is JOURNAL.md. Contributions welcome: see CONTRIBUTING.md.
Sequential section writing (deliberate: parallel section-writing measurably produces disjoint reports) Β· stage-level, not token-level, streaming Β· per-role model overrides are env-only Β· similarity dedup is string-based, not embedding-based (deliberate: Anthropic-only means no embedding endpoint, and it's free and deterministic) Β· live eval numbers not yet published (the checklist above fills them in). See JOURNAL.md for the reasoning behind each.