Appearance
date: 2026-06-09 tags: [hooks, claude-code, session, enforcement, brainstorm] status: active graduated_to:
A PreToolUse gate hook is global across sessions — scope it by CLAUDE_CODE_SESSION_ID or it blocks concurrent agents
Symptom — brainstorm's gate.sh (PreToolUse, exit 2) held all code-writes / issue-creation / build-* whenever any brainstorm.md was stage != done. With a brainstorm and code work running in different agent sessions at once, an unrelated code agent — and a second brainstorm — got wrongly blocked.
Root cause — hooks fire for every tool call in every session; the gate scanned the repo globally for an active brainstorm with no notion of which session owned it.
Fix — the brainstorm stamps session: $CLAUDE_CODE_SESSION_ID into the doc frontmatter; gate.sh reads its own CLAUDE_CODE_SESSION_ID (same env var on both sides, so the values match) and treats a doc as active only when session: matches — fail-open when the id is unset or no doc is owned. A dead session's brainstorm then can't block a new one. (.claude/hooks/gate.sh, SHA 70d2dcc.)
Guard — gate.sh's active_doc() session filter + the session: stamp in the skill's frontmatter contract. Convention for any session-scoped enforcement hook: key on CLAUDE_CODE_SESSION_ID and fail open. Graduate into a hooks rule if a second such hook appears (Idea #386 generalises this gate across skills).