After indexing a repo, agents can query local symbols, calls, dependencies, and Git history through the CLI or available MCP tools. Runtime hot-path analysis additionally needs ingested traces. The questions below help choose useful checks for a change.
These are investigation routines, not a guarantee against defects. Read the reported source, refresh the index as code changes, and run the project's required tests. Select the checks that answer the current question instead of treating every change as the same task.
Surface at a glance
Authoritative counts from roam surface --json
(v14.1.0). The MCP server exposes a tunable preset surface so the
agent sees what it needs, not the entire registry.
| Surface | Count | Notes |
|---|---|---|
| CLI commands | 287 | 280 canonical + 7 aliases. |
| MCP tools registered | 246 | Full registry — pick a subset via preset. |
MCP tools in core preset | 17 | Default for new agent integrations. |
| Languages | 28 | Tier-1 extractors plus tree-sitter fallback. |
| Result contracts | Command-specific | Shared analysis envelope conventions, plus MCP errors, metadata tools, and paginated handles. Inspect the relevant schema. |
1. Before editing — ask for context
$ roam context <symbol-or-file>
Returns ranked source locations and related code to inspect. Use
callers, callees, and test candidates to guide reading; the ranking
does not guarantee that every relevant file is present. Use full
--json output when saving evidence or making a gate decision.
2. Before deleting — ask for impact
$ roam impact <symbol>
Inspect callers and transitive relationships visible in the index.
A newly discovered caller is a reason to inspect the deletion's effect,
not proof that it breaks. Pair with
roam safe-delete <symbol> for a
SAFE, REVIEW, or UNSAFE verdict.
Unresolved use in an imported file requires review; an absent graph edge
does not prove that dynamic or external consumers do not exist.
3. Before merging — ask for critique
$ roam --json critique --working-tree --intent "Describe the intended change"
Patch-level structural review. Catches clones-not-edited
(the agent updated one of three near-identical implementations),
caller-impact spikes, and intent mismatch. Exits 5 when high-severity
findings are present. Inspect check_status and skipped-check
reasons: a partial critique is not merge approval. Clone comparison
requires a current roam --json clones --persist scan.
The working-tree form selects tracked staged and unstaged changes
against HEAD, not untracked files. For a different range, capture
the intended Git patch successfully and supply it with --input.
Inspect summary.review_source.
4. Before refactoring — simulate first
$ roam simulate move <symbol> <new-file> $ roam simulate extract <symbol> <new-file> $ roam simulate delete <symbol>
Clone the graph, apply the transform, and inspect predicted metric
changes before editing source. A simulation does not establish semantic
correctness. roam mutate is a separate source-change workflow;
roam plan-refactor plans a symbol refactor, while
roam split <file> proposes file-level decomposition.
5. Before optimising — ask for algorithmic risk
$ roam math $ roam algo --confidence high
Inspect candidate algorithmic risks that ordinary syntax/style checks can miss: nested-loop lookups becoming O(n²), N+1 queries, regex compiled inside hot loops, repeated JSON parsing, quadratic string concatenation, branching recursion without memoisation. Check the matched source, varying loop inputs, receiver identity, call ordering, and measured cost before applying advice; a matching pattern is not a performance proof.
Pairs with roam n1, roam missing-index,
and roam hotspots for ingested runtime evidence.
hotspots requires runtime traces; static churn/complexity
rankings are a different metric. See the
evidence limits.
The whole contract, in one block
# Before any edit $ roam context <target> # Before any deletion $ roam impact <target> $ roam safe-delete <target> # Before any merge $ roam --json critique --working-tree --intent "Describe the intended change" # Before any refactor $ roam --json simulate move <symbol> <new-file> $ roam plan-refactor <target> # Before any optimisation pass $ roam math $ roam hotspots --danger
The canonical JSON envelope
Analysis commands share envelope conventions, but command data, MCP error results, metadata tools, and response handles have different contracts. The following is an illustrative error-result sketch, not a universal success schema. Check the installed tool's schema and the actual result state before reading its summary.
{
"command": "<tool_name>",
"status": "<index_not_built | advisory_warnings | partial_failure | hard_failure | usage_error | rate_limited | stale_index>",
"isError": true,
"summary": {
"verdict": "<one-line, imperative, concrete-noun terminal>",
"level": "<blocker | warning | info>",
"partial_success": false,
"state": "<machine-readable state>"
},
"error_code": "<closed enum>",
"error": "<human-readable error text, never raw JSON dump>",
"hint": "<imperative: what to do next>",
"next_command": "<copy-pasteable roam command, when applicable>",
"retry_after_seconds": 60,
"agent_contract": {
"facts": ["<concrete-noun anchored fact>", "..."],
"next_commands": ["<copy-pasteable>", "# explanation..."]
},
"_meta": { "timestamp": "...", "index_age_s": 42 }
}
Result-reading rules:
isError: truesits inside a successful JSON-RPC result; it is not a protocol-level error. Protocol errors do not reliably reach the LLM context window.- Preserve useful observations from failed or partial results,
but keep missing computation explicit.
partial_success: falsealone does not establish success; the cold-start error uses that value too. - The
errorfield carries actionable guidance, never a raw exception trace. - Use
summary.verdictfor orientation, then inspect error state, required scope, freshness, failed checks, and caps. A completed zero-finding scan is valid within its bounds; an empty list without scan evidence is unknown. - Fetch required detail from response handles. Complete delivery does not repair incomplete computation; a complete requested projection need not include unrelated sections.
next_command(when set) is a literal copy-paste-executableroam <subcommand>string, not a description.
Worked example: the cold-start envelope an MCP tool returns
when .roam/index.db does not exist yet —
/docs/mcp-usage#the-cold-start-envelope.
Verdict vocabulary — concrete nouns only
Roam's maintained writing convention anchors
agent_contract.facts in concrete objects or measured
states. It is not a guarantee about how every model reasons. A
fact-string is anchored when its terminal token (last word,
punctuation stripped) is one of the canonical anchors. The
live set lives in
src/roam/output/formatter.py and is mirrored by
the LAW 4 lint at tests/test_law4_lint.py.
| Family | Representative anchors |
|---|---|
| Code structure | files, symbols, edges, nodes, cycles, clusters, layers, modules, commands, tools, capabilities, imports, endpoints, dependencies, packages, routes |
| Findings | findings, hotspots, smells, violations, warnings, errors, alerts, issues, gaps, leaks, secrets, vulnerabilities |
| Quality metrics | keys, values, chars, lines, tokens, bytes, items, entries, records, fields |
| State qualifiers | passed, failed, scanned, checked, affected, scored, confirmed, analyzed, skipped, reached |
| Time units | days, weeks, months, years, hours, minutes, seconds, milliseconds |
Wrong: "7 of 10 capabilities are AI-safe" (ends on
AI-safe, not anchored). Right:
"7 of 10 AI-safe capabilities" (ends on
capabilities, anchored). When an agent generates a
fact for a consumer, also check that the claim is supported and its
next action is usable. A grammatical anchor does not establish either.
The eight evidence questions
Roam can collect supported command evidence into a
ChangeEvidence packet organized around these eight
questions. Missing or incomplete evidence remains a gap; a packet
does not establish that every AI-assisted change was observed.
Each question maps to commands the agent already
runs as part of the contract above — the packet just makes the
answers portable for a reviewer.
| Question | Primitives |
|---|---|
| Who acted? | roam runs, roam replay, MCP receipt |
| What authority existed? | roam mode, roam permit, roam lease, roam constitution |
| What context was read? | roam context, roam retrieve, pr-bundle |
| What changed? | roam diff, roam pr-analyze, roam graph-diff |
| What could break? | roam impact, roam preflight, roam test-impact, roam vuln-reach |
| What policy applied? | roam rules, roam laws, roam check-rules |
| What verified it? | roam test-impact, roam critique, roam pr-bundle, roam runs verify |
| Who accepted risk? | roam permit, roam pr-bundle, audit trail |
Roam maps to and supports evidence for governance controls; it does not certify or make compliant. The evidence packet is portable input for the external GRC tool of your choice.
MCP boundary security
A valid packet, source hash, or signed ledger establishes only its checked contract. It does not independently prove the requested behavior, current-tree test execution, or active enforcement. Proof bundles retain review obligations and verifier results when written and read back; stronger trust still needs an independent consumer with the appropriate authority. Read the verification evidence guide for regression controls, serialization checks, and benchmark limits.
Roam owns the inside-server half of the agent's trust boundary: it runs locally as the same user as the editor, gates writes through a four-mode policy, and emits a tamper-evident decision receipt on every sensitive call. It is explicitly not a network gateway and does not proxy model traffic — gateway-class defences (semantic prompt-injection scanning, response interception, cross-server aggregation) are a complementary layer owned by your MCP host. See the Discussion #37 reply for the full inside-server-vs-gateway framing, and /docs/mcp-usage#security-stance for the public stance.
Egress secret redaction
Every MCP tool response passes through a structural secret-pattern
scan on the egress path
(redact_secrets_in_string /
redact_secrets_in_value) before the bytes leave the
server. Hits replace the secret with a stable placeholder and
stamp the receipt's redactions field with the
closed-enum reason secret. Structural injection-marker
observations use prompt_injection_marker; they are
signals, not secret substitutions. Consult the exported receipt schema
for the current vocabulary. Secret patterns cover GitHub
PAT (classic and fine-grained), OpenAI / Anthropic
sk- keys, AWS AKIA, Bearer tokens, PEM private-key
markers, and JWT. Per-pattern hit counts ride in
extra["redaction_details"] as
{pattern_id: hit_count}. These checks are bounded pattern
matching, not a guarantee that every secret or malicious instruction is detected.
Four-mode policy enforcement
Every MCP wrapper resolves the caller's mode
(read_only / safe_edit /
migration / autonomous_pr) and checks
the tool's required_mode before dispatch. The
receipt's policy_decision is a closed enum —
allow / deny /
escalate / redact /
not_evaluated / would_deny_dry_run —
reflecting an actual enforcement
decision at the MCP boundary, not a hard-coded allow. Resolution
is invocation-sensitive for mixed query/write wrappers: the query
form remains read-only, while an explicit persist or write control
raises both required_mode and the receipt's declared
effects. Configure the server's mode through its supported policy
interface and inspect the receipt's resolved mode and decision.
A CLI flag is not automatically an MCP argument; do not invent a
per-call mode parameter when the tool schema lacks one.
A generated .roam/constitution.yml remains fail-safe as
the command surface grows. New constitutions record a semantic SHA-256
of the exact generated modes snapshot in additive
generator metadata (the constitution document schema remains
version: 1). Roam follows newer generated defaults only
while the on-disk modes still match that recorded digest. Editing one
permission breaks generator ownership and keeps the customized lists
authoritative. In a partial customized policy, an omitted higher mode
inherits only the permissions already declared below it; absence never
imports a baked-in allow-list. Legacy files without a digest are also
authoritative:
roam constitution check reports their migration state,
roam constitution upgrade previews every per-mode addition
and removal, and --apply refuses a policy-changing legacy
or customized upgrade unless the caller also passes
--accept-mode-replacement and the preview's
--expect-modes-digest. That digest binds replacement to
the exact policy reviewed. The emitted recovery command includes the
audited --override-mode bootstrap escape so a stale policy
cannot block its own repair. The accepted write preserves unknown YAML
keys, uses an atomic compare-and-swap, and aborts if the file changes
during application.
HMAC-linked decision receipts
When an active run is available and linking succeeds, a receipt's
sha256 content hash is linked into the HMAC-chained ledger at
.roam/runs/<run_id>/events.jsonl. Receipts can also
exist without a run link. Inspect the actual linkage and verification
result before relying on offline tamper detection.
verify_chain_with_receipts() in
src/roam/runs/signing.py extends the standard
four-state run-verify envelope
(ok / tampered /
unsigned / key_missing) with a
receipt_integrity closed enum:
ok (every linked receipt's on-disk sha256 matches),
missing (a ledger event names a receipt file no
longer on disk), tampered (a receipt file no longer
hashes to the value the chain anchors), and
not_linked (no receipt-bearing events were found, or
chain tampering prevented receipt inspection). This verifier walks
ledger-linked receipts; it does not search for orphan receipt files.
Read the chain state as well as receipt integrity. Pre-link chains
remain compatible; no migration is needed.
Receipt schema export
The McpDecisionReceipt dataclass exports to a
Draft 2020-12 JSON Schema via
python -m roam.evidence.mcp_receipt_schema in the installed
Python environment. Gateway and
policy-enforcement-point developers can validate emitted
receipts against the schema before tailing them into SIEM. The
schema is schema-stable; field additions are additive.
What every McpDecisionReceipt carries
One JSON file per sensitive tool call, stored at
.roam/mcp_receipts/<run_id>/<tool_call>.json when
a valid run is selected, or under .roam/mcp_receipts/_no_run/
otherwise. Inspect storage and linkage failures in the actual result.
Frozen dataclass; canonical-JSON serialisation; stable sha256
content hash. Input/output hash fields contain digests, not raw
payloads. Other local artifacts, including response handles, can
contain analysis data. Recorded actor labels are not authenticated identity.
| Field | Purpose |
|---|---|
tool_call | Opaque per-invocation id (<tool>_<12-hex>). |
client_id | MCP client process id from ROAM_MCP_CLIENT_ID. |
tool_name | Canonical tool name (e.g. roam_preflight). |
actor_ref_id | Agent id from ROAM_AGENT_ID; ties to the ActorRef vocabulary. |
declared_side_effects | Tuple of read_only / write_filesystem / etc. from the tool registry. |
required_mode | read_only / safe_edit / migration / autonomous_pr. |
input_hash | sha256 of canonical-JSON input args. Never the args themselves. |
policy_decision | Closed enum: allow / deny / escalate / redact / not_evaluated / would_deny_dry_run. |
output_ref / output_hash | Artifact id for large output, or sha256 for small. Mutually exclusive. |
run_event_id | Link to .roam/runs/<id>/events.jsonl row. |
redactions | Closed-enum tuple of redaction reasons; stable across versions. |
extra | Free-form structured detail (e.g. redaction_details per-pattern counts). |
Reviewers and gateways consume receipts alongside the eight evidence questions on /docs/architecture#eight-evidence-questions and the worked PR-Replay packet under /audit#evidence.
Wire it into your agent
Roam ships a Model Context Protocol server and an auto-generated Claude Code skill. Preview the client configuration, connect it, and test the actual tool inventory — see /docs/integration-tutorials for Claude Code, Cursor, Codex, Gemini, and Amp.
Or run roam skill-generate --target claude to emit a
SKILL.md from the capability registry. Review the generated guidance
against the installed version, available tools, and your workflow;
generation alone does not prove the agent uses it correctly.
The principle behind the contract
Every command in Roam should answer a real engineering question that an agent or reviewer would ask. If a command doesn't map to a clear question, it's hidden, marked experimental, or improved. The goal isn't fewer commands — it's a clearer mental model.
Start with the uncertainty in the change. Choose a useful check, inspect its evidence, and keep the remaining uncertainty visible.
Where to next
Ready to try Roam? Install the free CLI · or read the command reference for the full surface.
Procurement and audit teams: the Agent Governance Evidence Pack turns the contract into a tamper-evident deliverable with control mapping to SOC 2 CC8.1, ISO/IEC 42001, NIST AI RMF, and EU AI Act Article 12.
See it run: The worked change-review demo — local queries, patch review, a saved bundle, and run-ledger verification.
Agent onboarding companions:
- /llms.txt — the LLM-friendly index of every Roam doc page. Drop this into your agent's bootstrap prompt to give it the full surface in one fetch.
- /docs/getting-started — installation and first checks for the person connecting the agent.
- /docs/mcp-usage — the MCP-specific call patterns: cold-start envelope, slow-tool handle pattern, typical agent flow, parameter aliases.
- /docs/mcp-usage#security-stance — the public inside-server-vs-gateway stance and which class of defence Roam owns versus which class belongs to the host.
- /docs/architecture#eight-evidence-questions —
the eight questions every
ChangeEvidencepacket answers about an AI-assisted change. - /governance — the buyer-facing Agent Governance Evidence Pack: the same eight questions framed as audit deliverables, with SOC 2, ISO/IEC 42001, NIST AI RMF, and EU AI Act Article 12 control mapping.
- /audit#evidence — the paid report's evidence questions and stated limits.
- /docs/architecture — how the call graph, evidence layer, and detector registry fit together. Read once; agents do not need it per call.