Files
claude-skills/skills/session-handoff/SKILL.md
vitya f1be677b0a fix(session-handoff): hook command literal path [v0.3.3]
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.
2026-05-25 06:54:15 +03:00

136 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
name: session-handoff
version: 0.3.3
description: "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 Q1Q10).
## 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)
- Плюс: **первый** 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
1. **Detect.** Проверить что `.tasks/NEXT_SESSION.md` существует. Нет — silent exit.
2. **Staleness check.** Прочитать frontmatter `_last_updated_`. Возраст > 7 дней → отметить user'у:
```
handoff от <date> (N дней назад) — возможно устарел.
Оверrайдить или продолжить?
```
Дождаться ответа перед продолжением.
3. **Summarize.** Прочитать тело handoff'а — 5 секций (recent commits / open треки / спроси user'а / не делать / memory updates).
4. **Orient.** Пересказать user'у одним блоком: «прошлая сессия предложила X (open треки + ask-items + don't-items + memory updates). Делаем?»
5. **Wait.** Не делать никаких действий до подтверждения user'ом. Default = orient + ask, **никакого auto-execute**.
### Write mode
1. **Scope check.** Это текущий проект (cwd с `.tasks/`). Никаких global мутаций, никаких других проектов.
2. **Mid-task capture.** Если в `.tasks/STATUS.md` есть 🔴 active task — захватить:
```
left mid-task: <slug>
where_stopped: <текст из STATUS.md>
```
3. **Compose content.** Собрать `.tasks/NEXT_SESSION.md`:
```markdown
---
_last_updated_: <ISO 8601 timestamp>
session_id: <hash или дата>
---
# Next session handoff
## Recent commits
- <slug>: <subject> (35 последних)
...
## Open треки
| Трек | Готовность | Entry-point |
|---|---|---|
| ... | ... | ... |
## Спроси user'а
- <pending decision 1>
- <waiting permission 2>
## Не делать (preemptive guards)
- <guard 1>
- <guard 2>
## Memory updates за сессию
- <что нового сохранилось / обновилось>
```
Пустую секцию — оставить заголовок + пометка `(нет на этом раунде)`. Чтобы next агент видел: не забыто, а пусто.
4. **Sliding overwrite.** `Write` поверх `.tasks/NEXT_SESSION.md` (предыдущее содержимое НЕ архивируется в `.archive/handoff-*.md` — sliding contract). История восстанавливается через `git log -p .tasks/NEXT_SESSION.md`.
5. **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 `SessionEnd` hook** — такого hook'а в Claude Code нет (есть только `SessionStart`, `UserPromptSubmit`, `PreToolUse`, `PostToolUse`, `Stop`, `Notification`). Триггер — фраза или substantive-commit detection в самом agent flow.
- **Не считать handoff авторитетным** на стороне читателя. Это рекомендация прошлой сессии, не директива. User может override любую её часть.