Hooks that need live session state only receive the transcript
Type: feature-request
Environment
- Claude Code version: 2.1.220
- OS: macOS 26.5.2 (Darwin 25.5.0)
- Platform: Claude subscription
What happened
We built a Stop-event gate that is supposed to check whether the work of a long unattended run actually finished before letting the session end. The only session-scoped input available to a hook is the transcript path, so the gate has to infer the current state by reading back what the model wrote earlier in the conversation.
That is inherently unreliable, and it fails in both directions:
- False positives: the gate fired on legitimate in-flight waits at least five times in one run, each costing a justification turn. In another run it fired three times in a single session for the same reason.
- Stale reads: an ownership marker written during an early phase of the run was still present in the transcript hours later and was read as the current state.
- Wrong identifiers: a naive read of the transcript head picks up injected memory and instruction content, so identifiers belonging to other work appear as if they belonged to this session. We had a guard extract the wrong work item this way and block a legitimate action.
The general shape: a hook that needs to know "what is this session currently doing" is forced to parse prose that was written for a human, and prose is not a state machine.
Expected
A structured, machine-readable session state object passed to hooks (or available via a small local query), covering at least: current working directory, current branch, active model, number of compactions so far, and the tool calls of the current turn — separated from injected instruction/memory content, so a hook can tell session facts from injected text.
This does not need to be a large surface. Even cwd + branch + model + "injected vs. authored" flags on transcript entries would remove most of the guesswork.
Repro
- Register a
Stophook and inspect its input: it receives a transcript path and little else. - Have it try to determine whether the session is currently waiting on an external process versus finished. There is no reliable signal to read.
Impact
Every user-built guardrail on top of hooks has to be probabilistic, which means it either produces false alarms (each one costing a turn) or is set so loose that it does not guard. Structured state is the difference between a deterministic hook and a heuristic one.