Building a Claude Code handoff, and measuring what it carries
Most of a handoff is already being delivered by something you didn't write. The part that isn't is the part worth writing.
Vondet / 2026-09-06 / 8 min read
You can stop in the middle of a refactor at lunch and pick it back up in a fresh window at night. The Claude Code handoff is well-travelled ground by now — people ship it as a handoff.md in the repo, as a slash command, as a skill, as a plugin. Any of them will hand off to a new session better than nothing would.
They earn that in a plain way. A committed file gives the next session a first move it does not have to guess at. A command that produces the same headings every time means that file looks the same next week.
We have used all of them, and we would take any of them over an empty window.
We wanted to know how much closer. So we started a session and pasted nothing at all. The first message was one sentence: “read the plan and carry on.”
That plan lives on a board outside the repo — layer 4 in the table below. Our own note there already said the working tree was clean, and it named the commit main was sitting on.
We pasted nothing into the window. We did not delete what we had already written down.
It came up knowing which repo it was in and what the last stretch of work had been about. Then it did something we had not asked for. At the top of its context, delivered before it took a single action, were the subject lines of our last five commits. The one at the top was not the commit our note had named.
It went and checked: git status, gh pr list, and git show on the commit the note pointed at, which was second in that list. Our note was out of date. We had written the hash into it, and then committed twice more before we stopped.
That is the affirmative result, and it is worth sitting with before the rest of this article. What caught our stale handoff was not the session being diligent. It was two layers disagreeing in front of it — the one we wrote by hand, and the one that shows up whether we write it or not.
Five things people do, and all of them help
None of this is new advice, and none of it depends on any particular tool. If you are not doing these yet, do these first.
1. Write a handoff.md and commit it. A file in the repo is readable by any session, in any window, on any machine, and it survives the one thing chat does not survive: closing the window. Keep it to what is in flight.
2. Make it a slash command or a handoff skill. A handoff command that always produces the same shape is better than remembering the shape. The value is not the automation. It is that the same headings come out every time, so the next session learns where to look. Ours checks git status --short and gh pr list --state open before it writes anything, because “I think it's clean” is not something the next session can verify.
3. Put the permanent rules in the instruction file, not the handoff. CLAUDE.md (or AGENTS.md) is read every session without anyone remembering to paste it. Anything that will still be true next month belongs there. Anything you find yourself pasting into every handoff is a rule that is in the wrong file.
That last one is a subject of its own. We wrote separately about why Claude Code ignores the rules you wrote — linked at the foot of this article — where the answer also turned out not to be memory, but something about how the rule was written.
4. Use the memory feature. It carries small durable facts across sessions without being asked. More on this below — it turned out to be doing more work than we thought.
5. Write commit messages as if they were the handoff. They are the one artifact that is guaranteed to still exist, in order, with dates, when everyone involved has forgotten. This one is nearly free, and it pays out in a way we did not expect.
The one thing that is still missing
Here is the problem, and it is not that any of the above fails. It is this:
When a handoff works, nothing tells you which part of it worked.
That sounds academic. It has two very practical consequences.
The first is that handoffs grow. Every time a session comes up confused, you add a paragraph. You never remove one, because you have no way to know which paragraphs were load-bearing. Ours had reached the point where writing it was a real chunk of a session's budget.
The second is worse. The parts that go stale keep getting pasted. A handoff that names a commit hash, an open PR, or “the tree is clean” is a snapshot of a moment.
Our note said main was at a particular commit — and it was, when we wrote it. We then committed twice more in the same session. The next session read the note, put it next to the commit subjects it had been handed for free, found the mismatch, and correctly went off-plan to deal with it.
It behaved well. But it spent its opening moves reconciling a document we wrote, against a repo we changed after writing it.
What is actually reaching the next session
So we split it up. When a new session comes up knowing something, that knowledge arrived through one of four layers — and only one of them is the handoff you wrote.
| Layer | Do you have to do anything? | Can you choose what goes in it? |
|---|---|---|
| 1. The instruction file (CLAUDE.md, AGENTS.md) | Write it once | Yes |
| 2. Automatic memory | No | Barely |
| 3. Git history | No | Only indirectly, by how you write commit messages |
| 4. Anything outside the repo (a board, a doc, a ticket) | Yes — someone has to go and read it | Yes |
Two of these surprised us.
Layer 2, automatic memory, was doing about half the job
We sat down and listed the practices we wanted to carry into the next session. They were small hard-won things, like “check that a write actually landed instead of trusting the response,” and “when you produce a number, run a second input before you publish it.” Eight items.
Then we opened the memory files and read what was already in them. Of the eight, three were already there in full, and a fourth partly. One more we had already written out on the board — layer 4 — before we started.
That leaves three: eight, minus four the memory was carrying, minus one we had already published elsewhere. Those three were in none of the layers; they existed only in our heads and in the note we were about to write. Half the list was going to arrive whether we wrote it or not.
Earlier the same day I had written, in a report, that the practices which stuck were sticking because we persist them in files we control. I was wrong — or at least I had credited the wrong layer.
A layer we had not counted was carrying half of it.
Layer 3, the git history, arrives with no action at all
At the top of a session's context, before we did anything, sat the subject lines of the last five commits. Not fetched — delivered. This is also what caught our stale note: the hash we had typed by hand was not the one at the top of a list we never wrote.
Chasing that mismatch, the session ran git show on the commit our note had named — second in the list, not the top one. It got back the full commit body, which in our repo is several paragraphs of reasoning, because we write commit messages carefully. We had handed over a detailed account of what we were in the middle of, without intending to hand over anything.
That is the good news and the trap in the same sentence. Tip 5 above works better than people think. It also means your git history is a handoff you are already publishing, whether or not you are writing it as one.
Layer 4 is the only one you can choose, and the only one someone has to go and read
That asymmetry is the whole shape of the problem.
Run this once, on your own repo
This takes one session and it will change what you write in your handoffs.
- 1. Before you start, copy out what is in your memory files. On Claude Code these live under ~/.claude/projects/<your-project>/memory/. Do this first — if you look afterwards you will not be able to tell what the session knew from what you just read.
- 2. Note the subject lines of your last five commits. That is roughly what is going to arrive on its own.
- 3. Open a fresh session and paste nothing. First message: “read <wherever your plan lives> and carry on.” Nothing else.
- 4. In the first one or two replies, write down everything it turned out to know. Then assign each item to a layer: it is in the instruction file, it is in memory, it is in the last five commit subjects or a git show away, or it is in none of those.
- 5. Delete from your handoff everything that landed in layers 1–3. Write only what is left.
And one rule falls out of our own mistake. If what is left contains a fact that can change — a hash, an open PR, “the tree is clean” — do not change it after you write it. Either write the handoff last, or write the state as something to check rather than something to believe.
A handoff that asserts a stale fact is worse than one that omits it, because the next session has no way to know which of your assertions are still true.
What this does not show
Sample size
The first attempt produced nothing usable
We never removed layer 4
One of the three left over may not be worth carrying
Four may not be the right number of layers
Arriving is not the same as being used
What would show we are wrong
Two things, either of which sinks this.
One. You run the procedure above, and a fresh session with nothing pasted correctly states a fact that is in none of the first three layers — not in the instruction file, not in memory, not reachable from recent commits. And it is not in the plan you pointed it at either, or anywhere else you told it to look. If that happens repeatedly, the four-layer split is missing something, and our “delete what is already arriving” advice is deleting things that were doing work.
Two. You clear your memory files, change nothing else, and the next session behaves the same. That would mean layer 2 was not carrying what we think it was carrying, and our half-the-list number is an artifact of our own repo.
Both are cheap to try. We would rather someone ran this and got a different answer than have our small numbers repeated.
Three of the four layers arrive whether you meant them to or not, and you cannot choose what is in them. Exactly one layer lets you decide what the next session sees — and it is the one that needs someone to go and read it. That is the layer we are building.
Vondet (vondet.com) is a plan that lives outside any one session, and that an agent can read and write directly. The durable part of a handoff then has somewhere to sit that is neither a chat window nor a file that goes stale the moment you commit again. We make it, we use it on our own work every day, and it is what we were measuring against here. Sign-up is not open yet; there is a waiting list. Before any of that matters, run the five steps on your own repo and see how many of your eight were already arriving — we would rather hear your fraction than have ours repeated.
These notes come from our own development work.