Run ledger
The run ledger is how BMO remembers runs after the moment passes: durable
agent_runs / agent_run_events for the agent runtime, plus an optional
in-memory OpenAI-compat ring when that HTTP surface is enabled.
Operators rarely “configure the ledger” — you read posture, confirm stores are healthy, then follow a run into Run observability or the Agent Debugger.
Two ledgers, one read model
Section titled “Two ledgers, one read model”| Ledger | Storage | When it matters |
|---|---|---|
agent_runs (durable) | SQLite in the app data dir | Always on with the daemon — powers /debugger, spawn history, APIs |
| OpenAI-compat (in-memory) | Process ring buffer | Only when [options.openai_compat] enabled = true and HTTP/autopilot serves chat |
runledger.BuildSnapshot feeds one formatted posture string to:
bmo config show-run-ledger(CLI)/run-ledger(TUI slash; aliases/run_ledger,/runledger,/ledger)- Runs sidebar chip
run_ledger_status(agent tool)
Every surface still shares the same posture shape, but the CLI is now an explicit detached projection: it reports durable-store and config truth from the current process while leaving the live ring and sticky runtime tracker to the attached runtime surfaces.
Step 1 — Read posture in the TUI
Section titled “Step 1 — Read posture in the TUI”After at least one real turn (so the ring has something to show), run:
/run-ledgerHow to read the report:
| Block | Meaning |
|---|---|
agent_runs: bootstrapped | Durable store is present — debugger/API can list rows |
openai_compat: … | Whether the compat ledger is enabled, idle, or degraded |
reconciliation: … | How the durable and OpenAI-compat ledgers relate right now |
sticky-degraded note | Recent persist ops failed; clears on next success |
ring capacity / saturated | In-memory telemetry bounds (metadata only) |
outcomes (action × outcome × count) | Histogram of ledger operations |
recent events | Hash-redacted run_ledger.fired / run_ledger.action tail |
IDs in this surface are FNV32-hashed prefixes — never raw run bodies, session text, or stack traces.
Detached CLI vs live runtime
Section titled “Detached CLI vs live runtime”bmo config show-run-ledger does not claim another process’s in-memory ring.
It can truthfully tell you whether the local agent_runs store bootstrapped
and whether OpenAI-compat is enabled in config, but it reports the live ring
and sticky-degraded tracker as unavailable until you inspect an attached
runtime surface such as /run-ledger, GET /v1/run-ledger/posture,
run_ledger_status, or bmo_get_run_ledger_status.
Reconciliation states
Section titled “Reconciliation states”The shared posture family now calls out how the two ledgers relate:
| State | Meaning |
|---|---|
aligned | The current durable and OpenAI-compat states are internally consistent. This includes the normal config-disabled OpenAI-compat case. |
detached | You are reading the detached CLI projection, so live ring and sticky recovery evidence are intentionally unavailable. |
one_sided_unavailable | One ledger is observable and the other is not. Treat this as a fail-closed status mismatch, not as healthy parity. |
degraded | One ledger is currently degraded, including sticky OpenAI-compat persistence failure. |
recovering | Recent bounded ring evidence shows a failure followed by a success. The live runtime is healthy again, but operators should still treat it as an active recovery window. |
Restart keeps durable agent_runs rows and OpenAI-compat retention policy, but
the process-local recent ring starts empty again. Detached inspection after
restart should therefore show durable-store truth without replaying old live
runtime telemetry.
Step 2 — Confirm a session has runnable history
Section titled “Step 2 — Confirm a session has runnable history”Switch to the session-family lens:
/run-observabilityYou should see recent_runs ≥ 1, latest_run_id, and view pointers to
/debugger and /cue-ledger. See Run observability.
Step 3 — Drill into evidence
Section titled “Step 3 — Drill into evidence”| Question | Go to |
|---|---|
| What happened step by step? | Agent Debugger — /debugger |
| Who acts next, with what evidence? | /cue-ledger on Run observability |
| Which tools fired in one run? | inspect_run_trace / HTTP trace lens |
OpenAI-compat tracing recipe
Section titled “OpenAI-compat tracing recipe”When compat is enabled, walk one HTTP completion end-to-end:
/run-ledger— confirm not sticky-degraded.bmo openai-compat runs list --limit 10— find a recent request id.bmo openai-compat runs events <request_id>—chat_started→ tool events →chat_done.- If
run_ledger.action … outcome=failed error_category=persist_failedappears in the posture ring, treat the ledger as degraded until the next successful op. - If posture moves from
degradedtorecovering, confirm the next attached/run-ledgerread stays healthy before treating the incident as closed.
Enable compat in bmo.toml when you need the HTTP ledger:
[options.openai_compat]enabled = truetool_policy = "chat_only" # or "auto_approve"ambiguity_policy = "ask"model_override_policy = "reject"Pair with bmo service start http or bmo service start autopilot.
Structured logs
Section titled “Structured logs”Each operation emits paired records into the bounded ring (capacity 32):
run_ledger.fired— one per op entryrun_ledger.action— boundedledger,action,outcomeafter completion
Filter examples:
run_ledger.firedrun_ledger.actionrun_ledger.action ledger=openai_compat outcome=failedrun_ledger.action error_category=persist_failedSticky-degraded contract
Section titled “Sticky-degraded contract”On OpenAI-compat persist failure the in-process tracker:
- Sets
sticky-degradedvisible on the live runtime surfaces: slash, sidebar,run_ledger_status,bmo_get_run_ledger_status, andGET /v1/run-ledger/posture. - Publishes
runevents.SubsystemDegraded. - Clears on the first subsequent successful op (
SubsystemRecovered).
Restart clears the flag — it is process-scoped.
Agent tools
Section titled “Agent tools”run_ledger_status— live JSON posture twin; safe, read-only, no prompt.list_recent_run_ledger_events— raw bounded ring export; safe, metadata-only, and distinct from durable row/event APIs.list_agent_runs/get_agent_run_events— same durable rows as/debugger.session_observability/run_cue_ledger/inspect_run_trace— Run observability family.
Related
Section titled “Related”- Agent debugger — durable timeline UI
- Run observability — bounded summary and cue/trace routing
- Terminal browser — paired posture/ring pattern donor
- Tools reference
