Claude Media
Claude Code Hooks完全ガイド — 30種類のイベント一覧と設定・実用レシピ

Claude Code Hooks完全ガイド — 30種類のイベント一覧と設定・実用レシピ

Claude Code Hooksは、ツール実行やセッション開始などのイベントに任意の処理を差し込む仕組みです。30種類の全イベント、settings.jsonの書き方、exit codeの意味、実用レシピとつまずき対策をまとめます。

Claude Code Hooksは、ツール実行・セッション開始終了・ユーザー入力・通知などのイベントに、ユーザー定義の処理を自動で差し込む仕組みです。「保存後の整形」「危険コマンドの遮断」「完了通知」のような繰り返し作業をClaude Codeの動作と一体化でき、LLMの判断任せではなく決定論的に必ず実行される点が最大の特徴です。

本記事では2026年6月時点でサポートされる30種類の全イベント、settings.json の構造と置き場所、exit codeとJSON出力による制御、実用レシピ、よくあるつまずきまでをまとめます。コピペで使えるレシピ集はClaude Code Hooks実例カタログ、最初の1個を動かす手順はClaude Code Hooksの設定方法(入門)で扱っているので、本記事は「全体像 + 仕様 + 設計判断」に集中します。

Claude Code Hooksとは

Claude Code Hooksとは、Claude Codeのライフサイクル上の特定のタイミングで自動実行される、ユーザー定義の処理(シェルコマンド・LLM評価・HTTP送信など)です。CLAUDE.mdに「編集後は必ずlintを実行して」と書く方法と違い、HooksはClaudeの判断を経由せず必ず実行されます。プロジェクトルールの強制・反復作業の自動化・既存ツールとの統合が主な用途です。

要点は次の5つです。

  • 設定ファイル ~/.claude/settings.json(全プロジェクト共通)または <project>/.claude/settings.json(プロジェクト固有)などに登録する
  • イベントの情報がJSONで標準入力(stdin)に渡されるので、jq などで必要な値を取り出して処理する
  • exit code 0で続行、exit code 2でブロック(ツール実行の拒否・プロンプト差し戻しなど、イベントによって効果が異なる)
  • 実行タイプは command(シェル)のほか、prompt(LLM評価)/ agent(サブエージェント検証)/ http(外部エンドポイント)/ mcp_tool(MCPツール呼び出し)の5種類
  • 同一イベントに複数のHookを登録すると並列実行され、同一コマンドは自動で重複排除される

Claude Code自体の全体像から知りたい場合はClaude Codeとは — エージェント型AIコーディングCLI完全ガイドを先に読むと位置付けが掴みやすくなります。

30種類のHookイベント一覧と発火タイミング

Claude Codeがサポートするイベントは2026年6月時点で30種類あり、「セッション単位」「ターン単位」「ツール実行・エージェント単位」「非同期」の4グループに整理できます。公開当初は1桁台のイベント数でしたが、現在は権限ダイアログ・ファイル監視・worktree・タスク管理まで対象が大きく広がっています。設定ファイルの hooks.<イベント名> キーに配列で登録します。

セッション単位(セッションごとに1回)

イベント名発火タイミング主な用途
SessionStart発火タイミングセッションの新規開始・再開時主な用途コンテキスト注入、環境変数の準備
Setup発火タイミング--init-only での起動時、または -p モードでの --init / --maintenance 実行時主な用途一度きりのセットアップ処理
SessionEnd発火タイミングセッション終了時主な用途後片付け、サマリ書き出し

ターン単位(ユーザー入力ごとに1回)

イベント名発火タイミング主な用途
UserPromptSubmit発火タイミングプロンプト送信時、処理前主な用途入力の検証・記録、コンテキスト追加
UserPromptExpansion発火タイミングスラッシュコマンドの展開時主な用途コマンド展開内容の検査
Stop発火タイミングClaudeが応答を完了した時主な用途完了通知、完了条件の検証
StopFailure発火タイミングAPIエラーでターンが終了した時主な用途失敗の記録・通知

ツール実行・エージェント単位

イベント名発火タイミング主な用途
PreToolUse発火タイミングツール実行の直前主な用途危険操作の遮断、入力の書き換え
PermissionRequest発火タイミング権限ダイアログの表示時主な用途許可判断の自動化
PermissionDenied発火タイミングツールが自動拒否された時主な用途拒否の記録、リトライ指示
PostToolUse発火タイミングツール実行の成功直後主な用途フォーマッタ、テスト、ログ
PostToolUseFailure発火タイミングツール実行の失敗直後主な用途失敗パターンの収集
PostToolBatch発火タイミング並列ツール呼び出し一式の完了後主な用途バッチ単位の検証
SubagentStart発火タイミングサブエージェントの起動時主な用途エージェント別の初期化
SubagentStop発火タイミングサブエージェントの完了時主な用途結果の集約・通知
TaskCreated発火タイミングタスクの作成時主な用途タスク管理ツールとの同期
TaskCompleted発火タイミングタスクの完了時主な用途進捗の外部記録
TeammateIdle発火タイミングチームのメンバーが待機に入る直前主な用途エージェントチーム運用の制御

非同期(メインの流れと独立に発火)

イベント名発火タイミング主な用途
Notification発火タイミングClaude Codeが通知を出した時主な用途OS通知・Slack連携
MessageDisplay発火タイミング応答テキストの表示時主な用途表示内容の加工
CwdChanged発火タイミング作業ディレクトリの変更時主な用途環境の切り替え
FileChanged発火タイミング監視対象ファイルの変更時主な用途設定ファイル変更の検知
ConfigChange発火タイミング設定ファイルの変更時主な用途設定変更の監査・ブロック
WorktreeCreate / WorktreeRemove発火タイミングworktreeの作成・削除時主な用途分離環境の準備と掃除
InstructionsLoaded発火タイミングCLAUDE.md等の読み込み時主な用途読み込まれた指示の追跡
PreCompact / PostCompact発火タイミングコンテキスト圧縮の直前・直後主な用途重要情報の退避と再注入
Elicitation / ElicitationResult発火タイミングMCPサーバーの入力要求時・応答時主な用途フォーム入力の自動化・記録

30種類すべてを覚える必要はありません。日常の自動化で使うのは PreToolUse / PostToolUse / Stop / Notification / SessionStart の5つが中心で、残りは「その境界で何かしたい」と思ったときに探せば足ります。

どのHookを選ぶか — 用途別早見表

実運用でよくあるニーズと推奨イベントの対応は次のとおりです。迷ったら「止めたいなら Pre* 系、観察して副作用を起こしたいなら Post* 系・Stop」が基本の判断軸になります。

運用ニーズ推奨イベント設計の要点
ファイル保存後の自動整形推奨イベントPostToolUse(matcher: Edit|Write)設計の要点stdinの tool_input.file_pathjq で取得して整形コマンドへ
危険コマンドの遮断推奨イベントPreToolUse(matcher: Bash)設計の要点コマンド文字列を検査してexit 2
保護ファイルへの書き込み遮断推奨イベントPreToolUse(matcher: Edit|Write)設計の要点パスが .env* 等に一致したらexit 2
長時間タスクの完了通知推奨イベントNotification または Stop設計の要点terminal-notifier やSlack Webhookを叩く
圧縮で消える文脈の再注入推奨イベントSessionStart(matcher: compact)設計の要点stdoutへの出力がClaudeのコンテキストに入る
完了条件を満たすまで止めない推奨イベントStop(type: prompt / agent)設計の要点"ok": false で作業を継続させる
権限ダイアログの自動応答推奨イベントPermissionRequest設計の要点JSON出力の behavior: "allow" で応答
コマンド実行ログの収集推奨イベントPostToolUse(matcher: Bash)設計の要点tool_input.command をファイルにappend
.env変更の検知推奨イベントFileChanged(matcher: .envrc|.env)設計の要点matcherはリテラルなファイル名の列挙
サブエージェント完了の集約推奨イベントSubagentStop設計の要点matcherにエージェント名を指定して振り分け

settings.jsonの構造と置き場所

Hooksは「イベント名 → matcherグループ → Hook定義の配列」という3階層で登録します。settings.json 全体のスキーマはClaude Code settings.json完全ガイドで扱っているので、ここではHooksに絞ります。

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "jq -r '.tool_input.file_path' | xargs prettier --write"
          }
        ]
      }
    ]
  }
}

主要キーの意味は次のとおりです。

キー役割
hooks.<イベント名>役割イベント別のmatcherグループ配列
matcher役割発火対象を絞る条件。ツール系イベントではツール名への正規表現マッチ。空文字や * で全件
hooks[].type役割command / prompt / agent / http / mcp_tool の5種類
hooks[].command役割typeが command のときの実行文字列。stdinにイベントJSONが渡される
hooks[].timeout役割タイムアウト秒数の上書き(既定はtype別、後述)

設定の置き場所は6箇所あり、スコープが異なります。

置き場所スコープ共有可否
~/.claude/settings.jsonスコープ自分の全プロジェクト共有可否不可(マシンローカル)
.claude/settings.jsonスコープ単一プロジェクト共有可否可(リポジトリにコミット)
.claude/settings.local.jsonスコープ単一プロジェクト共有可否不可(gitignore対象)
管理ポリシー設定スコープ組織全体共有可否管理者制御
プラグインの hooks/hooks.jsonスコーププラグイン有効時共有可否プラグインに同梱
Skill / エージェントのfrontmatterスコープそのコンポーネントの有効時共有可否コンポーネント定義内

複数の場所に同じイベントのHookを置くと両方とも実行されます。登録状態の確認はセッション内の /hooks コマンドで行えます。

/hooks

/hooks メニューは閲覧専用で、追加・変更は設定ファイルの直接編集(またはClaudeへの依頼)で行います。全Hookを一時停止したいときは設定に "disableAllHooks": true を書きます(管理ポリシー設定由来のHookを止めるには、管理ポリシー側にも同じ指定が必要です)。

Hookの5つの実行タイプ

Hookの実体はシェルコマンドだけではありません。typeフィールドで5種類の実行方式を選べます。

type実行されるもの既定タイムアウト
command実行されるものシェルコマンド(stdin入出力)既定タイムアウト10分
prompt実行されるものClaudeモデルによる単発の判定既定タイムアウト30秒
agent実行されるものツールアクセス付きサブエージェント検証既定タイムアウト60秒
http実行されるもの外部エンドポイントへのPOST既定タイムアウト10分
mcp_tool実行されるもの接続済みMCPサーバーのツール呼び出し既定タイムアウト10分

prompt タイプは「機械的なルールでは書けないが判断は単純」という場面に向きます。Hookの入力データとプロンプトをモデル(既定はHaiku)に渡し、"ok": true/false の判定だけを返させる方式です。たとえば Stop イベントに「依頼されたタスクがすべて完了しているか確認し、未完了なら理由を返す」というプロンプトを仕掛けると、Claudeは未完了のまま停止できなくなります。

agent タイプはさらに踏み込み、ファイル読み取りやコマンド実行のできるサブエージェントを起動して検証させます。最大50ターンのツール使用が許され、「テストを実際に走らせて全部通っているか確かめてから停止を許可する」といった実状態ベースの検証が書けます。ただしagent Hookは実験的機能と明記されており、本番運用では command タイプが推奨されています。サブエージェント自体の仕組みはClaude Code Sub-agents完全ガイドを参照してください。

入出力の仕組み — stdin JSONとexit code

Hookとの通信はstdin・stdout・stderr・exit codeの4経路で行われます。イベント発火時、Claude Codeはイベント固有のデータをJSONとしてHookのstdinに渡します。全イベント共通のフィールドは次のとおりです。

{
  "session_id": "abc123",
  "transcript_path": "~/.claude/projects/.../session.jsonl",
  "cwd": "/path/to/project",
  "permission_mode": "default",
  "hook_event_name": "PreToolUse"
}

これに加えて、PreToolUse / PostToolUse では tool_nametool_inputUserPromptSubmit では promptSessionStart では source(startup / resume / clear / compact)のようにイベント固有のフィールドが入ります。

exit codeの意味

Hookスクリプトのexit codeが次のアクションを決めます。

exit code挙動
0挙動成功。stdoutのJSONがあれば解釈される。SessionStart / UserPromptSubmit 等ではstdoutがClaudeのコンテキストに注入される
2挙動ブロック。stderrの内容がClaudeへのフィードバックになる。PreToolUse ならツール拒否、UserPromptSubmit ならプロンプト差し戻し、Stop なら停止の阻止
その他挙動非ブロックのエラー。stderrの1行目が画面に表示され、処理は続行

注意したいのは、exit 2の「ブロック」効果がイベントによって異なる点です。SessionStart / Setup / Notification などはexit 2でもブロックされず、stderrの表示のみで続行します。PostToolUse もツール実行が終わった後なので取り消し効果はありません。「やらせない」制御が効くのは実質的に PreToolUse / UserPromptSubmit / Stop 系が中心です。

JSON出力によるきめ細かい制御

exit codeは「ブロックするか黙るか」の2択しかありません。より細かく制御したいときは、exit 0でstdoutにJSONを出力します。代表的なフィールドは次のとおりです。

  • decision: "block" + reason:PostToolUse / Stop / PreCompact 等で使うブロック指示
  • hookSpecificOutput.permissionDecision:PreToolUse 専用。allow / deny / ask で権限フローを直接制御
  • hookSpecificOutput.updatedInput:PreToolUse でツールの引数そのものを書き換え
  • hookSpecificOutput.additionalContext:Claudeのコンテキストにテキストを注入
  • continue: false + stopReason:処理全体の停止

exit 2とJSON出力は併用できません。exit 2を返すとstdoutのJSONは無視されるため、「stderrで止める」か「exit 0 + JSONで細かく指示する」かのどちらかに統一します。

matcherと条件付き実行(if)

ツール系イベントのmatcherはツール名への正規表現マッチで、Bash(完全一致)/ Edit|Write(いずれか)/ mcp__github__.*(MCPツールの正規表現)のように書きます。MCPツール名は mcp__<サーバー名>__<ツール名> の形式です。

v2.1.85以降では if フィールドも使えます。これは権限ルールと同じ構文(Bash(git *) 等)で「ツール名 + 引数」まで見て発火を絞る仕組みで、「Bashの中でもgitコマンドのときだけ走らせる」が1行で書けます。ただしコマンドをパースできないときはHookが実行される方向に倒れる(fail-open)ため、確実な遮断は権限システム側で行い、if は実行回数の節約と考えるのが安全です。

実用レシピ — まず効果が出る5つ

設定例を5つ抜粋します。さらに多くのコピペ可能なレシピはClaude Code Hooks実例カタログにまとめています。

レシピ1:編集後にPrettierで自動整形(PostToolUse)

Edit|Write のmatcherで「ファイル編集ツールの直後」だけ発火させ、編集されたファイルパスを jq で取り出して整形します。

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "jq -r '.tool_input.file_path' | xargs prettier --write"
          }
        ]
      }
    ]
  }
}

レシピ2:保護ファイルへの書き込みを遮断(PreToolUse)

複雑な判定はスクリプトファイルに分離すると保守しやすくなります。${CLAUDE_PROJECT_DIR} はプロジェクトルートを指す変数で、cwdに依存せずスクリプトを参照できます。

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/protect-files.sh"
          }
        ]
      }
    ]
  }
}

スクリプト側では tool_input.file_path を保護パターン(.env / credentials 等)と照合し、一致したらstderrに理由を書いてexit 2します。Claudeにはその理由がフィードバックされるので、別の手段を考えて作業を続行できます。

レシピ3:gitコマンドだけポリシーチェック(if)

matcher: "Bash" だけだと全シェルコマンドでHookプロセスが起動しますが、if を足すとgitコマンドのときだけ起動します。

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "if": "Bash(git *)",
            "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/check-git-policy.sh"
          }
        ]
      }
    ]
  }
}

レシピ4:コンテキスト圧縮後に重要情報を再注入(SessionStart)

コンテキスト圧縮(compaction)で会話の詳細が失われたとき、SessionStartcompact matcherを使うと圧縮直後に必ず文脈を入れ直せます。stdoutに出力した内容がそのままClaudeのコンテキストに入ります。

{
  "hooks": {
    "SessionStart": [
      {
        "matcher": "compact",
        "hooks": [
          {
            "type": "command",
            "command": "git log --oneline -5"
          }
        ]
      }
    ]
  }
}

レシピ5:タスク完了までClaudeを止めない(Stop + prompt)

Stop イベントにpromptタイプのHookを置くと、「やり残しがないか」をモデルに判定させ、未完了なら作業を続けさせられます。

{
  "hooks": {
    "Stop": [
      {
        "hooks": [
          {
            "type": "prompt",
            "prompt": "Check if all tasks are complete. If not, respond with {\"ok\": false, \"reason\": \"what remains to be done\"}."
          }
        ]
      }
    ]
  }
}

よくあるつまずきと回避策

実運用で踏みやすい落とし穴を7つ挙げます。

つまずき1:matcherの大文字小文字違いで発火しない

matcherはツール名への大文字小文字を区別するマッチです。bashedit と書くと静かにスキップされます。発火しないときはまず /hooks で登録状態を確認し、次にmatcherの綴りをツールの正式名(Bash / Edit / Write)と突き合わせます。

つまずき2:exit 2でブロックしたつもりがPost系では効かない

PostToolUse でexit 2を返しても、ツールの実行自体は既に終わっているため取り消せません。「やらせない」制御は PreToolUse / UserPromptSubmit 側に置きます。

つまずき3:シェルプロファイルの出力がJSONを壊す

commandタイプのHookは非対話シェルで実行されますが、環境によっては ~/.bashrc 等のプロファイルが読み込まれます。プロファイルに無条件の echo があると、その出力がHookのJSON出力の前に混ざりパースエラーになります。プロファイル側で if [[ $- == *i* ]]; then echo ...; fi のように対話シェル限定にするのが根本対策です。

つまずき4:stdinのJSON構造がイベントごとに違う

tool_input / prompt / source など、stdinの構造はイベントごとに異なります。実装前にサンプルJSONをパイプで流して手元でテストすると確実です。

echo '{"tool_name":"Bash","tool_input":{"command":"ls"}}' | ./my-hook.sh
echo $?

つまずき5:複数Hookの実行順序に依存した設計

同一イベントの複数Hookは並列実行され、完了順は非決定的です。特に複数の PreToolUse Hookが updatedInput で同じツールの引数を書き換えると「最後に終わったものが勝つ」ため、引数を書き換えるHookは1イベントにつき1つに絞ります。

つまずき6:長時間処理でタイムアウト・応答悪化

commandタイプの既定タイムアウトは10分ですが、UserPromptSubmit は30秒、MessageDisplay は10秒に短縮されています。毎プロンプト前に走る処理に重いlintを仕込むと体感が大きく悪化するので、短時間で済む処理に限定するか timeout フィールドの調整と非同期化で逃がします。

つまずき7:設定したのに反映されない

設定ファイルの編集は通常ファイルウォッチャーが自動で拾いますが、数秒待っても /hooks に出ないときはセッションを再起動します。JSONの構文エラー(末尾カンマ・コメント)と置き場所の間違いも定番の原因です。デバッグの最終手段はデバッグログの確認で、起動時に出力先を指定して別ターミナルから追跡します。

claude --debug-file /tmp/claude.log
tail -f /tmp/claude.log

よくある質問

HooksとCLAUDE.mdの指示はどう使い分ければよいですか?

「必ず実行されるべき処理」はHooks、「判断の指針」はCLAUDE.mdです。CLAUDE.mdの指示はClaudeが読んで従う前提のため、忘れたり優先度を下げたりする余地があります。Hooksはライフサイクルに機械的に組み込まれるため、整形・遮断・通知のような決定論的ルールに向きます。

bypassPermissionsモードでもHooksは効きますか?

効きます。PreToolUse Hookは権限モードのチェックより前に発火し、permissionDecision: "deny" を返せば bypassPermissions モードや --dangerously-skip-permissions 指定でもツール実行をブロックできます。逆に、Hookの allow が設定側のdenyルールを上書きすることはできません。Hooksは制限を強める方向にだけ働きます。

Hooksでツールの引数を書き換えられますか?

書き換えられます。PreToolUse HookがJSON出力の hookSpecificOutput.updatedInput を返すと、ツールはその引数で実行されます。たとえば「特定ディレクトリへの書き込みを安全な場所へ付け替える」「コマンドにフラグを強制付与する」といった介入が可能です。

サブエージェントの動作にもHooksは発火しますか?

発火します。サブエージェント内のツール実行でも PreToolUse / PostToolUse が走り、stdinの agent_id / agent_type フィールドでメインセッションと区別できます。サブエージェント自体の起動・完了は SubagentStart / SubagentStop で捕捉でき、matcherにエージェント名を指定して振り分けます。

ヘッドレスモード(-pフラグ)での注意点はありますか?

PermissionRequest Hookは非対話モードでは発火しません。CI等で権限判断を自動化したい場合は PreToolUse Hookの permissionDecision を使います。また PreToolUse には defer という判定値があり、非対話モードでツール呼び出しを保留したままAgent SDK側で入力を集めて再開する構成も組めます。

まとめ

Claude Code Hooksは「観察」「副作用」「拒否」「文脈注入」をライフサイクル上の30イベントに割り当てる仕組みです。選び方の判断軸は次の3つに集約されます。

  1. 止めたい・書き換えたいなら PreToolUse / UserPromptSubmit:exit 2またはJSON出力で「やらせない」「引数を直す」が効く
  2. 観察・副作用なら PostToolUse / Stop / Notification:整形・テスト・通知・ログはこちら
  3. 判断が必要なら prompt / agent タイプ:機械的ルールで書けない検証はモデルに委ねる

仕様の全体像を押さえたら、Claude Code Hooks実例カタログのレシピから自分の運用に近いものを1つ動かしてみてください。設定ファイル全体の設計はClaude Code settings.json完全ガイド、サブエージェントとの組み合わせはClaude Code Sub-agents完全ガイドが次の一歩になります。Hooksは導入難度が低く効果が運用全体に長く効く領域なので、最初の1個から始めて運用の摩擦を消すたびに増やしていく形が続けやすいでしょう。

この記事を共有:XはてブLinkedIn