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 ...
Scanned 9/24/2026
npx -y skills add OneDro1d/dark-factory --skill handoff --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Handoff?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/onedro1d-handoff)More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.
---
name: handoff
description: 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 mechanical floor to PRECOMPACT.md, which the compact restore emits first. 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.
---
# 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
1. Resolves the active **notepad** (nearest ancestor of cwd with `NOTES.md`).
2. Writes the structured handoff to **`<notepad>/handoffs/<date>-<topic>.md`** —
inside the notepad, **never** the OS temp dir — so it is versioned and syncs.
3. **Redacts secrets** (API keys, tokens, bearer/JWT, private keys, `password=`…).
4. **References artifacts by path or URL** (PRDs, plans, ADRs, commits, diffs, per-repo
`df-context-store` findings) instead of duplicating their content.
5. **Suggests next skills** the receiving agent should invoke.
6. **Forces a `git push`** of the notepad (git add → commit → push, best-effort) so the
7. ⚠️ **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.
```bash
# 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. It also refuses an
empty body and any argument it does not take: there is no `--body-file` flag — pass the body
on stdin, or a file path as the third argument.
### Then record the session in durable memory
What Engram is, and how a machine is authorised to reach it, is documented in exactly one place: [Engram](../../../../../starter-kit/instance/AUTHENTICATION.md#engram).
A handoff is the notepad's entry point. It is **not** reachable from another notepad, another
machine, or a session six weeks from now that never opens this repo. So after publishing, write
one session record to Engram:
```bash
df-engram write --kind session --collection loom-sessions \
--title "<what this session actually changed, in a sentence>" \
--body-file <the handoff body, or a tighter summary> \
--mission "<mission id, when there is one>" \
--relates-query "<a one-sentence paraphrase of the outcome>" \
--corrects <document-id> # only for a record this supersedes, and only if you name it
```
- **`--relates-query` is not decoration.** It is the second search leg: the title finds keyword
neighbours, the paraphrase finds vector ones, and the two sets barely overlap. Omit it and the
tool falls back to the body's first sentence, which is a floor, not a substitute.
- **`--corrects` is a claim, so it is never inferred.** Pass it only for a document this record
genuinely supersedes. It takes the FULL document id — the eight-hex references in this estate's
notes are the first segment of a UUID and `engram_link` rejects them. Resolve the full
`document_id` from a search hit.
- **A TIMEOUT PROVES NOTHING.** `df-engram` parks the record `UNPROVEN` and does not retry, and it
is right not to: the indexing lag between a timed-out write and a findable document is 60-90 s,
and retrying inside it is what created duplicates by hand for months. Run `df-engram reconcile`
on a LATER turn.
- If the record cannot be sent at all (no token in this environment) the finding is still queued on
disk under `<notepad>/pending-engram/`. Nothing is lost; say so and move on.
The write also refreshes `<notepad>/.df/engram-recall.txt`, which is the line SessionStart injects
so the next cold session knows the store exists.
⚠️ **This is the one write that is NOT a second home for a fact.** The handoff points at artefacts
inside this notepad; the Engram record is how a session that has never seen this notepad finds the
work at all. Two different readers, not two copies.
### 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.
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!