roam-code
The local codebase intelligence layer that lets AI coding agents earn the right to change code — with evidence for what was checked.
Credential-free · 100% local by default (opt-in metrics-push is the only outbound surface) · tamper-evident ChangeEvidence packets · Apache 2.0 · runs entirely on your machine
281 commands · 244 MCP tools (16 in the default core preset) · 28 languages

Jump to — Why Roam · Install · The Compiler · Core commands · MCP server · AI-tool integration · Roam Guard (PR gate) · Performance · Compare · Pricing · FAQ
Why Roam is different
METR and FrontierCode both point at the same gap: passing tests is not the same as mergeable code. Roam is an agent-first CLI surface that gives the agent local graph facts before it edits, gates risky changes, and emits scoped evidence after the run. In the agent/review tools surveyed as of 2026-06-12, the differentiator is this combination:
- Credential-free. No account, no API key, no cloud login.
pip installand run. - 100% local by default. Source code never leaves the machine; air-gapped repos work like cloud repos. The single outbound surface (
roam metrics-push) is opt-in, summary-only, and prints its exact payload under--dry-run. - Tamper-evident
ChangeEvidencepackets. A Roam-guided change can compile into one portable packet — HMAC-chained run ledger + signed Code Graph Attestation + signed PR bundle — answering eight questions: who acted, what authority existed, what context was read, what changed, what could break, what policy applied, what verified it, who accepted risk. PR Replay maps those eight questions today: structural change/risk/policy axes are in scope, context and verification are partial, and missing identity/authority/approval evidence is disclosed instead of invented. Cursor logs the run; Roam records and verifies the evidence its producers captured. - MCP runtime security at the wrapper boundary. Every MCP response is scrubbed for secrets on egress, gated against the active mode (
read_only/safe_edit/migration/autonomous_pr) with a closed-enumpolicy_decision, and each decision receipt is HMAC-linked into the signed run ledger. Inside-server controls; the gateway layer (Interlock / Lasso / Portkey) composes on top — seedev/MCP-SECURITY-POSTURE.md.
Underneath sits a SQLite-backed graph of symbols, calls, imports, layers, git history, runtime traces, smells, clones, security flows, and algorithmic patterns across 28 languages — the same local facts queried before, during, and after a change.
Dependency-aware, not string-based. Roam knows Flask has 47 dependents and 31 affected tests; grep knows it appears 847 times. One command replaces 5-10 tool calls — <0.5s per query, plain-ASCII output, --json and --sarif envelopes for agents and CI.
| Without Roam | With Roam | |
|---|---|---|
| Tool calls | 8 | 1 |
| Wall time | ~11s | <0.5s |
| Tokens consumed | ~15,000 | ~3,000 |
Illustrative — a typical agent workflow on a 200-file Python project (Flask). Reproducible smoke transcript in docs/fresh-install-smoke.md; full indexing-rate harness in benchmarks/. Exact numbers vary with repo size, agent prompt, and model.
Install + first four commands
About two minutes from pip install to a verdict on whether your next edit is safe.
pip install "roam-code[mcp]" # 1. install with MCP server for Claude Code / Cursor / Continue
cd /path/to/your/repo
roam init # 2. index the repo into .roam/index.db (one-time, ~30s on most repos)
roam health # 3. composite 0-100 score: complexity, cycles, dark-matter coupling, dead code
roam preflight <symbol> # 4. blast radius + tests + complexity + architecture rules before you edit
Python 3.10+. pipx install roam-code and uv tool install roam-code work too. Drop [mcp] for CLI-only. See docs/fresh-install-smoke.md for a verbatim transcript of these four commands against a clean venv.
Step 4 is the payoff — roam preflight on a hot symbol returns a verdict before you touch it:
$ roam preflight open_db
VERDICT: Significant risk — CRITICAL, 1847 symbols in blast radius
Pre-flight check for `open_db (src/roam/db/connection.py:799)`:
Blast radius: 1847 symbols in 382 files [CRITICAL]
Affected tests: 617 direct, 962 transitive [OK]
Complexity: cc=30, nest=4 [CRITICAL]
Coupling: 2 files often change together [MEDIUM]
Conventions: no violations [OK]
Overall risk: CRITICAL
Risk driver: complexity (cc=30, CRITICAL)
An agent sees the blast radius before it edits — not after the tests fail.
pipx install roam-code # isolated environment (recommended)
uv tool install roam-code # uv-managed tool
pip install git+https://github.com/Cranot/roam-code.git # from source
# Docker (alpine-based)
docker build -t roam-code .
docker run --rm -v "$PWD:/workspace" roam-code index
docker run --rm -v "$PWD:/workspace" roam-code health
Works on Linux, macOS, and Windows. Windows: if roam is not found after installing with uv, run uv tool update-shell and restart your terminal.
The Compiler — your agent's first token already knows the answer
You ask your agent "who calls handleSave?" and watch it grep, open
three files, grep again, read a fourth — six turns and $1.30 later you get
the answer the repo's call graph held all along.
Roam ships a task compiler that ends that loop. Before your prompt reaches the model, roam recognizes what kind of question it is, runs the right code-graph lookups locally (~90 ms, zero model calls), and puts the answers into the prompt: the caller list with line numbers, the git history already filtered, the source around the bug line you cited. The agent's first words can be the answer.
For Claude Code it's one command, zero configuration:
pip install "roam-code[mcp]"
cd your-repo && roam init
roam hooks claude --write # compile-before + verify-after, wired into Claude Code
Then use claude exactly as you always do. Undo anytime with
roam hooks claude --uninstall --write. Compile-time context injection is
fail-open. After an edited turn, the Stop gate is deliberately fail-closed:
findings, malformed output, an unavailable check, or incomplete evidence must
be resolved before Claude reports completion. No-edit Q&A turns fast-exit.
What that buys you, measured head-to-head on Claude (same prompts, same repo, with and without the compiler — June 2026, 41 cells):
| Median per task | vanilla | compiled | delta |
|---|---|---|---|
| Agent turns (navigation/comprehension) | 6 | 1 | −83% |
| Input tokens | 271K | 53K | −80% |
| Cost | $1.30 | $0.48 | −63% |
| Wall time | — | — | −50% |
A second run on Opus shows the same direction at smaller magnitude (−33% turns overall; the best single cell hit −88%). And the compiler knows where it doesn't help: prompts that ask the agent to write code get no envelope at all — injection there was measured as pure overhead, so it spends your tokens only where it wins.
| Task | turns | input tokens | cost |
|---|---|---|---|
"where is open_db defined?" |
3 → 1 | 156K → 51K | $0.67 → $0.28 |
"which files depend on cli.py?" |
6 → 1 | 252K → 51K | $1.15 → $0.30 |
| "where is the env var configured?" | 9 → 1 | 497K → 53K | $1.40 → $0.31 |
| "what are the layers of this codebase?" | 5 → 1 | 271K → 50K | $1.42 → $0.41 |
"what changed in cli.py recently?" |
4 → 2 | 186K → 104K | $0.62 → $0.40 |
| "explain the compiler module's architecture" | 13 → 6 | 618K → 240K | $1.85 → $1.01 |
| "trace how a command becomes an MCP tool" | 12 → 8 | 464K → 303K | $1.25 → $1.01 |
| security-hook comprehension (hard, multi-file) | 6 → 2 | 267K → 117K | $1.15 → $0.56 |
| "what are the biggest cycles in this codebase?" (re-measured 06-11) | 6 → 1 | — | $0.65 → $0.07 |
| "where is the CLI entry point?" (trivial, re-measured 06-11) | 1 → 1 | 48K → 50K | $0.21 → $0.22 |
| "write a pytest for X" (generation, re-measured 06-11) | 5 → 7 | 275K → 396K | $0.61 → $0.45 |
The last two rows were the published LOSSES (trivial prompts once paid the envelope for nothing at +$0.20; generation once cost +17%). After the generation-skip lever (write-code prompts get a ~0.6 KB lean envelope or none — measured 3.5% of a 723-prompt real corpus) and the entry-point routing fix, both cells were re-measured at n=3 medians on the same model: generation flipped to a −26% cost / −18% wall win — input tokens rise (cache-read-heavy, cheap) while expensive output tokens drop −29% across more-but-cheaper turns — and the trivial cell is a tie within noise. Losses are findable because we publish them — and fixable because the compiler routes them.
Bug-fixing, ground-truth graded (a failing test must transition to passing — no LLM judging): 20 cells of planted bugs with real tracebacks — 10/10 fixed in both arms at −13% dollar cost. Read that honestly: n=10 cannot establish quality parity (the 95% interval on 10/10 spans [72%, 100%]), and the dollar saving comes with more tokens, not fewer on this task class — the envelope shifts spend into cheaper cache reads. No quality difference was detected; the sample has little power to detect one.
Routing, replayed on 723 real prompts from live agent sessions: 57% of envelopes ship pre-executed answers (L1 probes) — the envelope already contains the literal answer — and a further ~33% ship structured facts (context, not the literal answer), at p50 0.45 s cold / p50 92 ms live (warm cache) compile latency, fully local. Zero model calls.
Eval history by version — re-measured on every kernel change; losses are published, attacked, then re-measured. The table below is the summary ledger; raw per-cell data for the historical runs is retained privately, not in this repository:
| measured | kernel | what | result |
|---|---|---|---|
| Jun 09 | v13.4 | 41-cell nav/comprehension A/B | turns −83%, tokens −80%, cost −63% |
| Jun 09 | v13.4 | 20-cell ground-truth bugbench | 10/10 both arms (n=10 — no parity claim), $ −13% but tokens up |
| Jun 09 | v13.4 | trivial-prompt cell | +80% cost — published loss |
| Jun 09 | v13.4 | generation cell | +17% cost — published loss |
| Jun 11 | v13.6 | trivial-prompt cell, re-measured n=3 | tie ($0.21 → $0.22) |
| Jun 11 | v13.6 | generation cell, re-measured n=3 | −26% cost win |
| Jun 11 | v13.6 | "biggest cycles" cell, re-measured n=3 | −89% cost win ($0.65 → $0.07, 6→1 turns) |
| Jun 11 | v13.6 | 723-prompt routing replay | 57% L1 (answer-shipping) + ~33% facts, p50 0.45 s cold |
| Jul 11 | v13.7 | live dogfood rolling window (separate population, not the replay harness) | cold-compile median 410 ms |
Caveats that always ship with these numbers: trivial prompts the agent one-shots anyway gain nothing (now a within-noise tie after the lean/skip levers); cells are n=2–3 with medians and ranges.
Two independent A/B runs at different scales — the larger sample inverts the smaller. Reporting both honestly.
Run #1 (n=3 per cell, 27 cells, $16.88): compile appeared to dominate (−29% wall vs static). That static prompt included a "Hard cap: 4 tool calls" line that turned out to act as a quota.
Run #2 (n=3–7 per cell, 78 cells, $54.88, "Hard cap" line removed from static):
| Condition | Mean turns | Mean wall | Mean cost |
|---|---|---|---|
| vanilla | 7.0 | 33.2s | $0.68 |
| static / roam_agent | 5.8 | 25.1s | $0.66 |
| compile | 8.2 | 47.9s | $0.78 |
At scale, static (with the "Hard cap" line removed) is the winner: −17% turns and −24% wall vs vanilla, with cost within 3%. The compile-mode envelope was +91% wall vs static on hard structural tasks — variance probe revealed compile occasionally pushes the agent into over-tool-use (one t1 run hit 41 turns and $2.43). The compile-the-COMMAND itself is robust (250/250 latency cells, 14/15 fuzz, brief mode <300 chars across all 10 procedure families) — the issue is over-direction of the consuming agent, not the compiler.
Private raw cells are retained for audit; the public summary above is the quotable result.
Run #3 (2026-05-31, n=1, 24 cells, $12.78, on 8-task user-shape corpus after W34→W37 fixes):
| Condition | Mean turns | Mean wall | Mean cost |
|---|---|---|---|
| vanilla | 6.00 | 28.6s | $0.58 (1 cell timed out at 240s) |
| static / roam_agent | 5.38 | 39.9s | $0.63 |
| compile | 2.75 | 35.6s | $0.46 |
This run inverts Run #2 on a different corpus. Compile wins 7/8 shapes including stack-trace, "what does X do", "what changed recently", compare files, who calls X, file coupling, and trace-flow. The compiler fix wave between Run #2 and Run #3 added six new probes (stack-trace source slice, body-embed for explain, git-log for history, sibling-test embed, path-comparison diff, symbol-pickaxe) and four real bug fixes (callers-backtick fallback, dead-code wrong CLI, consumer-dict flattening, stack-trace classifier missing PascalCase Errors). Headline win: a "what files are coupled to X" task that took vanilla 20 turns / $1.20 / 64s collapsed to compile's 1 turn / $0.32 / 11s — embedded coupling pairs eliminate 19 turns of exploration. The +24% wall vs vanilla is the envelope cache-creation tax at n=1; expected to amortize at n≥3.
Static remains a non-improvement (0/8 wins vs vanilla, 1/8 marginal vs compile). Caveat: Run #3 is n=1 per cell; n=3 replication ($30-40) is pending.
Private per-task tables and raw cells are retained for audit; the public summary above is the quotable result.
Run #4 (2026-05-31, n=1, 24 cells, $13.00, same corpus after W43→W45 polish/improvements/corrections):
| Condition | Mean turns | Mean wall | Mean cost |
|---|---|---|---|
| vanilla | 5.25 | 39.6s | $0.63 |
| static / roam_agent | 4.75 | 32.8s | $0.61 |
| compile | 1.88 | 25.2s | $0.40 |
Compile now wins 8/8 shapes and the +24% wall penalty from Run #3 is gone: compile is −36% wall vs vanilla. Aggregate −64% turns / −36% cost / −36% wall vs vanilla on Opus 4.7. The flip came from three wave-43-to-45 changes: (a) a 60-second bounded cache on _run_roam subprocess calls, (b) anti-Read directives in the stack_trace_fix and synthesis_query answer contracts, and (c) richer enrichment in the write_pytest probe (sibling test + source under test + nearest conftest.py together). The biggest single delta: write_pytest went from 10 vanilla turns to 6 compile turns (−40%, saving $0.29 / cell). Static remains 0/8 wins and should be retired from the default bench-compile conditions in a future release.
Private per-task tables and raw cells are retained for audit; the public summary above is the quotable result.
Headless for scripts and CI: roam compile "<task>" --artifact auto.
Prefer a dedicated product CLI? The same loop ships as
compile-code —
starting with v0.2.0, install it from PyPI with pip install compile-code,
then run compile claude.
The verify half of the loop — what runs after every edit
The compile half front-loads facts; the verify half reviews what the agent
just changed. roam verify --auto scopes to the touched files, auto-selects
the checks that make sense for what changed (Python edits unlock the Python
checks, source edits unlock naming/duplicates), and runs:
- naming — against the codebase's own per-language convention (sampled
from production code only: test/vendored/generated files neither vote nor
get flagged, framework lifecycle names like
setUpare never touched) - imports — the hallucination firewall: every import must resolve — to the index, the stdlib, or a declared dependency. A module path that resolves to nothing fails as a likely hallucination; near-miss names get fuzzy did-you-mean candidates
- error handling / syntax / complexity / cycles / duplicates — scoped structural review with honest disclosure when any sub-check could not run
- secrets — a leak gate over every touched file: credential shapes
(cloud keys, tokens, PEM blocks) fail the check, and an optional
repo-local
.roam-leak-patterns.pycatalogue catches the strings your project must never publish - patterns (advisory,
--deep) — the algorithm/idiom catalog scoped to the diff: N+1 query shapes, loop-invariant calls, string-concat loops, each with the better approach and a fix sketch
The fix loop. Wired via roam hooks claude --write, findings come back
to the agent as an actionable list — fix, then re-verify — and the gate runs
again on each correction (Claude bounds consecutive continuations). A
human-reviewed exception can be recorded in .roam-suppressions.yml, keyed by
symbol so it survives refactors that shift line numbers; automatic hook
corrections cannot alter suppressions, policy, baselines, or verification
scope. The compile hook remains fail-open. The edited-turn Stop gate is quiet
only on a complete PASS and blocks when verification is unavailable,
malformed, incomplete, or reports non-advisory findings.
Scoping and debt control — the flags that make verify usable on a codebase with history:
roam verify --auto # changed files, auto-selected checks
roam verify --diff-only # only lines you changed vs HEAD
roam verify --changed-lines cli.py:40-90 # exact ranges (agent harnesses)
roam verify --baseline-write # snapshot current findings as accepted debt
roam verify --new-only # then: only NEW findings fail
roam verify --report --severity fail # whole-repo ranked punch-list (non-gating)
roam verify --off / --on # pause / resume the loop repo-wide
The commands that run beside it in the same post-edit stance:
| Command | Role in the loop |
|---|---|
roam verify-imports --path src/roam/cli.py |
The hallucination firewall, standalone — validates every import resolves |
roam delete-check --ci |
Gates a deletion diff on surviving references (exit 5 on BREAK-RISK) |
git diff | roam critique |
Clones-not-edited check + blast radius on the patch (exit 5 on high severity) |
roam verify --report --persist |
Writes findings to the registry so the compiler embeds them as known_findings in future envelopes — debt gets fixed opportunistically |
Measured, not asserted. The detector quality is pinned by three eval suites in CI: a planted-issues recall corpus (every category must catch its canonical positives), a clean-corpus false-positive lock (dogfooded on this repo: the naming rule alone dropped ~2000 FPs when test files stopped voting), and an adversarial suppression fuzz suite (suppressions survive refactors, never lose entries).
What's New
v13.10 (2026-07-19) — repeated work becomes measurable procedures, and post-edit verification becomes proof-complete. Privacy-preserving transcript/shell-template mining can nominate repeated-work interventions without exposing raw prompts or claiming causal savings; roam savings promotes only prospectively joined, integrity-checked outcomes. The Claude adapter now binds every edited turn to a strict Verify receipt and blocks unavailable, malformed, incomplete, or failing evidence. Roam owns the canonical hooks end to end—Compile Code no longer rewrites installed source. Full notes: CHANGELOG.md.
v13.6 (2026-06-11) — The verify loop grows teeth + compiler injection economics. The post-edit loop now runs a secrets leak gate by default (credential shapes + an optional repo-local .roam-leak-patterns.py catalogue) and an advisory algorithm/idiom sweep scoped to the diff; suppressions are symbol-keyed (refactor-proof) and the suppression file is append-only after a confirmed data-loss fix; the naming rule samples production code only (~2000 false positives removed on a test-heavy codebase) and verify --auto is 16× faster on sweeping diffs. The compiler learns injection economics — generation-shaped prompts get no envelope (measured pure overhead) — plus graph-ranked retrieval (PageRank + file-role + path-token blend), new answer probes (taint scan, world-model idempotency/side-effects, design patterns, scoped algo findings, and verify findings riding into envelopes as known_findings), and routing waves for trace/entry-point phrasings. New offline lock suites (procedure-registry lint, suppression fuzz corpus, self-dogfood FP lock, envelope byte budgets, L1-rate floor) and a prepush_check.py --release gate that proves the full CI surface green before any release push. Full diff in CHANGELOG.md.
v13.5 (2026-06-10) — Compiler coverage waves + the Claude Code adapter. Eight new compile intent procedures land from production-telemetry mining (file_history "what changed in X last week", repo_structure layers/clusters/health, entry_point_where with the authoritative [project.scripts] answer, config_where env-var lookup, module-name describe_file recall, session_meta, a zero-probe fast-path for self-contained batch prompts, and a bug_site_slice that embeds the source around "fix the bug in cli.py:45"); roam hooks claude --write wires the full compile-before/verify-after loop into Claude Code in one command (fail-open, idempotent, --no-verify / --uninstall); two reliability fixes seal a CliRunner stdout-swap race in the in-process probe pool and add a compiler fingerprint to all three compile cache keys; envelope-diff regression rules stop false-flagging budget bookkeeping keys. Compiler A/B on Claude (Fable 5): −83% turns / −80% input tokens / −63% cost on nav-comprehension (41 cells). Full diff in CHANGELOG.md.
v13.4 (released 2026-05-21) — Perf wave + Pattern-1 stabilisation + assurance hardening. Major detector speed-ups (clones 43.8s → 13.1s, intent 66s → 12s, doc-staleness 93s → 19s, sbom 30s → 9s — all byte-identical output), 17 commands now emit isError/status on error envelopes + 11 commands route their argless --json path through a proper envelope (Pattern-1C drift-guards added), a persisted per-snapshot spectral gap powering a real roam forecast failure budget, MCP prompt-injection marker scan on tool-call egress, release supply-chain hardening (PEP 740 attestations, tag-bound artifacts), and large false-positive cuts in feature-envy / shotgun-surgery / god-components. Full diff in CHANGELOG.md.
v13.3 (released 2026-05-19) — MCP runtime security + UX polish
- Egress secret-redaction at the MCP wrapper boundary, 4-mode
policy_decisionenforcement with shadow-mode (ROAM_MODE_DRY_RUN), HMAC-linkedMcpDecisionReceipt+receipt_integrityverdict onroam runs verify. - 3 new persisting detectors (
boundary,test-hermeticity,compatibility),roam doctoradvisory-vs-blocking split, and--jsonwarnings-channel discipline.
v13.2 (released 2026-05-16) — Evidence freshness + resolution disclosure
- Canonical unresolved-path envelopes across
impact/preflight/trace/test-map/context/safe-delete/split/why— one explicit "not found" shape in JSON mode. - Evidence freshness stamped at the producer. Runs record hashes for
.roam-rules.yml,.roam/constitution.yml,.roam/control-map.yml. - PR Replay evidence coverage improved. Replay path maps the 8 evidence questions, fully answers structural change/risk/policy axes, and marks identity/authority/approval evidence as partial, out of scope, or
producer_not_availableinstead of silently omitted.
v13.1 (released 2026-05-15) — Pattern-2 propagation + shared YAML helper + 3 flagship silent-fallback seals
- 3 flagship silent-fallback seals.
cmd_taint,cmd_health,cmd_doctornow emitstate="empty_corpus"+partial_success=Trueon unanalyzed repos instead of falseHealthy 100/100/No taint findings/all checks passedverdicts. - Shared YAML config-loader helper (
load_yaml_with_warnings). 5 of 7 surveyed loaders migrated; ~125 LOC removed. - 5 new live smell detectors.
type-switch,speculative-generality,empty-catch,cross-layer-clone,parallel-hierarchy—roam smellsnow ships 24 deterministic detectors. - 30+ behavioral Pattern-2 fixes + empty-corpus smoke sweep across 25+ detectors.
v13.0 (released 2026-05-13) — Agent-OS substrate + Laravel idioms + Vue SFC
- Agent-OS control plane. Repo-local substrates under
.roam/: constitution, HMAC-chained run ledger, multi-agent leases, portable agent memory, 4 cumulative modes (read_only→safe_edit→migration→autonomous_pr). - World-model classifiers (R28).
roam side-effects,roam idempotency,roam causal-graph,roam tx-boundaries. - Laravel dynamic-dispatch idioms. 7 of 8 implicit-edge idioms (Route closures, Eloquent scopes, Policy resolution, Observer registration, Job/Queue/Artisan dispatch).
- Vue SFC import graph.
.vuetemplate/script/style blocks parsed; component registrations resolved across the SFC boundary. - ~20 new CLI commands (
brief,next,mode,constitution,laws,memory,lease,runs,replay,agent-score,agents-md, …) and schema bump (USER_VERSION 12 → 13).
Full release notes in CHANGELOG.md.
Best for
- Agent-assisted coding — structured answers that cut tokens vs raw file exploration
- Large codebases (100+ files) — graph queries beat linear search at scale
- Architecture governance — health scores, CI quality gates, budget enforcement, fitness functions
- Safe refactoring — blast radius, affected tests, pre-change safety checks, graph-level editing
- Multi-agent orchestration — partition codebases for parallel agents with conflict-aware planning
- Security analysis — vulnerability reachability, auth gaps, CVE path tracing, taint analysis
- Algorithm optimization — detect O(n²) loops, N+1 queries, and 32 other anti-patterns with suggested fixes
When NOT to use Roam
- Real-time type checking — use an LSP (pyright, gopls, tsserver). Roam is static and offline.
- Small scripts (<10 files) — read the files directly.
- Pure text search — ripgrep is faster for raw string matching.
What's measured vs advisory
Roam's surfaces differ in how rigorously they've been validated — know which is which before you gate on them:
-
Repair-intent retrieval (
roam retrieve --repair-intent <patch>) — the one surface with a preregistered, held-out, stranger-repo result. Give it the diff of a fix you just made and it reranks toward the other files that need the same repair, rather than the files that merely look similar. Measured on 576 real multi-site fixes from 12 third-party repos (rich, aiohttp, httpx, fastapi, click, flask, jinja, werkzeug, pydantic, pytest, attrs, urllib3), frozen before scoring and shipped in-repo:vs plain lexical search delta 95% CI (bootstrap, n=2000) nDCG@10 +0.064 (0.605 vs 0.541) [+0.032, +0.097] P@3 +0.041 [+0.024, +0.058] MRR +0.059 [+0.026, +0.092] recall@10 +0.034 [−0.002, +0.070] — not significant That clears the preregistered bar (nDCG@10 ≥ +0.05 with a CI excluding zero) and it survived an adversarial falsifier. Read it for what it is: a real but modest improvement over lexical search on this task — not a step change. The one striking result underneath: our graph-sibling candidate pool on its own scores 0.258, far worse than lexical's 0.541. It only beats lexical once repair-intent reranking is applied. The reranking is not polish on a good pool — it is the reason the pool is usable at all.
Scope honestly: it needs a real patch as input, and it finds repair siblings. It is not a general-purpose search improvement, and recall is not measurably better. This is the only roam surface we would put in front of your codebase without hedging.
-
Reachability triage (
roam vuln-reach,roam sbom) — the most conservatively designed surface: reachability is derived only from import evidence (import sites and import edges, with file:line), never from symbol-name coincidence, so a CVE with no import evidence reports as unknown rather than reachable. Strong precision by construction; real-CVE recall on unfamiliar repos is still being measured — use it as a high-precision triage signal, and treat "unknown" as unverified rather than safe. -
Taint packs (
roam taint) — validated on synthetic fixtures; real-code recall on arbitrary repositories is low/unmeasured. Treat findings as leads to investigate, not a completeness guarantee; the--cigate is opt-in. -
Idiom & long-tail detectors (
roam auth-gaps,roam missing-index,roam over-fetch,roam n1, framework idioms) — advisory. Blind precision on unfamiliar repos is not yet measured for all of them, and framework idiom detectors that measured low on stranger repos are opt-in (not on the default surface). Review each finding; don't gate CI on these alone.
Core commands
Lead with the 5 verbs. The 5 core commands cover ~80% of agent workflows: understand, context, retrieve, preflight, critique. The remaining ~276 commands are detail surface for specialised workflows (taint, fleet, cga, oracle, eval, …) — they're called by agents on demand, not memorised. This is intentional design; under the hood the canonical surface is 281 commands (274 canonical + 7 aliases) organised into 7 categories (aliases for muscle memory: math → algo, churn → weather, digest / snapshot / trend → trends, onboard → understand, refs → uses), but you don't need to know that to start.
| Verb | What it does |
|---|---|
roam understand |
Full codebase briefing: stack, architecture, key abstractions, health, conventions, entry points |
roam context <symbol> |
AI-optimized context: definition + callers + callees + files-to-read with line ranges |
roam retrieve <task> |
Graph-aware context for free-form tasks ("trace login flow", "where is the n+1?") — FTS5 + structural rerank within a token budget |
roam preflight <symbol> |
Pre-change safety gate: blast radius + tests + complexity + coupling + fitness |
roam critique |
Verify a patch against the graph: clones-not-edited + blast radius + intent vs semantic-diff. Pipe git diff in; exit 5 on high severity |
The full surface spans 7 categories — Getting Started, Daily Workflow, Codebase Health, Architecture, Exploration, Reports & CI, and Refactoring. Run roam --help for the 5-verb core, roam --help-all for every command name, and roam surface --json for the machine-readable inventory. Every command accepts roam --json <cmd> for structured output and roam --sarif <cmd> for CI integration (SARIF 2.1.0, honoured by 36 commands).
The complete, always-current list with flags and examples lives in the Command Reference.
A few representative commands beyond the core five:
- Health & architecture:
roam health(0-100 score),roam weather(churn × complexity hotspots),roam smells(24 deterministic detectors),roam algo(34-task anti-pattern catalog),roam clusters/roam layers/roam cycles. - Change safety:
roam impact <symbol>(blast radius),roam diff(uncommitted-change blast radius),roam pr-risk(0-100 PR risk),roam diagnose <symbol>(root-cause ranking). - Backend quality:
roam n1(N+1 queries),roam auth-gaps,roam missing-index,roam over-fetch,roam taint(graph-reach taint, 10 rule packs). - Index-aware search:
roam search <pattern>,roam grep <pattern> -C 5(grep + bounded code packets + reachability + PageRank),roam grep <pattern> --whole-symbol(deduplicated enclosing functions/classes),roam uses <name>(graph-precise references, no string-literal false positives). - Multi-agent:
roam orchestrate --agents 3(conflict-aware partitioning),roam fleet plan,roam lease(parallel-agent coordination).
Walkthrough
How you'd use Roam to understand a project you've never seen before, using Flask as an example.
$ roam understand
Tech stack: Python (flask, jinja2, werkzeug)
Architecture: Monolithic — 3 layers, 5 clusters
Key abstractions: Flask, Blueprint, Request, Response
Health: 78/100 — 1 god component (Flask)
Entry points: src/flask/__init__.py, src/flask/cli.py
$ roam file src/flask/app.py # file skeleton: definitions + signatures + health
$ roam deps src/flask/app.py # what imports this file
$ roam weather # hotspots ranked by churn × complexity
$ roam health # composite 0-100 + god components / cycles / layer violations
$ roam context Flask # AI-ready context: files to read with line ranges
$ roam preflight Flask # pre-change gate: blast radius + tests + complexity + fitness
$ roam split src/flask/app.py # internal symbol groups + extraction suggestions
$ roam why Flask url_for Blueprint # role classification (Hub/Bridge/Core) + reach + risk
$ roam health --gate # CI quality gate (exit 5 on failure)
Ten commands. Complete picture: structure, dependencies, hotspots, health, context, safety checks, decomposition, and CI gates.
Integration with AI coding tools
Roam is designed to be called by coding agents. Instead of repeatedly grepping and reading files, the agent runs one roam command and gets a verdict-first envelope. roam preflight (above) replaces grep+read+test-impact+complexity+fitness in one ~3KB call; roam health rolls the whole codebase into one score:
$ roam health
VERDICT: Fair codebase (75/100) — 47 critical, 9 warnings, focus: god_components
Health Score: 75/100 | Tangle: 0.0% (7/33395 symbols in cycles)
Propagation Cost: 0.1% | Algebraic Connectivity: 0.0074
Health: 67 issues — 47 CRITICAL, 9 WARNING, 19 INFO
Breakdown: cycles [1 CRITICAL, 1 WARNING], god [31 CRITICAL, 8 WARNING, 11 INFO], bottlenecks [15 CRITICAL]
Top CRITICAL issues (run `roam --detail health` for the full breakdown):
cycle (5 symbols): _COMMANDS, complete, _reconstruct_command
god component: path (prop, degree=2408)
The verdict line works alone — an agent that reads nothing else still knows where to look. Pipe --json for the structured envelope your agent consumes.
Fastest setup (Claude Code): wire the compile/verify loop in one command — no config files, no MCP setup, no rules to write:
roam hooks claude --write # compile-before + verify-after hooks; --uninstall to undo
For other agents (or alongside the hooks), point them at Roam via instructions in their config file:
roam describe --write # auto-detects CLAUDE.md, AGENTS.md, .cursor/rules, etc.
roam describe --agent-prompt # compact ~500-token prompt — copy-paste into an existing config
roam minimap --update # inject/refresh an annotated codebase minimap (won't touch other content)
This teaches the agent which command fits each situation: roam preflight before changes, roam context for files to read, roam diagnose for debugging.
| Tool | Config file |
|---|---|
| Claude Code | CLAUDE.md in your project root |
| OpenAI Codex CLI | AGENTS.md in your project root |
| Gemini CLI | GEMINI.md in your project root |
| Cursor | .cursor/rules/roam.mdc (add alwaysApply: true frontmatter) |
| Windsurf | .windsurf/rules/roam.md (add trigger: always_on frontmatter) |
| GitHub Copilot | .github/copilot-instructions.md |
| Aider | CONVENTIONS.md |
| Continue.dev | config.yaml rules |
| Cline | .clinerules/ directory |
MCP Server
Roam includes a Model Context Protocol server for direct integration with MCP-aware tools.
pip install "roam-code[mcp]"
roam mcp
Default preset: core (17 tools: 16 core + roam_expand_toolset meta-tool).
244 MCP tools span 8 selectable presets (core, review, refactor, debug, architecture, compliance, compile-curated, full); core stays narrow to keep the prompt tight. Most tools are read-only index queries; side-effect tools are explicitly annotated. Set `ROAM_MCP_PRESET=full roa
No comments yet
Be the first to share your take.