PreToolUse: include the assistant message id (or guarantee the tool_use is flushed) so hooks can bind a call to its transcript record

Status Open
Reported on v2.1.292
Maintainer reply None cached
Activity 0 comments · opened Oct 8, 2026

What's wrong

PreToolUse hooks get transcript_path, tool_use_id and the schema-parsed tool_input. On 2.1.29x, the transcript often does not yet contain the pending tool_use, or the text earlier in the same assistant message, when the hook runs. This is the behavior described in #100051.

  • Short sessions: on 2.1.292 (Linux, interactive TUI, default settings), the record was missing at hook entry for every lone guarded call and appeared about 150 ms later.
  • Longer sessions: users of interactive and --bg sessions report that the record arrives only with the tool result, so a hook that polls the transcript never sees it.

Separately, the transcript keeps the model's raw tool input, while the hook receives the schema-parsed input:

  • With CLAUDE_CODE_FORK_SUBAGENT on (the interactive default on 2.1.292), the Agent schema has no run_in_background.
  • A model that sends run_in_background anyway has it in the transcript (as the string "false") and not in the hook payload.
  • A hook that compares the two copies therefore sees a mismatch it cannot explain.

What would fix it

Hooks that enforce ordering rules need either of these:

  1. The assistant message.id of the message that contains this tool_use, included in the PreToolUse payload.
  2. A documented guarantee that the assistant message, up to and including this tool_use, is written to the transcript before PreToolUse runs.

It would also help to document which normalizations PreToolUse applies to tool_input, or to include the raw input, so hooks can compare the two copies exactly.

Why it matters

gstack's /autoplan uses a PreToolUse guard. It checks that each review phase's report was shown to the user before the next phase starts. To work on 2.1.29x, it now evaluates the hook payload against the journaled records and treats the dropped run_in_background key as a known strip. Either change above would let it retire those heuristics and rely on a supported surface.

Environment

  • Claude Code 2.1.292 and 2.1.293
  • Linux x86_64
  • Interactive TUI, claude --bg with claude attach, and claude -p

View original on GitHub ↗