[DOCS] Unspecified multi-hook PreToolUse semantics (execution order, updatedInput visibility, conflict resolution)

Open 💬 3 comments Opened Jun 8, 2026 by karlkfi

Documentation Type

Missing documentation (feature not documented)

Documentation Location

https://code.claude.com/docs/en/hooks

Section/Topic

Hooks reference — PreToolUse behavior when multiple hooks match the same tool call

Current Documentation

The hooks reference documents single-hook behavior well: permissionDecision (allow/ask/deny) and hookSpecificOutput.updatedInput for rewriting a tool's input. For the multiple-hook case it only says matching hooks run "in series or parallel depending on configuration," and that deny takes precedence for permission rules. It does not describe how multiple PreToolUse hooks on the same tool interact.

What's Wrong or Missing?

When multiple PreToolUse hooks match the same tool call — a common real-world setup: a project .claude/settings.json hook plus one or more plugin hooks on the Bash matcher — the following are all unspecified:

  1. Execution order. "in series or parallel depending on configuration" doesn't state what configuration controls it, the default, or any ordering between scopes (project vs. plugin) or within a matcher (registration order).
  2. updatedInput visibility across hooks. If hook A returns updatedInput (rewriting tool_input.command), does hook B evaluating the same call see the original command or the rewritten one? Isolation vs. chaining is undocumented.
  3. Conflicting rewrites. If two hooks both return updatedInput for the same call, how is the conflict resolved (last-wins / merge / undefined)?
  4. Decision aggregation with rewrites. deny precedence is documented for permission rules, but the hook-to-hook aggregation of permissionDecision together with updatedInput is not.

Why it matters: you can't reason about correctness or security of a multi-hook setup without these guarantees. Can a hook that rewrites a Bash command change what a separate security-guard hook sees and decides for the same call? Does a hook's updatedInput even take effect when other PreToolUse hooks are registered?

This is not theoretical — it has been reported repeatedly and closed without a fix or documentation:

  • #15897 — "updatedInput PreToolUse response does not work when multiple PreToolUse hooks are executed" (with a root-cause analysis: a later passthrough hook's empty result overwrites an earlier hook's updatedInput). Closed NOT_PLANNED.
  • #11282 — "PreToolUse hook unable to both modify the tool inputs AND request user consent." Closed NOT_PLANNED.
  • #21533 — "[FEATURE] Sequential Hook Execution Option." Closed NOT_PLANNED.

Even if the behavior won't change, documenting the actual current semantics would let users design hooks that compose safely.

Suggested Improvement

Add a "Multiple matching hooks" subsection to the PreToolUse documentation that specifies:

  1. the execution order (or an explicit statement that hooks are unordered / run in parallel), including ordering across scopes (project vs. plugin) and within a matcher;
  2. whether updatedInput from one hook is visible to other hooks evaluating the same call (input isolation vs. chaining);
  3. the conflict-resolution rule when multiple hooks return updatedInput;
  4. how permissionDecision aggregates across hooks and how it interacts with updatedInput.

If the current behavior is that updatedInput is dropped when multiple hooks run (per #15897), state that explicitly so users don't rely on a rewrite that silently no-ops.

Impact

Medium - Makes feature difficult to understand

Additional Context

  • Claude Code 2.1.168, macOS.
  • Real setup that surfaced this: three PreToolUse hooks on the Bash matcher (a project hook that prepends a CPU/IO-throttle prefix to go build/go test, plus two guard plugins). The docs gave no way to determine whether the throttle rewrite is visible to the guards, or whether it applies at all when the guards are also registered.

View original on GitHub ↗

This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗