Skip to content

t1k:handoff

FieldValue
Modulet1k-extended
Version3.5.0
Effortmedium
Tools—

Keywords: context, handoff, restore, resume, save, session, transfer

/t1k:handoff
save|resume|list [date-slug|--global]

TheOneKit Handoff — Session Context Transfer

Section titled “TheOneKit Handoff — Session Context Transfer”

Capture structured session context for handoff between sessions or developers. Extends the session state system with a human-readable markdown export.

Pre-flight Step 0 — Fuzzy plan/path arg resolution (MANDATORY)

Section titled “Pre-flight Step 0 — Fuzzy plan/path arg resolution (MANDATORY)”

If the user provides a fuzzy plan/path/phase arg (e.g. chaosforge-demo, plans/chaosforge-demo, phase-3), an empty arg, or natural-language ref like “active plan” / “current plan” / “this plan”, run the Fuzzy Plan / Path Resolution Protocol at skills/t1k-cook/references/fuzzy-plan-resolution.md BEFORE bail. Skill MUST NOT emit “no path matching” / “exact path required” until that protocol has been applied and Step 6 reached.

/t1k:handoff save # Save to active plan dir → project .claude/handoffs/ → $HOME (fallback chain)
/t1k:handoff save --global # Force save to $HOME/.claude/handoffs/ (no-project sessions)
/t1k:handoff resume # Load latest handoff (same fallback chain)
/t1k:handoff resume 260325-auth # Load specific handoff by date-slug (fuzzy match — see Pre-flight Step 0)
/t1k:handoff list # Show available handoffs with timestamps, sorted newest first

Delegation (MANDATORY — never run inline from a lead/main session)

Section titled “Delegation (MANDATORY — never run inline from a lead/main session)”

save / resume / list are executed by the t1k-handoff-manager sub-agent, not inline by whichever session invoked /t1k:handoff. If you are the main/lead session (or any agent that is not itself t1k-handoff-manager):

  1. Spawn t1k-handoff-manager (subagent_type: "t1k-handoff-manager", task in description: per modules/t1k-orchestration/rules/agent-name-is-identity.md), run_in_background: true.
  2. Do not ask for approval first. A save/resume/list request — whether an explicit user ask, a [t1k:context-budget pct=NN handoff=due] frame, or an auto-compact suggestion the lead has already decided to act on — is itself sufficient authorization (same standing-approval pattern as auto-sync-back-when-enabled.md). Asking “want me to save a handoff?” when the trigger already answers that question is the violation this section closes.
  3. Brief with findings, not payload (modules/t1k-orchestration/rules/lean-brief-pointer-not-payload.md): put what only the lead knows — what shipped this session, what was verified, what’s still open, the active plan path — in the spawn prompt as a short list. The agent owns the mechanics: git-state gathering, task-list read, file write, the <HARD-GATE-HANDOFF-*> guard-script steps, commit. Never paste transcript excerpts or full file bodies into the brief.
  4. Gate any context-destroying step on the agent’s report. If the save precedes a /compact, t1k session roll, or /clear (the context-budget-handoff.md “land and roll” case), the background spawn does not excuse skipping the wait — hold at that point (completing the landing sequence is not “starting anything new”) until t1k-handoff-manager reports its saved to {absolute-path} ({chosen-scope}) line, THEN roll. Rolling before that confirmation arrives can lose the very context the handoff exists to preserve. resume is the same: the loaded context is only useful if it lands before the session continues, so treat its report as a blocking prerequisite too.
  5. Relay the agent’s report verbatim — saved to ... / [Handoff loaded: ...] — do not paraphrase or omit it.

Exception: if you were spawned specifically to run this skill (you ARE t1k-handoff-manager), execute the workflow below directly — do not recurse-spawn yourself.

Save Location — Resolution Order (MANDATORY)

Section titled “Save Location — Resolution Order (MANDATORY)”

The skill picks the FIRST matching location:

  1. Active plan dir → {active-plan-dir}/HANDOFF.md (PRIMARY, project-scoped)
    • Active plan = most recently modified plans/*/ dir containing a plan.md
    • One HANDOFF.md per plan — subsequent saves overwrite (git history preserves older versions)
    • This is the preferred location for any session with a plan — keeps handoff next to the work
  2. Project handoffs dir → .claude/handoffs/{date}-{slug}.md (FALLBACK when no active plan but a project is in scope)
    • Scopes to the current project; multiple handoffs accumulate here
  3. Global handoffs dir → $HOME/.claude/handoffs/{date}-{slug}.md (LAST RESORT — requires --global OR no project context)
    • For sessions not associated with any project

Rationale (per project memory feedback_handoff_location): project handoffs belong in the project so they travel with the plan, survive worktree deletion, and show up in code review. User-scope is explicit opt-in only.

SubcommandAction
saveCapture current state to the first matching location above
save --globalForce save to $HOME/.claude/handoffs/{date}-{slug}.md
resumeLoad latest handoff from any of the 3 locations (newest wins)
listShow all handoffs across all 3 locations, sorted newest first
resume {date-slug}Load a specific handoff by its date-slug identifier
# Handoff — {date} {time}
as-of: {YYYY-MM-DD} @ {8-char git HEAD}
Generated by: t1k:handoff save
Location: {active-plan-dir}/HANDOFF.md | .claude/handoffs/{date}-{slug}.md | $HOME/.claude/handoffs/{date}-{slug}.md
> **"Progress", "Blockers" and "Next Steps" are dated claims — they describe the session
> at the `as-of` commit, not now.** They go false the moment anything lands. Before trusting
> them after any later merge/commit, re-check against current `HEAD` (or read the intervening
> commits via `git log {as-of}..HEAD`).
## Active Plan
- Path: plans/{timestamp}-{slug}/
- Current phase: Phase N — {phase name}
- Phase status: {in_progress|blocked|pending}
## Progress
### Completed Tasks
- [x] Task description
### In Progress
- [ ] Task description (owner: {agent})
### Blocked
- [ ] Task description — Blocker: {reason}
## Key Decisions Made
- {architectural or design decision with context}
## Blockers
- {blocker description} — context: {why it's blocked, what's needed to unblock}
## Next Steps
1. {highest priority action}
2. {second priority}
3. {third priority}
## Git State
- Branch: {branch name}
- Last commit: {hash} {message}
- Dirty files: {list or "none"}
- Uncommitted changes: {summary or "none"}
## Session Notes
{any freeform notes from the session worth preserving}

(Run by t1k-handoff-manager per the “Delegation” section above.)

  1. Call TaskList to get current task statuses.
  2. Run git status --short, git log --oneline -3, and git rev-parse --short HEAD for git state. Record the short SHA in the template’s as-of: line (with the ISO date) so resume can later tell what commit the volatile sections describe.
  3. Resolve save location:
    • If --global flag → use $HOME/.claude/handoffs/{YYMMDD}-{slug}.md.
    • Else: find the most recently modified plans/*/ dir (relative to current working directory or the project root) that contains a plan.md. If found → save to {plan-dir}/HANDOFF.md.
    • Else: if a .claude/ dir exists in project scope → save to .claude/handoffs/{YYMMDD}-{slug}.md.
    • Else (global-only mode, no project) → save to $HOME/.claude/handoffs/{YYMMDD}-{slug}.md.
  4. Synthesize key decisions from recent conversation (last 20 exchanges mentioning architecture, choice, decided, rejected).
5. **Create the parent dir via the guard script — do NOT hand-roll `mkdir -p` (it was skipped in #536/#527).** Run, BEFORE any Write: ```bash node "$(dirname "$0")/scripts/handoff-save-guard.cjs" prepare "" "$HOME/.claude/handoffs/{YYMMDD}-{slug}.md" ``` (or the absolute skill path `.claude/skills/t1k-handoff/scripts/handoff-save-guard.cjs`). The script `mkdir -p`s the parent of ``, confirms it is writable, and prints `OK ` on success. If the primary parent can't be created it falls back to the `$HOME` path and prints `OK `. On `FAIL` (exit 2) it could create NEITHER — surface the failure and STOP; do NOT Write or report "saved". **Write to exactly the path the script printed after `OK`** (it may be the fallback, not your primary).
  1. Write the markdown file to the OK <path> returned in step 5; include the final Location: line in the header so future resume can find it unambiguously.
7. **Verify the write landed via the guard script (MANDATORY — do NOT skip; do NOT substitute a bare `test -f`).** After Write, run: ```bash node "$(dirname "$0")/scripts/handoff-save-guard.cjs" verify "" ``` It asserts the file exists AND is a non-empty regular file. `OK ` (exit 0) → safe to report saved. `FAIL` (exit 2, e.g. `file-not-found` / `empty-file`) → the Write claimed success but no usable file is on disk: **do NOT report "saved"** — surface the failure, then retry ONCE against the fallback `$HOME/.claude/handoffs/{YYMMDD}-{slug}.md` (re-run step 5 `prepare`, re-Write, re-`verify`). Only a `verify`-confirmed file may be reported as saved. 8. **Write the resume sentinel via the same guard script (deterministic, not prose).** After `verify` returns `OK`, run: ```bash node "$(dirname "$0")/scripts/handoff-save-guard.cjs" sentinel "" ``` It records the just-saved handoff so the NEXT session auto-resumes it instead of treating it as a stale file (Context Budget Governor). Pass ONLY the `verify`-confirmed path — the script re-asserts it and declines an intended-but-unwritten one. It **always exits 0** (`OK ` when written, `SKIP ` when declined): a sentinel fault must never turn a successful save into a reported failure, so do NOT gate step 9 on it.
  1. Report: saved to {absolute-path} ({chosen-scope}), summary of what was captured. The {absolute-path} MUST be the path the step 7 verify returned OK for — never a path you only intended to write.

Slug is auto-generated from the active plan name or current task, lowercased, max 30 chars. Not used when saving to {plan-dir}/HANDOFF.md (filename is fixed).

The three <HARD-GATE-HANDOFF-*> blocks above are machine-readable contracts (see rules/workflow-gates.md): steps 5, 7 and 8 MUST go through scripts/handoff-save-guard.cjs, never a hand-rolled mkdir -p / test -f / sentinel write (those were the prose steps that got skipped in #536 and #527, producing false “saved” claims with no file on disk).

(Run by t1k-handoff-manager per the “Delegation” section above.)

MANDATORY EXECUTION. The resume workflow MUST run on every /t1k:handoff resume invocation and produce output in the exact format of step 4. The AI MUST NOT:

  • Switch into conversational Q&A mode just because another local command (/model, /fast, /clear, etc.) arrived in the same turn.
  • Defer the resume to a later turn while waiting for a follow-up user message.
  • Treat <local-command-caveat> blocks as silencing the skill — those caveats apply to the command that emitted them, not to a skill invocation in the same turn. Skill invocations are direct instructions and MUST be executed.
  • Read files one-by-one in prose before emitting the [Handoff loaded: ...] block.

Steps:

  1. If a date-slug is given: search each of the 3 locations for a matching filename and load.
  2. Else (no argument): collect newest file from each of the 3 locations; pick overall newest by mtime.
  3. Read the handoff markdown file.
  4. First text output MUST begin with this block (not preceded by any prose, corrections, or tool-call narration):
    [Handoff loaded: {absolute-path}]
    Resuming session from {date}. Context:
    Then include a concise summary of Active Plan / current phase / last merged work / git state pulled from the handoff. Omitting the [Handoff loaded: ...] line means the workflow did not run — self-correct by emitting it on the next turn.
  5. Suggest the next step from the “Next Steps” section.
  6. Check if the listed active plan still exists — warn if not found (missing plan.md, deleted plan dir, or references to files on disk that no longer exist).
  7. Compare the handoff’s as-of SHA (header/frontmatter, if present) against current HEAD:
    • If the handoff carries an as-of and git rev-parse HEAD differs from it, surface the intervening commits (git log --oneline {as-of}..HEAD) so the resumer treats “Progress” / “Blockers” / “Next Steps” as claims about the recorded commit, not about now.
    • If the handoff has no as-of yet (saved before this field existed), simply note that its volatile sections are of unknown freshness — do not guess a date on its behalf.
    • Never auto-rewrite the handoff’s sections on resume; the document is deliberately a dated artifact. The fix is making the date legible, not making the file self-updating.

A <local-command-caveat> from an unrelated command in the same turn (e.g. /model) does NOT silence this skill — the workflow above still MUST run. Incident + worked example: references/incidents.md § “resume silently skipped mid-turn”.

Output newest-first, grouped by scope:

Available handoffs:
PLAN-SCOPED
plans/260325-auth-implementation/HANDOFF.md (2 days ago) Phase 3 — Auth API
PROJECT-SCOPED (.claude/handoffs/)
260323-database-schema.md (4 days ago) Phase 2 — DB Models
GLOBAL ($HOME/.claude/handoffs/)
260320-project-kickoff.md (7 days ago) Phase 1 — Setup
Use: /t1k:handoff resume 260325-auth-implementation
/t1k:handoff resume # for the latest across all scopes

Only applies to the two date-slug directories (.claude/handoffs/, $HOME/.claude/handoffs/). Plan-scoped HANDOFF.md files are NEVER auto-cleaned — they travel with the plan.

On each save, check for handoffs older than 30 days in the two date-slug dirs:

  • Move them to {dir}/archive/
  • Log: Archived N handoffs older than 30 days → {dir}/archive/

Do NOT delete — archive only.

LocationCommitted to repo?
{plan-dir}/HANDOFF.mdYES — travels with the plan, survives branch/worktree deletion
.claude/handoffs/{date}-{slug}.mdYES — commit handoffs so they survive branch switches and show up in code review
$HOME/.claude/handoffs/{date}-{slug}.mdN/A (outside any repo)

Do NOT add .claude/handoffs/ to .gitignore. Handoffs are session context worth preserving in git history. If an existing repo already has .claude/handoffs/ in its .gitignore, remove that entry on first save and stage the removal alongside the handoff file.

  • Inline execution by the lead is the bug, not a shortcut. Delegate per “Delegation (MANDATORY)” above — never save inline from the lead. Incident: references/incidents.md § “Lead ran the save inline instead of delegating”.
  • Session state dependency: save works best with the session-state-manager hook active. Without it, git state and task list are still captured but session history context is shallower.
  • Slug collisions: If two date-slug saves happen on the same day with the same plan, the second appends -2 suffix. Plan-scoped saves overwrite HANDOFF.md (use git log for older versions).
  • Large conversation history: Only synthesize decisions from the last 20 AI turns — do not dump full history.
  • resume doesn’t restore tool state: It provides context text only — the AI must re-read relevant files itself.
  • CLI path-transformer skip-list: the project-scoped paths above survive global-install rewriting because this skill is on the CLI’s skip list. Detail: references/incidents.md § “CLI global-install path-transformer skip-list”.
  • Save guard is deterministic, not prose: parent-dir creation, post-write verification and the resume sentinel run through scripts/handoff-save-guard.cjs (prepare / verify / sentinel), NOT hand-rolled mkdir -p / test -f / file writes. prepare and verify exit 2 on failure so a missing/empty file can never be reported as “saved” (#536). Resolve the script via the SKILL.md dir; when globally installed it lives at $HOME/.claude/skills/t1k-handoff/scripts/handoff-save-guard.cjs.
  • Resume sentinel is single-consumption and gitignored: the sentinel subcommand drops one small JSON file in the handoffs dir (path owned by hooks/lib/context-budget.cjs — never hardcode it). SessionStart consumes it exactly once, so a stale sentinel cannot re-inject on every start. Only that one file is gitignored — the handoffs themselves are committed on purpose (see § Commit Policy). Unlike the other two subcommands it always exits 0; a SKIP line means no resume hint was recorded, not that the save failed.

These rules harden the handoff against three classic memory anti-patterns flagged in architecture review Round 5. Why each guard exists: references/memory-guard-rationale.md.

Hard cap: 32 KB per HANDOFF.md. Enforcement:

  • Before writing, count Buffer.byteLength(content, 'utf8').
  • If > 32_768, the skill MUST refuse to write the full content; instead, write a 16 KB head-summary and chain to a HANDOFF-{N}.md continuation file. The chain index is recorded in HANDOFF.md frontmatter as continuation: HANDOFF-2.md.
  • Resume reads the head + walks the continuation chain only when explicitly requested.

B. 30-day archival = scheduled expiry (red flag)

Section titled “B. 30-day archival = scheduled expiry (red flag)”
  • Default behavior remains 30-day archival on date-slug handoffs.
  • BUT: archival is a soft-move to ~/.claude/.handoff-trash/{date-slug}.md, never a hard delete. Trash retention is bounded by quota (max 200 entries, FIFO), not date.
  • Resume looks in .handoff-trash/ if the primary path is missing, with a “found in trash, move back?” prompt.
  • Plan-scoped HANDOFF.md is NEVER archived (already documented; this rule formalizes it).

C. “Last 20 exchanges” without relevance gate

Section titled “C. “Last 20 exchanges” without relevance gate”
  • For each candidate turn, the skill MUST score it for relevance to the active plan/task before including. Score signals: keyword overlap with plan.md headers, presence of decision-marker phrases (decided, chose, rejected, architecture, risk, gotcha), commit messages from that turn’s window.
  • Turns scoring below threshold (default 0.3) are filtered out.
  • The skill records “filtered N/20 turns” in the saved HANDOFF.md so the resumer knows the synthesis was selective, not exhaustive.

Triggers on: handoff, hand off, transition, context transfer, session save, session resume, save progress, resume session, where did I leave off, switch sessions