claude-plugins · handoff

Session continuity — without the copy-paste.

Save the directive of a wrap-up session and surface it at the start of the next one. Replaces the manual "paste a prompt into the new window" workflow with an auto-save + confirm-on-resume loop.

handoff session-continuity session-start-hook workflow-automation
installbash
claude plugin install handoff@apurvbazari-plugins

That's it. The SessionStart hook activates automatically — no setup step required.

4
skills
1
active slot
4
resume options
90d
auto-archive
01 — how a handoff works

The save → resume loop

One save, one active slot, one confirmed resume. Click a stage to see detail in the side panel.

/handoff:save
save handoff
write
.claude/handoff/active.md
next session
SessionStart hook
/handoff:pickup
pickup → confirm

Wrap-up phrases like "pick this up later", "continue in new session", or "save handoff" auto-invoke /handoff:save. It presents a confirm before writing — false positives cost one click. The SessionStart hook on the next session reads active.md, runs stale and snooze checks, and routes Claude to the four-option pickup flow. Handoff never auto-executes a directive — you always confirm.

Trust model

The SessionStart hook wraps directive content in <untrusted-source> tags. Routing instructions and metadata are trusted; the saved directive is data you review, not commands Claude runs automatically. The four-option AskUserQuestion ensures confirmation before any action.

Cowork

The SessionStart hook is CLI-only — plugin-scoped hooks don't fire in Claude Cowork (it loads user-scoped settings only). A saved handoff won't surface automatically there; run /handoff:pickup manually to resume.

02 — skills

Four skills — save, pickup, check, discard

All under /handoff:<name>. save and pickup auto-invoke on intent; check auto-invokes but is read-only; discard is destructive and user-invoked only.

SkillInvocationWhat it does
/handoff:save auto Auto-invokes on a wrap-up phrase. Drafts a directive (next step, pointers, constraints, open questions) and confirms via AskUserQuestion before writing. Captures saved-at, saved-at-sha, saved-at-branch, saved-from-cwd frontmatter.
/handoff:pickup auto — after hook Auto-invokes after the hook surfaces a handoff. Re-reads from disk (surfaced content is treated as stale), runs cwd guard, then presents four options via AskUserQuestion: Execute / Edit / Discard / Save for later.
/handoff:check auto · read-only Reports whether an active handoff exists, its age, saved-at SHA and branch, how far the repo has moved past the saved SHA, and snooze status. Useful for "why isn't this surfacing?".
/handoff:discard user-only Archives the active handoff without acting — same effect as Discard in pickup, invocable from anywhere. disable-model-invocation prevents accidental auto-invocation.
the four resume options
OptionEffect
ExecuteAct on the directive in this session (guidance for judgement, not commands to run), then archive to archive/consumed-<ts>.md.
EditOpen active.md in $EDITOR, revise the directive, then re-present for another confirm round-trip.
DiscardArchive to archive/discarded-<ts>.md without acting. Use when the saved work is no longer relevant.
Save for laterLeave in place, snooze for 24h (configurable) so the next session start doesn't re-surface immediately.
03 — configuration

Optional settings.md — defaults work out of the box

Configuration is optional. Create .claude/handoff/settings.md to override any threshold. Settings are read as frontmatter by the hook and pickup skill on every invocation.

Zero-config default

Install and walk away. The built-in defaults (90-day stale threshold, 24-hour snooze, archive retention cap of 10) work for most workflows. Override only what you want to tune.

.claude/handoff/settings.mdyaml frontmatter
---
stale-commit-threshold: 3
stale-day-threshold: 90
deferral-snooze-hours: 24
gitignore-prompt: ask
archive-retention: 10
trigger-phrases: []
---
KeyDefaultEffect
stale-commit-threshold3Commits past saved-at-sha before the handoff is tagged "progress made" — a surface signal, not a behavior change.
stale-day-threshold90Days past saved-at before the hook silently auto-archives to expired-<ts>.md.
deferral-snooze-hours24Hours to suppress re-surface after "Save for later". No permanent suppression — re-surfaces after the window.
gitignore-promptaskask or never — whether the first save offers to add .claude/handoff/ to .gitignore.
archive-retention10Cap on archive file count (shared across consumed/discarded/expired). 0, unlimited, or -1 for no cap.
trigger-phrases(built-in list)Additions or overrides for the wrap-up phrase NL trigger list that auto-invokes /handoff:save.
04 — storage model

One active slot, a timestamped archive

Everything lives under .claude/handoff/. A single active file, an archive directory for consumed/discarded/expired handoffs, and an optional settings file. The first save offers to add the folder to .gitignore.

active.md
The active handoff

Single slot per repo. Frontmatter holds saved-at, saved-at-sha, saved-at-branch, saved-from-cwd. An existing handoff prompts before overwrite.

archive/consumed-<ts>.md
After Execute

The directive that was acted on, renamed (not deleted) — stays recoverable if you need to look back.

archive/discarded-<ts>.md
After Discard

Archived without acting — from the pickup flow or /handoff:discard. No action taken on the directive.

archive/expired-<ts>.md
Stale auto-archive

Moved here automatically once older than stale-day-threshold (default 90 days). No user action required.

settings.md
Optional config

Override thresholds, snooze window, gitignore behavior, archive retention, and trigger phrases. Edit directly — no re-install needed.

handoff · v1.0.2 · MIT · by Apurv Bazari