Compare commits
5 Commits
1c0d040347
...
5f6e4e7ed1
| Author | SHA1 | Date | |
|---|---|---|---|
| 5f6e4e7ed1 | |||
| b3ba22f4aa | |||
| 75d70f3a4c | |||
| d089df7e9f | |||
| cc6c321b57 |
49
.tasks/NEXT_SESSION.md
Normal file
49
.tasks/NEXT_SESSION.md
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
---
|
||||||
|
_last_updated_: 2026-05-24
|
||||||
|
session_id: 2026-05-24-session-handoff-cluster5
|
||||||
|
---
|
||||||
|
|
||||||
|
# Next session handoff
|
||||||
|
|
||||||
|
## Recent commits
|
||||||
|
- `b3ba22f` meta(tasks): fill close-note for [session-handoff-existing-projects-upgrade]
|
||||||
|
- `75d70f3` wiki(claude): add session-handoff trigger line + close existing-projects-upgrade
|
||||||
|
- `d089df7` fix(session-handoff): PowerShell hook body char count [v0.3.1]
|
||||||
|
- `cc6c321` feat(session-handoff): add PostToolUse commit-detector hook [v0.3.0]
|
||||||
|
- `1c0d040` chore(dist-hermes): rebuild project-bootstrap for v1.12.0
|
||||||
|
- `358ba14` meta(hermes): register session-handoff (mode: pending, intended: auto/productivity)
|
||||||
|
- `01bc714` feat(project-bootstrap): canonical template + Step 5.6 add session-handoff trigger [v1.12.0]
|
||||||
|
- `90c5be7` fix(skills): session-handoff yaml desc, double-quote [v0.2.1]
|
||||||
|
|
||||||
|
Plus 1 commit в `.admin` repo: `29724d41 wiki(claude): add session-handoff trigger line`.
|
||||||
|
|
||||||
|
## Open треки
|
||||||
|
|
||||||
|
| Трек | Готовность | Entry-point |
|
||||||
|
|---|---|---|
|
||||||
|
| `[session-handoff-test-trigger]` | ⚪ ready — **last blocker для `[session-handoff-review]`** | `.tasks/STATUS.md` L1377. **Requires fresh CC session** — current heavily primed install/bug-hunt контекстом, false-positive checks теряют валидность. Прогнать 6 whitelist phrases + 4 antipatterns против установленного `session-handoff v0.3.1`. |
|
||||||
|
| `[session-handoff-review]` | 🔵 blocked by test-trigger | Автоматически unblock'нется когда test-trigger 🟢. Acceptance: behavioral smoke (`session-handoff/SKILL.md` Steps на тестовом буфере) + finding-tasks через `tasks_create` если есть gaps. |
|
||||||
|
| `[session-handoff-posttooluse-hook]` follow-ups | 2 deferred | (a) live-hook e2e smoke — enable в `~/.claude/settings.json` (snippet в `skills/session-handoff/hooks/README.md`) + substantive commit → see `additionalContext` surface; (b) rebase/cherry-pick batch dedup. |
|
||||||
|
| `[session-handoff-existing-projects-upgrade]` per-machine | 5 deferred (4 unique + .workshop format decision) | victor/books, victor/pilorama98.ru, victor/pilonuxt, OpeItcLoc03/common, OpeItcLoc03/board-viewer — upgrade при следующем заходе в каждый. `.workshop/CLAUDE.md` намеренно SKIP (workspace-contract prose, не flat trigger list). |
|
||||||
|
| `.admin` push pending | committed `29724d41`, not pushed | `git -C ~/projects/.admin push origin master` если grant получен. |
|
||||||
|
|
||||||
|
## Спроси user'а
|
||||||
|
|
||||||
|
- **Прогонять `[session-handoff-test-trigger]` в этой сессии?** Рекомендация: **нет** — нужна чистая CC сессия (новый Claude Code instance), текущая heavily primed контекстом install/bug-hunt. False-positive (НЕ должен активироваться на «закрываем эту таску», «pause», «отбой», «разбегаемся») точно потеряют валидность.
|
||||||
|
- **Enable PostToolUse hook сейчас?** opt-in step из `skills/session-handoff/hooks/README.md`. После enable любой substantive commit triggers `additionalContext` system reminder автоматически. Cross-platform snippets для PowerShell / bash в README.
|
||||||
|
- **Push в `.admin` сейчас?** Cross-repo, отдельный Rule-4 grant нужен.
|
||||||
|
|
||||||
|
## Не делать (preemptive guards)
|
||||||
|
|
||||||
|
- **НЕ тестировать `[session-handoff-test-trigger]`** в этой же сессии — context priming делает false-positive smoke невалидным. Это explicit blocker для review acceptance.
|
||||||
|
- **НЕ enable hook автоматически в settings.json** без explicit user-action — install.sh deliberately НЕ мутирует user-level config. Opt-in design сохраняем.
|
||||||
|
- **НЕ auto-push `.admin`** — separate repo = separate Rule-4 grant (current session grant покрыл только claude-skills `origin/master`).
|
||||||
|
- **НЕ читать STATUS.md как single source of truth** для plan'а — handoff forward-looking, не replica. STATUS.md = full picture; handoff = "where we stopped + what's next + open questions".
|
||||||
|
- **НЕ apply `session-handoff` к `.workshop/CLAUDE.md`** без явной директивы — workspace-contract format mismatch, design decision этой сессии (см. `.tasks/session-handoff-existing-projects-upgrade.md` Decisions log).
|
||||||
|
|
||||||
|
## Memory updates за сессию
|
||||||
|
|
||||||
|
- **new**: `feedback_skill_description_yaml_colon_gotcha.md` — `: ` (colon-space) внутри bare-scalar YAML description ломает parsing → harness fallback к H1 заголовку → trigger phrases non-functional. Fix = wrap entire description в double-quotes. Symptom одинаковый с length-overflow, причина другая.
|
||||||
|
- **updated**: `feedback_skill_description_length_limit.md` — cross-reference на YAML colon gotcha (точка 5 "Также: спецсимволы..."); раздельные failure modes для description fallback.
|
||||||
|
- **MEMORY.md index**: added entry на новый feedback файл.
|
||||||
|
- **Не сохранилось** (по правилу "не дублировать что выводится из кода"): per-task technical decisions live в `.tasks/<slug>.md` Decisions log, не в memory.
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
# Task Board
|
# Task Board
|
||||||
_Updated: 2026-05-24 (session-handoff: install + bootstrap-template-extend + hermes-mapping 🟢; 3 из 7 кластера закрыто.)_
|
_Updated: 2026-05-24 (session-handoff: 5/7 кластера закрыто 🟢 — install/template-extend/hermes/posttooluse-hook/existing-projects-upgrade; review 🔵 still blocked by test-trigger.)_
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
Canonical layout. One block per task. Per-task deep context lives in
|
Canonical layout. One block per task. Per-task deep context lives in
|
||||||
@@ -1449,7 +1449,7 @@ Findings → follow-up tasks через tasks_create в claude-skills (slug `ses
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## ⚪ [session-handoff-posttooluse-hook] — Автоматизировать substantive-commit detection в session-handoff через PostToolUse hook (settings.json), вместо поведенческой памяти agent'а.
|
## 🟢 [session-handoff-posttooluse-hook] — Автоматизировать substantive-commit detection в session-handoff через PostToolUse hook (settings.json), вместо поведенческой памяти agent'а.
|
||||||
|
|
||||||
**Reason:** в текущем SKILL.md (v0.2.0) substantive-commit detection — поведенческое: agent сам после `git commit` помнит проверить эвристику `prefix-exclude AND (body>200 OR files>3) AND (первый non-trivial всегда)`. Менее robust, чем harness-уровневый hook. Один пропущенный «вспомнить» на середине сессии — handoff не обновляется, next агент работает с устаревшим состоянием.
|
**Reason:** в текущем SKILL.md (v0.2.0) substantive-commit detection — поведенческое: agent сам после `git commit` помнит проверить эвристику `prefix-exclude AND (body>200 OR files>3) AND (первый non-trivial всегда)`. Менее robust, чем harness-уровневый hook. Один пропущенный «вспомнить» на середине сессии — handoff не обновляется, next агент работает с устаревшим состоянием.
|
||||||
|
|
||||||
@@ -1459,27 +1459,16 @@ Findings → follow-up tasks через tasks_create в claude-skills (slug `ses
|
|||||||
|
|
||||||
**NB:** это harness-оптимизация поверх скила, не часть самого session-handoff. Скил остаётся работоспособным и без hook'а — просто менее автоматизирован. Bump SKILL.md MINOR не требуется (skill behavior не меняется).
|
**NB:** это harness-оптимизация поверх скила, не часть самого session-handoff. Скил остаётся работоспособным и без hook'а — просто менее автоматизирован. Bump SKILL.md MINOR не требуется (skill behavior не меняется).
|
||||||
|
|
||||||
**Status:** ready
|
**Status:** done
|
||||||
**Where I stopped:** (not started)
|
**Where I stopped:** done
|
||||||
**Next action:** 1. Открыть update-config flow (или вручную ~/.claude/settings.json).
|
**Closed by:** Shipped `skills/session-handoff/hooks/` (3 файла: `commit-detector.ps1`, `commit-detector.sh`, `README.md`). Hook reads PostToolUse JSON via stdin, парсит `git log -1`, на substantive emits `hookSpecificOutput.additionalContext` через JSON stdout → Claude Code surface'ит system reminder. **install.sh НЕ мутирует settings.json** — opt-in через README hook-config snippets (cross-platform Windows/Linux/macOS). SKILL.md body When-to-use получил mention "**Optional**: hook см. hooks/README.md". Bumps: 0.2.1 → 0.3.0 (initial hook capability) → 0.3.1 (PATCH PS bugfix: `$body = git log %b` возвращает Object[], `.Length` давало line count не char count — fix via `-join "`n"`). Stdin-pipe smoke (6 scenarios) ✓: substantive HEAD emits JSON (`body 1255 chars`, 6 files), --amend / not-git-commit / failed-commit / empty-stdin / malformed-JSON — silent skip. **Deferred** (partial close): live-hook e2e smoke (enable в settings.json + commit → see additionalContext) — отдельной сессией, чтобы не interfere с current commits + meta-feedback loop. Rebase/cherry-pick batch deduplication — defer to follow-up если actually annoys.
|
||||||
2. Добавить PostToolUse hook:
|
**Branch:** master
|
||||||
- matcher: `Bash`
|
|
||||||
- command pattern: содержит `git commit` (исключая `git commit --amend`? — design-вопрос)
|
|
||||||
- action: вызов helper-скрипта, который читает последний commit (`git log -1 --format`), парсит prefix/body/files, решает substantive vs trivial, и при substantive — invoke session-handoff write-mode на agent-стороне (через notification или прямое stdout-сообщение в agent).
|
|
||||||
3. Helper-скрипт — bash/powershell, лежит в ~/projects/claude-skills/skills/session-handoff/hooks/ (если решим, что hooks — часть скила и distribuируются вместе с install.sh).
|
|
||||||
4. Smoke test: сделать substantive commit в тестовом проекте → handoff должен обновиться без user-запроса. Сделать trivial `chore:` commit → handoff не трогать.
|
|
||||||
5. Документировать в SKILL.md секции When to use — «substantive-commit trigger автоматизирован через PostToolUse hook (см. hooks/)» — но только после успешного smoke. До этого момента — оговорка в SKILL.md остаётся «agent-side эвристика».
|
|
||||||
|
|
||||||
**Design-вопросы для реализатора:**
|
|
||||||
- Хук распределяется через install.sh скила (тогда нужно расширять install.sh) или конфигурируется через update-config вручную user'ом? Recommendation: install.sh добавляет hook автоматически, чтобы скил работал «из коробки».
|
|
||||||
- `git commit --amend` — триггерить или нет? (recommend: НЕ триггерить — амэнд обычно правка предыдущей сессии).
|
|
||||||
- Cherry-pick / rebase — каскад из множества коммитов, не должен спамить handoff write'ами. Recommend: триггер только на оригинальный commit-event (HEAD@{1} != HEAD предыдущий).
|
|
||||||
**Branch:** n/a
|
|
||||||
<!-- created-by: OpeItcLoc03@DESKTOP-NSEF0UK / from: OpeItcLoc03/workshop / 2026-05-24T18:31:07.605Z -->
|
<!-- created-by: OpeItcLoc03@DESKTOP-NSEF0UK / from: OpeItcLoc03/workshop / 2026-05-24T18:31:07.605Z -->
|
||||||
|
<!-- closed-by: vitya@DESKTOP-NSEF0UK / 2026-05-24 / partial: stdin smoke ✓; live-hook e2e deferred; rebase noise dedup deferred -->
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## ⚪ [session-handoff-existing-projects-upgrade] — Добавить trigger-line `session handoff: read on start, write on end` в CLAUDE.md уже инициализированных проектов (которые не получат строку через bootstrap, потому что инициализированы до session-handoff-bootstrap-template-extend).
|
## 🟢 [session-handoff-existing-projects-upgrade] — Добавить trigger-line `session handoff: read on start, write on end` в CLAUDE.md уже инициализированных проектов (которые не получат строку через bootstrap, потому что инициализированы до session-handoff-bootstrap-template-extend).
|
||||||
|
|
||||||
**Reason:** `session-handoff-bootstrap-template-extend` решает проблему только для **новых** проектов (greenfield bootstrap). Существующие проекты — `~/projects/.workshop/`, `~/projects/.admin/`, `victor/books`, `victor/pilorama98.ru`, `OpeItcLoc03/admin`, `OpeItcLoc03/common`, `OpeItcLoc03/board-viewer`, и прочие — handoff не подхватят, пока строка не появится в их CLAUDE.md вручную.
|
**Reason:** `session-handoff-bootstrap-template-extend` решает проблему только для **новых** проектов (greenfield bootstrap). Существующие проекты — `~/projects/.workshop/`, `~/projects/.admin/`, `victor/books`, `victor/pilorama98.ru`, `OpeItcLoc03/admin`, `OpeItcLoc03/common`, `OpeItcLoc03/board-viewer`, и прочие — handoff не подхватят, пока строка не появится в их CLAUDE.md вручную.
|
||||||
|
|
||||||
@@ -1487,28 +1476,11 @@ Findings → follow-up tasks через tasks_create в claude-skills (slug `ses
|
|||||||
|
|
||||||
**Out of scope:** не делать batch-режим в `project-bootstrap` — это потенциальный feature creep. Каждый проект upgrade'ится отдельно, либо вручную через Edit, либо через `project-bootstrap` в upgrade-режиме (skill description: «Initializes or upgrades a project in the current folder»).
|
**Out of scope:** не делать batch-режим в `project-bootstrap` — это потенциальный feature creep. Каждый проект upgrade'ится отдельно, либо вручную через Edit, либо через `project-bootstrap` в upgrade-режиме (skill description: «Initializes or upgrades a project in the current folder»).
|
||||||
|
|
||||||
**Status:** ready
|
**Status:** done
|
||||||
**Where I stopped:** (not started)
|
**Where I stopped:** done (partial — 2/7, see breakdown)
|
||||||
**Next action:** Два пути на выбор реализатора:
|
**Closed by:** Path A (manual edit-pass) на high/medium-pri списке. Локально на этой машине найдены 2 целевых проекта (`.workshop`, `.admin`) + cwd (`claude-skills`). Результат: **claude-skills/CLAUDE.md** добавлена строка (cluster commit `75d70f3`); **.admin/CLAUDE.md** добавлена + committed в .admin repo (commit `29724d41`, **NOT pushed** — Rule 4 cross-repo push needs separate approval). **`.workshop` SKIP** — CLAUDE.md там это workspace-contract prose (не flat trigger list), adding flat line нарушит project-discipline Rule 1. **5 проектов deferred** — не на этой машине: `victor/books`, `victor/pilorama98.ru`, `victor/pilonuxt`, `OpeItcLoc03/common`, `OpeItcLoc03/board-viewer` — upgrade per-machine при следующем заходе. Pattern: партиальное закрытие как `using-yt-tools-test-trigger` (split-out per-machine остаток). Acceptance partial: 2/7 upgraded + 1 design-decision skip + 4 deferred-per-machine = task scope addressed настолько насколько эта машина позволяет.
|
||||||
|
**Branch:** master (для cwd commit), .admin/master (для cross-repo commit)
|
||||||
**Path A — manual edit-pass (recommend для трекаемого списка проектов):**
|
|
||||||
1. Собрать список активных проектов: `ls ~/projects/ | grep -v "^\."` плюс dot-папки (`.workshop`, `.admin`, etc.).
|
|
||||||
2. Для каждого: открыть `<proj>/CLAUDE.md`, найти секцию с trigger-строками (где уже стоит `pull remote before work` или подобное), добавить `session handoff: read on start, write on end` рядом.
|
|
||||||
3. Commit per project: `wiki(claude): add session-handoff trigger line`.
|
|
||||||
4. Бамп проекта — не требуется (CLAUDE.md не versioned-артефакт).
|
|
||||||
|
|
||||||
**Path B — invoke project-bootstrap upgrade-mode per project:**
|
|
||||||
1. cd в каждый проект, вызвать `project-bootstrap` в upgrade-режиме (по skill description он умеет upgrade existing folder).
|
|
||||||
2. project-bootstrap (после `session-handoff-bootstrap-template-extend` taska выполнится) должен видеть отсутствующую строку и добавить.
|
|
||||||
3. Зависит от того, как project-bootstrap upgrade-режим обрабатывает CLAUDE.md — overwrite vs merge. Recommend сначала проверить на одном тестовом проекте.
|
|
||||||
|
|
||||||
**Приоритет проектов для upgrade'а (по моей оценке frequency-of-use):**
|
|
||||||
- High: `~/projects/.workshop/`, `~/projects/.admin/`, `victor/books`, `OpeItcLoc03/claude-skills` сам.
|
|
||||||
- Medium: `victor/pilorama98.ru`, `victor/pilonuxt`, `OpeItcLoc03/common`, `OpeItcLoc03/board-viewer`.
|
|
||||||
- Low: остальные, по мере захода.
|
|
||||||
|
|
||||||
**Skip:** проекты без `.tasks/` (handoff требует `.tasks/` — silent exit per Failure modes). Reorganized / archived проекты пропускать.
|
|
||||||
**Branch:** n/a
|
|
||||||
<!-- created-by: OpeItcLoc03@DESKTOP-NSEF0UK / from: OpeItcLoc03/workshop / 2026-05-24T18:31:25.936Z -->
|
<!-- created-by: OpeItcLoc03@DESKTOP-NSEF0UK / from: OpeItcLoc03/workshop / 2026-05-24T18:31:25.936Z -->
|
||||||
|
<!-- closed-by: vitya@DESKTOP-NSEF0UK / 2026-05-24 / partial: 2 done (cwd + .admin), 1 skip (.workshop format mismatch), 4 deferred (not on this machine); .admin push not done (Rule 4) -->
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|||||||
32
.tasks/session-handoff-existing-projects-upgrade.md
Normal file
32
.tasks/session-handoff-existing-projects-upgrade.md
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
# session-handoff-existing-projects-upgrade
|
||||||
|
|
||||||
|
## Goal
|
||||||
|
Добавить trigger-line `session handoff: read on start, write on end` в CLAUDE.md уже-инициализированных проектов, которые не получат строку через `[session-handoff-bootstrap-template-extend]` (тот template работает только для greenfield bootstrap).
|
||||||
|
|
||||||
|
## Key files
|
||||||
|
- `~/projects/claude-skills/CLAUDE.md:10` — добавлена строка после `pull remote before work` (cwd, commit'ится в кластере closure commit'а)
|
||||||
|
- `~/projects/.admin/CLAUDE.md:10` — добавлена аналогично; committed в .admin repo (commit `29724d41`); push deferred per Rule 4 (separate repo, separate approval)
|
||||||
|
|
||||||
|
## Decisions log
|
||||||
|
- 2026-05-24: **Path A — manual edit-pass** (per task description recommendation). Path B (project-bootstrap upgrade-режим per project) сложнее и требует проверки идемпотентности на тестовом проекте — overkill для 2-project pass.
|
||||||
|
- 2026-05-24: **.workshop — SKIP**. CLAUDE.md в `.workshop` это **workspace-contract prose**, не flat trigger-line list (структурированный markdown с табличками, `## Жёсткие правила`, `## Override project-discipline`). Adding flat trigger line в неё нарушает project-discipline Rule 1 (project conventions override). Workshop session-mode — brainstorm-dominant; может не benefit от session-handoff design'а который calibrated на code-impl сессии. Если в будущем понадобится — добавлять в `## Триггеры скилов v1` табличку как новый row.
|
||||||
|
- 2026-05-24: **5 проектов deferred — не на этой машине**: `victor/books`, `victor/pilorama98.ru`, `victor/pilonuxt`, `OpeItcLoc03/common`, `OpeItcLoc03/board-viewer`. Их upgrade per-machine — каждый где живёт.
|
||||||
|
- 2026-05-24: **Cross-repo commits** через `git -C <path>` (без cd, чтобы cwd shell state не drift'нул). Push deferred per Rule 4 — each separate repo нужен отдельный approval, не покрыт grant'ом текущей сессии.
|
||||||
|
|
||||||
|
## Open questions
|
||||||
|
- [ ] Push в .admin/ — не сделан в этой сессии (cross-repo push needs separate approval per Rule 4)
|
||||||
|
- [ ] 5 victor/* и OpeItcLoc03/* — upgrade per-machine; backlog для следующих заходов в каждый
|
||||||
|
|
||||||
|
## Completed steps
|
||||||
|
- [x] inventory: проверены 7 high/medium-pri проектов, локально присутствуют 2 (.workshop, .admin) + claude-skills cwd
|
||||||
|
- [x] edit claude-skills/CLAUDE.md — added line
|
||||||
|
- [x] edit .admin/CLAUDE.md — added line + commit (29724d41 in .admin repo, NOT pushed)
|
||||||
|
- [x] skip .workshop — CLAUDE.md format mismatch (workspace-contract, не flat trigger list)
|
||||||
|
- [x] document 5 deferred projects (not on this machine)
|
||||||
|
- [ ] STATUS.md → 🟢 (partial)
|
||||||
|
- [ ] commit closure in claude-skills
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
**Partial close**: 2/7 priority projects upgraded в этой сессии (claude-skills + .admin). 1 skipped (.workshop — design decision). 4 deferred (not on this machine). Pattern совпадает с `using-yt-tools-test-trigger` (closed partial, splits-out the per-machine рестарт).
|
||||||
|
|
||||||
|
Cross-project pushes намеренно не сделаны — каждый repo это separate decision; не аккумулирую в одну "большой push" approval.
|
||||||
39
.tasks/session-handoff-posttooluse-hook.md
Normal file
39
.tasks/session-handoff-posttooluse-hook.md
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
# session-handoff-posttooluse-hook
|
||||||
|
|
||||||
|
## Goal
|
||||||
|
Автоматизировать substantive-commit detection в `session-handoff` через PostToolUse hook на `Bash` matcher'е (settings.json уровне), вместо поведенческой памяти агента. Hook parses `git log -1`, применяет ту же substantive-эвристику что и в SKILL.md, и на hit emits `hookSpecificOutput.additionalContext` чтобы Claude Code surface'ил system reminder в следующей итерации агента.
|
||||||
|
|
||||||
|
## Key files
|
||||||
|
- `skills/session-handoff/hooks/commit-detector.ps1` — Windows/PowerShell hook script
|
||||||
|
- `skills/session-handoff/hooks/commit-detector.sh` — Linux/macOS POSIX hook script (требует python3 для JSON parsing)
|
||||||
|
- `skills/session-handoff/hooks/README.md` — opt-in инструкции, cross-platform settings.json snippets, smoke procedure
|
||||||
|
- `skills/session-handoff/SKILL.md` — body When-to-use updated: substantive-commit пункт получил «**Optional**: harness-side hook см. hooks/README.md»
|
||||||
|
- `skills/session-handoff/SKILL.md` frontmatter — bump 0.2.1 → 0.3.0 (MINOR: new opt-in capability)
|
||||||
|
|
||||||
|
## Decisions log
|
||||||
|
- 2026-05-24: **install.sh НЕ мутирует ~/.claude/settings.json**. Auto-rewriting user hook config — неправильная shape для install скрипта. Hooks ship as files; user enables once per machine. SKILL.md и hooks/README.md документируют opt-in step (раз сделал — работает на все sessions).
|
||||||
|
- 2026-05-24: **JSON output protocol**: hook возвращает `hookSpecificOutput.additionalContext` (per Claude Code PostToolUse hook protocol). На hit — JSON; на miss — silent exit 0 без output. Confirmed via claude-code-guide subagent (https://code.claude.com/docs/en/hooks.md § JSON Output Format).
|
||||||
|
- 2026-05-24: **--amend skip** (recommended в task design questions). Amend обычно правит prev session коммит, не новый work artifact.
|
||||||
|
- 2026-05-24: **rebase/cherry-pick noise — deferred**. Hook fires per commit, batch operations spam. Trade-off acceptable for opt-in v0.3.0; defer "только original commit-event (HEAD@{1} != HEAD)" к follow-up если actually annoys.
|
||||||
|
- 2026-05-24: **first-non-trivial-commit-of-session special case — NOT in hook**. Session boundaries are agent-state, не accessible from hook side. Hook uses only body/file thresholds. Под-detection on small first commits acceptable; agent-side эвристика остаётся как backup.
|
||||||
|
- 2026-05-24: **POSIX requires python3** for safe JSON parsing of PostToolUse stdin. Alternatives (sed/awk JSON parsing) fragile. Documented as dep in README.
|
||||||
|
|
||||||
|
## Open questions
|
||||||
|
- [ ] Live-hook smoke test — отдельной сессией (enable hook → substantive commit → see additionalContext surface). Не делалось в этой сессии чтобы не interfere с current commits.
|
||||||
|
|
||||||
|
## Completed steps
|
||||||
|
- [x] Research PostToolUse hook output protocol (claude-code-guide subagent)
|
||||||
|
- [x] Inspect existing ~/.claude/settings.json (no hooks currently configured)
|
||||||
|
- [x] Write commit-detector.ps1 (Windows)
|
||||||
|
- [x] Write commit-detector.sh (POSIX)
|
||||||
|
- [x] Write hooks/README.md (opt-in instructions cross-platform + smoke procedure)
|
||||||
|
- [x] Update SKILL.md body — When-to-use mentions hook as opt-in alternative
|
||||||
|
- [x] Bump SKILL.md 0.2.1 → 0.3.0 (MINOR — new capability)
|
||||||
|
- [x] Reinstall via scripts/install.ps1
|
||||||
|
- [x] stdin-pipe smoke (6 scenarios): substantive HEAD ✓ emits JSON; --amend / ls / empty / malformed / failed-commit ✓ silent skip
|
||||||
|
- [x] discover + fix PS bug: `git log %b` → string[], `.Length` was line count; `-join "`n"` fix; PATCH bump 0.3.0 → 0.3.1
|
||||||
|
- [x] STATUS.md → 🟢 (partial: stdin smoke ✓, live-hook deferred to separate session)
|
||||||
|
- [ ] commit (next)
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
Live-hook enable + e2e validation = separate task / separate session. Adding hook to settings.json in this active session would fire on every git commit done here, including the closure commit itself — meta-feedback loop best avoided.
|
||||||
@@ -7,6 +7,7 @@ use project wiki
|
|||||||
use task management system
|
use task management system
|
||||||
check across all projects
|
check across all projects
|
||||||
pull remote before work
|
pull remote before work
|
||||||
|
session handoff: read on start, write on end
|
||||||
follow project discipline
|
follow project discipline
|
||||||
follow tdd-criteria
|
follow tdd-criteria
|
||||||
delegate to interns when allowed
|
delegate to interns when allowed
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
name: session-handoff
|
name: session-handoff
|
||||||
version: 0.2.1
|
version: 0.3.1
|
||||||
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», «отбой», «разбегаемся»."
|
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», «отбой», «разбегаемся»."
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -26,6 +26,7 @@ Forward-looking, не timeline: handoff = связка новых вещей к
|
|||||||
- prefix НЕ в (`meta:`|`docs:`|`style:`|`chore:`|`fix typo`)
|
- prefix НЕ в (`meta:`|`docs:`|`style:`|`chore:`|`fix typo`)
|
||||||
- AND (body length > 200 символов OR files changed > 3)
|
- AND (body length > 200 символов OR files changed > 3)
|
||||||
- Плюс: **первый** non-trivial commit сессии — всегда триггерит, даже если ниже порога (старт работы = context shift).
|
- Плюс: **первый** 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):**
|
**Skip (false-positive guards):**
|
||||||
- «закрываем эту таску» — task close, не session. Это zone `using-tasks`.
|
- «закрываем эту таску» — task close, не session. Это zone `using-tasks`.
|
||||||
|
|||||||
91
skills/session-handoff/hooks/README.md
Normal file
91
skills/session-handoff/hooks/README.md
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
# session-handoff hooks
|
||||||
|
|
||||||
|
Opt-in PostToolUse hook that detects substantive `git commit` invocations and signals the agent ("consider running session-handoff write-mode") via a system reminder. Replaces the agent-side commit-detection heuristic in the SKILL.md `When to use` section with a deterministic harness-side trigger.
|
||||||
|
|
||||||
|
## 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. The hook is shipped as scripts; user enables it once per machine.
|
||||||
|
|
||||||
|
## Enable on Windows (PowerShell)
|
||||||
|
|
||||||
|
Add to `~/.claude/settings.json`:
|
||||||
|
|
||||||
|
```jsonc
|
||||||
|
{
|
||||||
|
"hooks": {
|
||||||
|
"PostToolUse": [
|
||||||
|
{
|
||||||
|
"matcher": "Bash",
|
||||||
|
"hooks": [
|
||||||
|
{
|
||||||
|
"type": "command",
|
||||||
|
"command": "pwsh -NoProfile -ExecutionPolicy Bypass -File \"$env:USERPROFILE\\.claude\\skills\\session-handoff\\hooks\\commit-detector.ps1\""
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
If `hooks.PostToolUse` already exists — append the matcher block to the array. Don't overwrite existing entries.
|
||||||
|
|
||||||
|
## Enable on Linux / macOS (bash)
|
||||||
|
|
||||||
|
```jsonc
|
||||||
|
{
|
||||||
|
"hooks": {
|
||||||
|
"PostToolUse": [
|
||||||
|
{
|
||||||
|
"matcher": "Bash",
|
||||||
|
"hooks": [
|
||||||
|
{
|
||||||
|
"type": "command",
|
||||||
|
"command": "bash ~/.claude/skills/session-handoff/hooks/commit-detector.sh"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The bash variant needs `python3` on PATH (used to parse the PostToolUse JSON stdin).
|
||||||
|
|
||||||
|
## What gets signalled
|
||||||
|
|
||||||
|
On a successful `git commit` whose subject prefix is not in {`meta`, `docs`, `style`, `chore`} or `fix typo`, **and** whose body exceeds 200 characters or which touches more than 3 files — the hook emits a `hookSpecificOutput.additionalContext` system reminder of shape:
|
||||||
|
|
||||||
|
> Substantive commit detected on `<cwd>`: `<subject>` (N files changed, body M chars). Consider invoking session-handoff write-mode to update `.tasks/NEXT_SESSION.md`.
|
||||||
|
|
||||||
|
On any of these → silent skip (exit 0, no JSON):
|
||||||
|
|
||||||
|
- malformed PostToolUse stdin
|
||||||
|
- Bash command isn't `git commit`
|
||||||
|
- command is `git commit --amend`
|
||||||
|
- commit returned non-zero exit
|
||||||
|
- cwd isn't a git work-tree
|
||||||
|
- subject prefix is in trivial set
|
||||||
|
- body ≤ 200 chars AND files ≤ 3
|
||||||
|
|
||||||
|
## Smoke test (without enabling the hook)
|
||||||
|
|
||||||
|
Pipe a synthetic PostToolUse JSON to the script. On Windows:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
$payload = @{
|
||||||
|
tool_input = @{ command = 'git commit -m "subject"' }
|
||||||
|
tool_response = @{ exit_code = 0 }
|
||||||
|
cwd = (Get-Location).Path
|
||||||
|
} | ConvertTo-Json -Compress
|
||||||
|
|
||||||
|
$payload | pwsh -NoProfile -File .\skills\session-handoff\hooks\commit-detector.ps1
|
||||||
|
```
|
||||||
|
|
||||||
|
If your `HEAD` is a non-trivial commit (e.g. recent `feat:` with > 200-char body or > 3 files), output is JSON containing `additionalContext`. Otherwise — empty stdout (silent skip).
|
||||||
|
|
||||||
|
## Caveats
|
||||||
|
|
||||||
|
- **Rebase / cherry-pick noise.** Every commit in a rebase or cherry-pick batch will re-fire the hook. Deferred to a follow-up if it actually annoys in practice; the hook is opt-in so the cost is bounded.
|
||||||
|
- **First-non-trivial commit of session.** The agent-side heuristic in SKILL.md treats the *first* non-trivial commit of a session as "always substantive" regardless of thresholds. The hook can't see session boundaries — uses only body/file thresholds. Slight under-detection on small first commits; acceptable trade-off for harness-side determinism.
|
||||||
|
- **No automatic write-mode invocation.** Hook only signals. The agent still decides whether to run session-handoff write-mode in response — keeps the user-agency invariant from SKILL.md `What NOT to do`.
|
||||||
72
skills/session-handoff/hooks/commit-detector.ps1
Normal file
72
skills/session-handoff/hooks/commit-detector.ps1
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
#!/usr/bin/env pwsh
|
||||||
|
# session-handoff PostToolUse hook (PowerShell).
|
||||||
|
#
|
||||||
|
# Reads PostToolUse JSON from stdin, detects whether the just-completed
|
||||||
|
# Bash tool call was a substantive `git commit`, and on hit emits JSON to
|
||||||
|
# stdout with `additionalContext` so Claude Code surfaces a system reminder
|
||||||
|
# in the next agent iteration ("substantive commit — consider session-handoff
|
||||||
|
# write-mode").
|
||||||
|
#
|
||||||
|
# Substantive heuristic (mirrors session-handoff SKILL.md):
|
||||||
|
# prefix NOT in (meta:|docs:|style:|chore:|fix typo) AND
|
||||||
|
# (body > 200 chars OR files > 3)
|
||||||
|
#
|
||||||
|
# Silent skip on: malformed JSON, no command, --amend, failed commit,
|
||||||
|
# non-git cwd, trivial prefix, below thresholds. Never blocks the tool call
|
||||||
|
# (PostToolUse cannot, by design).
|
||||||
|
|
||||||
|
$ErrorActionPreference = 'Stop'
|
||||||
|
|
||||||
|
# Read stdin
|
||||||
|
try {
|
||||||
|
$raw = [Console]::In.ReadToEnd()
|
||||||
|
if ([string]::IsNullOrWhiteSpace($raw)) { exit 0 }
|
||||||
|
$hook = $raw | ConvertFrom-Json -ErrorAction Stop
|
||||||
|
} catch {
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# Only Bash tool, only git commit (not --amend)
|
||||||
|
$cmd = $hook.tool_input.command
|
||||||
|
if (-not $cmd) { exit 0 }
|
||||||
|
if ($cmd -notmatch '(?<![\w-])git\s+commit(?![\w-])') { exit 0 }
|
||||||
|
if ($cmd -match '(?<![\w-])git\s+commit\b.*--amend') { exit 0 }
|
||||||
|
|
||||||
|
# Only on successful commit
|
||||||
|
if ($null -ne $hook.tool_response.exit_code -and $hook.tool_response.exit_code -ne 0) { exit 0 }
|
||||||
|
|
||||||
|
# Resolve cwd; require a git work-tree
|
||||||
|
$cwd = $hook.cwd
|
||||||
|
if (-not $cwd) { $cwd = (Get-Location).Path }
|
||||||
|
$inside = & git -C $cwd rev-parse --is-inside-work-tree 2>$null
|
||||||
|
if ($inside -ne 'true') { exit 0 }
|
||||||
|
|
||||||
|
# Parse last commit
|
||||||
|
$subject = (& git -C $cwd log -1 --format='%s').Trim()
|
||||||
|
# PowerShell collapses multi-line subprocess output into string[] — join back so
|
||||||
|
# .Length below is char count, not line count.
|
||||||
|
$body = ((& git -C $cwd log -1 --format='%b') -join "`n")
|
||||||
|
$files = ((& git -C $cwd diff-tree --no-commit-id --name-only -r HEAD) | Measure-Object).Count
|
||||||
|
|
||||||
|
# Trivial-prefix check (Conventional Commits prefix before optional scope + colon)
|
||||||
|
$prefix = $subject -replace '^([a-z]+)(\([^)]+\))?:.*$','$1'
|
||||||
|
$trivial = @('meta','docs','style','chore')
|
||||||
|
if ($trivial -contains $prefix) { exit 0 }
|
||||||
|
if ($subject -match 'fix\s+typo') { exit 0 }
|
||||||
|
|
||||||
|
# Threshold check (chars for body, count for files)
|
||||||
|
$bodyLen = if ($body) { $body.Length } else { 0 }
|
||||||
|
if ($bodyLen -le 200 -and $files -le 3) { exit 0 }
|
||||||
|
|
||||||
|
|
||||||
|
# Substantive — emit JSON
|
||||||
|
$msg = "Substantive commit detected on " + $cwd + ": ``" + $subject + "`` (" + $files + " files changed, body " + $bodyLen + " chars). Consider invoking session-handoff write-mode to update .tasks/NEXT_SESSION.md."
|
||||||
|
|
||||||
|
@{
|
||||||
|
hookSpecificOutput = @{
|
||||||
|
hookEventName = 'PostToolUse'
|
||||||
|
additionalContext = $msg
|
||||||
|
}
|
||||||
|
systemMessage = 'session-handoff: substantive commit detected'
|
||||||
|
suppressOutput = $false
|
||||||
|
} | ConvertTo-Json -Compress -Depth 5 | Write-Output
|
||||||
73
skills/session-handoff/hooks/commit-detector.sh
Normal file
73
skills/session-handoff/hooks/commit-detector.sh
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# session-handoff PostToolUse hook (POSIX). See commit-detector.ps1 for prose.
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
raw=$(cat)
|
||||||
|
[[ -z "$raw" ]] && exit 0
|
||||||
|
|
||||||
|
# Helper: extract a JSON path via python3
|
||||||
|
jget() {
|
||||||
|
python3 -c "
|
||||||
|
import sys, json
|
||||||
|
try:
|
||||||
|
d = json.loads(sys.argv[1])
|
||||||
|
out = d
|
||||||
|
for k in sys.argv[2].split('.'):
|
||||||
|
if isinstance(out, dict):
|
||||||
|
out = out.get(k)
|
||||||
|
else:
|
||||||
|
out = None
|
||||||
|
break
|
||||||
|
print('' if out is None else out)
|
||||||
|
" "$raw" "$1" 2>/dev/null || echo ''
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd=$(jget tool_input.command)
|
||||||
|
[[ -z "$cmd" ]] && exit 0
|
||||||
|
|
||||||
|
# Only `git commit`, not `--amend`
|
||||||
|
if ! echo "$cmd" | grep -qE '(^|[^[:alnum:]_-])git[[:space:]]+commit($|[^[:alnum:]_-])'; then exit 0; fi
|
||||||
|
if echo "$cmd" | grep -qE '(^|[^[:alnum:]_-])git[[:space:]]+commit\b.*--amend'; then exit 0; fi
|
||||||
|
|
||||||
|
# Only on successful commit (if exit_code present and non-zero, skip)
|
||||||
|
exit_code=$(jget tool_response.exit_code)
|
||||||
|
if [[ -n "$exit_code" && "$exit_code" != "0" ]]; then exit 0; fi
|
||||||
|
|
||||||
|
cwd=$(jget cwd)
|
||||||
|
[[ -z "$cwd" ]] && cwd=$(pwd)
|
||||||
|
|
||||||
|
# Require git work-tree
|
||||||
|
git -C "$cwd" rev-parse --is-inside-work-tree >/dev/null 2>&1 || exit 0
|
||||||
|
|
||||||
|
subject=$(git -C "$cwd" log -1 --format='%s')
|
||||||
|
body=$(git -C "$cwd" log -1 --format='%b')
|
||||||
|
files=$(git -C "$cwd" diff-tree --no-commit-id --name-only -r HEAD | wc -l | tr -d ' ')
|
||||||
|
|
||||||
|
# Trivial-prefix check
|
||||||
|
prefix=$(echo "$subject" | sed -E 's/^([a-z]+)(\([^)]+\))?:.*$/\1/')
|
||||||
|
case "$prefix" in
|
||||||
|
meta|docs|style|chore) exit 0 ;;
|
||||||
|
esac
|
||||||
|
echo "$subject" | grep -qE 'fix[[:space:]]+typo' && exit 0
|
||||||
|
|
||||||
|
# Threshold
|
||||||
|
body_len=${#body}
|
||||||
|
if [[ "$body_len" -le 200 && "$files" -le 3 ]]; then exit 0; fi
|
||||||
|
|
||||||
|
# Substantive — emit JSON via python3 to handle quoting safely
|
||||||
|
python3 -c "
|
||||||
|
import json, sys
|
||||||
|
msg = (
|
||||||
|
'Substantive commit detected on $cwd: \`' + '''$subject''' + '\` '
|
||||||
|
+ '($files files changed, body $body_len chars). '
|
||||||
|
+ 'Consider invoking session-handoff write-mode to update .tasks/NEXT_SESSION.md.'
|
||||||
|
)
|
||||||
|
print(json.dumps({
|
||||||
|
'hookSpecificOutput': {
|
||||||
|
'hookEventName': 'PostToolUse',
|
||||||
|
'additionalContext': msg,
|
||||||
|
},
|
||||||
|
'systemMessage': 'session-handoff: substantive commit detected',
|
||||||
|
'suppressOutput': False,
|
||||||
|
}))
|
||||||
|
"
|
||||||
Reference in New Issue
Block a user