Files
claude-skills/.wiki/concepts/session-handoff-skill-design.md
vitya e5839bd072 feat(wiki): document session-handoff skill design rationale
Capture the design decisions behind the session-handoff skill in a dedicated
`.wiki/concepts/session-handoff-skill-design.md` page, indexed and logged per
Karpathy LLM Wiki conventions. Covers the problem statement (cold-start fog
between CC sessions), the sliding-overwrite contract for `.tasks/NEXT_SESSION.md`,
the phrase whitelist + anti-pattern guards + ambiguity-asks-not-guesses rule,
the substantive-commit heuristic (prefix exclude AND (body>200 OR files>3) +
first-non-trivial-commit-always exception), the opt-in PostToolUse hook that
replaces agent-side memory with harness-side determinism, the orient+ask read
mode default, project scope guarantee, the five-section handoff content contract,
secret-detect abort, staleness-7d query, mid-task capture, precedent comparison
against using-tasks / MEMORY.md / log.md / Karpathy diary, and the closure
record of cluster 7/7 (install / hermes-mapping / bootstrap-template-extend /
posttooluse-hook / existing-projects-upgrade / test-trigger / review). Source
buffer: `~/projects/.workshop/.archive/2026-05-24-session-handoff-skill.md`
Round 1 design + Round 2 Q1–Q10 resolution.

Also serves as the live-hook e2e smoke artifact for the deferred follow-up from
`[session-handoff-posttooluse-hook]` — substantive commit (feat: prefix, body
well above 200 chars) should trigger the PostToolUse `commit-detector.ps1` hook
just enabled in `~/.claude/settings.json` and emit `hookSpecificOutput.additionalContext`
on the next agent turn.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-25 00:20:17 +03:00

9.8 KiB
Raw Blame History

title, type, updated
title type updated
session-handoff skill — design rationale concept 2026-05-25

session-handoff — design rationale

Why the skill exists in this shape, with the trade-offs that were considered and the decisions that closed them. Source buffer: ~/projects/.workshop/.archive/2026-05-24-session-handoff-skill.md (Round 1 brainstorm + Round 2 Q1Q10 resolution).

The problem

Every fresh CC session in a project starts cold. The agent re-reads STATUS.md, greps recent buffers, looks at MEMORY.md, and asks the user "where were we?". That's a recurring fog — the user already told the previous session what to do next, and the previous session may have already formulated the plan, but the bridge between sessions doesn't exist.

The fix: the agent writes a forward-looking handoff prompt at session boundaries, into a canonical location the next session reads on cold start. Sliding overwrite: one file, one current state, history through git log -p.

Why a new skill, not an extension

The shape was tempting to fold into using-tasks — it already touches .tasks/. But the lifecycles don't match:

  • using-tasks is per-task (switch, start, pause, close).
  • session-handoff is per-session (start-cold, end-warm).

Different triggers, different readers, different writers. Per-task state and per-session state happen to share a directory but they answer different questions.

Architecture

Location: .tasks/NEXT_SESSION.md. Sits next to STATUS.md so the using-tasks reader already walks .tasks/ on cold start and notices the handoff without an extra hook.

Sliding overwrite: every write fully replaces the file. No .archive/handoff-<date>.md fanout — git log -p .tasks/NEXT_SESSION.md is the history if anyone needs it. Rejected the append-with-archive variant because it produces N artefacts the user didn't ask for; the git-log path covers the same need on demand.

Project scope: no global state. Workshop and .admin/ sessions don't see each other. "Wrap up session" in one tree does not touch the other.

Modes: read on session start (orient + ask, never auto-execute); write on session-end phrase or on substantive commit.

Triggers — the resolved choices

Read-mode (session start)

Activated by the CLAUDE.md trigger line session handoff: read on start, write on end (canonical, added to project-bootstrap v1.12.0 template). On cold start: if .tasks/NEXT_SESSION.md exists and is fresh, summarise + ask user before any action. If _last_updated_ is older than 7 days, flag staleness explicitly: "handoff от (N days ago) — overwrite or continue?".

Default is orient + ask, never auto-execute. The previous session might have been wrong; user agency survives.

Write-mode — phrase whitelist

Strict whitelist (rejects close-but-different phrases):

  • Russian: «завершаем сессию», «сворачиваемся», «закругляемся»
  • English: «wrap up session», «end session», «we're done for now»

Explicit anti-patterns that must not trigger:

  • «закрываем эту таску» — task close, lives in using-tasks zone
  • «pause», «приостанови» — task-pause, not session-end
  • «отбой», «разбегаемся» — too broad; may refer to a different context
  • «сейчас завершу одну задачу и тогда поговорим» — partial completion

On ambiguity (e.g. «закругляемся» with a task-marker tail), the skill asks "session or task?" rather than guessing. Closing-bias is the failure mode to avoid.

Write-mode — substantive-commit heuristic

prefix NOT IN (meta:|docs:|style:|chore:|fix typo)
AND (body_length > 200 chars OR files_changed > 3)

Plus an explicit "first non-trivial commit of the session always triggers" exception. The reasoning: the start of work is itself a context shift worth recording, even when the first commit is small (bootstrap, scaffolding).

The thresholds are tuned to skip the noise (chore: bump dep, docs: typo) while catching the actual session-shaping commits. They're not magic numbers — they're the floor below which a handoff regen would dominate signal with noise.

Optional PostToolUse hook

A behavioral memory ("after git commit, check the substantive heuristic") is fragile — one missed check leaves the next session with a stale handoff. Solution: an opt-in PostToolUse hook (skills/session-handoff/hooks/commit-detector.{ps1,sh}) that emits a hookSpecificOutput.additionalContext system reminder after every substantive commit. Harness-side determinism replaces the agent-side memory.

Why opt-in, not auto-installed: install.sh deliberately does not mutate ~/.claude/settings.json. Auto-rewriting the user's hook config on every skill install is the wrong shape — user expects install.sh to copy files, nothing more. Hook is shipped as scripts; user enables once per machine via the snippet in hooks/README.md.

Known caveats:

  • Rebase / cherry-pick noise: every commit in a batch re-fires the hook. Deferred — opt-in bounds the cost.
  • Hook can't see session boundaries, so it under-detects small first-commits-of-session that the agent-side heuristic does catch. Acceptable trade-off for harness-side determinism.
  • Hook only signals; never auto-invokes write-mode. The agent still decides — preserves the user-agency invariant.

Handoff content contract

Five required sections. Empty sections keep their heading + (нет на этом раунде) note so the next agent sees "nothing to do here", not "missing":

---
_last_updated_: <ISO date>
session_id: <hash or date>
---

# Next session handoff

## Recent commits
- <slug>: <subject>   (35 most recent)

## Open треки
| Трек | Готовность | Entry-point |
|---|---|---|

## Спроси user'а
- <pending decision>

## Не делать (preemptive guards)
- <guard>

## Memory updates за сессию
- <what was saved / updated>

Handoff is forward-looking — a bridge of new things specific to the next turn, not an overview of the whole project. STATUS.md, MEMORY.md, and .wiki/log.md remain authoritative for their respective scopes. Don't duplicate them; reference them.

Mid-task capture

If a 🔴 active task exists in STATUS.md at write time, the handoff captures left mid-task: <slug> / where_stopped: <text>. Rationale: friction of refusing the user ("can't wrap up, you have active work") is worse than the cost of capturing the mid-task state for the next session to resume. User agency owns the call, not the skill.

Failure modes that exit early

  • CLAUDE.md missing the trigger line → silent exit (opt-in per project).
  • Not in a git work-tree → silent exit.
  • .tasks/NEXT_SESSION.md absent in read-mode → silent exit (first session of project).
  • Content matches secret patterns (AKIA…, sk-…, ghp_…, BEGIN PRIVATE KEY, password=…, etc.) → abort write, surface to user. File goes to git, no credentials.
  • Stale handoff (>7 days) in read mode → ask rather than silent — overwrite-or-continue is a user call.

What the skill explicitly doesn't do

  • Auto-execute action items from a read handoff. Default is orient + ask.
  • Append-with-archive. Sliding only.
  • Trigger on chore: / docs: / meta: commits, on broad farewells, or on partial-completion phrases.
  • Touch other projects. Per-project scope, full stop.
  • Depend on a harness SessionEnd hook — Claude Code doesn't have one. The available hooks are SessionStart, UserPromptSubmit, PreToolUse, PostToolUse, Stop, Notification. The substantive-commit detection rides on PostToolUse.

Precedent comparison

Source Lifecycle Why it doesn't cover the handoff case
using-tasks STATUS.md where_stopped / next_action per-task misses per-session orientation; handoff needs to bridge tracks, not lock onto one task
_queue.md parked topics passive park, not active handoff
MEMORY.md long-term facts not anchored to a session boundary
.wiki/log.md append-only chronology timeline, not active orientation
Karpathy daily logbook personal diary points to the past (what happened); handoff points to the future (what to do next)

Handoff is forward-looking; everything else is backward-looking or timeline-agnostic. That's the slot the skill fills.

Acceptance — how the cluster closed

The skill shipped 2026-05-24 at v0.1.0, with PowerShell hook bug-fix at v0.3.1. Closure cluster — 7/7 tasks:

  1. [session-handoff-install] — install.sh + reload + smoke.
  2. [session-handoff-hermes-mapping]pending mode in hermes/mapping.yaml.
  3. [session-handoff-bootstrap-template-extend]project-bootstrap v1.12.0 template gets the trigger line out of the box.
  4. [session-handoff-posttooluse-hook]hooks/ shipped, opt-in snippet documented, stdin smoke verified.
  5. [session-handoff-existing-projects-upgrade] — manual edit-pass on this machine; 4 repos deferred per-machine.
  6. [session-handoff-test-trigger] — 15/15 behavioral outcomes match (6 whitelist + 4 antipatterns + ambiguity ASK + read-mode R1/R2 + hook H1/H2/H3).
  7. [session-handoff-review] — 6/6 review dimensions ✓ via test-trigger smoke, 0 findings filed, skill v0.3.1 ships unchanged.

The smoke validated the load-bearing design decisions: ambiguity resolution by asking, the always-first-commit exception, default orient + ask in read-mode. None of them surfaced as gaps — every test came back as a confirmation of the resolved design.

  • pulling-before-work — the precedent for a CLAUDE.md-triggered skill that runs once per session at a defined boundary.
  • project-bootstrap v1.12.0+ — adds the canonical trigger line to new projects.
  • using-tasks — owns STATUS.md and <slug>.md; the handoff explicitly does not replicate them.