メインコンテンツへスキップ
フックはエージェントイベントに応答してコードを実行するコールバック関数です。ツールが呼び出されたり、セッションが開始したり、実行が停止したりするなどのイベントに対応します。フックを使用すると、以下のことができます。
  • 危険な操作をブロックする:破壊的なシェルコマンドや不正なファイルアクセスなど、実行前に危険な操作をブロックします
  • ログと監査:コンプライアンス、デバッグ、分析のためにすべてのツール呼び出しをログして監査します
  • 入力と出力を変換する:データをサニタイズしたり、認証情報を注入したり、ファイルパスをリダイレクトしたりします
  • 人間の承認を要求する:データベース書き込みや API 呼び出しなどの機密アクションに対して
  • セッションライフサイクルを追跡する:状態を管理したり、リソースをクリーンアップしたり、通知を送信したりします
このガイドでは、フックの仕組み、フックの設定方法、およびツールのブロック、入力の変更、通知の転送などの一般的なパターンの例を説明します。

フックの仕組み

1

イベントが発火する

エージェント実行中に何かが起こり、SDK がイベントを発火します。ツールが呼び出されようとしている(PreToolUse)、ツールが結果を返した(PostToolUse)、サブエージェントが開始または停止した、エージェントがアイドル状態である、または実行が完了したなどです。イベントの完全なリストを参照してください。
2

SDK が登録されたフックを収集する

SDK は、そのイベントタイプに登録されたフックをチェックします。これには、options.hooks に渡すコールバックフックと、対応する settingSources または setting_sources エントリが有効になっているときの設定ファイルからのシェルコマンドフックが含まれます。これはデフォルトの query() オプションで有効になっています。
3

マッチャーがどのフックを実行するかをフィルタリングする

フックに matcher パターン("Write|Edit" など)がある場合、SDK はそれをイベントのターゲット(たとえば、ツール名)に対してテストします。マッチャーのないフックは、そのタイプのすべてのイベントに対して実行されます。
4

コールバック関数が実行される

各マッチングフックのコールバック関数は、何が起こっているかについての入力を受け取ります。ツール名、その引数、セッション ID、およびその他のイベント固有の詳細です。
5

コールバックが決定を返す

任意の操作(ログ、API 呼び出し、検証)を実行した後、コールバックは出力オブジェクトを返します。これはエージェントに何をするかを指示します。操作を許可する、ブロックする、入力を変更する、または会話にコンテキストを注入するなどです。
次の例は、これらのステップをまとめたものです。PreToolUse フック(ステップ 1)を "Write|Edit" マッチャー(ステップ 3)で登録して、コールバックがファイル書き込みツールに対してのみ発火するようにします。トリガーされると、コールバックはツールの入力(ステップ 4)を受け取り、ファイルパスが .env ファイルをターゲットにしているかどうかをチェックし、permissionDecision: "deny" を返して操作をブロックします(ステップ 5)。

利用可能なフック

SDK はエージェント実行のさまざまなステージのフックを提供します。一部のフックは両方の SDK で利用可能ですが、その他は TypeScript のみです。

フックを設定する

フックを設定するには、エージェントオプション(Python では ClaudeAgentOptions、TypeScript では options オブジェクト)の hooks フィールドに渡します。
hooks オプションは辞書(Python)またはオブジェクト(TypeScript)です。ここで:

マッチャー

マッチャーを使用して、コールバックがいつ発火するかをフィルタリングします。matcher フィールドは、フックイベントタイプに応じて異なる値に対してマッチングされます。たとえば、ツールベースのフックはツール名に対してマッチングされ、Notification フックは通知タイプに対してマッチングされます。各イベントタイプのマッチャー値の完全なリストについては、Claude Code フックリファレンスを参照してください。 SDK マッチャーは設定ファイルのマッチャーと同じルールに従います。文字、数字、_-、スペース、,、および | のみを含むマッチャーは正確な文字列として比較され、| または , で区切られた代替案とオプションの周囲の空白があるため、Write|EditWrite, Edit はそれぞれこれら 2 つのツールと正確にマッチし、code-reviewer はそのエージェント型のみにマッチします。* のマッチャー、空の文字列、またはマッチャーを完全に省略すると、イベントのすべての発生にマッチします。 他の文字を含むマッチャーはアンカーなしの正規表現として評価されるため、^mcp__ はすべての MCP ツールにマッチし、Edit.*EditNotebookEdit の両方にマッチします。全文字列マッチが必要な場合は、正規表現を ^$ でラップします。 mcp__memory または mcp__brave-search のようなマッチャーは正確マッチ文字のみを含むため、正確な文字列として比較され、ツールにマッチしません。そのサーバーからすべてのツールにマッチするには、mcp__memory__.* を使用します。 ハイフンを正確マッチセットに含めるには、Claude Code ランタイム v2.1.195 以降が必要です。以前のバージョンでは、code-reviewer のようなハイフン付き名前はアンカーなしの正規表現として評価され、正確にマッチするには ^code-reviewer$ としてアンカーする必要があります。 可能な限り matcher パターンを使用して特定のツールをターゲットにします。'Bash' のマッチャーは Bash コマンドに対してのみ実行されますが、パターンを省略するとコールバックはそのイベントのすべての発生に対して実行されます。 ツールベースのフックの場合、マッチャーはツール名でのみフィルタリングされ、ファイルパスやその他の引数ではフィルタリングされません。ファイルパスでフィルタリングするには、コールバック内で tool_input.file_path をチェックします。
ツール名の発見: 組み込みツール名の完全なリストについてはツール入力型を参照するか、マッチャーなしでフックを追加して、セッションが行うすべてのツール呼び出しをログします。MCP ツール命名: MCP ツールは常に mcp__ で始まり、その後にサーバー名とアクション mcp__<server>__<action> が続きます。たとえば、playwright という名前のサーバーを設定した場合、そのツールは mcp__playwright__browser_screenshotmcp__playwright__browser_click などという名前になります。サーバー名は mcpServers 設定で使用するキーから取得されます。

コールバック関数

入力

すべてのフックコールバックは 3 つの引数を受け取ります。
  • 入力データ: イベント詳細を含む型付きオブジェクト。各フック型には独自の入力形状があります。たとえば、PreToolUseHookInput には tool_nametool_input が含まれ、NotificationHookInput には message が含まれます。TypeScript および Python SDK リファレンスで完全な型定義を参照してください。
    • すべてのフック入力は session_idcwd、および hook_event_name を共有します。
    • agent_idagent_type は、フックがサブエージェント内で発火するときに入力されます。TypeScript では、これらはベースフック入力にあり、すべてのフック型で利用可能です。Python では、これらは PreToolUsePostToolUsePostToolUseFailure、および PermissionRequest のオプションフィールドであり、SubagentStart および SubagentStop の必須フィールドです。
  • ツール使用 IDstr | None / string | undefined):同じツール呼び出しの PreToolUsePostToolUse イベントを相関させます。
  • コンテキスト: TypeScript では、キャンセル用の signal プロパティ(AbortSignal)を含みます。Python では、この引数は将来の使用のために予約されています。

出力

コールバックは 2 つのカテゴリのフィールドを持つオブジェクトを返します。
  • トップレベルフィールドはすべてのイベントで同じように機能します。systemMessage はユーザーにメッセージを表示し、continue(Python では continue_)はこのフック後にエージェントが実行を続けるかどうかを決定します。
  • hookSpecificOutput は現在の操作を制御します。内部のフィールドはフックイベントタイプに依存します。PreToolUse フックの場合、ここで permissionDecision"allow""deny""ask"、または "defer")、permissionDecisionReason、および updatedInput を設定します。"defer" を返すとクエリが終了し、後で再開できます。PostToolUse フックの場合、additionalContext を設定してツール結果に情報を追加できます。Claude がそれを見る前にツールの出力を置き換えるには、updatedToolOutput を設定します。これは両方の SDK のすべてのツールで機能します。古い updatedMCPToolOutput フィールドは MCP ツール出力のみを置き換え、非推奨です。
変更なしで操作を許可するには {} を返します。SDK コールバックフックは、Claude Code シェルコマンドフックと同じ JSON 出力形式を使用します。これはすべてのフィールドとイベント固有のオプションを文書化しています。SDK 型定義については、TypeScript および Python SDK リファレンスを参照してください。
複数のフックまたはパーミッションルールが適用される場合、denydefer より優先され、deferask より優先され、askallow より優先されます。いずれかのフックが deny を返す場合、他のフックに関係なく操作はブロックされます。

非同期出力

デフォルトでは、エージェントはコールバックが返されるのを待ってから続行します。フックが副作用(ログ、ウェブフック送信)を実行し、エージェントの動作に影響を与える必要がない場合、代わりに非同期出力を返すことができます。これはエージェントに、フックが完了するのを待たずに即座に続行するよう指示します。
非同期出力はエージェントが既に先に進んでいるため、ブロック、変更、またはコンテキストを注入することはできません。ログ、メトリクス、または通知などの副作用にのみ使用します。

ツール入力を変更する

この例は Write ツール呼び出しをインターセプトし、file_path 引数を書き直して /sandbox を先頭に追加し、すべてのファイル書き込みをサンドボックスディレクトリにリダイレクトします。コールバックは変更されたパスで updatedInput を返し、permissionDecision: 'allow' を返して書き直された操作を自動承認します。
updatedInput を使用する場合、permissionDecision: 'allow' を含めて変更された入力を自動承認するか、permissionDecision: 'ask' を含めてユーザーに表示する必要があります。'defer' の場合、updatedInput は無視されます。常に元の tool_input を変更するのではなく、新しいオブジェクトを返します。

コンテキストを追加してツールをブロックする

この例は /etc ディレクトリへの書き込みをブロックし、モデルとユーザーの両方に理由を説明します。
  • permissionDecision: 'deny' はツール呼び出しを停止します。
  • permissionDecisionReason はモデルに理由を伝えるため、再試行を避けます。
  • systemMessage はユーザーに何が起こったかを表示します。

特定のツールを自動承認する

デフォルトでは、エージェントは特定のツールを使用する前にパーミッションを求めるプロンプトを表示する場合があります。この例は、permissionDecision: 'allow' を返すことで読み取り専用ファイルシステムツール(Read、Glob、Grep)を自動承認し、ユーザー確認なしで実行できるようにしながら、他のすべてのツールは通常のパーミッションチェックの対象のままにします。

複数のフックを登録する

イベントが発火すると、すべてのマッチするフックが並列で実行されます。パーミッション決定の場合、最も制限的な結果が優先されます。単一の deny は、他のフックが何を返すかに関係なく、ツール呼び出しをブロックします。完了順序は非決定的であるため、別のフックが最初に実行されたことに依存するのではなく、各フックが独立して動作するように記述します。 以下の例は、すべてのツール呼び出しに対して 3 つの独立したチェックを登録します。

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

マルチツールマッチャーを使用して、関連するツール間で 1 つのコールバックを共有します。この例は、異なるスコープを持つ 3 つのマッチャーを登録します。
  • パイプで区切られた正確なリスト(Write|Edit|Delete)は、ファイル変更ツールに対してのみ file_security_hook をトリガーします。
  • 正規表現(^mcp__)は、名前が mcp__ で始まる任意の MCP ツールに対して mcp_audit_hook をトリガーします。
  • 省略されたマッチャーは、名前に関係なくすべてのツール呼び出しに対して global_logger をトリガーします。

サブエージェントアクティビティを追跡する

SubagentStop フックを使用して、サブエージェントが作業を完了するときを監視します。TypeScript および Python SDK リファレンスで完全な入力型を参照してください。この例は、サブエージェントが完了するたびに概要をログします。

フックから HTTP リクエストを行う

フックは HTTP リクエストなどの非同期操作を実行できます。フック内でエラーをキャッチして、処理されない例外がエージェントを中断しないようにします。 この例は、各ツールが完了した後にウェブフックを送信し、どのツールが実行されたかと実行時刻をログします。フックはエラーをキャッチして、失敗したウェブフックがエージェントを中断しないようにします。

通知を Slack に転送する

Notification フックを使用して、エージェントからのシステム通知を受け取り、外部サービスに転送します。通知は以下のようなイベントタイプに対して発火します。
  • permission_prompt(Claude がパーミッションを必要とする)
  • idle_prompt(Claude が入力を待機している)
  • auth_success(認証が完了した)
  • elicitation_dialogelicitation_complete、および elicitation_response(ユーザープロンプト引き出しフロー用)
各通知には、人間が読める説明を含む message フィールドと、オプションで title が含まれます。 この例は、すべての通知を Slack チャネルに転送します。Slack 受信ウェブフック URL が必要です。これは、Slack ワークスペースにアプリを追加し、受信ウェブフックを有効にすることで作成します。

一般的な問題を修正する

フックが発火しない

  • フックイベント名が正しく、大文字と小文字が区別されていることを確認します(preToolUse ではなく PreToolUse
  • マッチャーパターンがツール名と正確にマッチしていることを確認します
  • フックが options.hooks の正しいイベントタイプの下にあることを確認します
  • NotificationSubagentStop などの非ツールフックでマッチャーをサポートする場合、マッチャーは異なるフィールドに対してマッチングされ、Stop はマッチャーを完全に無視します(マッチャーパターンを参照)
  • エージェントが max_turns 制限に達するとセッションが終了する前にフックが実行される可能性があるため、フックが発火しない場合があります

マッチャーが期待どおりにフィルタリングしない

マッチャーはツール名のみをマッチングし、ファイルパスやその他の引数はマッチングしません。ファイルパスでフィルタリングするには、フック内で tool_input.file_path をチェックします:

フックタイムアウト

  • HookMatcher 設定で timeout 値を増やします
  • TypeScript で 3 番目のコールバック引数から AbortSignal を使用して、キャンセルを適切に処理します
UserPromptSubmit または UserPromptExpansion コールバックがタイムアウトを超過した場合、そのプロンプトはタイムアウトメッセージでブロックされ、セッションは続行されます。クエリを中断すると、保留中のツール呼び出しがキャンセルされます。v2.1.208 より前では、これらのイベントのコールバックタイムアウトはクエリを error_during_execution で終了し、保留中の PreToolUse コールバック中の中断はツール呼び出しを続行させる可能性がありました。

ツールが予期せずブロックされた

  • すべての PreToolUse フックで permissionDecision: 'deny' を返していないかチェックします
  • フックにログを追加して、返している permissionDecisionReason を確認します
  • マッチャーパターンが広すぎないことを確認します(空のマッチャーはすべてのツールにマッチングします)

変更された入力が適用されない

  • updatedInputhookSpecificOutput の内部にあり、トップレベルにないことを確認します:
  • 変更された入力を自動承認するには permissionDecision: 'allow' を返すか、ユーザーに承認を求めるには 'ask' を返します
  • hookSpecificOutputhookEventName を含めて、出力がどのフック型用かを識別します

Python でセッションフックが利用できない

SessionStartSessionEnd は TypeScript で SDK コールバックフックとして登録できますが、Python SDK では利用できません(HookEvent は除外されています)。Python では、設定ファイルで定義されたシェルコマンドフックとしてのみ利用可能です(たとえば、.claude/settings.json)。SDK アプリケーションからシェルコマンドフックをロードするには、setting_sources または settingSources で適切な設定ソースを含めます:
Python SDK コールバックとして初期化ロジックを実行するには、client.receive_response() からの最初のメッセージをトリガーとして使用します。

サブエージェントパーミッションプロンプトが増加する

複数のサブエージェントを生成する場合、各サブエージェントは個別にパーミッションをリクエストする可能性があります。サブエージェントは親エージェントのパーミッションを自動的に継承しません。繰り返されるプロンプトを避けるには、PreToolUse フックを使用して特定のツールを自動承認するか、サブエージェントセッションに適用されるパーミッションルールを設定します。

サブエージェントを使用した再帰的フックループ

サブエージェントを生成する UserPromptSubmit フックは、それらのサブエージェントが同じフックをトリガーする場合、無限ループを作成できます。これを防ぐには:
  • サブエージェント指標をチェックしてからサブエージェントを生成する前にフック入力をチェックします
  • 共有変数またはセッション状態を使用して、既にサブエージェント内にいるかどうかを追跡します
  • フックをトップレベルエージェントセッションのみに実行するようにスコープします

systemMessage が出力に表示されない

systemMessage フィールドはユーザーにメッセージを表示します。デフォルトでは SDK はメッセージストリームにフック出力を表示しないため、includeHookEvents(Python では include_hook_events)を設定しない限り、メッセージが表示されない場合があります。代わりにモデルにコンテキストを渡すには、additionalContextを返します。 フック決定をアプリケーションに確実に表示する必要がある場合は、別途ログするか、専用の出力チャネルを使用します。