HandOver.md – The File That Outlives The Session

This article is one chapter of my book Delphi in all its glory – AI-assisted development, the fifth book of the series.

Claude has amnesia. Not the poetic kind. The official documentation says it plainly: “Each Claude Code session begins with a fresh context window.”

You spent four hours with it yesterday. You explained why that TThread.ForceQueue cannot be replaced with PostMessage. You found out the hard way that two test projects have the same name and one of them cannot build. Today you open a new session and Claude knows none of it.

There are three official answers to this and none of them is enough.

claude –resume. It restores the conversation, and it is genuinely useful (described earlier in this book, see the chapter “Resuming Previous Conversations”). But the picker only offers the current directory sessions until you widen it with Ctrl+A. Your “yes, for this session” approvals do not come back: they live in the running process, not in the transcript, so a new process starts without them and you approve everything again. The same goes for plan mode and bypassPermissions, which the documentation says are “never restored”. And transcripts expire: Claude Code sweeps old ones after the retention period. Switch machines, or come back in three weeks, and there is nothing to resume.

Auto-compact. When the context fills up, Claude Code summarizes the conversation to make room. A summary is a lossy compression of four hours of work. Your specific instruction from thirty messages ago is gone, and you will not be told which one.

Auto memory. Claude writes its own notes into a memory folder – one per git repository – and the index file MEMORY.md is loaded at the start of every session (the first 200 lines or 25 KB, whichever comes first). This is a good feature and I use it. It is still not a resume, for one reason: Claude decides what goes in it, and Claude is deliberately stingy. The documentation says it “skips anything it can derive from the codebase”, skips anything your CLAUDE.md already says, and does not save something every session. You cannot make it hold the numbered next step, because it was never yours to write. It answers “what did I learn about this project”. It does not answer “what do I do in the next five minutes”.

So, I wrote the missing piece myself. It is one Markdown file per project and it is called HandOver.md.

What it is

HandOver.md sits in the project root, next to CLAUDE.md and the dproj. It is written for a Claude that remembers absolutely nothing, which means it has to be concrete. Real paths, real unit names, the exact next step, the exact command.

The rule that makes it work is the one people break first: it names ONE next task. Not a backlog. If three things are pending, the handover names the one to do next and points at todo.md for the rest. A handover listing ten tasks is a ToDo list wearing a disguise, and the next session wastes its first ten minutes deciding where to start.

Everything else follows from “what does a stranger need”. The file has nine sections, in a fixed order, and that order is the reading order for a cold start:

SectionHolds
Next taskThe one next task: goal line, then numbered steps
BlockerWhat stops it, and who owns it
StateDoes it build, do the tests pass
UnverifiedClaims never actually proven. Do not build on these
Key filesOnly the files the NEXT task touches
TrapsMistakes already made here. Do not relearn them
DecisionsSettled calls that must not be re-opened
Open questions for GabrielNeeds my answer before anything moves
Done (newest first)One line per past session, newest on top

Only three are required: Next task, State, Done. An empty section is noise the next session has to read past, so it gets dropped.

Two things never go in there: priority, and a changelog of every edit. Git already has the second one, and the first belongs to a different file. More on that in a moment.

The Traps section is the one that pays

This is the section I would keep if I had to delete the other eight. Here are three real lines out of the LightSaber handover, verbatim:

- TForm.Create(nil) raises EResNotFound in FMX. InitInheritedComponent returns
  FALSE when no ancestor has a .fmx resource (System.Classes.pas:4851) - use CreateNew.
- FMX.Objects declares its own TPath (:483), shadowing System.IOUtils.TPath when it
  comes later in the uses clause. Symptom: E2003 Undeclared identifier: Combine.
- Assert.WillRaise matches the exception class EXACTLY (DUnitX.Assert.pas:1165).
  Naming an ancestor such as Exception always fails when the code raises a descendant.

Every one of those cost me a session to find. Without the file, Claude rediscovers them at my expense, one at a time, forever. With the file, they are free.

I checked all three again while writing this chapter and they hold, in Delphi 13. Note that the line numbers are the version numbers, not the truth: InitInheritedComponent sits at line 4851 in Delphi 13, 4844 in Delphi 12, 4719 in Delphi 11. So, write the symbol name next to the number. The number rots at every release, the name does not.

Three files, three scopes

People confuse the handover with the other two files I keep, so here is the split:

  • Current Status.md – one three-line block per project, across all thirty-eight of them. It answers “which project do I open now”. Never “how do I resume it”.

  • HandOver.md – the durable memory of ONE project. Never deleted.

  • session-<task>.md, in the project .claude folder – the live notebook of ONE task in flight, written after every significant step because the process can die at any moment, deleted the moment that task closes.

The test is simple: if a fact only matters once you are already inside the project, it belongs in the handover, not in the status file.

The two upper files are stitched together by one rule that looks fussy and is not. The first line under Next task, Blocker and Done must stand alone and fit 140 characters, because those three lines get lifted verbatim into Current Status.md:

powershell -File "...\Tools\Status\Update-Status.ps1" -Project LightSaber
   -Done "<the Done first line>" -Next "<the Next task first line>"

Write the line once, in the handover, and the two files cannot drift. Write it twice and they are contradicting each other inside a week. A first line that only makes sense in context (“Continue with step 3”) breaks both files at once.

The skill

All of this is a skill, /light-md-HandOver, with three modes.

SAVE is the default. It reads the existing file first (never overwrite blind – the previous session may hold decisions this one never touched), folds the previous “Next task” into Done if it got finished, writes the new state, and then pushes the two headline lines into the status file. It fires when I say “prepare for shutdown”, “save the handover”, “I am going to bed” – and, more usefully, Claude fires it by itself when a long session is clearly ending or the context is about to run out.

PRUNE runs on demand, and automatically inside SAVE once the file passes about 120 lines. The principle is that detail decays and decisions survive. Done entries older than the last two sessions collapse to one line each, then group by theme. Key files from finished work get deleted. Superseded decisions keep the winner and the reason and lose the losers. Four things are never deleted: an open blocker, an unanswered question, a decision still in force, and anything marked UNVERIFIED – those are exactly what a cold session cannot reconstruct.

RESUME reads the file and reports three lines – last session with date and model, the next task, the blocker – then starts working. If the handover contradicts what it finds in the code, the code wins and the handover gets corrected on the next save.

What went wrong before I fixed it

Two things, and both were my fault.

The first is that the format drifted. Before I wrote a specification, every project invented its own headings. Across the files on disk I found “Pick up here”, “If resuming cold”, “Where we are right now”, “Plan”, “Batch status”, “Result”. Every one of them means “next task” or “done”, spelled differently. That costs twice: a cold session has to read the whole file to find where to start, and no script can extract anything reliably. The fix was a fixed nine-section spec plus a checker:

powershell -File "...\Tools\Status\Check-HandOverFormat.ps1"

It reports missing sections, invented headings, wrong order, and first lines over 140 characters. Legacy files are not bulk-rewritten – they get conformed on their next save, mapping each old heading onto the section that matches its meaning, dropping nothing.

The second failure is worse and it is the reason for the Unverified section. Claude is an optimist. Left alone it will write “fixed the focus-steal bug” into Done when what actually happened is that it changed three lines and never compiled them. A handover that reports success which did not happen is worse than an empty file, because the next session builds on it and you find out two days later. So the rule is in the skill in capital letters: if the tests failed, write that they failed. If a fix was never built, write UNVERIFIED.

My LightSaber handover carries six entries in that section right now, next to twenty-two traps. Those twenty-eight lines are not a defect. That is the file doing its job.


This was one chapter of a whole book

You just read one chapter of Delphi in all its glory – AI-assisted development: more than 400 pages about Claude Code and AI for Delphi programmers. Written by a Delphi programmer, with the failures documented next to the wins.

Leave a Comment

Scroll to Top