Claude Code HooksのPreToolUseとPermissionRequestの違い¶
Claude Code の Hooks には PreToolUse と PermissionRequest の2種類がある。両者はツール実行前に介入できる点は共通だが、発火タイミングと役割が異なる。
比較まとめ¶
deny ルール |
PreToolUse フック |
PermissionRequest フック |
|
|---|---|---|---|
| 仕組み | 宣言的なパターンマッチング | カスタムスクリプトによる動的判断 | パーミッションダイアログ直前に介入 |
| 柔軟性 | グロブパターンのみ | 任意のロジック(引数の中身まで検査可能) | 任意のロジック |
| 発火タイミング | ツール呼び出し後すぐ | deny ルールより前 | allow/deny どちらにも解決されなかった場合 |
| 用途 | シンプルなブロックルール | 複雑な条件判断・入力書き換え・ログ記録 | ダイアログ表示の自動化・委任 |
評価フローの詳細は Claude Codeのパーミッション評価フローとダイアログ表示条件 を参照。
PreToolUse¶
ツール呼び出しの最初に発火する。deny ルールよりも先に評価されるため、あらゆる操作をフックで制御できる。
設定の基本構造¶
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "/path/to/your-script.sh"
}
]
}
]
}
}
フックが受け取るデータ(stdin)¶
{
"hook_event_name": "PreToolUse",
"tool_name": "Bash",
"tool_input": { "command": "rm -rf /tmp/old" },
"session_id": "abc123",
"cwd": "/home/user/project"
}
スクリプトからの応答(stdout)¶
{
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "allow",
"permissionDecisionReason": "安全な操作です",
"updatedInput": { "command": "rm -rf /tmp/old --dry-run" },
"additionalContext": "Claudeへの追加情報"
}
}
permissionDecision:allow/block/ask_userupdatedInput: ツール入力を書き換える(オプション)
exit code による制御¶
| exit code | 動作 |
|---|---|
0 |
成功。stdout の JSON で詳細制御 |
2 |
ブロック。ツール実行を停止、stderr がエラーメッセージになる |
| その他 | 非ブロッキングエラー(実行は継続) |
実用例:危険コマンドのブロック¶
#!/bin/bash
INPUT=$(cat)
CMD=$(echo "$INPUT" | jq -r '.tool_input.command')
# rm -rf を含むコマンドをブロック
if echo "$CMD" | grep -q "rm -rf"; then
echo "危険なコマンドをブロックしました: $CMD" >&2
exit 2
fi
exit 0
PermissionRequest¶
パーミッションダイアログが表示される直前に発火する。allow にも deny にも解決されなかった操作に対してのみ呼び出される。matcher には引数レベルのパターンも使える。
設定の基本構造¶
{
"hooks": {
"PermissionRequest": [
{
"matcher": "Bash(npm test*)",
"hooks": [
{
"type": "command",
"command": "/path/to/validate.sh"
}
]
}
]
}
}
フックが受け取るデータ(stdin)¶
{
"hook_event_name": "PermissionRequest",
"tool_name": "Bash",
"tool_input": { "command": "npm test -- --coverage" },
"session_id": "abc123"
}
スクリプトからの応答(stdout)¶
{
"hookSpecificOutput": {
"hookEventName": "PermissionRequest",
"decision": {
"behavior": "allow",
"updatedInput": { "command": "npm test" }
}
}
}
behavior:allow/deny/ask_user- フックが何も返さず
exit 0で終了した場合は、デフォルトの挙動(ユーザーへのプロンプト表示)にフォールスルー
実用例:npm test を自動承認するスクリプト¶
#!/bin/bash
INPUT=$(cat)
CMD=$(echo "$INPUT" | jq -r '.tool_input.command')
if echo "$CMD" | grep -q "^npm test"; then
echo '{"hookSpecificOutput":{"hookEventName":"PermissionRequest","decision":{"behavior":"allow"}}}'
exit 0
fi
# それ以外はユーザーに委ねる
echo '{"hookSpecificOutput":{"hookEventName":"PermissionRequest","decision":{"behavior":"ask_user"}}}'
exit 0
matcher の書き方¶
"Bash" → Bashツールのみ
"Write|Edit" → WriteまたはEdit
"*" → すべてのツール
"Bash(npm test*)" → npm test で始まるBashコマンドのみ(PermissionRequestで有効)
"mcp__memory__.*" → memoryサーバーのMCPツールすべて
注意:matcher は大文字・小文字を区別する("bash" では Bash ツールにマッチしない)。
設定ファイルの場所¶
フックは3段階のレベルで管理できる。
| ファイル | 適用範囲 |
|---|---|
~/.claude/settings.json |
ユーザー全体のグローバル設定 |
.claude/settings.json |
リポジトリ内のプロジェクト共有設定(Git管理可能) |
.claude/settings.local.json |
コミットしたくない個人用ローカル設定 |
関連¶
引用元: Claude