What actually gets lost
Claude Code compacts a long conversation into a summary when the context window fills. Some things survive by
design: the docs list the project-root CLAUDE.md, auto memory and invoked skills (up to a size cap) as
re-injected after compaction. What does not survive intact is the conversation itself: "The summary keeps your
requests and key code snippets, but detailed instructions from early in the conversation may be lost." A new
session goes further: it "starts with a fresh context window, without the conversation history from previous
sessions." (/clear keeps the old session on disk; you can /resume it, but the new context starts empty.)
So the gap is task state that lives only in the conversation: the approach you already rejected, the two tests that
still fail, the deploy nobody has authorized yet. Practitioners see it:
- One DEV author tracked 18 instructions in each of two real conversations and found, after three compactions, "I had lost 33% of the instructions I tracked in one conversation and 57% in the other" — measured as whether each item was still written down, not whether it was followed (source).
- Agents redo failed work because "commit messages describe the diff that shipped, not the dead ends" (source).
When a handoff is worth it
Often it isn't. The AI Hero handoff guide puts it plainly: "/compact unless something is travelling."
(source). Same task, same session: compact. Persistent rules: CLAUDE.md.
A handoff earns its cost when work moves to a fresh session, another agent or a colleague and resuming wrong is
expensive. Compare:
Plain: Migration mostly done. Fix remaining issues and continue.
Structured: Rejected: approach A (evidence: …) State: 2 failing tests — recheck before trusting
First action: inspect the failures Deploy: NOT authorized
The second one is what session-handoff (Apache-2.0) asks the
writer to produce: state and where it is recorded, what was corrected and must not be repeated, the first authorized
action, and commands that re-verify anything that may have changed.
Three layers of checking — and what each cannot prove
| Layer | What it specifies or checks | What it does not prove |
|---|---|---|
Handoff contract (SKILL.md) |
what a handoff must contain | that the content is true |
| Lint (18 rules) | form: unanchored claims, missing cold read by a context-free reader, a pasted reading that no longer matches the file | correctness — only 9 of the 18 rules have a registered test that shows them catching the failure they target |
Readout (handoff_readout.py) |
numbers computed from the session transcript, pasted verbatim, reproducible byte-for-byte | that the detectors are valid, or that the next session acts correctly |
Abbreviated readout output (the full block is eight lines with an empty lesson table, nine with registered lessons):
READOUT_SNAPSHOT transcript path · lines read · sha256 · last timestamp · readout-script and lesson-table hashes
READOUT_PATTERNS per registered lesson: violations / opportunities (previous five windows)
READOUT_RECEIVE was a read call on the handoff file detected in the three tool calls after it was referenced
READOUT_RECOMPUTE the exact command that reproduces this block
The public lesson table ships empty: snapshot, receive, cost and size work out of the box; per-lesson counts
need you to register patterns (references/readout.md). Reproducibility tells you what was measured, not whether
the measurement is right.
Four measurement failures an independent review found
Before collecting any outcome data, a second model reviewed version 2.6.0 in two phases: it sealed its own findings
(hashes in a file) before it was allowed to open the author's numbers, and that order was checked from its
transcript timestamps. This is an internal review with a different model, not external replication. It returned
fix before retest; all four findings were reproduced locally before fixing:
-
Wrong observation source. The working-directory lesson read 0 in a session whose writer admitted moving the
working directory. The detector parsed command text and watched only some directories. It now counts the host's
environmentrecords whose new working directory is neither the start directory nor a temp directory. (The per-recordcwdfield was tried first and dropped: it flips between record types — one session showed 186 "changes".) - Threshold from the wrong population. Two rollback lines would have fired 44% and 16% of the time with nothing changed (bootstrap over baseline sessions). One became a direct count; the other was re-calibrated to 5% on the reference population — in-sample; the out-of-sample rate is not yet known.
- The measurement disturbed itself. One way of pasting the block back into the file changed the size reading, so recompute stopped matching.
- Mixed denominators. A summed rate added lessons with different denominators; one lesson was 59% of all violations.
Separately, two coders labelling 211 user messages for "requirement not met" agreed at κ = 0.27 (one coder labelling
twice: about 0.78). That label is not stable enough to be a baseline, so it isn't one.
These numbers come from the author's private session corpus, which is not published (raw transcripts contain paths
and code); the repository ships the detectors, tests and synthetic fixtures, not that corpus.
What is established, and what is not
- Publicly verifiable: the repository ships the readout implementation and regression fixtures, and CI passes on Linux with Python 3.12 and 3.13; the readout gives byte-identical output when the transcript snapshot, handoff file, prior-window inputs, script version and paths are held constant.
- From the author's private evaluation (corpus not public): the registered lesson detectors passed their validity checks, and in 131 of 138 internal handoffs the heuristic found a read call on the handoff file among the first three tool calls after its filename appeared in one of the receiving session's first three user messages. That does not establish that the read succeeded, that the content was understood, or that the next action was correct.
- Not established: that receiving agents preserve every instruction or make fewer repeated mistakes. That needs a comparison — plain summary vs. a generic structured handoff vs. this skill — on the same frozen tasks, scored by something the writer cannot edit. The next round measures per-lesson recurrence over ~30 new handoffs; the result gets published either way.
- Known limits: the readout parses Claude Code transcripts only (their format is internal and can change); the
receive check only recognizes handoff files named
HANDOFF_*.md; the recompute line does not shell-quote paths with spaces.
Try it, break it
mkdir -p "$HOME/.claude/skills"
git clone https://github.com/dormitivegit/session-handoff.git "$HOME/.claude/skills/session-handoff"
SKILL="$HOME/.claude/skills/session-handoff"
HANDOFF="/absolute/path/to/HANDOFF_billing-migration.md" # name it HANDOFF_*.md (see limits above)
SESSION="$HOME/.claude/projects/your-project/session-id.jsonl" # the transcript of the session that wrote it
python3 "$SKILL/scripts/lint_handoff.py" "$HANDOFF"
python3 "$SKILL/scripts/handoff_readout.py" --session "$SESSION" --handoff "$HANDOFF"
python3 "$SKILL/tests/run_tests.py" # the regression cases behind the fixes above
The most useful feedback is a sanitized failing case: a handoff where lint stayed clean but the next session still
resumed wrong. Open an issue with it.
Top comments (0)