Skip to main content
Hooks はユーザー定義のシェルコマンドです。Claude Code はそのライフサイクルの特定のポイントで実行され、決定論的な制御を提供します。LLM が実行を選択するのに依存するのではなく、特定のアクションが常に発生します。Hooks を使用して、プロジェクトルールを適用し、反復的なタスクを自動化し、Claude Code を既存のツールと統合します。 判断が必要な決定については、決定論的なルールではなく、Claude モデルを使用して条件を評価する プロンプトベースの hooks または エージェントベースの hooks を使用することもできます。 Claude Code を拡張する他の方法については、Claude に追加の指示と実行可能なコマンドを与えるための skills、分離されたコンテキストでタスクを実行するための subagents、プロジェクト全体で共有する拡張機能をパッケージ化するための plugins を参照してください。
このガイドでは一般的なユースケースと始め方をカバーしています。完全なイベントスキーマ、JSON 入力/出力形式、非同期 hooks や MCP ツール hooks などの高度な機能については、Hooks リファレンス を参照してください。

最初の hook をセットアップする

Hook を作成するには、設定ファイル に hooks ブロックを追加します。このチュートリアルではデスクトップ通知 hook を作成するため、Claude があなたの入力を待っているときにアラートを受け取ることができます。ターミナルを監視する代わりに。
1

hook を設定に追加する

~/.claude/settings.json を開き、Notification hook を追加します。ファイルが存在しない場合は、作成してください。以下の例は macOS 用に osascript を使用しています。Linux と Windows のコマンドについては、Claude が入力を必要とするときに通知を受け取る を参照してください。
設定ファイルに既に hooks キーがある場合は、オブジェクト全体を置き換えるのではなく、Notification を既存のイベントキーの兄弟として追加します。各イベント名は単一の hooks オブジェクト内のキーです:
CLI で実現したい内容を説明して、Claude にフックを書いてもらうこともできます。
2

設定を確認する

Claude Code のプロンプトで /hooks と入力して hooks ブラウザを開きます。新しいフックが Notification の下のリストに表示されます。
3

フックをテストする

Esc を押して CLI に戻ります。ステータスバーに ⏸ manual mode on が表示されるまで Shift+Tab を押し、権限が必要な操作を Claude に依頼してから、ターミナル以外のウィンドウに切り替えます。デスクトップ通知を受け取るはずです。

自動化できること

フックを使うと、Claude Code のライフサイクルの重要なタイミングでコードを実行できます。たとえば、編集後にファイルをフォーマットする、コマンドを実行前にブロックする、Claude が入力を必要としているときに通知を送る、セッション開始時にコンテキストを注入する、などです。フックイベントの完全な一覧は、フックリファレンスを参照してください。 各例には、設定ファイルに追加するだけで使える設定ブロックが含まれています。 別のモデルによるレビューを実行し、その結果をセッションにフィードバックするフックの本番環境での例については、security-guidance プラグインが Claude Code と統合する仕組みを参照してください。

Claude が入力を必要としているときに通知を受け取る

Claude が作業を終えて入力を必要としているときにデスクトップ通知を受け取れるようにします。これにより、ターミナルを確認しなくても他のタスクに切り替えられます。 このフックは Notification イベントを使用します。このイベントは、Claude が入力または権限を待っているときに Claude Code が発火させます。正確なタイミングについては、各通知タイプが発火するタイミングを参照してください。 以下の各タブでは、プラットフォームのネイティブな通知コマンドを使用しています。これを ~/.claude/settings.json に追加します。
osascript は、組み込みの Script Editor アプリを経由して通知を送ります。Script Editor に通知の権限がない場合、コマンドは何も表示せずに失敗し、macOS は権限を付与するよう求めてきません。ターミナルで次のコマンドを一度実行して、Script Editor を通知設定に表示させます。
この時点ではまだ何も表示されません。システム設定 > 通知 を開き、一覧から Script Editor を見つけて 通知を許可 をオンにします。コマンドを再度実行して、テスト通知が表示されることを確認します。
空の matcher は、すべての通知タイプで発火します。特定のイベントでのみ発火させるには、次のいずれかの値を設定します。 Claude Code は、ターミナルと、Claude Desktop、VS Code 拡張機能、その他 Agent SDK を通じて権限リクエストに応答するホストとで、permission_prompt のタイミングを異なる方法で計測します。両方のタイミングについては、各通知タイプが発火するタイミングを参照してください。 quota_auto_resume_fired、quota_auto_resume_stale、quota_auto_resume_disabled の matcher には Claude Code v2.1.234 以降が必要です。 ターミナルセッションでは、サンドボックス化されたコマンドのネットワークリクエストに対する permission_prompt には Claude Code v2.1.246 以降が必要です。 チームメイトのターミナルセットアップに関する質問に対する agent_needs_input には Claude Code v2.1.248 以降が必要です。 Claude Code のプロンプトで /hooks と入力し、フックが Notification の下に表示されることを確認します。

編集後にコードを自動フォーマットする

Claude が編集するすべてのファイルに対して Prettier を自動的に実行し、手作業なしでフォーマットの一貫性を保ちます。 このフックは Edit|Write matcher を指定した PostToolUse イベントを使用するため、ファイル編集ツールの後にのみ実行されます。コマンドは jq で編集されたファイルのパスを抽出し、Prettier に渡します。これをプロジェクトルートの .claude/settings.json に追加します。
フックをテストするには、JavaScript ファイルにシングルクォートの文字列を含む行を追加するよう Claude に依頼してから、ファイルを開きます。Prettier のデフォルト設定では、フックがそれらをダブルクォートに書き換えます。 フックが成功した場合、Claude Code は会話に何も表示しません。フックが実行されたことを確認するには、編集されたファイルが再フォーマットされていることを確認するか、フックの動作を確認するを参照してください。 Bash コマンドによる書き換えを含め、どのような方法で変更されても特定のファイルを再フォーマットするには、代わりに FileChanged フックを使用します。
このページの Bash の例では、JSON の解析に jq を使用しています。macOS では brew install jq、Debian や Ubuntu では apt-get install jq でインストールするか、jq のダウンロードを参照してください。

保護されたファイルへの編集をブロックする

Claude が .env、package-lock.json、.git/ 内のファイルなど、機密性の高いファイルを変更しないようにします。Claude は編集がブロックされた理由を説明するフィードバックを受け取るため、アプローチを調整できます。 この例では、フックが呼び出す別のスクリプトファイルを使用します。スクリプトは対象のファイルパスを保護パターンのリストと照合し、終了コード 2 で終了して編集をブロックします。
1

フックスクリプトを作成する

これを .claude/hooks/protect-files.sh に保存します。
2

macOS と Linux でスクリプトを実行可能にする

Claude Code がフックスクリプトを実行するには、スクリプトが実行可能である必要があります。
3

フックを登録する

Edit または Write ツールの呼び出しの前にスクリプトを実行する PreToolUse フックを .claude/settings.json に追加します。
4

フックをテストする

.env ファイルにコメントを追加するよう Claude に依頼します。Claude Code は編集が実行される前にそれをブロックし、スクリプトの Blocked: メッセージをフィードバックとして Claude に渡します。

コンテキスト圧縮後にコンテキストを再注入する

Claude のコンテキストウィンドウがいっぱいになると、コンテキスト圧縮によって会話が要約され、空き領域が確保されます。このとき重要な詳細が失われることがあります。compact matcher を指定した SessionStart フックを使用すると、圧縮のたびに重要なコンテキストを再注入できます。 Claude Code は、コマンドが stdout に書き出したプレーンテキストを Claude のコンテキストに追加します。この例では、プロジェクトの規約と最近の作業を Claude に思い出させます。これをプロジェクトルートの .claude/settings.json に追加します。
echo は、最近のコミットを表示する git log --oneline -5 のように、動的な出力を生成する任意のコマンドに置き換えられます。セッション開始のたびにコンテキストを注入する場合は、代わりに CLAUDE.md の使用を検討してください。環境変数については、リファレンスの CLAUDE_ENV_FILE を参照してください。

設定の変更を監査する

セッション中に設定ファイルやスキルファイルが変更されたタイミングを追跡します。ConfigChange イベントは、外部プロセスやエディターが設定ファイルを変更したときに発火するため、コンプライアンスのために変更をログに記録したり、許可されていない変更をブロックしたりできます。 この例では、各変更を監査ログに追記します。これを ~/.claude/settings.json に追加します。
matcher は設定の種類でフィルタリングします。指定できる値は user_settings、project_settings、local_settings、policy_settings、skills です。変更が反映されないようにブロックするには、終了コード 2 で終了するか、{"decision": "block"} を返します。入力スキーマの全体については、ConfigChange リファレンスを参照してください。 フックが変更を記録していることを確認するには、セッションの実行中に別のエディターで設定ファイルを編集してから、~/claude-config-audit.log を開きます。フックは変更ごとに、タイムスタンプ、ソース、ファイルパスを含む JSON を 1 行追記します。

ディレクトリやファイルが変更されたときに環境を再読み込みする

プロジェクトによっては、どのディレクトリにいるかに応じて異なる環境変数を設定します。direnv などのツールはシェルでこれを自動的に行いますが、Claude の Bash ツールはそれらの変更を自動的には取り込みません。 SessionStart フックと CwdChanged フックを組み合わせると、この問題を解決できます。SessionStart は起動したディレクトリの変数を読み込み、CwdChanged は Claude がディレクトリを変更するたびに変数を再読み込みします。どちらも CLAUDE_ENV_FILE に書き込み、Claude Code はこれを各 Bash コマンドの前にスクリプトのプリアンブルとして実行します。これを ~/.claude/settings.json に追加します。
.envrc があるディレクトリごとに一度 direnv allow を実行し、direnv がそのファイルを読み込めるようにします。direnv の代わりに devbox や nix を使用している場合は、direnv export bash の代わりに devbox shellenv または devbox global shellenv を使用すれば、同じパターンが機能します。 ディレクトリの変更のたびではなく特定のファイルに反応させるには、監視するファイル名を | で区切って列挙した matcher を指定して FileChanged を使用します。監視リストを構築する際、Claude Code はこの値を正規表現として評価するのではなく、リテラルのファイル名に分割します。同じ値が、ファイルの変更時にどのフックグループを実行するかのフィルタリングにも使われる仕組みについては、FileChanged を参照してください。この例では、作業ディレクトリ内の .envrc と .env を監視します。
入力スキーマ、watchPaths の出力、CLAUDE_ENV_FILE の詳細については、CwdChanged と FileChanged のリファレンス項目を参照してください。

特定の権限プロンプトを自動承認する

常に許可しているツール呼び出しについて、承認ダイアログをスキップします。この例では、Claude が計画の提示を終えて続行の承認を求める際に呼び出すツールである ExitPlanMode を自動承認するため、計画が準備できるたびにプロンプトが表示されることはなくなります。 上記の終了コードの例とは異なり、自動承認を行うには、フックが JSON の決定を stdout に書き出す必要があります。Claude Code は権限を求めようとするときに PermissionRequest フックを実行し、フックが "behavior": "allow" を返した場合は、ユーザーに代わってリクエストに応答します。 matcher によってフックのスコープが ExitPlanMode のみに限定されるため、他のプロンプトには影響しません。これを ~/.claude/settings.json に追加します。
フックが承認すると、Claude Code は plan モードを終了し、plan モードに入る前に有効だった権限モードを復元します。トランスクリプトには、ダイアログが表示されるはずだった場所に「Allowed by PermissionRequest hook」と表示されます。フックを経由する場合は常に現在の会話が維持されます。ダイアログのようにコンテキストをクリアして新しい実装セッションを開始することはできません。 代わりに特定の権限モードを設定するには、フックの出力に setMode エントリを含む updatedPermissions 配列を含めます。mode の値には default、acceptEdits、bypassPermissions などの任意の権限モードを指定し、destination: "session" を指定すると現在のセッションにのみ適用されます。
bypassPermissions は、バイパスモードがすでに利用可能な状態でセッションを開始した場合にのみ適用されます。具体的には、--dangerously-skip-permissions、--permission-mode bypassPermissions、--allow-dangerously-skip-permissions、またはユーザー設定、--settings、管理設定での permissions.defaultMode: "bypassPermissions" のいずれかを使用した場合です。permissions.disableBypassPermissionsMode によってバイパスモードが無効化されている場合や、制限モードでセッションを開始した場合は適用されません。Claude Code がこれを defaultMode として保存することはありません。
セッションを acceptEdits に切り替えるには、フックが次の JSON を stdout に書き出します。
matcher はできるだけ限定的にしてください。.* でマッチさせたり matcher を空のままにしたりすると、ファイルの書き込みやシェルコマンドを含む、すべてのツールの権限プロンプトが自動承認されてしまいます。決定フィールドの全体については、PermissionRequest リファレンスを参照してください。

hooks の仕組み

Claude Code は、ライフサイクルの特定のポイントで hook イベントを発火させます。イベントが発火すると、Claude Code はすべてのマッチングする hooks を並列で実行します。重複するハンドラーの扱い方については、Hook ハンドラーフィールド を参照してください。以下の表は各イベントとそれがトリガーされるときを示しています: 各 hook には、それがどのように実行されるかを決定する type があります。ほとんどの hooks は "type": "command" を使用し、シェルコマンドを実行します。他の 4 つのタイプが利用可能です:
  • "type": "http":イベントデータを URL に POST します。HTTP hooks を参照してください。
  • "type": "mcp_tool":設定済みの MCP サーバー上のツールを呼び出します。MCP tool hooks を参照してください。
  • "type": "prompt":シングルターン LLM 評価。プロンプトベースの hooks を参照してください。
  • "type": "agent":ツールアクセス付きマルチターン検証。エージェント hooks は実験的であり、変更される可能性があります。エージェントベースの hooks を参照してください。

複数の hooks からの結果を組み合わせる

複数の hooks が同じイベントにマッチする場合、すべての hook のコマンドが完了してから Claude Code は結果をマージします。1 つの hook が deny を返しても、兄弟 hooks の実行は停止されません。1 つの hook の deny が別の hook の副作用を抑制することに依存しないでください。 すべてのマッチングする hooks が完了した後、Claude Code はそれらの出力を組み合わせます。PreToolUse 許可決定については、最も制限的な答えが適用されます。順序は deny、defer、ask、allow です。additionalContext からのテキストはすべての hook から保持され、Claude に一緒に渡されます。 以下の例は Bash に 2 つの PreToolUse hooks を登録しています。最初のものはすべてのコマンドをログファイルに追加して 0 で終了します。2 番目のものはスクリプトを実行し、コマンドに rm -rf が含まれている場合は 2 で終了して拒否します:
Claude が rm -rf /tmp/build を実行しようとするとき、両方の hooks が並列で実行されます。ログ hook はコマンドを ~/.claude/bash.log に書き込み、0 で終了します。これは決定がないことを報告します。ガードレール hook は 2 で終了し、ツール呼び出しを拒否します。deny が優先されるため、Claude Code はコマンドをブロックし、Claude にガードレールの stderr を表示します。ログエントリはまだ書き込まれます。なぜなら、ログ hook は既に実行されているからです。

入力を読み取り、出力を返す

Hooks は stdin、stdout、stderr、および終了コードを通じて Claude Code と通信します。イベントが発火すると、Claude Code はイベント固有のデータを JSON としてスクリプトの stdin に渡します。スクリプトはそのデータを読み取り、作業を行い、終了コードを通じて Claude Code に次に何をするかを伝えます。

Hook 入力

すべてのイベントには session_id(セッションの一意の ID)や cwd(イベントが発火したときの作業ディレクトリ)などの共通フィールドが含まれていますが、各イベントタイプは異なるデータを追加します。Claude が Bash コマンドを実行するとき、PreToolUse hook は stdin で次のフィールドを受け取ります:
  • hook_event_name:hook をトリガーしたイベント
  • tool_name:Claude が使用しようとしているツール
  • tool_input:Claude がツールに渡した引数。Bash の場合、その command フィールドはシェルコマンドを保持します。
たとえば、npm test コマンドの hook 入力は次のようになります:
スクリプトはその JSON を解析し、これらのフィールドのいずれかに基づいて動作できます。UserPromptSubmit hooks は代わりに prompt テキストを取得し、SessionStart hooks は source(startup、resume、clear、compact、または fork)を取得するなど。リファレンスの 共通入力フィールド で共有フィールドを参照し、各イベントのセクションでイベント固有のスキーマを参照してください。

Hook 出力

スクリプトは stdout または stderr に書き込み、特定のコードで終了することで、Claude Code に次に何をするかを伝えます。以下は、コマンドをブロックする PreToolUse hook の例です:
0 と 2 以外の終了コードで有効な JSON 出力がない場合、ほとんどのイベントではアクションが続行されます。ただし、そのフックが 失敗時にアクションをブロックする ものである場合は除きます。onFailure が "block" に設定されたフックはその一例です。異議がないことを報告するには 0 で終了し、アクションをブロックするには 2 で終了します:
  • 終了 0:PreToolUse hook から 0 で終了しても、ツール呼び出しは通常の 権限フロー を経由します。終了 0 はツール呼び出しを承認しないためです。UserPromptSubmit、UserPromptExpansion、SessionStart、および PostModelSwitch hooks の場合、Claude Code は プレーンテキストとして扱う stdout を Claude のコンテキストに追加します。
  • 終了 2:stderr に理由を書き込みます。イベントによって、Claude がそれをフィードバックとして受け取って調整できる場合、ユーザーに表示される場合、ConfigChange や Elicitation のようにメッセージが表示されない場合があります。一部のイベントはブロックできません:SessionStart などの場合、終了 2 は stderr をユーザーに表示し、実行は続行されます。イベントごとの終了コード 2 の動作 で完全なリストを参照してください。
  • その他の終了コード:WorktreeCreate がゼロ以外の終了で失敗するなどのイベントごとの例外については、終了コード出力 を参照してください。その他のイベントでは、そのフックが失敗時にアクションをブロックするものでない限り、フックが stdout に出力した内容から該当するケースを確認してください:
    • スキーマ検証に合格した解析済みオブジェクト:Claude Code は終了コードを無視し、JSON だけが結果を決定し、フックはエラーとして報告されません。
    • スキーマ検証に失敗した解析済みオブジェクト、または Claude Code が JSON として解析しようとする ものの有効な JSON ではない stdout:アクションはブロックしないエラーとして続行されます。検証またはパースのメッセージについては、<hook name> hook error 通知を確認してください。
    • Claude Code が プレーンテキストとして扱う stdout、または空の stdout:アクションはブロックしないエラーとして続行されます。トランスクリプトには <hook name> hook error 通知が表示され、続いて Failed with non-blocking status code: を先頭に付けた stderr の最初の行が表示されます。stderr 全体をキャプチャするには、claude --debug を使用するか、セッション中に /debug を実行して デバッグログ を有効にしてください。

構造化 JSON 出力

終了コードはブロックするか沈黙するかのみを許可します。より多くの制御のために、終了 0 して stdout に JSON オブジェクトを出力します。
終了 2 で stderr メッセージでブロックするか、終了 0 で JSON で構造化制御を使用します。hook ごとに 1 つのアプローチを選択してください。混在させた場合の動作については、終了コード出力 を参照してください。
たとえば、PreToolUse hook はツール呼び出しを拒否して理由を Claude に伝えたり、ユーザーの承認のためにエスカレートしたりできます:
"deny" を使用すると、Claude Code はツール呼び出しをキャンセルし、permissionDecisionReason を Claude にフィードバックとして返します。 PreToolUse では、"ask" を返してユーザーに通常の権限プロンプトを表示したり、"allow" を返して対話的な権限プロンプトをスキップしたりすることもできます。"allow" の場合でも、拒否ルールと確認ルール(エンタープライズの管理 deny リストを含む)は引き続き適用され、次に対するプロンプトも引き続き表示されます: 4 番目の値 "defer" は、-p フラグ付きの 非対話モード で利用可能です。これを返すと、ツール呼び出しを保持したままターンが終了するため、Agent SDK ラッパーが入力を収集して再開できます。リファレンスの ツール呼び出しを後で延期する を参照してください。 PreModelSwitch hook は同じ permissionDecision フィールドを返します:"allow" はモデルスイッチを進行させ、"deny" はそれをキャンセルします。"ask" はインタラクティブセッションで /model を実行するときに確認を求めます。他の場所では、Claude Code は "ask" を拒否として扱います。PreModelSwitch 決定制御 を参照してください。 他のイベントは異なる決定パターンを使用します。たとえば、PostToolUse および Stop hooks はトップレベルの decision: "block" フィールドを使用し、PermissionRequest は hookSpecificOutput.decision.behavior を使用します。リファレンスの サマリーテーブル でイベント別の完全な内訳を参照してください。 UserPromptSubmit hooks の場合、代わりに hookSpecificOutput.additionalContext を使用して Claude のコンテキストにテキストを注入します。additionalContext を hookSpecificOutput の内側にネストします。JSON の最上位レベルに配置すると、Claude Code はそれを無視します。たとえば、この出力はすべてのプロンプトに現在のブランチ状態を追加します:
ブロックプロンプトとセッションタイトルの設定を含む完全な出力形状については、UserPromptSubmit 決定制御 を参照してください。 type: "prompt" の Hooks は出力を異なる方法で処理します:プロンプトベースの hooks を参照してください。

マッチャーで hooks をフィルタリングする

マッチャーなしでは、hook はそのイベントのすべての発生で発火します。マッチャーを使用すると、それを絞り込むことができます。たとえば、ファイル編集後にのみフォーマッターを実行したい場合(すべてのツール呼び出しの後ではなく)、PostToolUse hook にマッチャーを追加します:
"Edit|Write" マッチャーは Edit または Write ツール呼び出しでのみ発火し、Bash、Read、または他のツールでは発火しません。カンマもまた同じ方法で代替を区切るため、"Edit, Write" は同等です。マッチャーパターン を参照して、プレーン名と正規表現がどのように評価されるかを確認してください。
Claude はまた、シェルコマンドを実行することでファイルを作成または変更できます。コンプライアンススキャンまたは監査ログなど、hook がすべてのファイル変更を確認する必要がある場合は、ターンごとに 1 回作業ツリーをスキャンする Stop hook を追加してください。呼び出しごとのカバレッジの場合は、Bash|PowerShell もマッチさせ、スクリプトで git status --porcelain を使用して変更されたファイルと追跡されていないファイルをリストアップしてください。PowerShell hook 入力セクション は、Bash だけをマッチさせるのが十分でない理由を説明しています。ディスク上の特定のファイルが変更されたときに hook を実行するには、それを書き込んだものが何であれ、FileChanged hook を使用してください。
各イベントタイプは特定のフィールドでマッチします: 以下のタブは、異なるイベントタイプのいくつかのマッチャーを示しています。
Bash ツール呼び出しのみをマッチし、各コマンドをファイルにログに記録します。PostToolUse イベントはコマンドが完了した後に発火するため、tool_input.command は実行されたものを含みます。Hook は stdin で JSON としてイベントデータを受け取り、jq -r '.tool_input.command' はコマンド文字列のみを抽出し、>> はログファイルに追加します:

if フィールドでツール名と引数でフィルタリングする

if フィールドは 許可ルール構文 を使用して、ツール名と引数の両方で hooks をフィルタリングするため、hook プロセスはツール呼び出しがマッチするときにのみ生成されます。これは matcher を超えており、ツール名のみでグループレベルでフィルタリングします。 たとえば、すべての Bash コマンドではなく、Claude が git コマンドを使用するときにのみ hook を実行するには:
Hook コマンドが実行されるかどうかは、if パターンの形状と Claude が呼び出している Bash コマンドによって異なります: Claude Code がどのコマンドが Bash 入力を実行するかを判断できない場合、パターンに関係なく hook を実行します。Bash マッチングテーブル は、Claude Code がサブコマンドで絞り込むことができる、またはできないコマンド形状をカバーしています。フィルターはベストエフォートであるため、ハード allow または deny を強制するには、hook ではなく 許可システム を使用してください。 if フィールドは許可ルールと同じパターンを受け入れます:"Bash(git *)"、"Edit(*.ts)" など。複数のツール名をマッチさせるには、それぞれ独自の if 値を持つ別のハンドラーを使用するか、パイプ交替がサポートされている matcher レベルでマッチします。 if はツールイベントでのみ機能します:PreToolUse、PostToolUse、PostToolUseFailure、PermissionRequest、および PermissionDenied。他のイベントに追加すると、hook が実行されるのを防ぎます。

hook の場所を設定する

Hook を追加する場所がそのスコープを決定します: Claude Code で /hooks を実行して、イベント別にグループ化されたすべての設定済み hooks を参照します。 hooks を無効にするには、設定ファイルで "disableAllHooks": true を設定します。Claude Code は 設定の優先順位 の後に残された値を読み取るため、プロジェクトの設定ファイルはあなたのものをオーバーライドできます。管理設定で設定された Hooks は、disableAllHooks がそこにも設定されていない限り、実行されます。各レベルの完全な範囲については、disableAllHooks を参照してください。 Claude Code が実行中に設定ファイルを直接編集する場合、ファイルウォッチャーは通常、hook の変更を自動的に取得します。

プロンプトベースの hooks

決定論的なルールではなく判断が必要な決定については、type: "prompt" hooks を使用します。シェルコマンドを実行する代わりに、Claude Code はプロンプトと hook の入力データを Claude モデルに送信して決定を下します。より多くの機能が必要な場合は、model フィールドで異なるモデルを指定できます。 モデルの唯一の仕事は、その決定を JSON として返すことです:
  • "ok": true:アクションが続行されます
  • "ok": false:何が起こるかはイベントによって異なります:
    • Stop および SubagentStop:reason は Claude にフィードバックとして返されるため、作業を続けます。ただし、応答が "impossible": true も設定している場合は、その条件が決して満たされることのない条件として印付けられ、その場合 Claude Code は停止を許可してターンが終了します
    • PreToolUse:ツール呼び出しが拒否されます。デフォルトではターンが終了し、拒否の reason は警告行としてチャットに表示されます。フックに continueOnBlock: true を設定すると、代わりに reason を Claude にツールエラーとして返すため、調整して続行できます
    • PostToolUse:デフォルトではターンが終了し、reason は警告行としてチャットに表示されます。continueOnBlock: true を設定すると、reason を Claude にフィードバックとして返し、代わりにターンを続行します
    • PostToolBatch、UserPromptSubmit、および UserPromptExpansion:ターンが終了し、reason は警告行としてチャットに表示されます
この例は Stop hook を使用して、要求されたすべてのタスクが完了しているかどうかをモデルに尋ねます。モデルが条件がまだ満たされていないため "ok": false を返す場合、Claude は作業を続け、reason を次の指示として使用します:
完全な設定オプションについては、リファレンスの プロンプトベースの hooks を参照してください。

エージェントベースの hooks

エージェント hooks は実験的です。動作と設定は将来のリリースで変更される可能性があります。本番ワークフローについては、コマンド hooks を優先してください。
検証がファイルの検査またはコマンドの実行を必要とする場合、type: "agent" hooks を使用します。プロンプト hooks は単一の LLM 呼び出しを行いますが、エージェント hooks は条件を返す前にファイルを読み取り、コードを検索し、他のツールを使用できる subagent を生成します。 エージェント hooks は "ok" / "reason" 応答形式を使用し、デフォルトのタイムアウトが 60 秒で、最大 50 ツール使用ターンです。プロンプト hooks の impossible フィールドはサポートされていません。ok: false の場合、Claude Code はエージェント hooks を同じイベント上で continueOnBlock: true を持つプロンプト hooks と同じ方法で処理するため、PreToolUse と PostToolUse ではターンが続行されます。エージェント hooks には continueOnBlock フィールドがありません。フィールドを含む エージェント hooks の設定 を参照してください。これには Claude Code が hooks の JSON 入力に置き換える $ARGUMENTS プレースホルダーが含まれます。 この例は Claude が停止することを許可する前にテストが合格することを検証します:
Hook 入力データだけで決定を下すのに十分な場合はプロンプト hooks を使用します。コードベースの実際の状態に対して何かを検証する必要がある場合はエージェント hooks を使用します。 完全な設定オプションについては、リファレンスの エージェントベースの hooks を参照してください。

HTTP hooks

type: "http" hooks を使用して、シェルコマンドを実行する代わりに、イベントデータを HTTP エンドポイントに POST します。エンドポイントはコマンド hook が stdin で受け取るのと同じ JSON を受け取り、HTTP レスポンスボディを使用して同じ JSON 形式で結果を返します。 HTTP hooks は、Web サーバー、クラウド関数、または外部サービスに hook ロジックを処理させたい場合に便利です。たとえば、チーム全体のツール使用イベントをログに記録する共有監査サービス。 この例はすべてのツール使用をローカルログサービスに POST します:
エンドポイントは、コマンドフックと同じ 出力形式 の JSON ボディで応答し、Claude Code はレスポンスのステータスも確認します:
  • 2xx ステータス:ツール呼び出しをブロックするには、ボディで適切な hookSpecificOutput フィールドを返します。
  • その他のステータス、またはリクエストが失敗した場合:Claude Code は ノンブロッキングエラー を報告し、アクションを続行させます。失敗したエンドポイントでアクションをブロックするには、フックに onFailure: "block" を設定します。
ヘッダー値は $VAR_NAME または ${VAR_NAME} 構文を使用した環境変数補間をサポートします。allowedEnvVars 配列にリストされている変数のみが解決されます。他のすべての $VAR 参照は空のままです。 完全な設定オプションとレスポンス処理については、リファレンスの HTTP hooks を参照してください。

制限事項とトラブルシューティング

制限事項

フックを設計する際は、以下の制約に留意してください。
  • コマンドフックは stdout、stderr、終了コードのみを介して通信します。/ コマンドやツール呼び出しをトリガーすることはできません。additionalContext を介して返されたテキストはシステムリマインダーとして挿入され、Claude はこれをプレーンテキストとして読み取ります。HTTP フックは代わりにレスポンスボディを介して通信します。
  • フックのタイムアウトはタイプによって異なります。フックごとに timeout フィールド(秒単位)で上書きできます。
    • command、http、mcp_tool:10 分。Claude Code は、UserPromptSubmit、PreModelSwitch、PostModelSwitch フックではこのデフォルトを 30 秒に、MessageDisplay では 10 秒に引き下げます。
    • prompt:30 秒。
    • agent:60 秒。
    • SessionEnd フックは、タイプを問わず 1.5 秒の割り当て時間を共有します。設定でフックごとにより長い timeout を指定している場合、Claude Code は最大 60 秒までそれに合わせて割り当て時間を引き上げます。
  • PostToolUse フックは、ツールがすでに実行されているため、アクションを元に戻すことはできません。
  • PermissionRequest フックは、Claude Code がユーザーに権限を求めようとするとき、またはプロンプトを表示できない呼び出しをそのままでは自動的に拒否するときに発火します。-p フラグを使用した非対話モードでも、dontAsk モード以外では引き続き実行され、どのフックも判断せず、他に応答できるものもない呼び出しは拒否されます。
  • Stop フックは、タスクの完了時だけでなく、Claude が応答を終えるたびに発火します。ユーザーによる中断では発火しません。API エラーの場合は代わりに StopFailure が発火します。
  • 複数の PreToolUse フックがツールの引数を書き換えるために updatedInput を返す場合、最後に完了したものが有効になります。フックは並列に実行されるため、順序は非決定的です。同じツールの入力を複数のフックで変更することは避けてください。

フックと権限モード

設定ファイルやプラグインの hooks/hooks.json 内のフックでは、権限ルールが許可する範囲を超えて制限を緩めることはできず、フックの "deny" はすべての権限モードで有効です。
  • "allow" に対して引き続き有効なもの:"allow" を返すフックは、設定の拒否ルールを回避することはできず、以下のプロンプトを抑制することもできません。
plan モードでは、PreToolUse フックがファイル編集に対して "allow" を返しても、フックがない場合にその編集が受けるのと同じプロンプト、ブロック、または承認が適用されます。フックによる承認に対するこの制限を解除するには、プランを承認するか、別の権限モードに切り替えてください。
  • すべての権限モードでの "deny":permissionDecision: "deny" を返すフックは、bypassPermissions モードや --dangerously-skip-permissions を使用している場合でもツールをブロックします。PreToolUse フックは、dontAsk を含むすべての権限モードにおいて、権限モードのチェックより前に発火します。これにより、ユーザーが権限モードを変更しても回避できないポリシーを適用できます。
マシンに管理設定がなく、セッションで Team または Enterprise プランの /login 認証情報を使用していない場合、PreToolUse フックがブロックした呼び出しを mod が承認できます。代わりに API キーや長期間有効な CLAUDE_CODE_OAUTH_TOKEN で実行されるセッションは、そのログインが保存されている場合でも、そのログインを使用していません。plan モードでは、mod がそのようなブロックされた呼び出しを承認できるのは読み取り専用の場合のみであり、ファイル編集は承認できません。mod の承認がルールやフックを通過しないケースについては、フックで権限を拡張するを参照してください。

フックが発火しない

フックは設定されているが、一度も実行されない場合。
  • /hooks を実行し、フックが正しいイベントの下に表示されていることを確認します
  • matcher のパターンがツール名と正確に一致していることを確認します。matcher は大文字と小文字を区別します
  • 正しいイベントタイプをトリガーしていることを確認します。PreToolUse はツールの実行前に、PostToolUse は実行後に発火します。PermissionRequest フックは Claude Code がユーザーに権限を求めようとするときに発火します。非対話の場合については制限事項を参照してください

出力にフックエラーが表示される

トランスクリプトに「PreToolUse hook error: …」のようなメッセージが表示される場合。
  • スクリプトが予期せずゼロ以外のコードで終了しています。サンプルの JSON をパイプで渡して手動でテストします。
  • 「command not found」と表示される場合は、絶対パスまたは ${CLAUDE_PROJECT_DIR} を使用してスクリプトを参照します。シェルのクォートを完全に回避するには、"args": [] を追加して exec 形式に切り替えます。これにより、シェルを介さずにスクリプトが直接起動されます
  • 「jq: command not found」と表示される場合は、jq をインストールするか、JSON の解析に Python/Node.js を使用します
  • メッセージに blocking because Git Bash wasn't found が含まれる場合は、Windows 上で Claude Code が Git Bash を見つけられず、失敗またはタイムアウトしたフックがツール呼び出しをブロックしています。修正方法については Git Bash のない Windows で失敗したフックを参照してください
  • 通知に JSON 検証メッセージが表示される場合、フックの stdout は JSON として解析されましたが、スキーマ検証に失敗しています。JSON 解析メッセージが表示される場合、stdout は JSON オブジェクトのように見えましたが、有効な JSON ではありませんでした。どちらも終了コード 0 の場合でも発生します。 解析の失敗を修正するには、文字列の連結ではなく jq などの JSON エンコーダーを使用してペイロードを組み立て、値に含まれる引用符やバックスラッシュがエスケープされるようにします。終了コードと JSON の組み合わせについては、リファレンスの終了コードの出力セクションで説明しています
  • スクリプトがまったく実行されていない場合は、実行可能にします:chmod +x ./my-hook.sh

/hooks にフックが設定されていないと表示される

設定ファイルを編集したが、フックがメニューに表示されない場合。
  • ファイルの編集は通常自動的に反映されます。数秒経っても表示されない場合は、ファイルウォッチャーが変更を検出できなかった可能性があります。セッションを再起動して強制的に再読み込みしてください。
  • JSON が有効であることを確認します。末尾のカンマやコメントは使用できません
  • 設定ファイルが正しい場所にあることを確認します。プロジェクトのフックは .claude/settings.json、グローバルのフックは ~/.claude/settings.json です
  • メニューに Only hooks from managed settings run here と表示される場合は、組織が allowManagedHooksOnly を設定しています。ユーザー、プロジェクト、ローカルの設定ファイル内のフックは実行されず、一覧にも表示されません

Stop フックがブロック上限に達する

Claude が停止せずに作業を続け、その後 Stop フックが連続してブロックした回数が多すぎるという警告とともにターンを終了する場合。 Claude Code は、Stop フックが間に Claude によるツール呼び出しを挟まずに 8 回連続でブロックすると、そのフックを上書きします。フックスクリプトでは、すでに継続をトリガーしたかどうかを確認する必要があります。JSON 入力から stop_hook_active フィールドを解析し、true の場合は早期に終了します。
フックが収束するまでに正当な理由で 8 回を超える反復が必要な場合は、CLAUDE_CODE_STOP_HOOK_BLOCK_CAP で上限を引き上げてください。

フックの JSON が効果を持たない

フックは有効な JSON を出力しているが、判断が反映されず、トランスクリプトにもエラーが表示されない場合。どの原因に該当するかを確認してください。
  • JSON の前に余分な出力がある:他の何かが先に stdout に書き込んでいます。通常はシェルプロファイル内の無条件の echo です。そのため出力が { で始まらなくなります。JSON の前に出力されるシェルプロファイルの出力を参照してください。
  • フィールドの階層が間違っている:各フィールドの配置を JSON 出力の形式と比較してください。たとえば、permissionDecision はトップレベルではなく hookSpecificOutput の内側に配置する必要があります。フィールドの階層が間違っているを参照してください。

JSON の前に出力されるシェルプロファイルの出力

フックは非対話シェルで実行されますが、Git Bash や、BASH_ENV が ~/.bashrc を指しているなどの一部の設定では、それでもプロファイルが読み込まれます。プロファイルが出力した内容はすべて、フックの JSON より先に stdout に届きます。
フックが非同期でない限り、Claude Code は { で始まらない出力をプレーンテキストとして読み取るため、JSON は無視されます。フックは終了コード 0 で終了しているため、トランスクリプトにもエラーは表示されません。この原因に該当するかを確認するには、claude --debug で Claude Code を起動してフックをトリガーし、デバッグログで Hook output does not start with { を検索します。これを修正するには、プロファイル内の echo 文を、対話シェルでのみ実行されるように囲みます。
$- 変数にはシェルのフラグが含まれており、i は対話を意味します。フックは非対話シェルで実行されるため、echo はスキップされます。

フィールドの階層が間違っている

フックが permissionDecision や additionalContext を hookSpecificOutput の内側ではなくトップレベルで返した場合でも、JSON は解析されますが、Claude Code は誤って配置されたフィールドをエラーを報告せずに無視します。どのフィールドが無視されたかを確認するには、claude --debug で Claude Code を起動し、デバッグログで Hook JSON output had unrecognized keys を検索します。

フックの動作を確認する

Ctrl+O を押してトランスクリプトビューを開き、フックの結果を確認します。
  • 成功:フックの JSON が systemMessage や Stop フックのフィードバックなどを表示しない限り、何も表示されません。
    • フックが実行されたことを確認するには、ファイルが再フォーマットされたなどの効果を確認します
  • ブロッキングエラー:ほとんどのイベントでは、ブロックに伴うメッセージが表示されます(例:Blocked: rm commands are not allowed)。ConfigChange や Elicitation などの一部のイベントでは、メッセージは表示されません。メッセージの出どころについては終了コード 2 で説明しています。
  • 非ブロッキングエラー:<hook name> hook error という通知と短い説明が表示されます。説明は、Failed with non-blocking status code: の後に続く stderr の最初の行や、JSON の検証メッセージまたは解析メッセージなどです。アクションは続行されています。
特定の終了コードと stdout に対する結果(イベントごとの例外を含む)を調べるには、リファレンスの終了コードの出力を参照してください。 フックの終了コード、stdout、stderr を含む実行の詳細をすべて確認するには、デバッグログを読みます。claude --debug-file /tmp/claude.log で Claude Code を起動して既知のパスに書き込み、別のターミナルで tail -f /tmp/claude.log を実行します。このフラグを付けずに起動した場合は、セッションの途中で /debug を実行してログを有効にし、ログのパスを確認します。

詳細を学ぶ