Imported from bradspit7/context-skills (
skills/analyze-handoff/SKILL.md). Install upstream withnpx skills add bradspit7/context-skills --skill analyze-handoff. Copyright stays with the author.
Analyze Handoff
Slim session resumption for same-day continuation. The cheap sibling to analyze-context. Reads one file, produces a 3-line summary, stops.
Why this exists: large projects accrete heavy context layers — it's not unusual for a mature project's HANDOFF + memory + context.md to sum to 100K+ tokens. Paying that cold-start cost on same-day continuation is wasteful — the user almost always just needs "where am I, what's next." This skill does that for ~5K tokens. Use analyze-context when you actually need the full briefing (multi-day gaps, first session in a project, or an explicit request); a machine switch goes through device-sync, which ends with analyze-context's short arrival briefing.
When to fire
Trigger phrases (explicit):
/analyze-handoff/handoff- "quick resume"
- "where was I"
- "what's next" (when context indicates same-day continuation)
Proactively fire when:
- User has explicitly invoked the slash command — that's the only proactive case.
- All other proactive triggers deliberately omitted to avoid stomping
analyze-context.
The routing that actually reaches this contract: analyze-context's Step 1 currency script emits a RESUME CLASS signal and, on a clean SAME-DAY RESUME CANDIDATE, downgrades that run into THIS skill's contract (handoff-only read, 3-line summary). So this contract executes even when the user habitually types /analyze-context — measured 2026-07-04: direct invocation happened 0 times in 204 sessions, so the downgrade is the load-bearing path. Direct triggers above still work.
Do NOT fire when:
- User asks for a full briefing ("catch me up", "brief me on this project", "what's the state", "give me the picture", "what were we working on") — those are full-briefing phrases, route to
analyze-context - More than ~24 hours since the last activity in this project — full briefing is safer when state may have shifted
- User just switched machines — route to
device-sync(arrival pull: repo + memory transport), which hands off toanalyze-contextfor its currency gate + the short arrival briefing; a cross-machine handoff needs the gate's branch survey to catch wrong-branch staleness on branches this machine never checked out, and any FINDING there forces the full briefing - No
HANDOFF.md/CONTEXT.md/continuation/context.mdpresent at all → tell user "no handoff present; want full /analyze-context?" and stop - User signaled a concrete first task — they don't want a briefing at all, just go
Workflow
Step 0 — Machine identity check
Run hostname (or echo $COMPUTERNAME on Windows) and match it against a known-machines mapping kept somewhere persistent (e.g., a section in your ~/.claude/CLAUDE.md). Surface the result in the summary header: **Machine:** <machine-name>. If unknown, flag it: "Unknown hostname <x> — verify cross-machine setup."
Cost: 1 bash command. Trivial.
Step 1 — Locate the handoff doc
Look in this order, stop at first match:
<project-root>/HANDOFF.md(also checkcontext/HANDOFF.md)<project-root>/CONTEXT.md(top section to first---divider only)<project>/continuation/context.md(top pickup point to first---only)
Whichever matches first is the pickup doc — Step 3's freshness probe and the stale warning run against that path, never a literal HANDOFF.md. A CONTEXT.md- or continuation/context.md-only project stale-checked against HANDOFF.md gets empty git log output, so the check silently no-ops against the wrong file.
Multi-dev projects (HANDOFF-<name>.md files present): read the slim shared HANDOFF.md PLUS the top entry of your own HANDOFF-<dev>.md (identity via gh api user --jq .login mapped through the project CLAUDE.md, fallback git config user.name). Still slim — two small reads, no others' files, no feed backlog.
If none found: tell the user "No HANDOFF/CONTEXT file present. Want me to run /analyze-context for a full briefing instead?" Stop.
Step 2 — Read just enough
- HANDOFF.md present → read it fully. (It's supposed to be slim per
update-contextdiscipline. If it's grown to 1000+ lines, surface that as a hint that anupdate-contextcleanup is overdue.) If the pickup doc is ITSELF the docket and is over ~40KB, the same bound below applies to it. - CONTEXT.md / context.md only → read top section only, stopping at the first
---divider (= the current pickup point). Do NOT chunk-read the whole file. That'sanalyze-context's territory. - Do NOT read memory dir, archive, plans, or specs. The docket IS in scope (Step 4): surface the open items the handoff already carries. Only if the docket lives in a separate file the handoff points to as the home of open items, read that one file too — nothing else. Bound the docket read (G#566).
wc -cit first. At or under ~40KB read it fully; above that read only its OPEN-ITEM REGION -- the header plus the open/next-tasks section, stopping at the first Resolved/Archived/Closed heading -- and state the remainder as a number in the summary (docket: read 38KB of 419KB (open-rows region); 381KB of closed history not read). Never silently omit; if the remainder cannot be derived, sayUNKNOWNrather than nothing. Bound to the SECTION, never to a leading byte slice: a docket whose newest rows sit at the bottom would lose exactly the rows the resume needs. This isanalyze-contextStep 3's size valve, which the slim path skips Steps 2-4 to reach and therefore never inherited -- measured, a slim resume was authorized to read an 83,590 B handoff plus a 427,410 B docket while this skill's own description claims ~5K tokens. - Standing rulings, one read-only call. When this skill runs on its own (not as
analyze-context's slim path, whose gate already printed them), runbash ~/.claude/skills/analyze-context/scripts/rulings-line.shfrom the project root and keep itsRULED OUTlines for Step 4. A next-morning resume on the same machine is exactly when a killed option gets proposed back, and this skill is that resume. A missing helper printscould not check: carry that line, never drop it. - Do NOT run
git pull/git fetchunless the user asked.
Step 3 — Stale-check
Before producing the summary, check the handoff's freshness with git evidence (header stamps are advisory, not proof):
git log -1 --format=%ci -- <pickup-doc>(the doc matched in Step 1, not a literalHANDOFF.md) for last modification, andgit rev-list --count <that-sha>..HEADfor commits-behind — include both in the summary header:<pickup-doc>: <date> (<N> commits behind HEAD). If thatgit logreturns empty output (the pickup doc is untracked/uncommitted — test the output, not the exit code), fall to the file-mtime evidence below instead of reading a blank as "fresh"- No git repo → file mtime (
ls -l/stat) is the fallback evidence
Escalation-on-doubt header checks (cheap, run alongside the freshness probe):
- Branch mismatch — in a git repo where the HANDOFF header stamps
**Branch:**(perupdate-context's header template): compare it togit branch --show-current. A mismatch means the last wrap was written from a different branch than the one checked out now — the wrong-branch case the slim skill otherwise only names but never detects. Escalate (/analyze-context) and stop; don't summarize off a header that describes another branch's state. Read-only command — never checkout, fetch, or pull. (Safe no-op if the header lacks the field.) - No parseable header — an unparseable header withholds two independent facts, and git supersedes only ONE of them. Date axis: in a git repo the commits-behind evidence above already supersedes a missing
**Updated:**, so a stale-date escalation on that ground alone is redundant — skip it. Machine axis: git does NOT supersede a missing**Machine:**/**Last write from:**stamp — a commit records an author, not the machine that wrote the doc — so an unconfirmable machine still blocks, in a git repo as much as outside one, and the routing gate enforces exactly that (currency-check.sh,no machine stamp ... (cannot confirm same machine)→ FULL). In a NON-git project neither axis has a substitute: no parseable header at all → escalate to/analyze-contextand stop.
If last-modified is more than ~24h ago (1 day — matching the currency-check routing gate that downgrades into this contract), OR the HANDOFF is more than ~3 commits behind HEAD (work landed after the last wrap — the handoff can't describe it), flag it before summarizing:
"
<pickup-doc>was last updated YYYY-MM-DD (X days ago / N commits behind HEAD). May be stale — want full briefing via/analyze-contextinstead?"
Then wait for direction. Don't produce the slim summary on stale data — the user may make decisions based on it.
Step 4 — Produce the 3-line summary + docket
**Last completed:** <one line — most recent shipped work>
**Next intended:** <one line — the top ACTIONABLE item; if none is actionable now, say so ("no actionable pickup — see docket")>
**Blocker:** <one line if any open blocker / pending decision; otherwise "none">
**Ruled out:** <the RULED OUT lines, verbatim: each a dated claim with its source, re-checked before it is relied on; "none -- read N source(s)" when it says so>
**Docket:**
- <marker> <ID> — <one line per row>
- ...
Reproduce the handoff's docket section (its "Next tasks" / open-items / docket rows) in the order it lists them, one line each, preserving each row's status marker (🟢/🟡/⏸ etc.) so a parked or deprioritized row is never shown as actionable — surface each by its stable ID (G#/#N). Include still-open pending decisions. Skip only rows the handoff has moved to its Resolved/done section (✅/✖); a row that still lives in the open docket but reads "closed/deprioritized" stays, carrying its marker. Don't expand into the full briefing's per-item detail — one line each is the contract. If the handoff only points to a separate docket file as the home of open items, read that one file too (cheap, and it's the whole point of a resume). Optionally append: "Want full briefing? /analyze-context."
Step 5 — Stop
Wait for user direction. Do NOT drift into reading memory, archive, or specs on speculation. The summary + docket are the deliverable; the user picks the next item.
What NOT to do
- Don't read the memory directory — tier-2/3 reading is
analyze-context's territory. - Don't invoke recall-layer commands (
/memory-search,/recall) — they mandate downstream file reads that burn the ~5K budget this skill exists to protect. Memory recall isanalyze-context's read-side duty, not this skill's. - Don't read archive or older pickup points — same.
- Don't produce the 6-section structured briefing — that's
analyze-context's output shape. - Don't auto-escalate to
analyze-contextif the slim summary feels thin. Tell the user; let them decide. - Don't write anything — read-only skill, like
analyze-context. - Don't
git pullunless user asked. - Don't try to be
analyze-context-lite. Be intentionally narrow. The cost savings ARE the point.
Fail modes
- HANDOFF stale (>~24h / >3 commits behind HEAD) → flag and ask before summarizing. Slim summary on stale state misleads.
- HANDOFF references commits not in this worktree's git log → strong signal of worktree mismatch. Stop, ask user which worktree is authoritative. Same rule as
analyze-context's currency gate; the slim version doesn't exempt you. - Wrong-branch silent staleness (cross-machine indicator) → if the HANDOFF header's machine stamp (
**Machine:**per update-context's header; legacy docs may say**Last write from:**; either label's value may be backtick-wrapped) names a different machine than the currenthostname, the previous session ran on the other machine and may have continued work on a feature branch this machine has never checked out. The slim skill deliberately does NOT runanalyze-context's full branch-recency survey (the currency-check script's branch survey) — that's the cost line the slim skill exists to avoid. So it cannot resolve this case safely. Escalate instead: "HANDOFF's machine stamp is<other-machine>. Cross-machine handoff means recent work may live on a branch this machine doesn't have. Recommend/device-sync(arrival pull + memory sync, then/analyze-context's branch survey and arrival briefing) before trusting the slim summary." Then stop. Same goes for any other signal of branch-per-feature drift (e.g., a recentgit pulloutput the user shares showed[new branch]lines). - Multi-day gap detected (per JSONL transcript timestamps or git activity gap) → don't produce a slim summary. Recommend
/analyze-contextinstead. - Project has no HANDOFF.md but has
continuation/context.md→ fall through to top-pickup-only read. Still slim. Note the missing HANDOFF in the summary so user knows to run/update-contextlater. - User invoked
/analyze-handoffafter a >1-week gap → flag explicitly: "Long gap since last activity — full briefing recommended." Don't produce slim summary on stale state. - User immediately follows up with a question that needs full-briefing context → run
/analyze-contextnow; the slim was insufficient. Note this so the user calibrates which skill to invoke next time. - Wave-N / date headers are not currency proof → HANDOFF.md often opens with
Updated: <date>/wave-N closeout — <summary>headers. They tell you when this paragraph was written, not whether a newer one exists on a sibling branch. The slim skill cannot verify currency across branches by design (that's the currency gate's job). So any signal that branches-other-than-current may carry newer HANDOFF.md commits — recentgit fetchoutput showed[new branch]lines, the project's commit history shows multiple lifecycle-named branches (wave-N,*-handoff-refresh,*-context-update) committed in the last 24h, or the header's machine stamp (**Machine:**, legacyLast write from:) ≠ current hostname — means the slim skill cannot trust the header alone. Escalate to/analyze-contextand stop. The slim skill's currency confidence is bounded by what one branch-local HANDOFF.md can prove; when the workflow uses branch-per-feature, that's not enough. - User disputes the slim summary's claim → immediately escalate to
/analyze-context. Do not search more files. The most common reason a slim summary is wrong is currency drift across branches, which the slim skill cannot detect.
Alternatives / related skills
analyze-context(full sibling) — full briefing for multi-day gaps, first session in a project, or an explicit request; after a machine switch,device-syncruns it in its short arrival mode. Use when you need the structured 6-section output (recently shipped / in-flight / locked decisions / open docket / known issues / behavioral rules / next-step suggestion). Costs significantly more depending on project size.update-context— session-end persistence. Keeps HANDOFF.md current so this skill stays useful. The slimmer your HANDOFF, the cheaper this skill is.
Do NOT
- Don't claim "no context" without checking all three locations (HANDOFF.md / CONTEXT.md / continuation/context.md).
- Don't invoke this AND
analyze-contextin the same session — alternatives, not stages. - Don't omit the stale-check — slim summary on stale data is a trap.
