Quick Start
1
Simple Usage
Open a run, append a couple of events, then close it.
2
Resume after a crash
Compute
replay_index() and drive the loop — journalled model calls and tools return their recorded results instantly, so the LLM is not re-billed and side-effecting tools are not re-run.How It Works
The loop is re-driven from the top on resume; recorded steps return cached results while real work restarts at the first un-journalled step. The journal, run ledger, checkpoints, and inbound journal are four adjacent persistence primitives — pick correctly with this map.Configuration Options
The journal is a zero-dependency SQLite primitive with a single constructor argument.RunJournal(db_path=None) constructor
Event kinds — the five boundaries the journal records:
JournalEvent dataclass
RunMeta dataclass
RunJournal public methods
Import the primitive and its event kind constants directly:
Common Patterns
Three patterns cover the full open → journal → resume lifecycle. Journal every boundary as it happens. Record amodel_decision, tool_call, tool_result, and iteration at each step.
replay_index(); a hit skips re-execution.
running after a crash is a resume candidate.
Best Practices
Journal at every meaningful boundary
Journal at every meaningful boundary
The five event kinds cover every point where re-execution would be either wasteful (
model_decision) or unsafe (tool_call/tool_result, approval). Omitting a boundary means that boundary re-runs on resume.Always append the iteration event alongside model_decision/tool_result
Always append the iteration event alongside model_decision/tool_result
last_iteration() reads this to restore the loop cursor exactly on resume; without it the resumed loop must scan the journal to find its position.Bind a checkpoint_id before appending tool events
Bind a checkpoint_id before appending tool events
open_run(..., checkpoint_id=...) (or a later set_checkpoint) is what lets a resume restore the workspace to a consistent state before replaying — otherwise replay may run against a workspace that has drifted.Use assert_replay_order() in tests, not in production hot loops
Use assert_replay_order() in tests, not in production hot loops
The full
(seq, kind) position-aware compare is the determinism guardrail — perfect for test coverage of your loop wiring, unnecessary on every replay step in production.Related
Run Ledger
Tracks run status (queued/running/done) — the journal tracks the per-event cursor.
Checkpoints
Workspace file snapshots bound via
checkpoint_id for restore-before-replay.Durable Approvals
Approval decisions journalled as
KIND_APPROVAL events for pause-for-approval HITL.Inbound Journal
Webhook dedup and in-flight recovery — a different scope from run-state replay.

