Record compact progress inside an active task. Append-only; the body arrives on stdin.
A checkpoint is not a small handover. A handover is a deliberate continuation package
written when a worker stops; a checkpoint is what was true a moment ago, short enough that
the next worker's context can quote it whole. checkpoint.max_body_lines in the policy
enforces that difference — a body over the cap is refused with the suggestion to write a
handover instead, rather than truncated.
Writes: state/checkpoints/<ts>--<branch>--<head>--<rand>.md, mode 0600, created
atomically with link, never staged. Front matter is computed exactly as for a handover; a
body containing identity fields is refused. Also updates checkpoint_at on the task record
and appends task.checkpoint to the ledger.
An empty body is allowed and writes no file: it updates checkpoint_at only, which is what
check --checkpoint has always done. The two are the same operation; checkpoint is the
one that can also say what was true.
--derivecomposes the body from git and the ledger instead of reading stdin: the commit, the working tree, how many files have changed since the task started, the commits since then, and the count of blockers. It stays inside the same cap, and it is what the provider's compaction event runs — a compaction discards the conversation while the work continues, and the moment it is announced is the only moment anything can be written about a context that is about to stop being reachable.--showprints the newest checkpoint for this worktree and branch — for the active task when there is one, and otherwise the newest whatever task it names.--listlists this worktree's checkpoints, newest first, with each one's git label.
A checkpoint belongs to the episode, not to a task. It is written whether or not a task
is open and whatever outcome the last one reached. It relates the active task unless a
different, still-open episode opened that task (ADR 0164); then its Markdown task_id is
none, its ledger event omits task_id, and it leaves the task's checkpoint_at alone.
check --checkpoint uses the same rule. A derived checkpoint uses that same prepared
relation for its body; it cannot describe another episode's task as its own.
This refused with 12 (no active task) and 15 (the task is no longer active) until ADR
0052. Those two refusals are the 2026-09-05 outage: a task marked handed_over and never
replaced silenced this repository's progress records for six days, while episodes went on
opening and closing and every health check passed.
Exit 10 when the body carries identity fields or exceeds the cap.
$ majordomus checkpoint <<'EOF'
OAuth state mismatch reproduced with the fixture in test/fixtures/callback.json.
Cause is in callback normalisation, not in the comparison.
Next: regression test before touching the implementation.
EOF
.ai/local/state/checkpoints/20260903T194500Z--main--3f2a9c1--8c1d0e4a2b6f9317.md