1 ファイル変更+32-2

この更新の概要

複数のフックが同一イベントにマッチした際の動作仕様と、結果の統合ルールに関する詳細な説明が追加されました。PreToolUseフックにおいて、最も制限の強い判定(deny > ask > allow)が最終的な決定として採用される仕組みが明確化されています。また、一方が拒絶(deny)を返しても他のフックの実行は停止されないため、副作用の抑制を目的としたフック設計には注意が必要であると記されています。Bashツールを利用した具体的な実装例が追記され、ログ記録と制限スクリプトが並行して動作する様子が示されました。

hooks-guide+32-2

複数のフックがマッチした際の結果の優先順位や、フックが並列に実行される仕様についての詳細な解説が追加されました。Bashコマンドのログ出力と実行制限を同時に行う具体的なJSON設定例と、その挙動に関する説明が追記されています。

@@ -437,8 +437,6 @@ Hook events fire at specific lifecycle points in Claude Code. When an event fire
| `ElicitationResult` | After a user responds to an MCP elicitation, before the response is sent back to the server |
| `SessionEnd` | When a session terminates |
When multiple hooks match, each one returns its own result. For decisions, Claude Code picks the most restrictive answer. A `PreToolUse` hook returning `deny` cancels the tool call no matter what the others return. One hook returning `ask` forces the permission prompt even if the rest return `allow`. Text from `additionalContext` is kept from every hook and passed to Claude together.
Each hook has a `type` that determines how it runs. Most hooks use `"type": "command"`, which runs a shell command. Four other types are available:
- `"type": "http"`: POST event data to a URL. See [HTTP hooks](#http-hooks).
@@ -446,6 +444,38 @@ Each hook has a `type` that determines how it runs. Most hooks use `"type": "com
- `"type": "prompt"`: single-turn LLM evaluation. See [Prompt-based hooks](#prompt-based-hooks).
- `"type": "agent"`: multi-turn verification with tool access. Agent hooks are experimental and may change. See [Agent-based hooks](#agent-based-hooks).
### Combine results from multiple hooks
When multiple hooks match the same event, every hook's command runs to completion before Claude Code merges the results. One hook returning `deny` does not stop sibling hooks from executing. Don't rely on one hook's `deny` to suppress side effects in another hook.
After all matching hooks finish, Claude Code combines their outputs. For `PreToolUse` permission decisions, the most restrictive answer wins: `deny` overrides `ask`, which overrides `allow`. Text from `additionalContext` is kept from every hook and passed to Claude together.
The example below registers two `PreToolUse` hooks on `Bash`. The first appends every command to a log file and exits 0. The second runs a script that exits 2 to deny when the command contains `rm -rf`:
```json
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "jq -r .tool_input.command >> ~/.claude/bash.log"
},
{
"type": "command",
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/block-rm-rf.sh"
}
]
}
]
}
}
```
When Claude tries to run `rm -rf /tmp/build`, both hooks execute in parallel. The logging hook writes the command to `~/.claude/bash.log` and exits 0, which reports no decision. The guardrail hook exits 2, which denies the tool call. The deny wins, so Claude Code blocks the command and shows Claude the guardrail's stderr. The log entry is still written because the logging hook already ran.
### Read input and return output
Hooks communicate with Claude Code through stdin, stdout, stderr, and exit codes. When an event fires, Claude Code passes event-specific data as JSON to your script's stdin. Your script reads that data, does its work, and tells Claude Code what to do next via the exit code.