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
3 changed files with 28 additions and 16 deletions
Live-hook e2e smoke выполнен на commit'е`bcb500b` (build dist-hermes, 4 файла, prefix `build:` → substantive). Hook script logic подтверждён на синтетическом replay'е — корректный JSON с`additionalContext` ("Substantive commit detected... 4 files changed, body 0 chars."). **Caveat:** в этой агент-сессии `additionalContext` в system-reminders **не наблюдался** после реального коммита — либо surface ушёл только в user-UI, либо есть propagation gap к agent context. Следующий substantive-commit должен подтвердить или опровергнуть.
Live-hook e2e smoke **реально** закрыт после fix'а`f1be677` (v0.3.3). До этого hook был мёртв на Windows из-за PowerShell-style `$env:USERPROFILE` в install snippet — Claude Code запускает hook command через git-bash, который мангляет `$env:USERPROFILE` в `":USERPROFILE\..."` и PowerShell падает на bad filename. Synthetic replay через PowerShell tool в обход harness давал false-positive «работает». Retract'нул вчерашний optimistic закрытие cluster-item.
Fix: install snippet в `hooks/README.md` теперь рекомендует **литеральный абсолютный путь**`C:\Users\<you>\.claude\...`с явным «Why literal path» разделом (объясняет почему `$env:VAR` / `%VAR%` / `~` все ломаются через bash-harness chain). Settings.json на этой машине обновлён, CC получил перезагрузку, hook теперь surface'ит `additionalContext` post-substantive-commit (verified this session — этот handoff пишется ровно после такого surface'а).
-`269318d` meta(handoff): regen NEXT_SESSION for cluster 7/7 done [dogfood]
-`2673efb` meta(tasks): close session-handoff cluster 7/7 [test-trigger + review]
`bcb500b` — **NOT pushed** (autopush этой сессии не давался). Branch is 1 commit ahead of `origin/master`.
`f1be677` — **NOT pushed** (autopush этой сессии не давался). `bcb500b` + `ef6fad7` похоже подтянулись на origin внешне между ходами (`origin/master..HEAD` пуст до `f1be677`).
## Open треки
## Open треки
| Трек | Готовность | Entry-point |
| Трек | Готовность | Entry-point |
|---|---|---|
|---|---|---|
| **Hook propagation verification** | smoke partial — script OK, agent-surface unclear | Сделать любой substantive-commit (feat/fix/build с body>200 OR files>3) и проверить, появляется ли «Substantive commit detected...» в system-reminders **следующего** turn'а агента. Если нет — file ⚪ follow-up task с разбором (timing? UI-only surface? matcher bug?). Если да — smoke 🟢 чисто. |
| **Hook propagation per-machine fix** | this machine 🟢, others ⚪ | Каждая машина с уже-enabled hook'ом имеет broken `$env:USERPROFILE` в `~/.claude/settings.json` (если устанавливали по pre-v0.3.3 snippet'у). Fix: открыть `~/.claude/settings.json`, заменить `$env:USERPROFILE` на литеральный `C:\Users\<you>\` (Windows) или оставить как есть (Linux/macOS — bash snippet не страдает). Restart CC. Затем смоук substantive commit'ом. |
- **Push разрешён?** `bcb500b` (dist-hermes rebuild) pending push к `origin/master`. Autopush этой сессии не давался.
- **Push разрешён?** `f1be677` (hook fix) pending push к `origin/master`. Autopush этой сессии не давался.
- **Hook propagation gap** — investigate now (file ⚪ task + reproduce) или wait-and-see на следующий substantive commit?
- **Cluster session-handoff финально закрыт?** Все 7/7 🟢 в STATUS.md, smoke реально пройден post-fix, propagation gap resolved. Можно считать кластер архивно-done и убрать из «Open треки»?
- **Что дальше?** Рекомендация: следующий substantive-commit как natural smoke continuation (cycles up: skill-readmes batch — каждый README → 1 substantive commit → hook surface наблюдение). Альтернативы: existing-projects-upgrade per-machine, active-platform-eval resume.
- **Что дальше?** Рекомендация: `[skill-readmes]` caveman cluster — natural next step (READMEs нужны, каждая = substantive commit = ещё точка hook-наблюдения для confidence). Альтернативы: existing-projects-upgrade per-machine (быстро через ssh + edit), active-platform-eval resume.
## Не делать (preemptive guards)
## Не делать (preemptive guards)
- **НЕenable hook автоматически** в чужих settings.json — opt-in deliberate (install.sh не мутирует config).
- **НЕповторять synthetic-replay аргумент** как доказательство e2e — он валиден только для script logic, не для harness chain. Реальный smoke = реальный substantive commit + наблюдение system-reminder в **следующем** turn'е агента.
- **НЕapply session-handoff к `.workshop/CLAUDE.md`** — workspace-contract format mismatch, design decision cluster'а.
- **НЕenable hook автоматически** в чужих settings.json — opt-in deliberate.
- **НЕ apply session-handoff к `.workshop/CLAUDE.md`** — workspace-contract format mismatch.
- **НЕ считать smoke полностью 🟢** пока agent-surface не воспроизведён хотя бы раз — script-isolation проходит, end-to-end через harness — ещё нет.
- **НЕ читать STATUS.md как single source** для plan'а — handoff forward-looking, не replica STATUS.md.
- **НЕ читать STATUS.md как single source** для plan'а — handoff forward-looking, не replica STATUS.md.
## Memory updates за сессию
## Memory updates за сессию
- **Не сохранилось** — single observation про propagation gap не валидирована повторно, пока в NEXT_SESSION'е как finding, не в memory. Promote'ить если воспроизведётся.
- **Кандидат на feedback memory:** «PowerShell-style `$env:VAR` в Claude Code hook command'е на Windows ломается через git-bash outer shell — использовать литеральный абсолютный путь». Single observation воспроизведена и пофикшена в одной сессии, root cause confirmed двумя независимыми сигналами (user-side error + my "propagation gap"). Worth saving для предотвращения повтора на других hook'ах в будущем. **Не сохранил автоматически** — спросить user'а сохранять или нет.
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», «отбой», «разбегаемся»."
@@ -10,6 +10,8 @@ Opt-in PostToolUse hook that detects substantive `git commit` invocations and si
Add to `~/.claude/settings.json`. Use `powershell` for stock Windows (PS 5.1, always present); use `pwsh` if you have PowerShell 7+ installed. The hook script runs cleanly under both.
Add to `~/.claude/settings.json`. Use `powershell` for stock Windows (PS 5.1, always present); use `pwsh` if you have PowerShell 7+ installed. The hook script runs cleanly under both.
**Substitute `C:\\Users\\<you>` with your actual home path before pasting** — see "Why literal path" below.
```jsonc
```jsonc
{
{
"hooks":{
"hooks":{
@@ -19,7 +21,7 @@ Add to `~/.claude/settings.json`. Use `powershell` for stock Windows (PS 5.1, al
@@ -34,6 +36,16 @@ If `hooks.PostToolUse` already exists — append the matcher block to the array.
**Restart Claude Code after editing `settings.json`** — hooks are loaded at session start. A running session won't pick up the new hook until it's restarted (close + reopen the CC instance). Verify the hook is active by making a substantive commit and checking for a `Substantive commit detected on ...` system reminder in the next turn.
**Restart Claude Code after editing `settings.json`** — hooks are loaded at session start. A running session won't pick up the new hook until it's restarted (close + reopen the CC instance). Verify the hook is active by making a substantive commit and checking for a `Substantive commit detected on ...` system reminder in the next turn.
### Why literal path (no `$env:USERPROFILE` / `%USERPROFILE%` / `~`)
Claude Code on Windows invokes hook commands through **git-bash**, not PowerShell or cmd.exe directly. The outer-shell layer mangles shell-specific variable references before PowerShell ever sees the args:
-`$env:USERPROFILE` (PowerShell syntax) → bash treats `$env` as an empty variable and the rest `:USERPROFILE\...` becomes a literal, so PowerShell receives `-File ":USERPROFILE\..."` and fails with `неверный формат имени` / "invalid filename format".
-`%USERPROFILE%` (cmd syntax) → bash passes through literally, PowerShell doesn't expand it, same failure.
-`~/.claude/...` → bash expands `~` to git-bash-style `/c/Users/<you>/...`, which PowerShell's `-File` can't resolve to a real Windows path.
Literal absolute path with `C:\\Users\\<you>\\...` (escaped backslashes for JSON) survives every outer shell unchanged. `settings.json` is per-user anyway — portability across machines isn't a concern at this layer.
## Enable on Linux / macOS (bash)
## Enable on Linux / macOS (bash)
```jsonc
```jsonc
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.