---
name: handoff
description: Use when ending a session to create a handoff document so a fresh agent can continue the work
---

# handoff

audience: AI coding agents first. Imperative, BLUF.

Produce what a fresh agent needs to continue: a prose handoff doc, AND — when the work is resumable multi-task execution — a durable session-state JSONL so `run-plan` can pick it up by slug.

## 1. Prose handoff doc (always)

Summarize the current conversation so a fresh agent can continue. Save to **OS temp dir** — NOT the workspace (it is ephemeral session scratch).
- Include a "suggested skills" section: which skills the next agent should invoke.
- **No duplicate content** from other artifacts (PRDs, plans, ADRs, specs, issues, commits, diffs, the JSONL below). Reference by path/URL.
- User passed args → treat as the next session's focus; tailor the doc.

## 2. Session-state JSONL (when handing off resumable execution work)

**Emit / finalize the harness-native JSONL when the next session will EXECUTE a multi-task or multi-wave plan** (`≥2 tasks/waves`, or the run will compact). Trivial single-shot handoff → skip; prose doc is enough.

This is the file `run-plan` loads. It lives in the repo, not temp:
- **Path:** `docs/plans/YYYY-MM-DD-<PLAN_SLUG>.jsonl` (in-repo, durable — `run-plan` globs `docs/plans/*-<slug>.jsonl`). Distinct from the prose doc's OS-temp location.
- **Schema owned by `brainstorm` (its "Session File" section). Follow it EXACTLY — do NOT invent or copy the schema here; read brainstorm's spec and reuse the record vocabulary** (`meta` line 1 with no `schema` key, then `goal`/`methodology`/`intent`/`direction`/`anchor`/`task`/`session_memory`/`gated`). One JSON record per line, never pretty-printed.

**Procedure:**
1. **A matching JSONL already exists** (`docs/plans/*-<slug>.jsonl`) → do NOT create a second and do NOT touch its `task` lines — the harness engine's own journal at `runstate/<slug>.jsonl` is the sole progress ground truth, not this file. Append a `session_memory` line for any in-flight context worth keeping, then go to step 3.
2. **No JSONL exists** but the next session needs one → create it at the path above using brainstorm's schema:
   - `meta` (line 1): `slug`, `base_branch`, `gate0_mode`, `preset` — no `schema` key.
   - Durable header: one `goal`, `methodology`, `intent` record; each standing user rule as a `direction` (`verbatim`, quoted exactly); `anchor` records pointing to the spec + plan docs (point, never copy their prose).
   - `task` records: the FULL list from the plan doc's wave table, each with `id`/`wave`/`seat`/`tier`/`desc`/`requires_decision`. This file is authored once; it is never rewritten for status — the harness engine's journal tracks progress.
3. **Surface the slug** to the user in the handoff output: `"Session slug: <slug> — resume with runplan <slug> (add --retry-blocked to re-attempt blocked tasks; the engine journal is the resume source of truth, not this plan file)."` They cannot resume a slug they never saw.

## Base-branch gate (MUST — run before finalizing any execution JSONL)

The executor cuts its integration branch from `meta.base_branch`. A wrong/missing base makes the implementer rebuild the plan's prerequisites from scratch → a giant bogus diff no review can cover. Both procedure paths (reconcile-existing AND create-new) MUST pass this before the JSONL is considered final.

Run the TESTED gate — do NOT re-derive the checks or reformulate the commands:

```
bash ~/.claude/workflows/lib/handoff-base-gate.sh <repoRoot> <jsonlPath> [<amendedPath>...]
```

`<amendedPath>...` = the paths your tasks amend/extend an EXISTING module at — YOUR judgment which tasks those are; pass their paths and the gate verifies each already exists on the base. The gate reads `meta.base_branch` from the JSONL and prints ONE line of JSON: `{"pass":bool,"checks":[{"name","ok","detail"}]}`. Four checks: **set** (base_branch present/non-empty), **resolves** (names a real commit), **prefer-remote-tracking** (FAILS when a local base provably lags its `origin/<base>` — a stale base misses merged prerequisites), **carries-deps** (each amended path already exists on the base).

`pass:false` → STOP, do not finalize. Read the failing check's `detail` and fix:
- **set** → set `meta.base_branch` now (see brainstorm's `base_branch` rule); never hand off without it.
- **prefer-remote-tracking** → use the `origin/<base>` ref the detail names.
- **carries-deps** → the base predates the prerequisite (WRONG base); find where the path lives (`git branch -a --contains <P>` / `git log --all --oneline -- <P>`) and set that base instead.

This is the gate that makes the build-from-wrong-base failure unrepeatable.

## Common mistakes

- Writing the JSONL to OS temp → `run-plan` globs `docs/plans/`; temp is for the prose doc only.
- Re-inventing or pasting the schema here → it drifts from `brainstorm`'s; point to that one source.
- Creating a second JSONL when one already exists for the slug → reconcile the existing file, never fork it.
- Pretty-printing the JSONL → one record per line.
- Emitting the JSONL but not telling the user the slug → unresumable.
