Auto-Checkpoint
Auto-Checkpoint creates a lightweight git commit after successful file
mutations, giving you fine-grained crash recovery and a clear audit trail.
In the current runtime, that follow-up runs after direct-apply mutation tools
such as write, edit, multiedit, and semantic LSP edits, and after
staged_accept / staged_accept_all when staged changes are actually
applied.
[options.auto_checkpoint]enabled = truerequire_clean_tree = falsemax_commits_per_session = 0llm_commit_message = falseRequirement: Requires a git repository with at least one existing commit.
Options
Section titled “Options”| Option | Default | Description |
|---|---|---|
enabled | false | Enable auto-checkpoint |
require_clean_tree | false | Only checkpoint when no untracked/unstaged files unrelated to the edit are present |
max_commits_per_session | 0 | Cap on remembered checkpoint commits per session (0 = unbounded) |
llm_commit_message | false | When true, use the last assistant message as the commit message (sanitized); otherwise use synthetic bmo: apply <tool> ... |
Restoring a git checkpoint (undo)
Section titled “Restoring a git checkpoint (undo)”Safety note: undo uses git reset --hard and discards working-tree changes
that are not preserved elsewhere. Inspect git diff and create a backup or
manual checkpoint before running it.
To undo auto-checkpoint commits, use the CLI: bmo checkpoint undo --steps N --yes, the agent tool checkpoint_undo with steps and confirm: true, or the TUI recovery hub /undo. For example, one step undoes the last commit. All three surfaces use the same destructive git reset --hard HEAD~N behavior in the repo root. They rewind the latest git commit; BMO does not currently verify commit provenance before running the reset.
Session checkpoints (separate feature)
Section titled “Session checkpoints (separate feature)”BMO also supports session checkpoints: named snapshots of a session’s state (message count and todos) that you can restore later. This is independent of git. For the full session concept (when to checkpoint vs branch vs new session), see Sessions. For the broader docs taxonomy, see Concept Map.
- TUI: Open the Sessions dialog, select a session, then ctrl+k to create a checkpoint (default name) or ctrl+e to open the Checkpoints list for that session. In the Checkpoints list, select one and press Enter (or r) to restore; confirm with y. Restoring truncates messages and restores todos to that point.
- CLI:
bmo checkpoint create [name],bmo checkpoint list, andbmo checkpoint restore <checkpoint-id>default to the most recently updated top-level session in the active data dir. Pass--session-idto target a different session. Restore still requires--yesto confirm. - API:
POST /v1/sessions/{id}/checkpoints(create),GET /v1/sessions/{id}/checkpoints(list; bound callers reuse the trusted session),POST /v1/sessions/{id}/checkpoints/{checkpointId}/restore(restore).
Session checkpoints do not affect git history; they only affect the conversation and task list for that session.
Posture and observability (Session capsules)
Section titled “Posture and observability (Session capsules)”The session-checkpoint surface - internally session capsules - exposes a
single posture read model that powers every operator surface. All six surfaces
report the same Posture snapshot and recent-events ring, so the TUI slash
and sidebar chip, CLI, HTTP, agent, and MCP views never disagree.
Where to read it (6 surfaces, one source of truth)
| Surface | Entry point |
|---|---|
| CLI | bmo config show-session-capsules (--json for machine-readable) |
| HTTP | GET /v1/sessions/{id}/checkpoints/posture |
| TUI slash | /session-capsules |
| TUI sidebar | Capsules |
| Agent tool | list_recent_session_capsule_events |
| MCP tool | bmo_get_session_capsules_posture |
The checkpoint GET reads (list, get, and posture) follow the same
bound-session contract as other parity HTTP reads: a trusted bound caller
inherits its current session, and an unbound caller uses the path session id.
Create and restore remain path-addressed mutations.
Posture states — closed-set, machine-readable. The state field is one of
uninitialized, ready, or degraded. degraded is sticky: it stays
asserted for the configured sticky window after a workspace-snapshot or
store-persist failure so a quiet partial write cannot read as healthy on the
next list/get.
Recent events ring (16 entries, FIFO). The ring stores only bounded
metadata: session-id, checkpoint-id, and checkpoint-name are stored as
FNV32 8-hex hashed prefixes — never as raw values. Raw todos JSON, raw
checkpoint names, and raw session ids never appear in posture output, agent
tool replies, MCP tool replies, or structured logs (field discipline).
Sticky-degraded latch — asserted when:
- a workspace-snapshot capture or restore fails during create/restore (the row is consistent but the snapshot is partial);
- the in-memory checkpoint store’s
Savereturns an error;
cleared automatically when a successful create + workspace-snapshot pair lands inside the sticky window. The latch is process-global and resets on restart (cross-process latch persistence is intentionally out of scope).
Tracing recipe. When you need to correlate a session-capsule episode end to end:
bmo logs --tail 500 \ | jq -c 'select(.msg|startswith("session_capsule."))'Filter to lifecycle failures only:
bmo logs --tail 500 \ | jq -c 'select(.msg=="session_capsule.action" and .action=="workspace_snapshot_failed")'Each session_capsule.fired and session_capsule.action log line carries an
invocation_id that pairs the open and close of one lifecycle episode, plus
the same hashed session_id_hash / checkpoint_id_hash you see in the
posture output and the recent-events ring. Cross-reference any of those three
surfaces by matching the hashes — never the raw ids, which never leave the
process.
Use cases
Section titled “Use cases”- Crash recovery — if the agent goes off track, restore to the last known-good state
- Audit trail — every file change is a commit with a message describing what the agent did
- Safe experimentation — let the agent try risky refactors; roll back instantly if it goes wrong