| name | handoff |
| description | Update docs/HANDOFF.md and docs/HISTORY.md after a work session — verify which open items actually shipped, move them to the history doc, record any trap hit, and re-check the facts that go stale. Use at the end of a session that changed behaviour, before handing off, or whenever the handoff doc has drifted out of date. |
Closing out a session
docs/HANDOFF.md is the file someone reads before deciding what to build next.
That makes staleness worse than absence: a to-do list that mixes shipped work
with open work sends the reader to re-implement something that already exists,
or to skip something that does not.
This skill keeps that from happening. It takes ten minutes and it is the whole
reason the doc split is worth maintaining.
Read docs/README.md first if you are unsure which
document a given piece of writing belongs in — this skill only covers moving
things between HANDOFF and HISTORY.
The one rule
Verify against source, never against a commit message.
A commit that says "add the rules cap" may have added a constant and no gate.
A commit that says "wire up X" may have wired half of it. The only evidence
that an item shipped is the code that implements it.
Verify at a file:line, but write the citation as a symbol — the
function, type, or constant. A line number in a doc is wrong the moment
another lane lands, and it rots silently: on 2026-08-26 two refs drifted
within the hour, and one of them was itself a repair of an earlier stale
ref. Where a line is genuinely needed, name the commit it was verified
against.
This is not pedantry — it is the specific failure that produced a 1,965-line
handoff. Items were struck through when their commit landed, and the ones that
were never struck through silently became indistinguishable from the ones that
were never built.
Procedure
0. Claim the file before writing it
docs/HANDOFF.md and docs/HISTORY.md are single-writer documents that
every lane accumulates into — announced, never raced. Before editing either:
ls .git/worktrees/*/MERGE_HEAD 2>/dev/null
Check ListAgents for live peer sessions, say you are about to write the
handoff, and sequence behind whoever already claimed it. Two sessions editing
the same handoff is a conflict in the one file whose job is telling the next
session what happened.
1. Find out what actually changed
git log --oneline --since="<date the handoff was last updated>"
git diff --stat <last-handoff-commit>..HEAD
The handoff's own git history tells you when it was last touched:
git log -1 --format=%ad --date=short -- docs/HANDOFF.md
2. Test every open item, not just the ones you worked on
Walk ## What to do next top to bottom. For each item, decide:
| Verdict | What to do |
|---|
| Shipped | Confirm in source, cite the symbol, then move it to HISTORY (step 3) |
| Partial | Rewrite the item to describe only the part that is still missing — a half-done item described as whole is the worst kind of stale |
| Still open | Leave it. If the reason it is open has changed, say so |
| Obsolete | Move to HISTORY with one line on why it stopped making sense. Do not simply delete — the next person will re-propose it |
Fast ways to check:
grep -n 'Subcommand' -A40 mecha-cli/src/main.rs
grep -n '<key>' mecha-core/src/config.rs
grep -nE '^pub mod' mecha-core/src/lib.rs
If an item is large, delegating the verification sweep to a subagent works
well — give it a line range and demand named evidence for every "shipped"
verdict: the function, type, or constant that implements it, and the file
that holds it.
3. Move shipped work to HISTORY, do not strike it through
Delete the item from HANDOFF. Add it to docs/HISTORY.md under
## What shipped, and when, in the prose paragraph for its date — not as a
bullet, and not as ~~struck through~~.
Strikethrough is how the old handoff got long: it kept every completed item in
the reader's way forever. HISTORY is where completed work lives.
While an item is in your hand, check whether a docs/*-DESIGN.md or
*-RESEARCH.md still describes the same thing as unbuilt. The convention
(docs/README.md) is an addendum line at the top pointing at HISTORY, never
a rewrite of the body. A design doc that describes shipped behaviour as
unbuilt is the handoff failure one file over — it is also something someone
reads before deciding what to build next.
4. Record any trap you hit
If something cost you more than about half an hour, it belongs in
docs/HISTORY.md under ## Traps already hit, in the matching cluster
(Measuring / Learning / Providers / Environment).
Write it as what broke, then the general lesson. The lesson is the part
that transfers:
The hook timeout covered the wait but not the stdin write, so a hook that
never read its input hung forever. Audit what sits outside every timeout,
not just what is inside it.
A trap with no general lesson is a changelog entry — put it in the changelog.
5. Re-verify the facts that rot
These go stale silently. Check them every time:
cargo test --workspace 2>&1 | grep -E '^test result'
python3 -c "
import json, collections
t=collections.Counter(); n=0
for line in open('eval/cases.jsonl'):
s=line.strip()
if not s or s.startswith('//'): continue
n+=1
for tag in json.loads(s).get('tags',[]): t[tag]+=1
print(f'{n} cases, {len(t)} tags')"
curl -s localhost:8080/props | jq '{total_slots, n_ctx: .default_generation_settings.n_ctx, vision: .modalities.vision}'
systemctl --user list-unit-files | grep mecha
When the claim is about an installed artifact, ask the artifact what it
can do — mecha sessions health --json for a new field, mecha tools --json for a tool, strings for a literal. A fresh mtime is not a fresh
build (mtime records when a file was written, not what it was built from),
and version strings do not distinguish builds either; both premises can be
true while the inference is false, which is exactly how it went wrong on
2026-08-26.
Anything in ## Environment as left that you verified should carry the date
you verified it. Anything you could not verify should say so rather than
carrying an old claim forward.
6. Check for material that belongs elsewhere
Read the file for things that are not current state or open work. There is no
line budget — a project with a lot genuinely open has a long handoff, and
truncating it to hit a number is how a real item gets deleted instead of
finished. What matters is that everything in it is the right kind of thing:
- Explaining why a subsystem is shaped a certain way → that subsystem's
section of
docs/ARCHITECTURE.md; only an invariant any session could
trip over on any run goes in CLAUDE.md, which rides in every agent's
context and is priced accordingly
- A completed thing, or a lesson →
docs/HISTORY.md
- A question you researched → its own
docs/*-RESEARCH.md
- A thing designed but not yet built → its own
docs/*-DESIGN.md
- How a user operates the feature →
website/docs/
Length is a symptom worth reading, not a rule to enforce. If the file has
grown, ask what grew: more open work is honest, and a section that has
quietly become an essay is the thing to move.
7. Follow the cross-references
Moving a section breaks any pointer into it. Before committing:
grep -rn "HANDOFF" --include=*.md --include=*.rs --include=*.sh . \
--exclude-dir=target --exclude-dir=node_modules
Repoint anything that referred to content you moved.
What good looks like
After this pass, a reader who has never seen the project should be able to
open docs/HANDOFF.md and answer three questions without opening any other
file, and without opening the source to check whether the doc is lying:
- Does it build and pass, and what should I run first?
- What is actually true about the system right now?
- What is genuinely unbuilt, and which piece is cheapest to start on?
If any answer requires reading the code to confirm the doc, the pass is not
finished.
Anti-patterns
- Striking items through instead of moving them. The list only grows.
- Trusting your own commit message. You wrote it before you finished.
- Citing
file:line in the doc. Lines rot silently across merges — cite
the symbol, and name the verified commit where a line is unavoidable.
- Racing another lane into a single-writer doc. Announce first (step 0);
a merge conflict in the handoff defeats the file's whole purpose.
- Recording a measurement without its conditions. A number with no arm,
no
n, and no date is not a result and will mislead someone later.
- Carrying an unverified environment claim forward. Say "unverified" —
a stale fact stated confidently costs more than a gap.
- Adding a "future ideas" section. That is what the research docs are for;
ideas with no verified gap behind them turn the handoff back into a wishlist.