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

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

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

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

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

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完全ガイドを先に読むと位置付けが掴みやすくなります。

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

Claude Codeがサポートするイベントは33種類あり、「セッション単位」「ターン単位」「ツール実行・エージェント単位」「非同期」の4グループに整理できます。ごく少数のイベントから始まりましたが、現在は権限ダイアログ・ファイル監視・worktree・タスク管理に加え、モデル切り替えまで対象が広がっています。設定ファイルの hooks.<イベント名> キーに配列で登録します。cdによる作業ディレクトリの変更だけを捉えるCwdChangedフックも用意されています。

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

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

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

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

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

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

非同期・ライフサイクル周辺(一部は同期的にブロック可)

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

WorktreeCreate だけは扱いが特殊で、定義すると git worktree による既定の作成処理を丸ごと置き換えます。SVNやPerforceでworktreeを切りたいときの差し替え点として用意されています。既定処理ごと置き換わるので、.worktreeinclude も処理されません。.env のようなファイルをコピーしたい場合は、Hookスクリプトの中で行ってください。

v2.1.251で加わったPreModelSwitchとPostModelSwitchは、モデル切り替えそのものをHookの対象にします。/modelやピッカーからの切り替えを事前に止めたり、切り替え後にモデル別の指示を差し込んだりできます。フォールバックやセッション再開時の自動復元ではPreModelSwitchは発火せず、PostModelSwitchだけが走ります。

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

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

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

運用ニーズ推奨イベント設計の要点
ファイル保存後の自動整形推奨イベントPostToolUse(matcher: Edit|Write)設計の要点stdinの tool_input.file_path を jq で取得して整形コマンドへ
危険コマンドの遮断推奨イベント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役割発火対象を絞る条件。評価規則は書いた文字によって3通りに切り替わる(後述)。空文字や * で全件
hooks[].type役割command / prompt / agent / http / mcp_tool の5種類
hooks[].command役割typeが command のときの実行文字列。stdinにイベントJSONが渡される
hooks[].timeout役割タイムアウト秒数の上書き(既定はtype別、後述)

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

置き場所スコープ共有可否
~/.claude/settings.jsonスコープ自分の全プロジェクト共有可否不可(マシンローカル)
.claude/settings.jsonスコープ単一プロジェクト共有可否可(リポジトリにコミット)
.claude/settings.local.jsonスコープ単一プロジェクト共有可否不可(gitignore対象)
管理ポリシー設定スコープ組織全体共有可否管理者制御
プラグインの hooks/hooks.jsonスコーププラグイン有効時共有可否プラグインに同梱
SkillのfrontmatterスコープSkill呼び出し後、そのセッションの終わりまで共有可否Skillファイル内
サブエージェントのfrontmatterスコープそのサブエージェントの実行中のみ共有可否エージェントファイル内

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

/hooks

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

Hookの5つの実行タイプ

Hookの実体はシェルコマンドだけではありません。typeフィールドで5種類の実行方式を選べます。httpタイプの設定項目はClaude CodeのHooksをHTTPエンドポイントで受けるで扱っています。

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_name と tool_input、UserPromptSubmit では prompt、SessionStart では source(startup / resume / clear / compact / fork)のようにイベント固有のフィールドが入ります。

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 はexit 2でもブロックされず、stderrが画面に出るだけで続行します。Setup と Notification はさらに割り切られていて、exit codeもstderrも無視されます。SetupとInstructionsLoadedの実務的な使い分けはClaude Code Setup/InstructionsLoadedフックの実務設定にまとめています。PostToolUse もツール実行が終わった後なので取り消せません。

一方で、ブロックできるイベントは PreToolUse / UserPromptSubmit / Stop だけではありません。次のイベントもexit 2で止められます。

イベントexit 2の効果
UserPromptExpansionexit 2の効果展開をブロック
SubagentStopexit 2の効果サブエージェントの停止を阻止
TeammateIdleexit 2の効果チームメイトの待機入りを阻止し、作業を続けさせる
TaskCreatedexit 2の効果タスクの作成を巻き戻す
TaskCompletedexit 2の効果完了扱いを阻止
ConfigChangeexit 2の効果設定変更の反映をブロック(policy_settings は対象外)
PostToolBatchexit 2の効果次のモデル呼び出し前にエージェントループを停止
PreCompactexit 2の効果コンパクションをブロック
PreModelSwitchexit 2の効果モデル切り替えをブロック

例外は PermissionRequest です。このイベントだけはexit 2が解釈されず、権限フローがそのまま進みます。拒否したいときは次節のJSON出力(hookSpecificOutput.decision)を使います。

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

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

  • decision: "block" + reason:PostToolUse / Stop / PreCompact 等で使うブロック指示
  • hookSpecificOutput.permissionDecision:PreToolUse(allow / deny / ask / defer)と PreModelSwitch(allow / deny / ask)で、権限フローやモデル切り替えを直接制御
  • hookSpecificOutput.updatedInput:PreToolUse でツールの引数そのものを書き換え
  • hookSpecificOutput.additionalContext:Claudeのコンテキストにテキストを注入
  • hookSpecificOutput.decision.behavior:PermissionRequest 専用。allow / deny でユーザーに代わって権限リクエストに応答
  • continue: false + stopReason:処理全体の停止

exit 2とJSON出力は排他ではありません。強いのはexit 2です。stdoutに permissionDecision: "allow" を書いてもブロックは覆りません。ただしJSON自体は読み捨てられず、systemMessage のような付随フィールドは併用できます。ブロック理由に使われるのは、JSONにブロック決定があればその reason、なければstderrの内容です。

matcherと条件付き実行(if)

ツール系イベントのmatcherはツール名で発火を絞ります。ここで見落としやすいのが、書いた文字によって評価のされ方が3通りに切り替わることです。

matcherの書き方評価例
* / 空文字 / 省略評価全件(そのイベントのすべての発火で走る)例(該当なし)
英数字と _ - 半角スペース , | のみ評価完全一致(| , 区切りなら列挙)例Bash / Edit|Write / Edit, Write
それ以外の文字を含む評価非アンカーのJavaScript正規表現例mcp__github__.*

つまり Edit|Write は正規表現ではなく完全一致のリストです。逆に正規表現として扱われた側は部分一致なので、Edit.* は NotebookEdit にも当たります。全体一致させたいときは ^Edit$ のようにアンカーを付けてください。MCPツール名は mcp__<サーバー名>__<ツール名> の形式です。

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

もう1点、落とし穴があります。if が評価されるのはツール系の5イベント(PreToolUse / PostToolUse / PostToolUseFailure / PermissionRequest / PermissionDenied)だけです。それ以外のイベントに if を書いたHookは、条件の内容にかかわらず一度も実行されません。エラーも出ません。Stop や SessionStart に付けて「動かない」と悩む前に、ここを確認してください。

実用レシピ — まず効果が出る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)で会話の詳細が失われたとき、SessionStart の compact matcherを使うと圧縮直後に必ず文脈を入れ直せます。stdoutに出力した内容がそのままClaudeのコンテキストに入ります。

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

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

Stop イベントにpromptタイプのHookを置くと、「やり残しがないか」をモデルに判定させ、未完了なら作業を続けさせられます。モノレポでは、Nxのaffectedと組み合わせて変更範囲だけを検証する設計をClaude CodeでNxのaffectedをフックから使う設計にまとめています。

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

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

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

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

matcherは完全一致でも正規表現でも大文字小文字を区別します。bash や edit と書くと静かにスキップされます。発火しないときはまず /hooks で登録状態を確認し、次にmatcherの綴りをツールの正式名(Bash / Edit / Write)と突き合わせます。

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

PostToolUse でexit 2を返しても、ツールの実行自体は既に終わっているため取り消せません。「やらせない」制御は PreToolUse / UserPromptSubmit 側に置きます。ただしPost系のexit 2が無意味なわけではありません。stderrの内容はClaudeにフィードバックされるので、「整形に失敗した」「テストが落ちた」を伝えて次の手を打たせる用途には使えます。

つまずき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 / PreModelSwitch / PostModelSwitch は30秒、MessageDisplay は10秒です。SessionEnd はさらに短く、1.5秒を全Hookで分け合います(個別の timeout を長くするとバジェットもその値まで上がり、上限は60秒)。

毎プロンプト前に走る処理に重いlintを仕込むと、体感が大きく悪化します。短時間で済む処理に絞るか、timeout フィールドを調整してください。処理そのものが長いなら、Hook定義に async: true を付けてバックグラウンドへ逃がします(この場合 timeout は適用されません)。

つまずき7:ワークスペースを信頼するまでHookは保留される

Claude Codeは設定ファイル由来のHookを実行する前にワークスペースの信頼状態を確認します。対話セッションでは、そのフォルダ(または信頼が及ぶ親ディレクトリ)の信頼ダイアログを承諾するまですべての設定ファイルのHookが保留されます。自分の ~/.claude/settings.json も例外ではありません。「グローバル設定に書いたのに新しいリポジトリで動かない」の典型的な原因がこれです。

逆方向のリスクもあります。-p フラグやAgent SDKのセッションでは信頼ダイアログが表示されず、フォルダは信頼済みとして扱われます。つまり、自分が信頼していないリポジトリの .claude/settings.json にコミットされたHookがそのまま走ります。他人のリポジトリに claude -p をかける前には、.claude/ 配下の設定を確認してください。あるいは --settings '{"disableAllHooks": true}' でHookを止めて実行します。

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

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

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が発火するかどうかは、そのセッションで権限リクエストが実際に上がるかで決まります。Agent SDKの canUseTool コールバックを持つ構成やバックグラウンドのサブエージェントでは、権限ダイアログを表示できなくてもHookは発火します。この場合、どのHookも決定を返さなければツール呼び出しが拒否されるので、許可・拒否を明示的に返してください。返し方は hookSpecificOutput.decision.behavior で、このイベントではexit 2が解釈されません。

一方、素の claude -p では権限プロンプト自体が発生しないため、PermissionRequest に掛けるものがありません。--permission-prompt-tool を指定した実行も同じく、権限判断の自動化は PreToolUse 側で行います。

PreToolUse には defer という判定値もあり、ツール呼び出しを保留したままAgent SDK側で入力を集めて再開する構成が組めます。これも非対話モード限定で、対話セッションでは警告が出て無視されます。もう1つ制約があり、働くのは1ターンのツール呼び出しが1つだけのときに限られます(複数同時のときは警告付きで無視され、通常の権限フローに進みます)。

まとめ

Claude Code Hooksは「観察」「副作用」「拒否」「文脈注入」をライフサイクル上の33イベントに割り当てる仕組みです。選び方の判断軸は次の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