The handoff log
A coding session runs out of room mid-task. The next one, maybe a different agent entirely, needs to know what was actually finished. Here is the file that answers that.
I run this mesh with two coding agents, Claude and Codex, and sometimes my own hands. Any one of them can pick up a job the others started. The failure that kept happening early on was a session hitting a context or usage limit partway through something, with no reliable way for whoever came next to tell what had been finished from what had merely been attempted. A log that says “should work” when the real state is “untested” is worse than no log, because it invites the next session to build on sand.
The fix is a pair of files per project, written by a small CLI.
The one diagram
The two files
HANDOFF.md is an append-only running log, newest entry on top, plain
markdown. Each entry is a timestamp, which agent wrote it, what was just done,
the current state (done versus not done, said plainly), and the concrete next
steps. It is the full history and it is never rewritten, only added to.
HANDOFF.yml is the bounded machine-readable snapshot the next session
actually reads. It carries latest, the current checkpoint in full, plus
trail, the last few checkpoints compressed to one line each. The trail exists
so a hasty or thin checkpoint cannot erase the trajectory that led to it.
The CLI
Both files are only ever written through npm run handoff:
handoff -- start <slug> --agent <name> --summary <what you're doing>
handoff -- checkpoint <slug> --agent <name> --done ... --state ... --next ... [--tests ...]
handoff -- finish <slug> --agent <name> --done ... --state ... --next ...
handoff -- resume <slug>
You run start when you begin substantive work, checkpoint after every
verified milestone and at least every thirty minutes while actively changing
things, and finish before a planned stop. On takeover you run resume and
read only that concise output, not the whole markdown history.
The CLI serialises writers with a per-project lock and replaces both files
atomically. It rejects a checkpoint or finish from an agent that is not the
current active owner, and it rejects starting work that already has a live
owner. That is what stops two sessions quietly overwriting each other.
The discipline that makes it work
The mechanism is the easy part. The rule is: a checkpoint distinguishes what is
verified from what was attempted, includes the actual test output, names the
blockers that are still open, and gives exactly one concrete next action. “Ran
the suite, 14 pass, 2 fail on the timezone helper, next is fixing
toLocal()” is a good checkpoint. “Made progress on tests” is not.
Why plain files
More than one kind of agent has to read and write this, and so does a person
with a text editor. A database means choosing one access pattern and building an
API in front of it that every other tool has to learn. A folder of .md and
.yml files means every tool that already knows how to open a file can join in
with no integration work.
What is verified vs assumed
Verified: I have handed work between Claude and Codex through this on real
projects, including this site. The resume output plus git status and the
last few commits has been enough to continue without re-deriving decisions.
Assumed: that the thirty-minute checkpoint cadence is right rather than too often or not often enough. It has not obviously failed either way yet.
-x