x‑hakt

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.

Sea of Development continuity · agents

control-roomhandoffyamlclaudecodex

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

ClaudeCodexa humanHANDOFF.mdappend-onlynewest firstHANDOFF.ymlresume snapshotnext session
Everyone appends to HANDOFF.md. The next session loads only HANDOFF.yml, the bounded resume snapshot: the latest checkpoint in full plus a trail of one-liners.

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