Install
$ agentstack add skill-nanwulan-claude-handoff-skill-claude-handoff-skill ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ● Network access Used
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
Handoff V2 — Project State Management
Overview
Handoff is the project memory layer for Claude Code. It answers one question:
> "If I open this project in a fresh session, what do I need to know to start working immediately?"
It does this with two files:
| File | Role | Lifespan | |------|------|----------| | PROJECT.ftmd | Project long-term memory — accumulates decisions, failures, environment | Persistent. Lives as long as the project. | | HANDOFF-YYYY-MM-DD.ftmd | Session snapshot — what happened THIS session, what's next | Short-lived. Read once then archived. |
Together they form a complete picture: PROJECT.ftmd tells you the project's history and identity; HANDOFF.ftmd tells you exactly where to pick up.
FTMD Format
FTMD stands for Frictionless Transfer Markdown Document. Standard Markdown (CommonMark + GFM tables), UTF-8, LF line endings. No YAML frontmatter, no custom syntax — the filename IS the metadata.
Every factual claim tagged [V] (verified) or [?] (recalled from memory).
PROJECT.ftmd — Long-Term Memory
This file lives at project root and is never deleted. Each /handoff updates it incrementally.
Sections
| # | Section | Update Rule | |---|---------|-------------| | 1 | Snapshot | Overwritten each time — current stage, progress estimate, last-updated date | | 2 | Environment | Overwritten each time — auto-captured from the system | | 3 | Decision Log | Appended — each entry dated, newest first | | 4 | Failure Memory | Appended — each entry dated, newest first | | 5 | Open Questions | Replaced each time — currently unresolved questions |
Format
# Project:
## Snapshot
- **Stage:** Feature Development | Bug Fixing | Refactoring | Prototyping | Maintenance
- **Progress:** rough percentage or "just started" / "nearing completion"
- **Focus:** one-line description of current work
- **Updated:** YYYY-MM-DD
## Environment
| Variable | Value |
|----------|-------|
| OS | Linux x86_64 (or Windows 11, macOS 15, etc.) |
| Shell | bash 5.2 |
| Node | v22.3.0 |
| Python | 3.12.4 |
| Git | 2.47.0 |
| Claude Code | (from `claude --version`) |
| Package Manager | npm 10.x |
| Workspace | /home/user/projects/my-app (or C:\Users\...\my-app) |
## Decision Log
### 2026-07-26 — Use FTMD format over JSON/YAML
- **Context:** Needed a structured handoff format.
- **Decision:** Plain Markdown with 9-section convention.
- **Why:** No tooling dependency, Git-diffable, human-readable.
- **Rejected:** JSON (not readable), YAML (fragile indentation), SQLite (overkill).
## Failure Memory
### 2026-07-26 — Tried to install xyz package
- **Attempt:** `npm install xyz`
- **Result:** Build failed with native module error
- **Root cause:** Node version too new for xyz's node-gyp bindings
- **Lesson:** Pin xyz to v2.x or use Node 20 LTS
## Open Questions
- Q: Migrate to TypeScript? → waiting on team decision
- Q: Use Redis or Postgres for session store? → needs benchmark
Update Rules
On every /handoff:
- Snapshot: Replace. Reflect current reality — verify against file state (and git status, if this is a git repo). Don't guess.
- Environment: Replace. Re-run all capture commands fresh.
- Decision Log: Append only if this session made new decisions. Don't duplicate. Cap: 30 entries max. If exceeded, delete the oldest (bottom of file) before appending.
- Failure Memory: Append only if this session hit new pitfalls. Don't duplicate. Cap: 30 entries max. Same cleanup rule as Decision Log.
- Open Questions: Replace. Remove resolved ones, add new ones.
If PROJECT.ftmd doesn't exist: create it with all sections populated.
HANDOFF.ftmd — Session Snapshot
Generated fresh each /handoff. Nine required sections:
| # | Section | Content | |---|---------|---------| | 1 | Task | What are we building? One paragraph of project context. | | 2 | Completed | What is done and verified. Each item tagged [V] or [?]. | | 3 | Git Snapshot | Branch, last commit, changed files (from git status / git diff --stat). If not a git repo, write "N/A — not a git repo". | | 4 | Blocked | Two categories: 🔧 Technical (symptom, hypothesis, file/line) and 👤 Needs decision (question for user). | | 5 | Next Steps | Ordered, actionable. Each names a specific file or endpoint. | | 6 | Pitfalls | What went wrong this session. Symptom → root cause → correct approach. | | 7 | Decisions | This session's decisions and WHY. Include rejected alternatives. | | 8 | File Map | Table: file path → what it does. Only files touched this session. | | 9 | Startup Protocol | Commands to run the project, ordered list of files to read first. |
If the session is the project's first, omit sections 6 and 7 (no history yet). Add bonus sections for env vars or API endpoints if applicable.
Environment Auto-Capture
Run these commands during /handoff generation. No user input needed.
| What | Command | |------|---------| | OS | uname -o or ver | | Shell | echo $SHELL or $SHELL --version | | Node | node --version | | Python | python3 --version or python --version | | Git | git --version | | Claude Code | claude --version | | Package Manager | check for package-lock.json (npm), yarn.lock, pnpm-lock.yaml | | Workspace | pwd |
Only run commands that exist. Skip any that fail — don't block the handoff.
Commands
/handoff (main)
Generate HANDOFF + update PROJECT + run cleanup. This is the primary command. No arguments needed.
Step-by-step:
- Run Short-Session Gate check. If all 4 criteria met, ask user before proceeding.
- Run Verification Protocol (git status/diff if available, re-read files, run tests if available).
- Collect Environment info via auto-capture commands.
- Optional — claude-mem: If claude-mem tools are available (see "Optional: claude-mem Integration"), search for this project's observations and cross-reference with claims. Add "From Memory (claude-mem)" bonus section to the HANDOFF. If NOT available: skip silently.
- Generate
HANDOFF-YYYY-MM-DD.ftmdwith all 9 sections. - Update
PROJECT.ftmd: replace Snapshot + Environment, append Decision Log + Failure Memory, replace Open Questions. - Run Cleanup Rules.
/handoff timeline
Read PROJECT.ftmd and display Decision Log + Failure Memory in chronological order (oldest first). No new file generated.
This shows decision evolution — when and why the team changed direction, abandoned approaches, or discovered pitfalls. It is NOT a development log: don't list file edits or timestamps. Only entries with strategic weight belong here.
If PROJECT.ftmd doesn't exist: "📭 这个项目还没有长期记忆。下次 /handoff 时会自动创建。"
/handoff status
Read PROJECT.ftmd Snapshot and output a one-line status:
> 项目: handoff skill | 阶段: Feature Development | 进度: ~70% | 焦点: V2 dual-file model | 更新: 2026-07-26
If PROJECT.ftmd doesn't exist: "📭 还没有项目状态文件。输入 /handoff 来创建。"
/handoff doctor
Check project health. Report what's present and what's missing:
| Check | Looks for | |-------|-----------| | PROJECT.ftmd | Exists? Has all 5 sections? | | Latest HANDOFF | Exists? How old? | | Git repo | git status works? (Skip if not a git repo — mark "N/A") | | Environment | All fields captured? | | Tests | Test suite exists? Last run passed? (Skip if none — mark "N/A") | | claude-mem | If available: recent observations for this project? If not: mark "N/A (not installed)" |
Output as a checklist with ✅ / ⚠️ / ❌ markers. End with a one-line recommendation.
Verification Protocol
Nothing goes in the handoff from memory alone. Before writing:
- Git reality check (if available): Run
git status,git log --oneline -5,git diff --stat. Use diff output verbatim in Git Snapshot and File Map. If this is not a git repo, skip git verification — mark Git Snapshot as "N/A (not a git repo)" and proceed. - Re-read referenced files: Every file the handoff mentions must be re-read during generation.
- Re-run tests (if available): If the project has tests, run them. "Tests pass" is only written from output produced NOW. If no test suite exists, skip.
Tag every claim: | Tag | Meaning | |-----|---------| | [V] | Verified against the project files during this handoff — trustworthy | | [?] | Recalled from memory, not re-checked — treat as a lead only |
Every [V] claim MUST include its evidence source. Write it inline, not as a separate column. The evidence answers: "How would the next session verify this independently?"
- ✅ Good:
Login redirect fixed [V] (AuthGuard.tsx:42, 7 tests pass in auth-guard.test.tsx) - ✅ Good:
Token expiry check added [V] (src/utils/token.ts:15, commit a1b2c3d) - ❌ Bad:
Login redirect fixed [V]— no evidence, untrustworthy
If you can't name a file, test, or specific location that proves the claim, downgrade it to [?].
If verification fails (tests fail, unexpected git state, file deleted), don't abort. Tag affected claims [?] and add a "Verification Notes" bonus section.
Optional: claude-mem Integration
Handoff is fully self-contained — it works perfectly without any external tools. claude-mem is an optional knowledge base that, IF available, enhances Handoff with cross-project context.
How to detect claude-mem
claude-mem is available when the session has tools matching mcp__*mem-search*. If no such tools exist: skip ALL claude-mem steps silently. The handoff is complete without them.
When claude-mem IS available
On Write: During /handoff generation, search memory for this project's observations. Add a "From Memory (claude-mem)" bonus section to HANDOFF.ftmd with 3–5 most relevant past observations.
On Read: After reading HANDOFF in a new session, search memory for the project to surface relevant institutional knowledge alongside the session snapshot.
In Doctor: Report whether recent observations exist for this project.
Data Boundary
| Data type | Belongs to | Example | |-----------|-----------|---------| | User preferences, habits | claude-mem | "Prefers TypeScript" | | Long-term tech stack choices | claude-mem | "This org uses React + Next.js" | | Current task, immediate next step | handoff | "Refactoring login module, OAuth not done" | | This session's decisions | handoff → PROJECT.ftmd | "Chose JWT over session tokens" | | Pitfalls and lessons from this project | handoff → PROJECT.ftmd | "Don't use xyz v3 with Node 22" |
Rule of thumb: If it's true across projects or sessions → claude-mem. If it's specific to what's happening right now in this project → handoff.
Short-Session Gate
Before generating, check ALL four. If ALL true, ask: "这次会话较短,确定要写交接文档吗?"
| Gate | Criteria | |------|----------| | Topics | Fewer than 3 distinct user-initiated topics | | Output | No files were created or modified | | Decisions | No architectural/technical decisions were made | | Duration | The conversation was purely Q&A / information lookup |
Meeting just 1–2 is not enough to gate. All four must align.
Save Location
Determine in this order — try each, if it fails or doesn't exist, move to the next:
- Git root (
git rev-parse --show-toplevel) — if this is a git repo - Directory containing
package.json,Cargo.toml,pyproject.toml,go.mod, or similar project marker - Current working directory — if it contains source files, config files, or looks like a project
- Fallback: Current working directory — always available, always writable
PROJECT.ftmd → saved at the resolved project root (priority 1-3) or fallback directory (priority 4).
HANDOFF-YYYY-MM-DD.ftmd → same location as PROJECT.ftmd. If saved to fallback directory (priority 4), use topic slug: HANDOFF--YYYY-MM-DD.ftmd to avoid filename collisions.
Never save to /tmp/ or Desktop.
Cleanup Rules
Apply on every /handoff invocation:
| Rule | Action | |------|--------| | Read → done | After reading a HANDOFF in a new session, rename to .ftmd.done | | Stale purge | Delete .done files older than 7 days | | HANDOFF count cap | Keep at most 3 active HANDOFF .ftmd files per project. Delete oldest beyond cap. | | PROJECT.ftmd | Never auto-deleted. It is the project's long-term memory. |
New Session Protocol
Two triggers activate this protocol:
| Trigger | Source | Action | |---------|--------|--------| | Auto-detect (unread) | SessionStart hook detects HANDOFF-*.ftmd (not .done) | Model reads immediately — unread HANDOFF means the user wants to continue. No need to ask. | | Auto-detect (archived) | SessionStart hook detects only .ftmd.done files | Model asks: "📝 上次的交接文档已归档。要不要看看最近的项目状态?" | | Manual | User says "先读 HANDOFF" (canonical resume command) | Read immediately without asking |
Step 0 — Auto-Read (Unread HANDOFF)
When the SessionStart hook detects an unread HANDOFF (HANDOFF-*.ftmd, not .done), the model reads it immediately without asking. The presence of an unread HANDOFF is itself the user's intent signal — they opened a new session to continue where they left off. Asking "要不要先读?" is unnecessary friction.
> 模型看到信号后直接执行 Step 1,无需等待用户确认。
When the hook detects only archived files (.ftmd.done), the model asks first — the user may not want to revisit old state.
Rationale: Unread HANDOFF = continuation intent. The user wrote it last session, didn't mark it done, and opened a new session. Every extra click between them and resuming work is friction with no benefit.
Step 1 — Read
When triggered (auto-detect OR manual "先读 HANDOFF"), read in this order:
- PROJECT.ftmd first — understand the project's identity, history, environment
- **Latest HANDOFF-.ftmd* (without
.done) — get the current task state and next steps - If claude-mem is available: Search memory for this project — surface relevant observations alongside the handoff. If not available: Skip. Steps 1–2 provide sufficient context to start working.
Multiple HANDOFFs: Read only the newest. Mark all older HANDOFF .ftmd files as .done.
No files exist: Reply: "没有找到交接文档。这是一个全新的开始。"
Stale warning: If the newest HANDOFF is older than 14 days: "⚠️ 这份交接文档已过两周,信息可能已过时。是否仍然继续?"
Recovery Protocol
After reading PROJECT.ftmd and HANDOFF, execute these steps before doing any work:
- Verify git state (if this is a git repo) —
git status,git log --oneline -3. Does the branch and last commit match the HANDOFF's Git Snapshot? If not, note the discrepancy. If not a git repo, skip this step. - Spot-check [V] claims — pick 1–2
[V]claims from the Completed section, re-read the referenced file or re-run the referenced test. If evidence doesn't hold, downgrade mentally to[?]. - Confirm next step — read the first item in Next Steps. State it to the user: "HANDOFF says the next step is X. Continue from here?"
If the HANDOFF is confirmed valid, begin working from Next Steps. Don't re-explore the project from scratch.
Source-of-Truth Rank
- Running code — what's on disk right now
- Test output — what tests actually say
- Project docs — README, spec, architecture docs
- PROJECT.ftmd — the project memory file
- This HANDOFF — the session snapshot
- Older handoffs — archived
.donefiles
If conflict found: state it explicitly ("PROJECT.ftmd says X, but code shows Y. Following the code.") and update PROJECT.ftmd accordingly.
Degradation Detection
Reactive: Context Rot
Watch for: contradicting earlier decisions, re-deriving settled conclusions, describing stale file contents, repeating failed approaches.
First sign: "💡 上下文可能正在退化。要不要 /handoff 保存进度?" Second sign: "⚠️ 退化迹象增多,建议尽快 /handoff。" Never suggest more than twice per session.
Consecutive rejection: If the user declines 2 consecutive
…
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: nanwulan
- Source: nanwulan/claude-handoff-skill
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.