Skip to main content
Glama

Descartes

doubt, until what remains is certain.

CI

🔭 Sibling project: The Askertoday's AI answers, this one asks.

The Asker learns to ask the sharpest questions to understand a subject; Descartes learns to doubt until what remains is certain. Two halves of one idea: the right question beats the confident answer. → https://github.com/pranjalbhatia710/the-asker

🪶 Landing page →  ·  descartes --epigraph for a passing thought from the man himself.

An MCP server that, on a prompt, doubts every decision in a plan, doubts its own doubts, and answers them — grounding every answer in real evidence — iterating until the plan stops producing new load-bearing doubts. Then it hands back a refined plan plus the few decisions only you can make.

The point: no unexamined assumption reaches the work, so hallucination has no room to hide.


The loop

On a prompt, Descartes runs recursive Cartesian doubt:

  1. Draft the plan / decisions.

  2. Doubt every load-bearing decision (one of 11 doubt operators per doubt).

  3. Doubt the doubts — prune the trivial and manufactured ones.

  4. Answer each surviving doubt only from real evidence:

    • code doubts → resolved from the context you pass in,

    • world doubts → resolved via Exa (cited, confidence-scored),

    • ungroundable → marked NEEDS_HUMAN.

  5. Doubt the answer — recurse: each settled answer is itself doubted (the question behind the question), spawning the next layer of doubts, bounded by depth and a global doubt budget.

  6. Bank it — every grounded finding accumulates into a knowledge base that feeds the next round of doubting and the final plan.

  7. Revise the plan with what survived, and repeat from step 2.

The output is therefore a doubt tree (each entry carries depth + parent), not a flat list, plus a knowledge_base of accumulated facts.

Stopping rule: the loop stops the moment a full pass produces no new load-bearing doubt — that is convergence. It might be pass 3 or pass 9. 20 is a hard ceiling, never a target, and recursion is bounded by DESCARTES_MAX_DEPTH (default 3) and DESCARTES_DOUBT_BUDGET (default 64). It never manufactures doubt to keep going.

Grounding rule: every answer resolves against real evidence or becomes a question for you. Low-confidence Exa is never asserted. 20 rounds of self-answered, ungrounded doubt would be 20 rounds of confident hallucination — so that is forbidden by construction.


Related MCP server: loom-go

Two engines (auto-selected)

If you set…

Descartes runs…

FIREWORKS_API_KEY

a panel of distinct Fireworks model families. Agreement = settled; disagreement = real uncertainty → the doubt is escalated.

nothing (in a client that supports MCP sampling)

Claude alone — the client's own model runs the whole loop.

OPENROUTER_API_KEY

single-model "Claude alone" via OpenRouter (fallback when sampling is unavailable).

no keys at all

a deterministic operator-template fallback, so it never hard-fails.

EXA_API_KEY is independent: set it to ground world doubts in any mode.

No keys? It still works — with just Claude

You do not need any API keys. Inside an MCP client that supports sampling (Claude Code), the whole loop runs on the client's own Claude model — code doubts are resolved by reading the context you pass in, and anything that needs an external fact or a human decision is handed back to you.

And if even sampling isn't available, Descartes does not guess. It will not fake-confirm a doubt from keyword matching; it surfaces every load-bearing doubt as a question in needs_user and tells you so. Every doubt() result carries an engine and a plain-English note describing exactly how it was powered, so a degraded run is never silent. The one rule it never breaks: no answer without evidence — otherwise, ask you.


3-step setup

# 1. install
git clone https://github.com/pranjalbhatia710/descartes-mcp && cd descartes-mcp
pip install -e .

# 2. (optional) bring your own keys — copy names only, fill in your .env
cp .env.example .env        # .env is gitignored; never commit it

# 3. run it (stdio MCP server)
descartes                   # or: descartes --selftest   to prove the loop converges
descartes --demo            # watch it doubt, live, in your terminal

Watch it work

descartes --demo runs a scripted doubt session and renders it live — a spinner while it thinks, a self-drawing doubt tree ( top-level, recursion), colour-coded statuses (✓ confirmed · ✗ refuted · ⚑ for you), the knowledge base filling, and a CONVERGED banner.

Inside Claude Code, the real doubt() tool reports the same events to the client as MCP progress + log notifications, so you see it working as it runs. It never prints to stdout — that channel is the MCP protocol. Set DESCARTES_VERBOSE=1 to also stream compact progress to the server's stderr log.

Add to Claude Code

Add this to your Claude Code MCP config (e.g. .mcp.json in your project, or via claude mcp add). Keys live in your shell / config env — never in committed files:

{
  "mcpServers": {
    "descartes": {
      "command": "descartes",
      "args": [],
      "env": {
        "FIREWORKS_API_KEY": "${FIREWORKS_API_KEY}",
        "EXA_API_KEY": "${EXA_API_KEY}",
        "OPENROUTER_API_KEY": "${OPENROUTER_API_KEY}"
      }
    }
  }
}

Then ask Claude to "use descartes to doubt this plan" and pass the relevant files as context.


Tools

doubt(prompt, context="", max_passes=20)

Runs the loop above. Returns:

{
  "passes_used": 4,
  "converged": true,
  "plan": "<the refined, doubt-hardened plan>",
  "doubt_log": [
    { "id": 1, "pass": 1, "depth": 0, "parent": null,
      "operator": "assumption", "doubt": "...", "kind": "code",
      "status": "CONFIRMED|REFUTED|UNKNOWN|NEEDS_HUMAN",
      "resolution": "...", "source": "..." }
  ],
  "doubt_tree": [ { "depth": 0, "children": [ { "depth": 1, "children": [] } ] } ],
  "knowledge_base": [
    { "claim": "...", "verdict": "CONFIRMED", "evidence": "...", "source": "...", "depth": 0 }
  ],
  "needs_user": [ "<the few decisions only you can make>" ],
  "engine": "claude-sampling",
  "note": "<plain-English: how this run was powered>",
  "max_depth_reached": 2
}

doubt_log is the flat record (each entry stamped with depth + parent); doubt_tree is the same data nested; knowledge_base is everything Descartes grounded along the way, which it builds on instead of re-deriving.

needs_user is the product: it separates what Descartes resolved itself from what it genuinely needs you for. Kept short — the truly blocking ones only.

ground(query)

Exa deep search → cited, confidence-scored facts. Used inside the loop; callable directly. Low confidence → status: "UNKNOWN" (never asserted).

verdict(result)

Pass a doubt() result. Returns { proceed, blocking_questions }. proceed is true only if the plan converged with no open load-bearing doubt; otherwise you get the blocking questions.


Doubt operators

Every doubt is tagged with one operator (shipped as data in descartes/operators.py):

assumption · falsify · inversion · named_source · edge_case · quantify · root_cause · reversibility · second_order · define · deletion


Benchmarks — how much better is doubting?

The honest metric isn't accuracy (that tracks whatever model you plug in). It is: of a plan's load-bearing assumptions, how many reach the work unexamined? On a seeded fixture of 6 real-shaped plans with 19 hand-labeled assumptions (benchmark/coverage.py):

approach

examined

grounded from evidence

asked of you

reach work unexamined

ship the plan as-is

0 (0%)

0

0

19 (100%)

Descartes

19 (100%)

12

7

0 (0%)

Unexamined assumptions reaching the work fall from 100% → 0%. Of the 19 it surfaces, Descartes grounds 12 itself and hands you only the 7 that genuinely need a human. This is the conservative floor — deterministic, in the spirit of The Asker's synthetic floor. A real model only widens the gap by catching assumptions the labels missed and recursing deeper.

Convergence (benchmark/bench.py) — it stops the moment a pass adds no new doubt, and a runaway is capped:

scenario

doubt depth

passes

converged

trivial

0

1

moderate

3

4

deep

11

12

spiral-guard

40

20 (capped)

❌ by design

Convergence is exactly depth + 1 passes and never exceeds 20. Both benchmarks run in CI on every push.


Part of a bigger idea — meet The Asker

Descartes has a sibling: The Asker"Today's AI answers. This one asks." An RL environment where an agent learns to understand any subject by asking the sharpest questions, watching a field of candidates collapse to the truth in as few questions as possible, and beating frontier models that just guess.

They are two halves of one thesis: the right question beats the confident answer. Guessing is where hallucination comes from; both tools replace it with questioning.

  • The Asker asks, to understand — it learns, by reward alone, which question removes the most uncertainty.

  • Descartes doubts, to be certain — it questions every decision, then recursively questions its own answers, until nothing unexamined remains.

Point The Asker at a subject and watch it learn what to ask. Point Descartes at a plan and watch it refuse to guess. → github.com/pranjalbhatia710/the-asker


Development & tests

pip install -e ".[dev]"      # pytest + ruff
ruff check descartes/ tests/ benchmark/
pytest -q                    # tests, no network (all backends are mocked)
python -m benchmark.bench    # convergence benchmark (see Benchmarks above)
python -m benchmark.coverage # coverage benchmark (see Benchmarks above)

The suite locks down the load-bearing invariants: the loop always terminates and never exceeds the hard ceiling of 20, it converges as soon as a pass adds no new doubt, it recurses (questioning its own answers) bounded by depth and a node budget, nothing is asserted without evidence (ungroundable → NEEDS_HUMAN, low-confidence Exa → UNKNOWN), needs_user is exactly the NEEDS_HUMAN doubts, and panel disagreement escalates to the human. tests/test_regressions.py carries one guard per bug found by the adversarial audit. CI (.github/workflows/ci.yml) runs lint + tests + the self-test + both benchmarks on Python 3.10–3.13.

Safety

  • Bring your own keys. Read from env only (os.environ.get), never stored, never logged, never committed. .env is gitignored; .env.example has names only.

  • Every external call is wrapped in try/except + timeout + retry — one failure never kills a run.

  • Exa results are cached and time-boxed so a pass stays fast; panel size is capped on the live path (DESCARTES_PANEL_SIZE).

License

MIT — see LICENSE.

Available Tools

3 tools
doubtA

Doubt every decision in a plan, doubt the doubts, and answer each from real evidence — codebase context for code doubts, Exa for world doubts — or flag it for the human. Iterate until the plan produces no new load-bearing doubt (convergence). 20 is a hard ceiling, never a target.

Args: prompt: the task / plan to harden. context: real evidence (paste relevant files, types, tests, notes) used to resolve code doubts without guessing. max_passes: convergence ceiling (clamped to 20).

Returns: {passes_used, converged, plan, doubt_log, needs_user, engine, open_doubts}

ParametersJSON Schema
NameRequiredDescriptionDefault
promptYes
contextNo
max_passesNo

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries full burden. It thoroughly explains the iterative behavior, convergence condition, hard ceiling on max_passes, and the role of context. It also lists return fields, giving a clear picture of what the tool produces.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is well-structured: a concise overview, followed by clear Args and Returns sections. Every sentence adds value without redundancy. It is front-loaded with the core concept.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's complexity (iterative doubt resolution, 3 parameters, no output schema), the description is complete. It covers behavior, parameter semantics, return format, and usage context. No gaps are apparent.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0%, but the description fully documents all three parameters in the Args section. It adds meaning beyond the schema: prompt is the task/plan, context is real evidence, max_passes is the convergence ceiling clamped to 20. This is comprehensive.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool's purpose: to doubt every decision in a plan, iteratively resolve doubts with evidence, and converge on a hardened plan. It uses specific verbs and resources, and distinguishes itself from siblings (ground, verdict) by its iterative doubt-resolution process.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides clear guidance on when to use the tool: for hardening plans against doubts. It specifies how to use context (codebase for code doubts, Exa for world doubts) and to flag for human when needed. It mentions the hard ceiling of 20 passes. However, it does not explicitly exclude cases where alternatives like ground or verdict would be more appropriate.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

groundB

Exa deep search -> cited, confidence-scored facts (used inside the loop). Low confidence is reported as UNKNOWN and never asserted.

ParametersJSON Schema
NameRequiredDescriptionDefault
queryYes

TDQS

B3.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, but the description adds important behavioral details: it reports low confidence as UNKNOWN and never asserts them. This helps an agent understand the tool's reliability and handling of uncertain facts.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is two sentences with no redundancy. Each sentence adds value: the first defines the core action, the second clarifies a key behavioral rule. It is efficiently structured.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given one parameter, no output schema, and no annotations, the description covers the main behavior and a critical detail (UNKNOWN handling). However, the loop context is vague, and return format is not described, leaving some ambiguity.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With 0% schema description coverage, the description only mentions the query parameter implicitly via 'Exa deep search' but adds no specifics on query format, constraints, or examples. The parameter semantics are underexplained.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states that the tool performs Exa deep search to retrieve cited, confidence-scored facts and mentions it's used inside a loop. This distinguishes it from siblings like 'doubt' and 'verdict', though not explicitly.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides minimal usage context: 'used inside the loop' implies a specific workflow but fails to specify when to use this tool versus alternatives or when to avoid it.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

verdictA

Gate a doubt() result. Proceed only if the plan converged with no open load-bearing doubt remaining; otherwise return the blocking questions.

ParametersJSON Schema
NameRequiredDescriptionDefault
resultYes

TDQS

A3.6/5.0
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description must fully disclose behavior. It describes the decision logic (proceed or return questions) but does not specify whether the tool has side effects, requires authentication, or how it processes the input. As a gate function, it likely only inspects state, but this is not confirmed.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is very concise—only two sentences. It front-loads the core action ('Gate a doubt() result') and follows with clear conditions. Every sentence adds value without redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given no output schema, no annotations, and a single parameter with no description, the description is minimally complete: it explains the tool's function and decision condition. However, it lacks details on error handling, the expected input structure, and the format of the output (blocking questions), which may confuse an agent unfamiliar with the system.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With 0% schema description coverage for the single parameter 'result', the description must compensate. It only says 'Gate a doubt() result', implying the parameter should be a doubt result object, but provides no structure or constraints (e.g., required fields, type expectations) for this generic object.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses a specific verb 'Gate' and resource 'doubt() result', clearly stating the tool's purpose: to either proceed if the plan converged without doubt or return blocking questions. It distinguishes itself from siblings 'doubt' and 'ground' by referring to the output of doubt().

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly states when to use the tool: after a doubt() result, to decide based on convergence. It implies the condition for proceeding and what to do otherwise, but does not explicitly mention when not to use or alternative tools, though the sibling context provides some differentiation.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 3 tool updatesv0.1.0
    • First observeddoubt
    • First observedground
    • First observedverdict

TDQS

A3.7/5.0

Scored across 3 tools

Disambiguation5/5

Each tool serves a distinct role: doubt handles the iterative planning and doubt resolution, ground performs factual retrieval, and verdict gates the output. No overlap in functionality.

Naming Consistency3/5

Names are single words but mix verb and noun forms ('ground' as verb, 'verdict' as noun) without a consistent pattern like verb_noun.

Tool Count4/5

Three tools is minimal but well-scoped for the plan hardening domain, covering the main loop, evidence gathering, and output gating without apparent bloat.

Completeness4/5

The tool set covers the core workflow: iterative doubt resolution (doubt), external fact retrieval (ground), and a validation gate (verdict). Minor gaps like plan editing are absent but the core loop is complete.

Maintenance

ActivityStale
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    B
    maintenance
    An MCP server that structures AI reasoning as directed acyclic graphs of semantic thoughts, enabling explicit dependencies, assumption tracking, and cascade invalidation for transparent decision-making.
    7 npm
    5
    MIT
  • A
    license
    Not graded
    quality
    C
    maintenance
    A thinking assistant MCP server that helps you reason through problems using structured frameworks like first principles and sequential thinking, starting wherever you are — clear, messy, or fragmentary.
    5 npm
    MIT
  • A
    license
    A
    quality
    D
    maintenance
    An MCP server that records decisions, rejected alternatives, and justifications, and retrieves them later to avoid re-litigating past choices. It stores data locally in SQLite and Markdown.
    2
    Apache 2.0
  • A
    license
    A
    quality
    D
    maintenance
    An MCP server that acts as an AI assumption firewall, intercepting risky decisions, detecting contradictions, and routing human approval requests via Telegram or Slack.
    8
    1
    MIT