[FEATURE] Add turn_status field to Stop hook payload (done vs waiting_on_user)

Resolved 💬 1 comment Opened Apr 16, 2026 by ojhurst Closed May 24, 2026
  • [x] I searched existing issues and didn't find a duplicate
  • [x] This is a single feature request

Problem Statement

The Stop hook fires at every end-of-turn with the same payload (session_id, transcript_path, stop_hook_active) regardless of whether the assistant finished its work or is genuinely waiting for the user to respond. Hooks that want to react differently in those two cases — reminder/nudge systems, approval queues, "did Claude ask a question I missed?" notifications — have to parse the last assistant text themselves.

Text-based heuristics miss rhetorical questions, quoted questions, and asks phrased with unusual wording. LLM-based classifiers add 2+ seconds of latency per turn-end, which is prohibitive.

Concrete scenario: I built a nudge system that writes a reminder file when Claude finishes a turn waiting on user input. A daemon speaks that reminder aloud after 5 minutes of silence. The regex-based matcher in the hook only checks the final sentence, so responses like:

Want me to build X? Here is what it would do...

(question in the penultimate sentence) silently drop to the floor. False negatives mean I lose my train of thought because no reminder fires.

Proposed Solution

Add a turn_status field to the Stop hook payload:

{
  "session_id": "...",
  "transcript_path": "...",
  "stop_hook_active": false,
  "turn_status": "done"
}

With values "done" or "waiting_on_user". Claude already knows internally whether it ended the turn with a question/ask or a completion — this just exposes it to hooks.

Hook code becomes a one-liner:

TURN_STATUS=$(echo "$INPUT" | jq -r '.turn_status')
if [ "$TURN_STATUS" = "waiting_on_user" ]; then
  # write the nudge / surface the prompt / add to approval queue
fi

Alternative Solutions

  1. Regex-based last-text matching — brittle, misses edge cases (rhetorical questions, unusual phrasings, asks not in the final sentence).
  2. Send last assistant text to an LLM classifier (claude -p) — adds ~2 seconds per turn-end, costs capacity.
  3. Require the model to emit a special end-of-turn token — adds prompt burden, still requires parsing.

None work as well as a deterministic server-side flag.

Priority

Medium

Feature Category

Developer tools

Use Case Example

Escalating-nudge daemon: the assistant finishes a turn asking a question. After 5 minutes of silence the daemon speaks "First reminder…" with the last two sentences of context; at 10 minutes "Second reminder…"; at 15 minutes "Final reminder…". When the user responds, a UserPromptSubmit hook clears the reminder file. Without turn_status, the Stop hook has to classify intent from text. A single .turn_status == "waiting_on_user" check would eliminate all the guessing.

Additional Context

This blocks any hook that wants to react differently to "Claude is done" vs "Claude is asking you something" — approval queues, audit logs, reminder systems, focus-mode integrations, voice modes.

Environment

  • Claude Code Version: 2.1.112
  • Platform: Anthropic API (Max subscription)
  • Operating System: macOS 26.3.1 (arm64, Apple M2 Pro, 16 GB)
  • VS Code: 1.114.0
  • VS Code extension: anthropic.claude-code 2.1.112
  • Terminal/Shell: VS Code integrated terminal, zsh 5.9

View original on GitHub ↗

This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗