Vondet

All notes

Measured

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.

LayerDo you have to do anything?Can you choose what goes in it?
1. The instruction file (CLAUDE.md, AGENTS.md)Write it onceYes
2. Automatic memoryNoBarely
3. Git historyNoOnly 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 itYes

Two of these surprised us.

A two-by-two chart of four handoff layers. Arrives on its own and cannot be chosen: automatic memory and git history. Arrives on its own and can be chosen: the instruction file. Someone has to go and read it, and can be chosen: anything outside the repo. The fourth quadrant is empty.
Figure. Four routes by which something reaches the next session, placed on two axes: whether it arrives without you doing anything, and whether you choose what is in it. Three of them sit on the left — they arrive on their own — and two of those you cannot choose. Exactly one layer is both chosen and only reachable if someone goes and reads it. That one is what the pasted handoff was written for.

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. 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. 2. Note the subject lines of your last five commits. That is roughly what is going to arrive on its own.
  3. 3. Open a fresh session and paste nothing. First message: “read <wherever your plan lives> and carry on.” Nothing else.
  4. 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. 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

This is one repo, one model family, and a session count you can count on one hand. The “eight items” were a list we chose by hand that week, not a survey of everything a handoff could contain, so a different week would give a different fraction. Auto memory behaviour and what a session receives at startup are things we observed, not specifications we verified; they can change with a version or a setting. It is a signal, not a measurement: take the shape of the finding, not the ratio, and check your own environment rather than trusting our numbers.

The first attempt produced nothing usable

We tried it twice and the first attempt did not produce numbers we could use — the preconditions we had set were not met when it ran. The second attempt is the one described here, and even there we stopped counting partway through, because the session read something we had written and we could no longer separate what it worked out from what it was told.

We never removed layer 4

The plan the session was told to read lives outside the repo and was readable the whole time. What we removed was the pasted handoff, not everything we had written down. A run with layers 1–3 only is a different experiment, and we have not done it.

One of the three left over may not be worth carrying

Of the three items that were left, one turned out on a later check to be possibly not a live hazard any more — the thing it warned about had been fixed underneath us. Counting items left over is not the same as counting things worth handing over.

Four may not be the right number of layers

We did not test whether four layers is the right number. Shell history, editor state, and open files are all plausible fifth layers that we did not look at.

Arriving is not the same as being used

We measured what a session could have known. Whether a fact changed what it did is a separate question, and a harder one — we only have a clean read on it for the one case where two layers disagreed in front of the session and it went to check.

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.