Just-in-time checkpoints

Checkpoints are declarative gates inside activities that halt the workflow until an external condition is met — usually your explicit confirmation. The agent cannot skip past one: the server records the active checkpoint in session state and refuses to advance until it is resolved.

Canonical source: docs/checkpoint.md.

Where you stay in control

A checkpoint is a step where the workflow deliberately stops until you decide something: approve a design, pick an option, confirm a commit.

Single-agent flow

The checkpoint flow A sequence with three participants: you, the agent, and the server. The agent reaches a checkpoint step and calls yield underscore checkpoint; the server records it. The agent calls present underscore checkpoint and receives the message and options, presents the decision to you, and you choose. The agent submits your choice with respond underscore checkpoint, then calls resume underscore checkpoint and continues working with any variable updates. You Agent Server yield_checkpoint checkpoint recorded, work pauses present_checkpoint message + options presents the decision to you your choice respond_checkpoint → resume_checkpoint work continues with any variable updates from your choice
The checkpoint flow with one agent. The agent yields at the checkpoint, fetches the message and options, presents the decision to you, submits your choice, and resumes.

Your choice can set workflow variables — picking "skip the audit" or "include migration" changes which activities and steps run afterwards. Some checkpoints define a default option and can auto-advance after a timeout; the server still enforces the timer.

Multi-agent bubble-up

Background workers cannot ask you questions directly, so a checkpoint bubbles up the agent hierarchy to the user-facing agent, and the resolution travels back down.

Checkpoint bubble-up and resume The worker yields a checkpoint to the server, which records it as the session's active checkpoint, and emits an empty checkpoint yield block to the orchestrator, which relays it to the meta orchestrator. The meta orchestrator reads the open checkpoint from the session, presents the decision to you, and submits your choice to the server. The resolution then travels back down: the orchestrator wakes the worker, which calls resume underscore checkpoint and continues. Worker (L2) 1. yield_checkpoint 8. resume_checkpoint Orchestrator (L1) relays the yield up, wakes the worker after Meta (L0) 4. present_checkpoint 6. respond_checkpoint You 5. decide 2. empty checkpoint_yield 3. relayed unchanged presents options your choice 7. effects passed down wake + variable updates top arrows: the pause bubbles up · bottom arrows: the resolution travels back down
Bubble-up and resume. The worker yields (1) and emits an empty <checkpoint_yield> block that travels up through the orchestrator (2–3); the meta orchestrator reads the open checkpoint from the session (4), you decide (5), and it submits your choice (6); effects travel back down (7) and the worker calls resume_checkpoint (8) before continuing.

Yielding

When a worker reaches a checkpoint step it calls yield_checkpoint. The server records the checkpoint as activeCheckpoint in session.json. The worker emits an empty <checkpoint_yield> block in its final output and stops; the orchestrator relays the block upward, and the user-facing agent reads the open checkpoint from the session with present_checkpoint. A new checkpoint cannot be yielded while one is already active — nested yields are a hard error.

Resolving

The meta orchestrator calls present_checkpoint to fetch the human-readable message, options, and effects, presents the decision through the host UI, then finalizes with respond_checkpoint in exactly one of three modes:

ModeMeaningServer enforcement
option_idYou selected an optionOption validated against the definition; minimum response time (default 3s) blocks instant self-resolution
auto_advanceTimer elapsed, use the default optionOnly for checkpoints with autoAdvanceMs; the full timer must have elapsed since the yield
condition_not_metConditional checkpoint's prerequisite is falseOnly valid when the checkpoint defines a condition

The server clears activeCheckpoint, records the decision and any variable effects (e.g. setVariable: { is_monorepo: true }) in the session state, and returns the effects to the caller.

Resuming

Agents wake in reverse order using the host's resume mechanism, with effects passed down as plain instructions. The worker then calls resume_checkpoint, which verifies the checkpoint was resolved and returns the checkpoint answered, the option chosen, the variables that option set, and the exit it selected, if any; an exit carrying ends_activity ended the activity at the checkpoint, so the worker runs none of the remaining steps. Called while the checkpoint is still active, it is a hard error. In inline (single-agent) execution the wake is a no-op persona switch; the server-side gates are identical.

A checkpoint used at several sites

A checkpoint reused at several sites is a routine: the gate is declared once under the owning workflow's routines/, and each site is a kind:routine step that refers to it. A gate that is not part of a larger run is a one-step routine. The routine declares what it takes and what it produces, and its body is held against that signature; the reference prefixes every identifier the run contributes, so two sites cannot collide on a step id or a replay key. The loader materializes the reference before delivery, so yield, present, respond and every downstream consumer see an ordinary full checkpoint. The check:duplicate-bodies guard reports a checkpoint body authored inline at two sites.

Why this design