Skip to content

Journal posture

Journal posture is the fast health view for BMO’s Journal subsystem. It tells you whether the Journal read path is available, correctly partitioned, and recently healthy without loading or rendering a session’s narrative entries.

The Journal itself is a cross-subsystem dated narrative — derived on read from runevents, workspace trail, scheduler history, and related telemetry. Posture answers “can I read it safely right now?”; /journal and bmo journal export answer “what happened in this session?”

You need…Use
A quick health check before export or MCP readPosture surfaces below
The dated story across subsystems for one session/journal, bmo journal export, bmo_get_journal
Operator notes on a specific entry/journal (a to annotate) or bmo journal annotate
Plan-contract drift after a parallel runbmo journal export --filter=plans --session=<id>

Posture and narrative share partition discipline but not the same payload: posture is metadata-only; narrative includes entry kinds, verbs, objects, and provenance.

After at least one turn (so the recent ring has telemetry to report), run:

/journal-status

The underscore alias also works:

/journal_status
Journal posture readout
Live BMO TUI: `/journal-status` prints the shared metadata-only posture — state, partition binding, ring capacity, action × outcome histogram, and hash-redacted recent journal telemetry. Same envelope as `bmo config show-journal --format=json`, `GET /v1/posture/journal`, and `bmo_get_journal_posture`.

How to read the report:

BlockMeaning
state / availableWhether the in-process Journal read path is healthy (up) or blocked (degraded, disabled)
shared_runtime / partition_boundShared-capable runtimes must be partition-bound before reads succeed
partition_id_hashFNV32-hashed partition prefix — never the raw partition id
ring capacity / ring size / ring saturatedProcess-local metadata ring bounds (capacity 16)
outcomes (action × outcome × count)Histogram of recent journal.fired / journal.action events
captured_atWhen this snapshot was taken

IDs and bodies never appear here. Raw session ids, entry text, tool output, and annotation prose stay on the narrative and export paths.

When posture is up, open the per-session lens:

/journal

Short alias:

/j
Journal narrative dialog
Live BMO TUI: `/journal` opens the per-session dated narrative — Observation, Decision, Action, Outcome, and Annotation rows derived on read from existing telemetry, with provenance and cross-links to debugger, adaptive, and workspace surfaces.

Operator moves inside the dialog:

KeyAction
rRefresh from the underlying read layer
oOpen the cross-linked surface for the focused entry (debugger, adaptive, workspace, …)
aAttach an operator annotation to the focused entry
Filter inputNarrow rows by kind, subsystem, verb, or object text

Each row is tagged with an entry kind — Observation, Decision, Action, Outcome, or Annotation — and carries mandatory provenance. Missing fields render as honest literals (partition: n/a, contract: not attributed), not back-filled guesses.

Every posture surface reads the same journal.PostureSnapshot:

SurfaceExample
CLI (in-process when attached)bmo config show-journal --format=json
TUI slash/journal-status
HTTPGET /v1/posture/journal
MCPbmo_get_journal_posture

Narrative parity is a separate family with the same session binding:

SurfaceExample
CLI exportbmo journal export --session=<id> --format=md
TUI dialog/journal
HTTPGET /v1/sessions/{id}/journal
MCPbmo_get_journal

Support script — is Journal readable before paging export?

Terminal window
bmo config show-journal --format=json | jq -e '.available == true'
bmo journal export --session="$SESSION" --format=json | jq '.entries | length'

Incident triage — posture first, narrative second

  1. In the TUI, run /journal-status. If state is degraded with partition_bound: false, fix options.mesh.partition_id before any export.
  2. When available is true, run /journal and filter for [Outcome] rows tied to the failing run id (hashed prefixes in posture; full provenance in the dialog detail pane).
  3. Cross-link (o) into /debugger for the ordered event stream on that run.

Plan-contract drift review after a session

Terminal window
bmo journal export --filter=plans --session="$SESSION" --format=md --out /tmp/plans-journal.md

Look for plan_breach_refused, plan_breach_acknowledged, and plan_budget_breach rows — the Journal surfaces enforcement as part of the cross-subsystem story without replaying one run in isolation.

MCP agent — posture without narrative bodies

An attached agent can call bmo_get_journal_posture to learn partition binding and recent ring health, then call bmo_get_journal only when entry rows are required. Annotations remain operator-only; agents cannot write via MCP.

Operator annotation on a decision row

Terminal window
bmo journal annotate --target=run_abc123:42 --note="Reviewed reshape; approved for staging"

In the TUI, focus the row in /journal and press a for the same path.

Every posture surface reads the same journal.PostureSnapshot, which includes:

  • state and available
  • whether the runtime is shared-capable
  • whether a mesh partition is bound
  • the hashed partition identifier when present
  • the recent journal.fired / journal.action ring size, capacity, and saturation
  • an action × outcome histogram over recent Journal operations
  • capture timestamps plus oldest/newest event timestamps when the ring is non-empty

The built-in posture builder currently emits:

StateMeaning
disabledJournal-backed storage is not available in this runtime.
upJournal posture is available and, when needed, correctly partition-bound.
degradedThe runtime is shared-capable but not partition-bound, so posture is surfaced as unavailable instead of risking cross-tenant reads.

bmo config show-journal run from a shell outside an attached BMO process reports the same JSON envelope but may show state=unavailable / live_runtime_observed=false because it cannot observe the in-process ring. The TUI slash, HTTP route, and MCP tool are the live surfaces.

Use /journal-status when you are already in a session and need truth about the running app. Use bmo config show-journal in scripts that only need config and partition binding facts from the current invocation context.

Journal posture exists partly to make the fail-closed partition rule obvious before an operator hits a session export path.

When BMO runs in a shared-capable runtime, options.mesh.partition_id must be set. If the runtime is shared but not partition-bound:

  • state becomes degraded
  • available becomes false
  • the posture still reports ring and partition metadata so the operator can see why the Journal is unavailable

This matches the Journal topic’s broader rule that shared runtimes must not serve cross-tenant Journal reads. bmo journal export and GET /v1/sessions/{id}/journal fail closed with the same invariant.

Journal posture includes a process-local recent-event ring with fixed capacity 16. Each record is metadata only:

  • event kind (journal.fired or journal.action)
  • hashed session or partition identifiers
  • scope and source labels
  • bounded action, outcome, reason, result-count, and latency metadata

Raw session IDs, partition IDs, entry bodies, prompt text, and annotation text do not enter the posture surface.