第5章 フック
「ファイルを編集したら毎回フォーマッタを実行してほしい」「特定のコマンドは絶対にブロックしたい」——
こうした 確実に毎回実行される自動処理 は、プロンプトや CLAUDE.md への記述では実現できません。
モデルは指示を「忘れる」可能性があるからです。
フック(Hooks) は、エージェントループの特定のタイミングでハーネスが 必ず 実行するシェルコマンドです。
モデルの判断を介さないため、決定論的に動作します。
5.1 フックイベント一覧
Section titled “5.1 フックイベント一覧”| イベント | 発火タイミング | 主な用途 |
|---|---|---|
| PreToolUse | ツール実行の直前 | 危険なコマンドのブロック、入力の検証 |
| PostToolUse | ツール実行の直後 | フォーマッタ・Lint の自動実行 |
| UserPromptSubmit | ユーザーがプロンプトを送信した時 | コンテキストの自動注入、入力チェック |
| Notification | Claude が許可待ち・入力待ちになった時 | デスクトップ通知・Slack 通知 |
| Stop | Claude が応答を完了した時 | 完了通知、後続処理のトリガー |
| SubagentStop | サブエージェントが完了した時 | サブタスクの結果検証 |
| PreCompact | コンパクション(要約)の直前 | 履歴のバックアップ |
| SessionStart | セッション開始時 | 環境情報の注入 |
| SessionEnd | セッション終了時 | クリーンアップ、ログ記録 |
flowchart LR
U["UserPromptSubmit"] --> Pre["PreToolUse"]
Pre --> T["ツール実行"]
T --> Post["PostToolUse"]
Post --> Pre
Post --> S["Stop"]
5.2 基本的な設定方法
Section titled “5.2 基本的な設定方法”フックは settings.json の hooks セクションに定義します。
matcher でどのツールに反応するかを絞り込めます。
{ "hooks": { "PostToolUse": [ { "matcher": "Edit|Write", "hooks": [ { "type": "command", "command": "pnpm biome check --write \"$(jq -r '.tool_input.file_path' <<< \"$CLAUDE_HOOK_INPUT\")\" 2>/dev/null || true" } ] } ] }}この例では、Edit / Write ツールでファイルが変更されるたびに Biome フォーマッタが自動実行されます。
フックコマンドには、イベントの詳細(ツール名・入力パラメータなど)が JSON として標準入力 から渡されます。jq で必要なフィールドを取り出すのが定番パターンです。
5.3 PreToolUse でのブロック — 終了コードによる制御
Section titled “5.3 PreToolUse でのブロック — 終了コードによる制御”フックの 終了コード には意味があります。
| 終了コード | 意味 |
|---|---|
| 0 | 続行を許可。 標準出力は(イベントにより)コンテキストに追加される |
| 2 | ブロック。 標準エラー出力がモデルにフィードバックされる |
| その他 | エラーとして扱われるが実行は続行 |
危険なコマンドを確実にブロックする例:
{ "hooks": { "PreToolUse": [ { "matcher": "Bash", "hooks": [ { "type": "command", "command": "python3 ~/.claude/hooks/block-dangerous.py" } ] } ] }}import json, re, sys
data = json.load(sys.stdin)command = data.get("tool_input", {}).get("command", "")
BLOCKED = [r"rm\s+-rf\s+/", r"git\s+push\s+--force\s+.*main"]
for pattern in BLOCKED: if re.search(pattern, command): print(f"ブロック: '{command}' は禁止パターンに一致します", file=sys.stderr) sys.exit(2) # 終了コード2 = ブロックし、理由をモデルに伝える
sys.exit(0)5.4 実用レシピ集
Section titled “5.4 実用レシピ集”編集後にテストを自動実行
Section titled “編集後にテストを自動実行”{ "hooks": { "PostToolUse": [ { "matcher": "Edit|Write", "hooks": [ { "type": "command", "command": "pnpm test --silent --passWithNoTests" } ] } ] }}許可待ちになったらデスクトップ通知(macOS)
Section titled “許可待ちになったらデスクトップ通知(macOS)”{ "hooks": { "Notification": [ { "matcher": "", "hooks": [ { "type": "command", "command": "osascript -e 'display notification \"Claude が入力を待っています\" with title \"Claude Code\"'" } ] } ] }}全ツール実行をログに記録(監査用)
Section titled “全ツール実行をログに記録(監査用)”{ "hooks": { "PreToolUse": [ { "matcher": "", "hooks": [ { "type": "command", "command": "jq -c '{time: now, tool: .tool_name, input: .tool_input}' >> ~/.claude/tool-audit.jsonl" } ] } ] }}5.5 フック設計の注意点
Section titled “5.5 フック設計の注意点”- フックは無条件に実行される — モデルの判断を通らないため、フック自体のバグはすべてのセッションに影響します。
まず手動でスクリプトをテストしてから登録しましょう - 実行時間に注意 — 重いフック(フルテストスイートなど)は毎回の編集を遅くします。
対象を絞るか、軽量なチェックに留めます - 信頼できる設定のみ — フックは任意のシェルコマンドを実行します。
他人のリポジトリの.claude/settings.jsonに悪意あるフックが含まれる可能性に注意してください(初回に確認プロンプトが表示されます) - 設定変更後は
/hooksコマンドで現在有効なフックを確認できます
- フックは、エージェントループの特定タイミングでハーネスが必ず実行する処理。
「毎回確実に」はフックで実現する - PreToolUse(実行前の検証・ブロック)と PostToolUse(フォーマット・テスト)が二大用途
- 終了コード 2 でツール実行をブロックし、理由をモデルにフィードバックできる
- 強力な分、フック自体の品質とセキュリティには注意が必要