- 危険な操作をブロックする:破壊的なシェルコマンドや不正なファイルアクセスなど、実行前に危険な操作をブロックします
- ログと監査:コンプライアンス、デバッグ、分析のためにツール呼び出しをログに記録して監査します
- 入力と出力を変換する:データをサニタイズしたり、認証情報を注入したり、ファイルパスをリダイレクトしたりします
- 人間の承認を要求する:データベース書き込みや API 呼び出しなどの機密アクションに対して
- セッションライフサイクルを追跡する:状態を管理したり、リソースをクリーンアップしたり、通知を送信したりします
フックの仕組み
1
イベントが発火する
エージェント実行中に何かが起こり、SDK がイベントを発火します。ツールが呼び出されようとしている(
PreToolUse)、ツールが結果を返した(PostToolUse)、サブエージェントが開始または停止した、エージェントがアイドル状態である、または実行が完了したなどです。イベントの完全なリストを参照してください。2
SDK が登録されたフックを収集する
SDK は、そのイベントタイプに登録されたフックをチェックします。これには、
options.hooks に渡すコールバックフックと、対応する settingSources または setting_sources エントリが有効になっているときの設定ファイルからのシェルコマンドフックが含まれます。これはデフォルトの query() オプションで有効になっています。3
matcher がどのフックを実行するかをフィルタリングする
フックに
matcher パターン("Write|Edit" など)がある場合、SDK はそれをイベントのターゲット(たとえば、ツール名)に対してテストします。matcher のないフックは、そのタイプのすべてのイベントに対して実行されます。4
コールバック関数が実行される
各マッチングフックのコールバック関数は、何が起こっているかについての入力を受け取ります。ツール名、その引数、セッション ID、およびその他のイベント固有の詳細です。
5
コールバックが決定を返す
任意の操作(ログ、API 呼び出し、検証)を実行した後、コールバックは出力オブジェクトを返します。これはエージェントに何をするかを指示します。操作を許可する、ブロックする、入力を変更する、または会話にコンテキストを注入するなどです。
PreToolUse フック(ステップ 1)を "Write|Edit" matcher(ステップ 3)で登録して、コールバックが Write ツールと Edit ツールに対して発火するようにします。トリガーされると、コールバックはツールの入力(ステップ 4)を受け取り、ファイルパスが .env ファイルをターゲットにしているかどうかをチェックし、permissionDecision: "deny" を返して操作をブロックします(ステップ 5)。
file_path が /.env で終わる Write または Edit の呼び出しを、大文字・小文字を問わず拒否します。Windows では file_path は C:\project\.env のようにバックスラッシュを使用するため、このフックは C:\project\.env への Write または Edit の呼び出しを許可します。
利用可能なフック
SDK はエージェント実行のさまざまなステージのフックを提供します。一部のフックは両方の SDK で利用可能ですが、その他は TypeScript のみです。フックを設定する
フックを設定するには、エージェントオプション(Python ではClaudeAgentOptions、TypeScript では options オブジェクト)の hooks フィールドに渡します。このスニペットは、上記の例から protect_env_files(Python)または protectEnvFiles(TypeScript)のようなフックコールバックを既に定義していることを前提としています。
hooks オプションは辞書(Python)またはオブジェクト(TypeScript)です。ここで:
- キーはフックイベント名です(例:
'PreToolUse'、'PostToolUse'、'Stop') - 値はマッチャーの配列です。各マッチャーには、オプションのフィルタパターンとコールバック関数が含まれます
マッチャー
マッチャーを使用して、コールバックがいつ発火するかをフィルタリングします。matcher フィールドは、フックイベントタイプに応じて異なる値に対してマッチングされます。たとえば、ツールベースのフックはツール名に対してマッチングされ、Notification フックは通知タイプに対してマッチングされます。
SDK マッチャーは設定ファイルのマッチャーと同じルールに従います。そのセクションでは、正確な文字列と正規表現の評価パス、バージョン要件、および各イベントタイプのマッチャー値を文書化しています。
可能な限り
matcher パターンを使用して特定のツールをターゲットにします。'Bash' のマッチャーは Bash コマンドに対してのみ実行されますが、パターンを省略するとコールバックはそのイベントのすべての発生に対して実行されます。
コールバック関数
入力
すべてのフックコールバックは 3 つの引数を受け取ります。- 入力データ: イベント詳細を含む型付きオブジェクト。各フック型には独自の入力形状があります。たとえば、
PreToolUseHookInputにはtool_nameとtool_inputが含まれ、NotificationHookInputにはmessageが含まれます。TypeScript および Python SDK リファレンスで完全な型定義を参照してください。- すべてのフック入力は
session_id、cwd、およびhook_event_nameを共有します。 agent_idとagent_typeは、フックがサブエージェント内で発火するときに入力されます。TypeScript では、これらはベースフック入力にあり、すべてのフック型で利用可能です。Python では、これらはPreToolUse、PostToolUse、PostToolUseFailure、およびPermissionRequestのオプションフィールドであり、SubagentStartおよびSubagentStopの必須フィールドです。
- すべてのフック入力は
- ツール使用 ID(
str | None/string | undefined):同じツール呼び出しのPreToolUseとPostToolUseイベントを相関させます。 - コンテキスト: TypeScript では、キャンセル用の
signalプロパティ(AbortSignal)を含みます。Python では、この引数は将来の使用のために予約されています。
出力
コールバックは 2 つのカテゴリのフィールドを持つオブジェクトを返します。- トップレベルフィールドはすべてのイベントで受け入れられます。
systemMessageはユーザーにメッセージを表示し、continue(Python ではcontinue_)はこのフック後にエージェントが実行を続けるかどうかを決定します。一部のイベントはこれらを破棄するか、別の場所に配信します。各イベントのセクションはフックページでそれらがどこに着地するかを説明しています。 hookSpecificOutputは現在の操作を制御します。内部に設定するフィールドはフックイベントタイプに依存します。PreToolUseフックの場合、ここでpermissionDecision("allow"、"deny"、"ask"、または"defer")、permissionDecisionReason、およびupdatedInputを設定します。"defer"を返すと、stop_reasonが"tool_deferred"である結果メッセージでターンが終了するため、後で呼び出しを再開できます。PostToolUseフックの場合、additionalContextを設定してツール結果に情報を追加できます。Claude がそれを見る前にツールの出力を置き換えるには、updatedToolOutputを設定します。これは両方の SDK のすべてのツールで機能します。古いupdatedMCPToolOutputフィールドは MCP ツール出力のみを置き換えます。- TypeScript SDK では、
PostToolUseコールバックはclassifierContextを返すこともできます。これはツール呼び出しの結果に関する短いメモで、auto モードの権限分類器用です。コールバックはアプリケーション独自のプロセスで実行されるため、分類器はメモで中継するユーザーステートメントをユーザーの意図として重視する可能性があります。このフィールドは TypeScript Agent SDK v0.3.236 以降が必要です。auto モード分類器の結果に注釈を付けるは長さの上限、同期のみのルール、およびメモに何を入れないかをカバーしています。
{} を返します。SDK コールバックフックは、Claude Code シェルコマンドフックと同じ JSON 出力形式を使用します。これはすべてのフィールドとイベント固有のオプションを文書化しています。SDK 型定義については、TypeScript および Python SDK リファレンスを参照してください。
複数の
PreToolUse フックが異なる決定を返す場合、deny は defer より優先され、defer は ask より優先され、ask は allow より優先されます。非同期出力
デフォルトでは、エージェントはフックが返されるのを待ってから続行します。フックがログやウェブフック送信などの副作用を実行し、エージェントの動作に影響を与える必要がない場合、代わりに非同期出力を返すことができます。これはエージェントに、フックが完了するのを待たずに即座に続行するよう指示します。このスニペットでは、Python のsend_to_logging_service と TypeScript の sendToLoggingService は、定義する任意のログ関数の代わりです。
非同期出力はエージェントが既に先に進んでいるため、ブロック、変更、またはコンテキストを注入することはできません。ログ、メトリクス、または通知などの副作用にのみ使用します。
例
このセクションのいくつかの例では、コールバック関数のみを示しています。実行するには、フックを設定するで示すように、オプションのhooks フィールドで対応するイベントの下にコールバックを登録してください。
ツール入力を変更する
この例では、Write ツールの呼び出しをインターセプトし、file_path 引数の先頭に /sandbox を付加するように書き換えます。コールバックは、変更後のパスを含む updatedInput と、書き換えた操作を自動承認するための permissionDecision: 'allow' を返します。
変更後の入力を自動承認するには
updatedInput と permissionDecision: 'allow' を組み合わせ、ユーザーに表示するには permissionDecision: 'ask' を組み合わせます。permissionDecision を省略した場合も変更後の入力は適用され、通常の権限評価を経由します。'defer' の場合、updatedInput は無視されます。元の tool_input を変更するのではなく、常に新しいオブジェクトを返してください。./sandbox や /tmp/sandbox など書き込み可能なパスに設定し(macOS ではルートレベルの /sandbox ディレクトリを作成できません)、エージェントにファイルの書き込みを依頼します。メッセージストリーム内の Write ツールの結果には、Claude が要求したパスではなく、サンドボックスのプレフィックスが付いたパスが示されます。
コンテキストを追加してツールをブロックする
この例では、file_path が /etc で始まるツール呼び出しを拒否し、その理由をモデルとユーザーの両方に説明します。
permissionDecision: 'deny'はツール呼び出しを停止します。permissionDecisionReasonはモデルに理由を伝えます。systemMessageは何が起きたかをユーザーに表示します。
Write|Edit matcher を指定して PreToolUse の下にコールバックを登録し、エージェントに /etc 配下でのファイル作成を依頼します。メッセージストリーム内の Write ツールの結果に Writing to /etc is not allowed が含まれ、ファイルは作成されません。
特定のツールを自動承認する
デフォルトでは、エージェントは特定のツールを使用する前に権限を求めることがあります。この例では、permissionDecision: 'allow' を返すことで読み取り専用のファイルシステムツール(Read、Glob、Grep)を自動承認し、ネットワークパスからの読み取りを除いて、ユーザーの確認なしで実行できるようにします。その他のツールはすべて通常の権限チェックの対象のままです。
複数のフックを登録する
イベントが発生すると、一致するすべてのフックが並列に実行されます。権限の決定については、最も制限の厳しい結果が適用されます。1 つのフックのdeny でツール呼び出しはブロックされます。完了順序は非決定的であるため、別のフックが先に実行されていることに依存せず、各フックが独立して動作するように記述してください。
以下の例では、それぞれ matcher を省略した 3 つの独立したチェックを登録します。例中のフック名(Python の audit_logger や TypeScript の auditLogger など)は、ユーザーが定義するコールバックを表しています。
複数ツールの matcher でフィルタリングする
複数ツールの matcher を使用すると、関連するツール間で 1 つのコールバックを共有できます。この例ではスコープの異なる 3 つの matcher を登録しており、例中の各フックはユーザーが定義するコールバックを表しています。- パイプ区切りの完全一致リスト(
Write|Edit|NotebookEdit)は、Write、Edit、NotebookEdit ツールに対してfile_security_hookをトリガーします。 - 正規表現(
^mcp__)は、名前がmcp__で始まるすべての MCP ツールに対してmcp_audit_hookをトリガーします。 - matcher を省略すると、ツール名でフィルタリングせずに
global_loggerをトリガーします。
サブエージェントのアクティビティを追跡する
SubagentStop フックを使用して、サブエージェントが作業を完了したタイミングを監視します。入力型の全体については、TypeScript および Python の SDK リファレンスを参照してください。この例では、サブエージェントが完了するたびに概要をログに記録します。
[SUBAGENT] Completed: の行を出力します。
フックから HTTP リクエストを送信する
フックは HTTP リクエストなどの非同期操作を実行できます。エラーは伝播させず、フック内でキャッチしてください。 この例では、各ツールの完了後に Webhook を送信し、どのツールがいつ実行されたかを記録します。フックは Webhook の失敗によるエラーをキャッチします。通知を Slack に転送する
Notification フックを使用すると、エージェントからのシステム通知を受け取り、外部サービスに転送できます。SDK セッションでは、Claude Code は次の通知タイプに対してこのフックを実行します。
permission_prompt:権限リクエストがcanUseToolコールバックで約 6 秒間待機した時点で発生します。TypeScript Agent SDK v0.3.233 以降、または Python Agent SDK v0.2.139 以降が必要ですelicitation_completeおよびelicitation_response:ユーザーへの入力要求(elicitation)フロー用
idle_prompt、auth_success、elicitation_dialog などのその他のタイプは、SDK セッションでは実行されないインタラクティブ UI から Claude Code が発行します。
各通知には、人間が読める説明を含む message フィールドと、オプションで title が含まれます。
この例では、すべての通知を Slack チャンネルに転送します。Slack の Incoming Webhook URL が必要です。これは、Slack ワークスペースにアプリを追加し、Incoming Webhook を有効にすることで作成できます。
Notification イベントが発生すると、フックは通知の message の先頭に Agent status: を付けて、Webhook の送信先チャンネルに投稿します。
一般的な問題を修正する
フックが発火しない
- フックイベント名が正しく、大文字と小文字が区別されていることを確認してください(
preToolUseではなくPreToolUse) - matcher パターンがツール名と正確に一致していることを確認してください
- フックが
options.hooksの正しいイベントタイプの下にあることを確認してください - matcher をサポートする非ツールフック(
NotificationやSubagentStopなど)の場合、matcher は異なるフィールドに対してマッチし、Stopは matcher を完全に無視します(matcher パターンを参照) - エージェントが
max_turns制限に達した場合、フックが実行される前にセッションが終了するため、フックが発火しない可能性があります
matcher が期待通りにフィルタリングしない
matcher はツール名のみをマッチし、ファイルパスや他の引数はマッチしません。ファイルパスでフィルタリングするには、フック内でtool_input.file_path を確認してください:
フックタイムアウト
Claude Code は各コールバックをタイムアウト付きで実行します。タイムアウトはHookMatcher の timeout フィールドで秒単位で設定します。設定しない場合、Claude Code はイベントのデフォルトを使用します:ほとんどのイベントで 600 秒、UserPromptSubmit、PreModelSwitch、PostModelSwitch で 30 秒、MessageDisplay で 10 秒です。Claude Code は SessionEnd コールバックをシャットダウン中に実行します。これは短い SessionEnd タイムアウト予算(デフォルトで 1.5 秒)の下で実行されます。
コールバックがタイムアウトを超過した場合、Claude Code はそれをキャンセルし、その出力を破棄し、セッションはハングするのではなく続行します。次に何が起こるかはイベントによって異なります:
PreToolUse:Claude Code はツール呼び出しをブロックします。その代わりに、Claude はフックがタイムアウト前に応答しなかったことを示すツール結果を受け取り、ターンが続行されます。v2.1.210 より前では、Claude Code はタイムアウトを Claude にユーザー拒否として報告していたため、無人セッションは停止して入力を待つようになっていました。PostToolUseおよびPostToolUseFailure:Claude Code はツール結果を保持し、ターンが続行されます。UserPromptSubmitおよびUserPromptExpansion:Claude Code はフックとタイムアウトを名前で示すメッセージでプロンプトをブロックし、セッションが続行されます。v2.1.208 より前では、これらのイベントのコールバックがタイムアウトした場合、Claude Code はクエリをerror_during_executionで終了していました。StopおよびSubagentStop:タイムアウトしたコールバックは決定を返さないとカウントされます。エージェントまたはサブエージェントは、そのコールバックがそれを許可したかのように停止し、イベントの他のフックからの決定が適用されます。Claude Code v2.1.273 より前では、タイムアウトしたStopまたはSubagentStopコールバックは失敗したフック実行としてカウントされ、Claude Code はイベントの他のフックの決定を破棄していました。SessionStart:タイムアウトしたコールバックは出力を返さないとカウントされ、セッションは他のSessionStartフックの出力で続行されます。PreModelSwitch:Claude Code はモデルスイッチをブロックします。応答しないフックはスイッチを承認していません。Notification、PreCompact、PostModelSwitchなどの他のイベント:Claude Code は失敗をログに記録して続行します。
Stop または SessionStart コールバックが初めてタイムアウトした場合、Claude Code はメッセージストリームに SDKInformationalMessage も追加します。これはセッションを駆動するアプリが応答しなかったことを示します。その後のタイムアウトはアプリが応答しない間、そのメッセージを繰り返しません。
コールバックが保留中の間にクエリを中断した場合、Claude Code は保留中のツール呼び出しをキャンセルします。v2.1.208 より前では、PreToolUse コールバックが保留中の間に中断した場合、ツール呼び出しは引き続き進行する可能性がありました。
コールバックがより多くの時間を必要とする場合は、その HookMatcher で高い timeout を設定してください。TypeScript では、タイムアウトが発火したときにキャンセルを適切に処理するために、3 番目のコールバック引数から AbortSignal を使用してください。
ツールが予期せずブロックされた
- すべての
PreToolUseフックでpermissionDecision: 'deny'の戻り値を確認してください - フックにログを追加して、返している
permissionDecisionReasonを確認してください - matcher パターンが広すぎないことを確認してください:空の matcher はすべてのツールにマッチします
変更された入力が適用されない
-
updatedInputがトップレベルではなくhookSpecificOutputの内側にあることを確認してください: -
updatedInputをpermissionDecision: 'defer'と組み合わせないでください。これは変更された入力を削除します。permissionDecisionを省略することは問題ありません:変更された入力は通常の権限評価を通じて引き続き適用されます。また、'allow'を返して変更された入力を自動承認するか、'ask'を返してユーザーに承認を求めることもできます -
hookSpecificOutputにhookEventNameを含めて、出力がどのフックタイプ用であるかを識別してください
Python でセッションフックが利用できない
SessionStart と SessionEnd は TypeScript で SDK コールバックフックとして登録できますが、その HookEvent タイプがそれらを省略しているため、Python SDK では利用できません。Python では、.claude/settings.json などの設定ファイルで定義された シェルコマンドフックとしてのみ利用できます。SDK アプリケーションがどの設定ファイルをロードするかは、setting_sources または settingSources によって決まります。このオプションを設定する場合は、フックを含むソースを含めてください:
client.receive_response() からの最初のメッセージをトリガーとして使用してください。
サブエージェント権限プロンプトが増加する
複数のサブエージェントをスポーンする場合、各サブエージェントは独自のツール呼び出しに対して権限を個別に求める可能性があります。繰り返されるプロンプトを避けるには、PreToolUse フックを使用して特定のツールを自動承認するか、権限ルールを設定してください。サブエージェントは 親会話から権限ルールを継承します。
サブエージェントを使用した再帰的フックループ
サブエージェントをスポーンするUserPromptSubmit フックは、それらのサブエージェントが同じフックをトリガーする場合、無限ループを作成できます。これを防ぐには:
- 共有変数またはセッション状態を使用して、既にサブエージェント内にいるかどうかを追跡してください
- フックをトップレベルエージェントセッションのみで実行するようにスコープしてください
systemMessage が出力に表示されない
systemMessage フィールドはモデルではなく、ユーザーにメッセージを表示します。Claude Code v2.1.227 以降では、フックの systemMessage はメッセージストリームに SDKInformationalMessage として表示される可能性があります。表示されるかどうかはイベントによって異なります。フックページの各 イベントのセクションは、出力がどのように表示されるかを説明しています。代わりにモデルにコンテキストを渡すには、additionalContext を返してください。
v2.1.227 より前では、SDK はメッセージストリームのフック出力を SessionStart および Setup フックのみで表示していました。他のイベントの場合、出力は includeHookEvents(Python では include_hook_events)が追加するライフサイクルイベントにのみ表示されていました。そのオプションのエントリは、各フックイベントが生成するライフサイクルイベントをカバーしています。
フック決定をアプリケーションに確実に表示する必要がある場合は、それらを個別にログに記録するか、専用の出力チャネルを使用してください。
関連リソース
- Claude Code フックリファレンス:完全な JSON 入力/出力スキーマ、イベント文書、およびマッチャーパターン
- Claude Code フックガイド:シェルコマンドフックの例とウォークスルー
- TypeScript SDK リファレンス:フック型、入力/出力定義、および設定オプション
- Python SDK リファレンス:フック型、入力/出力定義、および設定オプション
- パーミッション:エージェントが何をできるかを制御します
- カスタムツール:エージェント機能を拡張するツールを構築します