Coding agents forget what they learned, assume what they don't know, and break code they can't see. The substrate is a fast, mostly-deterministic check that runs before an agent edits your code: it flags an unclear task, picks the cheapest capable model, and shows what an edit will break — all from the repo you already have, with no extra LLM call.
In Claude Code it runs automatically. In other tools you (or the agent) run one command.
Why this exists, in one line: a model with frozen weights keeps no durable state between independent calls, sees only a bounded context, never updates its weights from outcomes, and cannot reliably verify itself without external evidence. Prompting does change what it does inside one context, but it cannot supply those guarantees; this layer supplies persistence and verification from the outside — one tested way to do it, not the only possible one. Full argument: the white paper (HTML, with the 2026-09-21 and 2026-09-26 corrections · PDF, a pre-correction edition). (Corrected 2026-09-26: this line used to say "no memory, no foresight, a fixed window. Those faculties can't be prompted in"; see the white paper's Corrections.)
Install Forge (plugin · npm · github:) per README → 60-second quickstart,
then inside any project:
forge init # writes each AI tool's native config from one source
forge atlas # build the code graph (needed for blast-radius checks)forge init configures Claude Code, Codex, Cursor, Gemini, Aider, Copilot, Windsurf, Zed,
Continue, and OpenClaw (plus MCP config for Roo and VS Code). On Claude Code the check then
runs on every prompt automatically.
You don't have to remember to use it.
In Claude Code — a hook runs the substrate on every prompt and adds a short note only when something needs attention (unclear task, big blast radius, pricey model). It never blocks and never nags on a clean, simple task. Real example — you type "refactor computeTax in math.js" and the agent silently receives:
Forge substrate — pre-action advisory (advisory, never blocks):
- Under-specified (high risk). Ask before editing:
• What constraints must be respected: performance, dependencies, style, or compatibility?
- Suggested model: Haiku 4.5 (simple); escalate only on a verifier failure.
- Predicted blast radius (2: 2 reverse): invoice.js (reverse), math.js (reverse). Review these before editing.
- Verify with: review impacted files before editing · run the narrowest affected test first
In other AI tools (Codex, Cursor, Gemini, Aider…) — forge init writes a rule into their
config file telling the agent to run the check itself, and exposes it as MCP tools it can call.
See In other AI tools.
forge substrate "<what you want to do>"It runs the whole check and gives a plain verdict. Two real examples:
Vague task → it tells you to ask first:
$ forge substrate "make the auth better"
proceed: ASK FIRST
assumption: high risk · completeness 0.23
clarify:
- What exactly should this produce, and how will we know it is correct?
impact: 0 file(s) predictedClear task → it clears you and shows the blast radius:
$ forge substrate "Change verifyToken in src/auth.js to require length > 20; update tests"
proceed: yes
assumption: low risk · completeness 0.88
route: Haiku 4.5 (simple)
impact: 3 file(s) predicted — 3 reverse
- src/auth.js (reverse)
- src/login.js (reverse) ← imports verifyToken; you didn't mention it
- src/session.js (reverse) ← imports verifyToken; you didn't mention it
verify:
- run the narrowest affected test first, then the broader suiteThe second run found the two files that import verifyToken but you never named — the
"forgot the coupled file" bug, caught before the edit. Each file is tagged with the
relation that reached it: reverse (depends on the change), sibling (shares a dependency
with it) or forward (the change depends on it). The check walks all three by default
because the reverse-only walk missed the sibling files that were 94.7% of the empirical
refutation's misses; siblings and forward files are co-change candidates, lower precision
than dependents, and the enforce gate counts dependents only. Add --json for machine-readable
output (see Use it in a script).
forge substrate bundles these. Run any one on its own when that's all you need.
| Command | Answers | One-line example |
|---|---|---|
forge preflight "<task>" |
Is this task clear enough to start? | flags names not in the repo + vague words |
forge route "<task>" |
Which model is cheapest-but-capable? | trivial → Haiku · hard → Opus/Fable |
forge impact <symbol|file> |
What will this edit break? | reverse-dependency blast radius |
forge scope <file…> |
Can this be split into sessions? | independent vs. coupled files |
forge anchor "<goal>" |
Are my changes still on the stated goal? | flags changed files that drifted off-goal |
forge verify |
Did it actually work? | runs the real tests/build, not the model's word |
Inside an agent session (FORGE_SESSION_ID, or Claude Code's CLAUDE_CODE_SESSION_ID),
forge substrate's goal-drift and minimality checks, forge anchor and forge lean read
only what that session changed since its SessionStart baseline. Older dirt is left out, and
so is a file another live session's trail claims (the completion gate's attribution rule).
Before the session has changed anything, minimality reports "pre-existing diff (not
measured)" instead of critiquing someone else's diff.
The wider v0.5 surface — forge context (budgeted assembly + completeness gate),
forge imagine [--run] (predicted breaks + minimal dry-run suite), forge diagnose
(doom-loop), forge ledger / forge reuse (proof-carrying memory + code cache), and
forge uicheck (the design gate) — is documented with real outputs in
docs/GUIDE.md → Command reference.
Real output for the two most-used:
$ forge preflight "fix the thing in authManager so it works properly"
- `authManager` — not found in the code. Different name, or should it be created?
- Ambiguous: "properly" — state concrete acceptance criteria.
- Which specific file, module, component, or symbol should this change touch?$ forge impact verifyToken
target: verifyToken ✓ found
impacted files: 3
- src/auth.js
- src/login.js
- src/session.jsField-by-field: what each verdict means and the action to take —
docs/GUIDE.md → Reading substrate output.
The short version: ASK FIRST means ask, route means start cheap, impact means
read those files first, and verify means show the output before saying "done".
Tools without a hook surface get the substrate two ways, both written by forge init:
a rule in their native config telling the agent to run forge substrate "<task>" --json
before ambiguous/expensive/mutating work, and MCP tools (substrate_check,
assumption_gate, predict_impact, route_task, scope_files) any MCP-capable agent
can call directly. Details + the exact rule wording:
docs/GUIDE.md → Auto-use inside an agent.
Forge never pretends it can force a hook into a tool that has none — it's ambient on Claude Code, and agent-invoked everywhere else.
OpenClaw is agent-invoked in exactly this sense. It picks up the rules on its own (the
execution folder's AGENTS.md becomes project context), but its MCP registry is your global
~/.openclaw/openclaw.json, which Forge will not write to. forge sync leaves the
definition in .openclaw/mcp.json; you register it once with
openclaw mcp add forge-cortex --command forge --arg cortex-mcp. Forge installs nothing
into OpenClaw's own hook system.
Add --json to any command for machine-readable output — gate your agent's next step on
okToProceed, feed route.tier to your model picker, read impact.impactedFiles before
editing. Every knob (ask threshold, blast-radius sensitivity, routing signals, assumption
questions, the verify checklist, the ambient hook wording) is a small pure function or a
JSON default. Full JSON shape and the extension table:
docs/GUIDE.md → Use it in a script ·
Extending Forge.
The substrate's default judgments are deterministic rubrics — no model call, no dependency.
Set FORGE_LLM=1 to add a thin, opt-in semantic layer on top: a cheap claude -p
call proposes a completeness reading (M2), a complexity band (M1), the coupled edges the
regex graph misses (impact), and whether an off-goal file actually serves the goal (M4).
Open the interactive diagram: pan, zoom, search, and trace any node.
The model proposes; the deterministic rubric, the code graph, and the tests verify. The verdict only moves when the proposal survives that check — otherwise it falls back, unchanged.
The model is never the judge — only a proposer. Every proposal is verified before it can move a verdict, in the direction of the paper's tabayyun gate (49:6). By default the reconcile is bidirectional but rail-guarded — a verified reading can lower caution as well as raise it, but never past a hard floor:
- routing — the proposer votes a band and the reconcile compares it with the band the
deterministic score is already in. A vote for a lower band moves the score to that band's
ceiling only when the vote's p(band) reaches
llm.minConfidence, and never below a strong-signal (algorithmic/architectural) floor, so a "distributed rate-limiter" can't be talked down to the cheap tier. A vote for a higher band is not applied — escalation follows a verifier failure, never the model's self-assessment (§5.1). The tier it would have picked is reported asllm.escalateTo, an advisory recommendation that nothing acts on at routing time: it is recorded against the task, andforge diagnose --task "<task>"names it once the same failure signature has recurredTHRASH_Ktimes — a real external check failing, which is the only thing that may buy a bigger model (§5.1). The one exception is opt-in: withroute.mode: "unattended"(orforge route --mode unattended) a vote with p(premium) ≥ 0.9 raises to the premium tier and a mid-or-higher vote with p ≥ 0.5 to at least mid, because an agent nobody watches has no cheap retry loop; that mode also adds a writes-code floor, a keyword risk floor and a top-tier gate, each reported inpolicy.steps(see docs/ORCHESTRATION.md); - the assumption gate — can clear a false ask or add one, but never clears a task
with no concrete anchor, or one naming symbols/files the repo doesn't define (those floors
guard clearing only — they never raise an ask the rubric didn't). The rubric's completeness
and the proposer's are on different scales, so only their ask/proceed verdicts are compared,
and the proposer flips the rubric only when it holds its verdict with p ≥
llm.minConfidence; - impact edges — kept only if the file is real and a grep confirms the reference;
- goal-drift — rescues an off-goal file only with a goal-referencing reason (off→on only).
Note — set
llm.bidirectional: falseinsource/substrate.jsonfor the conservative mode (caution can only ever increase: the gate can only tighten, the tier never moves).
It is fail-safe: any error, timeout, or unparseable reply falls back to the deterministic
path (behaviour is byte-identical with the flag off), and it never blocks. --json output
carries an llm.provenance map (deterministic / llm-cleared / llm-tightened /
llm-lowered / llm-raise-deferred / llm-overruled / llm-verified) per faculty so every model-touched decision is
auditable. Off by default; the ambient Claude Code hook stays deterministic unless you also set
FORGE_LLM_AMBIENT=1. Config lives in
source/substrate.json → llm.
Heuristic, not benchmarked; the graph is regex-approximate; assumption detection is
lexical by default (FORGE_LLM=1 adds the verified refinement above — proposals are
checked against the repo/graph/tests before they count, never trusted blind); auto-run
needs a hook surface. Tests and human corrections always win. The full, canonical list:
docs/GUIDE.md → Honest limits.
- White paper — the full argument: HTML (with the 2026-09-21 and 2026-09-26 corrections) · PDF (historical, pre-correction edition; provenance in research/HISTORICAL_EDITIONS.md). Its two prototype results were refuted on real data — see research/empirical-refutation/.
- Package overview — headline results (refuted; see its banner) and prototypes
- Evidence map — every load-bearing statistic re-graded against primary sources (5 confirmed, 5 vendor-reported, 2 dropped); since 2026-09-26 it also grades claim support, study design, replication and transfer scope separately
- Ecosystem map — each capability vs. the real 2026 tool stack
- Prototype source — the auditable Python originals
- Claim status registry — every load-bearing headline with its status (implemented / measured / refuted / hypothesis / partial / reported) and evidence
research/cognitive-substrate/ is the canonical source. Four files here are byte-identical
copies kept for readers of docs/, and node scripts/claims-status.mjs --check fails when they
drift (sha256):
Copy in docs/cognitive-substrate/ |
Canonical source |
|---|---|
cognitive_substrate_whitepaper.html |
research/cognitive-substrate/cognitive_substrate_whitepaper.html |
cognitive_substrate_whitepaper.pdf |
research/cognitive-substrate/cognitive_substrate_whitepaper.pdf |
evidence_map.md |
research/cognitive-substrate/evidence/evidence_map.md |
ecosystem_map.md |
research/cognitive-substrate/evidence/ecosystem_map.md |
Edit the canonical file, then copy it over (node scripts/claims-status.mjs --sync-copies does
that). deliverable-package.md is not a copy: it is an adapted
edition of research/cognitive-substrate/EXECUTIVE_SUMMARY.md with links rewritten for this
folder, so it is edited by hand alongside it.
How the paper maps to what ships (all 11): memory → recall/cortex/ledger ·
learning → cortex + ledger oracles · imagination → imagine [--run]/impact ·
self-correction → verify/diagnose · impact-awareness → atlas/impact · M1 routing →
route · M2 assumption gate → preflight/context · M3 decomposition → scope ·
M4 goal-anchoring → anchor · M5 minimality → lean/uicheck design · M6 verification →
verify/substrate.