PostToolUse hook in `~/.claude/settings.json` was using `$env:USERPROFILE` (PowerShell syntax), but Claude Code on Windows runs hook commands through git-bash. Bash treats `$env` as an empty variable, leaving `":USERPROFILE\..."` as the literal `-File` argument — PowerShell fails with "invalid filename format" and the hook never fires. Install snippet in hooks/README.md now uses literal absolute path `C:\Users\<you>\.claude\...` with a "Why literal path" section explaining why `$env:VAR` / `%VAR%` / `~` all break through the bash-harness chain on Windows. Retracts the v0.3.0 "live-hook e2e smoke done" closure — that result was from synthetic replay through the PowerShell tool, which bypassed the broken harness chain. Real e2e verification requires this fix plus a CC restart, then a substantive commit to observe `additionalContext` surface.
11 KiB
name, version, description
| name | version | description |
|---|---|---|
| session-handoff | 0.3.3 | Sliding handoff between CC sessions via .tasks/NEXT_SESSION.md. Read on session start: orient agent, ask user before action. Write on session-end phrase or substantive commit. Session-end phrases: «завершаем сессию», «сворачиваемся», «закругляемся», «wrap up session», «end session», «we're done for now». Trigger-line in CLAUDE.md: `session handoff: read on start, write on end`. Skip task-zone phrases: «закрываем эту таску», «pause», «отбой», «разбегаемся». |
session-handoff
Sliding handoff prompt между CC сессиями. На старте — читает .tasks/NEXT_SESSION.md, ориентирует агента и спрашивает user'а перед действиями. При substantive commit'е или session-end фразе — перезаписывает handoff для следующей сессии. Sliding overwrite: один файл, история — через git log -p .tasks/NEXT_SESSION.md.
Forward-looking, не timeline: handoff = связка новых вещей конкретно для следующего разворота, не overview всего проекта. STATUS.md / MEMORY.md / .wiki/log.md остаются авторитетными для своего scope'а.
Дизайн-источник: ~/projects/.workshop/.archive/2026-05-24-session-handoff-skill.md (Round 1 design + Round 2 resolved Q1–Q10).
When to use
Read mode (session start):
- CLAUDE.md проекта содержит trigger-строку
session handoff: read on start, write on end. - Файл
.tasks/NEXT_SESSION.mdсуществует.
Write mode (session end / substantive commit):
- User'ская фраза из whitelist:
- русский: «завершаем сессию», «сворачиваемся», «закругляемся»
- английский: «wrap up session», «end session», «we're done for now»
- ИЛИ — agent только что сделал substantive commit. Эвристика:
- prefix НЕ в (
meta:|docs:|style:|chore:|fix typo) - AND (body length > 200 символов OR files changed > 3)
- prefix НЕ в (
- Плюс: первый non-trivial commit сессии — всегда триггерит, даже если ниже порога (старт работы = context shift).
- Optional: substantive-commit detection может быть автоматизирован harness-side через PostToolUse hook — см.
hooks/README.mdдля opt-in инструкций. С enabled hook'ом первая часть becomes deterministic (parser-side, не behavioral memory).
Skip (false-positive guards):
- «закрываем эту таску» — task close, не session. Это zone
using-tasks. - «pause», «приостанови» — task-pause, не session-end.
- «отбой», «разбегаемся» — слишком broad, может относиться к другому контексту.
- «сейчас завершу одну задачу и тогда поговорим» — частичное завершение.
- Не-git папка, или
.tasks/отсутствует — silent exit. - CLAUDE.md проекта НЕ содержит trigger-строку — silent exit.
При неоднозначности — ASK, не угадывать: «закрываем сессию или таску?»
Inputs
Read mode:
.tasks/NEXT_SESSION.md— sliding handoff, должен существовать.- Текущая дата (для staleness check против
_last_updated_).
Write mode:
git log --oneline -5— последние commits сессии..tasks/STATUS.md— open треки + 🔴 active task'и (для mid-task capture).- Контекст сессии — pending user-decisions, waiting permissions, memory updates, preemptive guards.
Steps
Read mode
- Detect. Проверить что
.tasks/NEXT_SESSION.mdсуществует. Нет — silent exit. - Staleness check. Прочитать frontmatter
_last_updated_. Возраст > 7 дней → отметить user'у:Дождаться ответа перед продолжением.handoff от <date> (N дней назад) — возможно устарел. Оверrайдить или продолжить? - Summarize. Прочитать тело handoff'а — 5 секций (recent commits / open треки / спроси user'а / не делать / memory updates).
- Orient. Пересказать user'у одним блоком: «прошлая сессия предложила X (open треки + ask-items + don't-items + memory updates). Делаем?»
- Wait. Не делать никаких действий до подтверждения user'ом. Default = orient + ask, никакого auto-execute.
Write mode
- Scope check. Это текущий проект (cwd с
.tasks/). Никаких global мутаций, никаких других проектов. - Mid-task capture. Если в
.tasks/STATUS.mdесть 🔴 active task — захватить:left mid-task: <slug> where_stopped: <текст из STATUS.md> - Compose content. Собрать
.tasks/NEXT_SESSION.md:Пустую секцию — оставить заголовок + пометка--- _last_updated_: <ISO 8601 timestamp> session_id: <hash или дата> --- # Next session handoff ## Recent commits - <slug>: <subject> (3–5 последних) ... ## Open треки | Трек | Готовность | Entry-point | |---|---|---| | ... | ... | ... | ## Спроси user'а - <pending decision 1> - <waiting permission 2> ## Не делать (preemptive guards) - <guard 1> - <guard 2> ## Memory updates за сессию - <что нового сохранилось / обновилось>(нет на этом раунде). Чтобы next агент видел: не забыто, а пусто. - Sliding overwrite.
Writeповерх.tasks/NEXT_SESSION.md(предыдущее содержимое НЕ архивируется в.archive/handoff-*.md— sliding contract). История восстанавливается черезgit log -p .tasks/NEXT_SESSION.md. - Stage.
git add .tasks/NEXT_SESSION.md— попадает в следующий commit сессии (или в текущий, если запись была вызвана session-end фразой).
Failure modes
- CLAUDE.md без trigger-строки → silent exit, не вмешиваться. Скил project-opt-in.
- Не git-repo /
.tasks/отсутствует → silent exit. Скил требует обоих условий. .tasks/NEXT_SESSION.mdотсутствует в read mode → silent exit (первая сессия проекта, нечего читать).- Неоднозначная фраза («закругляемся» в контексте отдельной таски, а не сессии) → ASK user'а «закрываем сессию или таску?», не угадывать.
- Secret detected. Содержимое handoff'а матчит паттерны секретов (
AKIA...,sk-...,ghp_...,ssh-rsa,BEGIN PRIVATE KEY, JWT в обычном виде,password=/token=без obfuscation) → abort write, не записывать. Файл идёт в git — не место для credentials. Сообщить user'у с указанием подозрительной строки, дать дочистить контекст руками. - Stale handoff (> 7 дней) в read mode → не silent, спросить user'а оверrайдить или продолжить (Q9 resolved 2026-05-24).
- Mid-task без STATUS.md entry в write mode → записать handoff без mid-task секции, не блокировать.
Side effects
- Записывает / перезаписывает
.tasks/NEXT_SESSION.md(project-scope only). - Файл git-tracked, попадает в commit (либо вместе с session work, либо отдельным commit'ом).
- Никаких других файлов:
.archive/не плодим (sliding),.wiki/log.mdне дёргаем (это не promoted event),STATUS.mdне правим. - Никаких global мутаций, никаких других проектов, никаких user-level config writes.
What NOT to do
- Не auto-execute действия из read handoff'а. Default = orient + ask. Прошлая сессия могла ошибиться; user agency сохраняем.
- Не append-with-archive. Sliding only.
.archive/handoff-<date>.mdсоздавать не нужно — это создавало бы N artefact'ов, которые user не хочет. История — через git log. - Не триггерить на task-zone phrases («закрываем эту таску», «pause»), broad farewells («отбой», «разбегаемся»), partial completions («сейчас завершу одну задачу и тогда поговорим»).
- Не писать секреты в handoff. Если контент матчит secret-patterns — abort, попросить user'а вычистить контекст.
- Не на каждом commit'е. Только substantive (см. эвристика в When to use). Trivial
chore: bump depилиdocs: typoНЕ триггерят, иначе handoff'ы шумят. - Не дублировать STATUS.md / MEMORY.md. Handoff = forward-looking связка новых вещей для следующего разворота, не overview всего проекта. Open треки — да, но как мостик «вот где остановились», не как replica STATUS.md.
- Не cross-project. Per-project scope. «Завершаем сессию» в
.workshop/не трогает.admin/и наоборот. - Не зависеть от harness
SessionEndhook — такого hook'а в Claude Code нет (есть толькоSessionStart,UserPromptSubmit,PreToolUse,PostToolUse,Stop,Notification). Триггер — фраза или substantive-commit detection в самом agent flow. - Не считать handoff авторитетным на стороне читателя. Это рекомендация прошлой сессии, не директива. User может override любую её часть.