handoff — publish a deliberate Handoff doc into the notepad
Notes vs Handoff — the terminology split (read first)
agent-notepad keeps working memory in two tiers, and this skill owns only the second:
- Notes — the continuous tier.
NOTES.md (compact, rewritten in place) plus the
append-only journal (sessions/<ISO8601>_<id>.jsonl). Kept fresh automatically by
the Stop / PreCompact / UserPromptSubmit hooks and auto-loaded every SessionStart. You
do not invoke a skill for Notes — they just accrue.
- Handoff — the deliberate tier. A single structured document you publish on
demand at a meaningful boundary (milestone, teammate hand-off, end of a work block).
This is what
/handoff produces.
A Handoff summarizes the current Notes into a durable, shareable artifact; it does
not replace them. Notes are the stream; a Handoff is a snapshot you deliberately cut
and push. When in doubt: routine progress → let the Notes hooks capture it; a real
checkpoint someone else (or a fresh you) will read cold → publish a Handoff.
What this does
Resolves the active notepad (nearest ancestor of cwd with NOTES.md).
Writes the structured handoff to <notepad>/handoffs/<date>-<topic>.md —
inside the notepad, never the OS temp dir — so it is versioned and syncs.
Redacts secrets (API keys, tokens, bearer/JWT, private keys, password=…).
References artifacts by path or URL (PRDs, plans, ADRs, commits, diffs, per-repo
df-context-store findings) instead of duplicating their content.
Suggests next skills the receiving agent should invoke.
Forces a git push of the notepad (git add → commit → push, best-effort) so the
⚠️ Update NOTES.md yourself, and commit it WITH the handoff. Operator rule, 2026-07-29:
"Commit the handoff together with the session's NOTES.md update and any deploy-evidence, so
the checkpoint is one coherent commit."
⛔ This is not bookkeeping — it is the only thing that makes the handoff reachable.
session-start.sh injects NOTES.md, DIGEST.md and repos.manifest.json; it does not
read handoffs/. A handoff published without a Notes update is invisible to every cold
session — and the restore that misses it looks completely healthy.
MEASURED 2026-09-04: a /clear restored a NOTES.md seven weeks stale while that day's
handoff went unread. Nothing errored; the restore banner appeared and looked fine.
⚠️ A healthy restore banner is not evidence the payload is current.
handoff is immediately available on other machines / to teammates.
When to use
- Wrapping a session or work block; handing to a teammate or a fresh agent.
- Hitting a milestone worth a durable checkpoint.
- Explicit asks: "create a handoff", "hand this off", "checkpoint for next session",
"prep for a fresh agent", "summarize the session for continuation".
⚠️ The handoff is the SINGLE ENTRY POINT for a cold session
Operator decision, 2026-09-01. A handoff must be the only document a fresh session has to
read to become oriented. Not the first of five — the only one. Everything else it needs, it
reaches through the handoff.
That is a contract on what a handoff must contain:
- Where the work stands, in a few sentences a cold reader can act on.
- The one next action. Not a menu.
- A link to every artefact touched — the mission map, the tickets, the PRs, the files, the
findings. By path or URL, in a list, so nothing has to be hunted for.
- What is blocked and on whom.
⚠️ It POINTS. It does not RESTATE. The Mission Map holds the decisions; the tracker holds
ticket state; the repos hold the code. A handoff that copies those becomes a second store of
the same facts, and two stores drift — which is the one-artifact-two-homes failure this whole
model exists to remove. Entry point, not authority. If you find yourself explaining a
decision rather than linking to where it was recorded, stop and link.
⚠️ Test it the only way that works: could someone who was NOT in this session pick up this
file alone and continue? If they would have to already know which mission, which ticket, or
which repo — it is not a handoff yet, however complete it feels from inside the session.
Why this matters more after compaction than at a milestone
Native compaction is lossy and unversioned. When it fires, the hooks re-inject what they have —
so whatever the handoff does not carry is simply gone from the new window. A five-document
read order degrades to whichever documents the compacted agent still remembers to open. One
self-sufficient document does not have that failure mode.
For automatic survival across auto-compaction, the Notes and PreCompact hooks do the
mechanical capture — you do not run this skill for that. But they capture session mechanics:
files touched, recent intent. They cannot know which ticket was claimed or what "done" means
here. That judgement is this skill's, which is why the 85% context gate tells you to call it
rather than trusting the hooks alone.
How to run
Compose the handoff body (the sections below), then publish via the helper. The
helper writes the file, redacts, commits, and pushes; it prints the path it wrote.
# Resolve the helper under BOTH install modes.
# plugin mode -> ${CLAUDE_PLUGIN_ROOT}/lib/...
# install.sh mode -> ~/.claude/hooks/agent-notepad/lib/...
# ⚠️ ${CLAUDE_PLUGIN_ROOT} is set ONLY when agent-notepad is loaded as a PLUGIN. Under
# install.sh it is EMPTY, and a bare "${CLAUDE_PLUGIN_ROOT}/lib/publish-handoff.sh" collapses
# to "/lib/publish-handoff.sh" — an absolute path that does not exist. This fallback existed
# here and NOT in the top-level twin that installs, so the installed skill documented a
# command that could not run. Fixed there 2026-08-31; keep the two in step.
PUBLISH_HANDOFF="${CLAUDE_PLUGIN_ROOT:-$HOME/.claude/hooks/agent-notepad}/lib/publish-handoff.sh"
# body on stdin; args: <notepad-root> <topic>
printf '%s' "$HANDOFF_BODY" \
| "$PUBLISH_HANDOFF" "$NOTEPAD_ROOT" "Arb bot milestone"
If $PUBLISH_HANDOFF does not exist, agent-notepad is not installed — say so and stop.
Do not hand-roll the write: the helper owns the notepad-root guard, the redaction
pass, the commit and the forced push, and the AGENT_NOTEPAD_* test overrides.
$NOTEPAD_ROOT is the current notepad (the nearest ancestor with NOTES.md; the
SessionStart hook already resolved it). The helper refuses (non-zero exit, no write)
if the target is not a notepad — a Handoff only belongs in a notepad.
Suggested body sections
- Objective / current goal — one line; the done-criteria from
SCOPE.md.
- State — what is done, what is in flight.
- Decisions — key choices + rationale (mirror durable ones into the code repo's
DECISIONS.md via context-management).
- Next action — the single most important next step.
- Blocked — what is blocked and on whom. ⚠️ The heading must contain the word
Blocked:
handoff-completeness-gate.py looks for a heading matching /blocked/,
and "blockers" does not match it. Measured on four separate validate runs — a handoff
written exactly as this list used to describe was rejected by the gate that reads it.
- Artifacts — reference by
repo:file:line, PR/commit SHA, or URL. Do not paste
their contents.
- Suggested next skills — e.g.
df-tdd-developer, df-qa, context-management,
plus whichever memory-recall skill the instance binds (Tier-2; do not assume a name).
Guarantees & boundaries
- Target-overridable / test-safe: the notepad root is an argument;
AGENT_NOTEPAD_DATE
overrides the date stamp and AGENT_NOTEPAD_PUSH_LOG records push attempts. Tests point
all three at temp dirs — the helper never hardcodes a real repo or remote.
- Best-effort push: every git step is
|| true; a missing/broken remote still leaves a
written, committed handoff and a zero exit.
- Writes only under the notepad. Never touches
~/.claude, the palace, or any repo
outside the notepad. Live memory is read-only elsewhere; this skill only writes files
and pushes the notepad's own git repo.
1---2name: handoff-23description: Publish a deliberate, structured Handoff document for the current objective into the active notepad and force a git push so it syncs across machines. Use when wrapping a session, handing to a teammate or fresh agent, hitting a milestone, or asked to "create a handoff", "write a handoff", "checkpoint for next session", "hand this off". Writes to <notepad>/handoffs/<date>-<topic>.md (NOT a temp dir), redacts secrets, references artifacts by path/URL, suggests next skills. In agent-notepad this is the on-demand Handoff tier — distinct from the continuous Notes tier (NOTES.md + journal). WARNING - 'hooks keep it fresh' holds ONLY on the compaction path, where pre-compact.sh writes a delimited pc-floor block into NOTES.md. On /clear nothing does, because PreCompact never fires - so NOTES.md is whatever the agent last wrote, and it MUST be refreshed in the same commit as the handoff.4---56# handoff — publish a deliberate Handoff doc into the notepad78## Notes vs Handoff — the terminology split (read first)910agent-notepad keeps working memory in **two tiers**, and this skill owns only the second:1112- **Notes** — the *continuous* tier. `NOTES.md` (compact, rewritten in place) plus the13 append-only journal (`sessions/<ISO8601>_<id>.jsonl`). Kept fresh **automatically** by14 the Stop / PreCompact / UserPromptSubmit hooks and auto-loaded every SessionStart. You15 do **not** invoke a skill for Notes — they just accrue.16- **Handoff** — the *deliberate* tier. A single **structured document** you publish on17 demand at a meaningful boundary (milestone, teammate hand-off, end of a work block).18 This is what `/handoff` produces.1920A Handoff **summarizes** the current Notes into a durable, shareable artifact; it does21**not** replace them. Notes are the stream; a Handoff is a snapshot you deliberately cut22and push. When in doubt: routine progress → let the Notes hooks capture it; a real23checkpoint someone else (or a fresh you) will read cold → publish a Handoff.2425## What this does26271. Resolves the active **notepad** (nearest ancestor of cwd with `NOTES.md`).282. Writes the structured handoff to **`<notepad>/handoffs/<date>-<topic>.md`** —29 inside the notepad, **never** the OS temp dir — so it is versioned and syncs.303. **Redacts secrets** (API keys, tokens, bearer/JWT, private keys, `password=`…).314. **References artifacts by path or URL** (PRDs, plans, ADRs, commits, diffs, per-repo32 `df-context-store` findings) instead of duplicating their content.335. **Suggests next skills** the receiving agent should invoke.346. **Forces a `git push`** of the notepad (git add → commit → push, best-effort) so the35367. ⚠️ **Update `NOTES.md` yourself, and commit it WITH the handoff.** Operator rule, 2026-07-29:37 *"Commit the handoff together with the session's NOTES.md update and any deploy-evidence, so38 the checkpoint is one coherent commit."*3940 ⛔ **This is not bookkeeping — it is the only thing that makes the handoff reachable.**41 `session-start.sh` injects `NOTES.md`, `DIGEST.md` and `repos.manifest.json`; it does **not**42 read `handoffs/`. A handoff published without a Notes update is invisible to every cold43 session — and the restore that misses it looks completely healthy.4445 **MEASURED 2026-09-04:** a `/clear` restored a `NOTES.md` seven weeks stale while that day's46 handoff went unread. Nothing errored; the restore banner appeared and looked fine.47 ⚠️ **A healthy restore banner is not evidence the payload is current.**48 handoff is immediately available on other machines / to teammates.4950## When to use5152- Wrapping a session or work block; handing to a teammate or a fresh agent.53- Hitting a milestone worth a durable checkpoint.54- Explicit asks: "create a handoff", "hand this off", "checkpoint for next session",55 "prep for a fresh agent", "summarize the session for continuation".5657## ⚠️ The handoff is the SINGLE ENTRY POINT for a cold session5859Operator decision, 2026-09-01. **A handoff must be the only document a fresh session has to60read to become oriented.** Not the first of five — the only one. Everything else it needs, it61reaches *through* the handoff.6263That is a contract on what a handoff must contain:6465- **Where the work stands**, in a few sentences a cold reader can act on.66- **The one next action.** Not a menu.67- **A link to every artefact touched** — the mission map, the tickets, the PRs, the files, the68 findings. By path or URL, in a list, so nothing has to be hunted for.69- **What is blocked and on whom.**7071⚠️ **It POINTS. It does not RESTATE.** The Mission Map holds the decisions; the tracker holds72ticket state; the repos hold the code. A handoff that copies those becomes a second store of73the same facts, and two stores drift — which is the one-artifact-two-homes failure this whole74model exists to remove. **Entry point, not authority.** If you find yourself explaining a75decision rather than linking to where it was recorded, stop and link.7677⚠️ **Test it the only way that works: could someone who was NOT in this session pick up this78file alone and continue?** If they would have to already know which mission, which ticket, or79which repo — it is not a handoff yet, however complete it feels from inside the session.8081### Why this matters more after compaction than at a milestone8283Native compaction is lossy and unversioned. When it fires, the hooks re-inject what they have —84so whatever the handoff does *not* carry is simply gone from the new window. A five-document85read order degrades to whichever documents the compacted agent still remembers to open. One86self-sufficient document does not have that failure mode.8788For *automatic* survival across auto-compaction, the Notes and PreCompact hooks do the89mechanical capture — you do not run this skill for that. **But they capture session mechanics:90files touched, recent intent.** They cannot know which ticket was claimed or what "done" means91here. That judgement is this skill's, which is why the 85% context gate tells you to call it92rather than trusting the hooks alone.9394## How to run9596Compose the handoff **body** (the sections below), then publish via the helper. The97helper writes the file, redacts, commits, and pushes; it prints the path it wrote.9899```bash100# Resolve the helper under BOTH install modes.101# plugin mode -> ${CLAUDE_PLUGIN_ROOT}/lib/...102# install.sh mode -> ~/.claude/hooks/agent-notepad/lib/...103# ⚠️ ${CLAUDE_PLUGIN_ROOT} is set ONLY when agent-notepad is loaded as a PLUGIN. Under104# install.sh it is EMPTY, and a bare "${CLAUDE_PLUGIN_ROOT}/lib/publish-handoff.sh" collapses105# to "/lib/publish-handoff.sh" — an absolute path that does not exist. This fallback existed106# here and NOT in the top-level twin that installs, so the installed skill documented a107# command that could not run. Fixed there 2026-08-31; keep the two in step.108PUBLISH_HANDOFF="${CLAUDE_PLUGIN_ROOT:-$HOME/.claude/hooks/agent-notepad}/lib/publish-handoff.sh"109110# body on stdin; args: <notepad-root> <topic>111printf '%s' "$HANDOFF_BODY" \112 | "$PUBLISH_HANDOFF" "$NOTEPAD_ROOT" "Arb bot milestone"113```114115If `$PUBLISH_HANDOFF` does not exist, agent-notepad is not installed — say so and stop.116Do **not** hand-roll the write: the helper owns the notepad-root guard, the redaction117pass, the commit and the forced push, and the `AGENT_NOTEPAD_*` test overrides.118119`$NOTEPAD_ROOT` is the current notepad (the nearest ancestor with `NOTES.md`; the120SessionStart hook already resolved it). The helper **refuses** (non-zero exit, no write)121if the target is not a notepad — a Handoff only belongs in a notepad.122123### Suggested body sections124125- **Objective / current goal** — one line; the done-criteria from `SCOPE.md`.126- **State** — what is done, what is in flight.127- **Decisions** — key choices + rationale (mirror durable ones into the code repo's128 `DECISIONS.md` via context-management).129- **Next action** — the single most important next step.130- **Blocked** — what is blocked and on whom. ⚠️ The heading must contain the word131 **Blocked**: `handoff-completeness-gate.py` looks for a heading matching `/blocked/`,132 and "blockers" does not match it. Measured on four separate validate runs — a handoff133 written exactly as this list used to describe was rejected by the gate that reads it.134- **Artifacts** — reference by `repo:file:line`, PR/commit SHA, or URL. Do **not** paste135 their contents.136- **Suggested next skills** — e.g. `df-tdd-developer`, `df-qa`, `context-management`,137 plus whichever memory-recall skill the instance binds (Tier-2; do not assume a name).138139## Guarantees & boundaries140141- **Target-overridable / test-safe:** the notepad root is an argument; `AGENT_NOTEPAD_DATE`142 overrides the date stamp and `AGENT_NOTEPAD_PUSH_LOG` records push attempts. Tests point143 all three at temp dirs — the helper never hardcodes a real repo or remote.144- **Best-effort push:** every git step is `|| true`; a missing/broken remote still leaves a145 written, committed handoff and a zero exit.146- **Writes only under the notepad.** Never touches `~/.claude`, the palace, or any repo147 outside the notepad. Live memory is read-only elsewhere; this skill only writes files148 and pushes the notepad's own git repo.