| name | handoff |
| description | Compose a complete, durable build-loop handoff document from the current run state, and optionally launch a fresh session with it injected. Use when crossing a context boundary (context limit, planned restart, worktree GC). Triggers: 'hand off', 'handoff', 'new session', 'context limit', 'restart', 'fresh session', '/build-loop:compose-handoff'. |
| user-invocable | true |
Build-Loop Handoff
Compose a complete, durable handoff document from the current build-loop run state,
then (optionally) launch a fresh session in the STABLE checkout with that document injected.
When to use
- Context window approaching limit mid-build.
- Planned restart at a session boundary (e.g. deploying a plugin update requires a restart).
- A worktree about to be GC'd — extract state before the folder disappears.
- Handing off work to a peer agent or co-developer.
The seven content classes a handoff must carry
Derived empirically (2026-07-26): a generated handoff was cold-read by fresh agents at
three model tiers, scored, repaired, and re-tested. Every failure fell into one of seven
classes. A handoff missing any one of them produces an agent that can restate the work
but cannot act on it. Ranked by how much damage the omission causes.
| # | Class | The question it answers | Failure when missing |
|---|
| 1 | Orientation | What is this product, for whom, on what stack? | Reviewer inferred "Apple app" only from xcodebuild in a gotcha. Everything downstream is guesswork. |
| 2 | Constraints / non-goals | What must I NOT do? | The single most-cited gap. This is the class truncation kills first, because non-goals sit at the END of an intent file. |
| 3 | Landmines | What will bite me on my FIRST action? | Stale run-id markers, set push-holds, emptied state blocks. Each fires before any real work begins. |
| 4 | Authorization | Am I allowed to just start? | Absent this, an agent picks the most visible queue item — which may be another run's unpaid audit debt. |
| 5 | Verification recipe | How do I build/test, and what must I never run? | Without it an agent reaches for the obvious tool and gets a false green. |
| 6 | Open decisions | What is genuinely undecided, who owns it, what decides it? | A dangling "may have been wrong" with no owner and no criterion is unresolvable by the next agent. |
| 7 | Provenance | How trustworthy is this record itself? | A reconstructed or overridden record read as ground truth is worse than no record. |
Two cross-cutting rules learned the same way:
- Never truncate a class-2 or class-6 section. Both live at the end of their source
files, so any line cap removes exactly the text that carries the constraint.
- Counts are claims. A queue count that silently caps (or counts a derived
INDEX.md
instead of items/) understates open work. Titles alone are not enough either — carry
the frontmatter fields that decide whether an item is safe to pick up
(status, classify, judgment_verdict, owed_layers, blocked_by).
Recall and confidence are different failures with different fixes
This is the finding that mattered most, and it is not obvious: an agent can score full
marks on recall and still refuse to act.
Measured on one document across four rounds. Haiku answered 10/10 factual questions
correctly while rating its own confidence 2/5 — it had every fact and would not touch
the repo. Adding more facts would not have helped, because facts were never the gap.
| Failure | Caused by | Symptom | Fix |
|---|
| Recall | Omission — truncation, silent caps, missing orientation | "NOT IN DOC", wrong counts, guessing the tech stack | Put the content in (classes 1–5) |
| Confidence | Unresolved implication — a flag with no interpretation | Correct answers, low self-rating, "I'd have to read the code first" | State what each flag means for the reader (classes 6–7) |
Concretely, what moved Haiku from 2/5 to 5/5 was not new information. It was:
- Queue items carrying
judgment_verdict / classify / owed_layers, so "Judgment owed —
bl-…-codex-299759" became something a reader could triage instead of fear.
- The open decision gaining an owner and a criterion for deciding, so it read as
assigned rather than abandoned.
- The override gaining an explicit cost ("runs zero tests") and bound (what it does
and does not invalidate), so it read as disclosed rather than alarming.
Rule: every warning in a handoff must carry its own interpretation. A flag without a
"so what" transfers anxiety, not information — and a cautious reader responds by doing
nothing, which is the exact outcome the handoff exists to prevent.
How to test a handoff (the cold-read protocol)
Do not self-assess a handoff. Dispatch a fresh agent whose ONLY artifact is the document
path, tell it to open nothing else, and score it. Brief it and the test is worthless.
Run the same fixed question set at two model tiers, because they detect different
defects:
| Tier | Detects | Why |
|---|
| Weakest available (Haiku) | Unresolved implications | It will not infer past an ambiguity; low confidence with correct answers pinpoints class 6/7 gaps |
| Strongest available (Opus) | Internal contradictions | It cross-references sections and finds claims that cannot both be true |
Ask for CONFIDENCE (1-5), GAPS, and CONTRADICTIONS explicitly, and instruct the
agent to answer "NOT IN DOC" rather than guess — otherwise general knowledge silently
fills holes and the doc scores better than it deserves. Tell it to be harsh; a comfortable
review is a useless one.
Question set that surfaced every defect found (adapt the nouns, keep the shapes): what is
this product and for whom · what platforms and storage · what was just done and is it
finished · what builds/tests it and what must you never run · what is and is it done · name three forbidden things · how many queue items and which are
audit debt · did this ship through a normal gate · what decision is owed, who owns it,
what decides it · which field proves no new run started and which must you not read · why
is this record untrustworthy · what is the trap when searching for callers · are you
authorized to start · what must you run after adding a file · who wrote this record and
when relative to the work.
Expect the strong tier to challenge your evidence, not just your prose. On the final
round Opus accepted every fact and still flagged that a "three platforms build clean"
claim was overstated — the third platform's target excluded the directory the changed
files lived in, so its green proved the change could not break it, not that it was
verified. That correction came from the review, not from the author.
What it composes
Nine fixed sections (always the same order; absent data renders as "n/a"):
| # | Section | Source |
|---|
| 1 | North Star (intent) — incl. Orientation + glossary | .build-loop/intent.md (inlined WHOLE) |
| 2 | Current Goal — incl. open decisions | .build-loop/goal.md (inlined WHOLE) |
| 3 | Phase + Live Checklist | .build-loop/state.json (execution + runs[]) |
| 4 | Git State | git status + git log |
| 5 | Queues | followup/, backlog/, ux-queue/, issues/ |
| 6 | Gotchas / Lessons | .build-loop/feedback.md |
| 7 | Last Run Summary | state.json.runs[-1] |
| 8 | Resume Instructions | generated (workdir, phase context) |
Usage — no flag (emit doc)
python3 ${CLAUDE_PLUGIN_ROOT}/scripts/handoff --workdir "$PWD"
Prints the handoff doc to stdout. Pipe to a file or share directly.
python3 ${CLAUDE_PLUGIN_ROOT}/scripts/handoff --workdir "$PWD" --output handoff.md
Writes to a file instead.
python3 ${CLAUDE_PLUGIN_ROOT}/scripts/handoff --workdir "$PWD" --json
Emits a JSON envelope {document, sources, errors, ts} for programmatic use.
Usage — --launch (fresh session)
The command surface (/build-loop:compose-handoff --launch) handles this. The skill provides
the doc; the command layer handles host-specific launch.
What --launch does:
- Compose the handoff doc from the CURRENT run state.
- Write it to
.build-loop/handoff-latest.md in the STABLE checkout.
- Start a fresh host session at the STABLE checkout root (not the worktree).
- Inject the handoff doc so the new session opens with full context.
Host behavior:
| Host | Launch method | Handoff injection |
|---|
| Claude Code | claude --print with doc as initial prompt prefix | Inline in opening message |
| Codex | codex with --context flag or stdin | Depends on Codex version |
| Unknown / unsupported | Emit doc + print instructions, exit 0 | Manual paste |
The --launch path always writes .build-loop/handoff-latest.md regardless of host
support — the doc is the primary deliverable; launch is a convenience.
Important: launch always targets the STABLE checkout (git worktree list → the
[bare] or main entry), not the current worktree. Worktrees may be GC'd before the
new session starts.
KISS/DRY note
scripts/handoff/__main__.py reads .build-loop/ using only json, pathlib,
and subprocess from the standard library — no new dependencies. It does NOT
re-implement state parsing; it reads state.json directly at the same paths the
orchestrator already writes. Tests: scripts/handoff/test_handoff.py (13 tests).
Host-agnostic design
The skill provides structured data + instructions. The host coding agent's LLM
interprets and acts on the handoff doc. No vendor-specific API calls. The --launch
CLI path uses the host's own CLI, isolated in commands/compose-handoff.md's conditional
block — the skill logic is identical across Claude Code, Codex, and future hosts.