概要
Claude Code のライフサイクルの特定の時点で自動実行される、ユーザー定義のシェルコマンド・HTTP エンドポイント・LLM プロンプト。ターミナル、IDE 拡張、デスクトップアプリ、Claude Code on the web のいずれでも同じ hook イベントが発火する。
仕様
実行の流れ
- イベントが発火し matcher が一致すると、イベントの JSON コンテキストが hook ハンドラに渡される。command hook では stdin、HTTP hook では POST のリクエストボディ
- イベントのカデンス
- セッションに 1 回:
SessionStart、SessionEnd - ターンに 1 回:
UserPromptSubmit、Stop、StopFailure - agentic loop 内のツール呼び出しごと:
PreToolUse、PostToolUse(EndConversationの呼び出しは両方をスキップする)
- セッションに 1 回:
イベント一覧
| イベント | 発火するタイミング |
|---|---|
SessionStart | セッションの開始・再開時 |
Setup | --init-only での起動時、または -p モードでの --init / --maintenance 時 |
UserPromptSubmit | プロンプト送信時、Claude が処理する前 |
UserPromptExpansion | ユーザーが打ったコマンドがプロンプトに展開されるとき、Claude に届く前。展開をブロックできる |
PreToolUse | ツール呼び出しの実行前。ブロックできる |
PermissionRequest | ツール呼び出しに permission の判断が必要なとき |
PermissionDenied | auto mode の classifier がツール呼び出しを拒否したとき。{retry: true} でモデルに再試行可能と伝える |
PostToolUse | ツール呼び出しの成功後 |
PostToolUseFailure | ツール呼び出しの失敗後 |
PostToolBatch | 並列ツール呼び出しのバッチ全体が解決した後、次のモデル呼び出しの前 |
Notification | Claude Code が通知を送るとき |
MessageDisplay | アシスタントメッセージのテキストが表示される間 |
SubagentStart | subagent が起動されたとき |
SubagentStop | subagent が終了したとき |
TaskCreated | TaskCreate でタスクが作られるとき |
TaskCompleted | タスクが完了としてマークされるとき |
Stop | Claude が応答を終えたとき |
StopFailure | API エラーでターンが終わったとき。出力と終了コードは無視される |
TeammateIdle | agent team の teammate がアイドルになろうとするとき |
InstructionsLoaded | CLAUDE.md や .claude/rules/*.md がコンテキストへ読み込まれたとき。セッション開始時と遅延読み込み時に発火する |
ConfigChange | セッション中に設定ファイルが変わったとき |
CwdChanged | 作業ディレクトリが変わったとき(Claude が cd を実行したときなど) |
DirectoryAdded | /add-dir や SDK の register_repo_root で作業ディレクトリがセッション中に追加されたとき |
FileChanged | 監視対象のファイルがディスク上で変わったとき。matcher で監視するファイル名を指定する |
WorktreeCreate | --worktree、isolation: "worktree"、バックグラウンドセッションのために worktree が作られるとき。既定の git 挙動を置き換える |
WorktreeRemove | セッション終了時、subagent 終了時、バックグラウンドセッション削除時に worktree が削除されるとき |
PreCompact | context compaction の前 |
PostCompact | context compaction の完了後 |
Elicitation | MCP サーバーがツール呼び出し中にユーザー入力を要求したとき |
ElicitationResult | ユーザーが MCP の elicitation に応答した後、サーバーへ返す前 |
SessionEnd | セッション終了時 |
設定の構造
JSON の settings ファイルで 3 段のネストとして定義する。
- 反応する hook イベントを選ぶ
- 発火条件を絞る matcher group を追加する
- 一致したときに動く hook handler を 1 つ以上定義する
用語: hook event(ライフサイクル上の地点)、matcher group(フィルタ)、hook handler(実行されるシェルコマンド・HTTP エンドポイント・MCP ツール・プロンプト・agent)。
定義場所
| 場所 | スコープ | 共有 |
|---|---|---|
~/.claude/settings.json | 全プロジェクト | いいえ |
.claude/settings.json | 単一プロジェクト | はい(リポジトリにコミット可) |
.claude/settings.local.json | 単一プロジェクト | いいえ |
| Managed policy settings | 組織全体 | はい(管理者が制御) |
Plugin の hooks/hooks.json | plugin が有効なとき | はい |
| Skill / agent の frontmatter | そのコンポーネントがアクティブな間 | はい |
- settings ファイル、managed policy settings、plugin の hooks は subagent 内でも動く。subagent がツールを呼ぶと
PreToolUse/PostToolUseなどがメイン会話と同じ hook を発火させ、入力にagent_idとagent_typeが入る - 管理者は
allowManagedHooksOnlyで user / project / plugin の hook をブロックできる。managed settings のenabledPluginsで強制有効化した plugin の hook は除外される - hook のエントリは settings のレベル間で置き換えではなくマージされる。
disableAllHooksは managed settings の外からは managed hook を無効化できない - HTTP hook の allowlist(
allowedHttpHookUrls、httpHookAllowedEnvVars)は managed policy settings を含むすべてのソースの hook に適用される - Claude Code on the web の cloud session はローカルの
~/.claude/settings.jsonを読まない
matcher パターン
| matcher の値 | 評価のされ方 |
|---|---|
"*"、""、省略 | すべてに一致 |
英数字、_、-、スペース、,、| のみ | 完全一致、または | / ,(前後の空白は許容)区切りの完全一致リスト |
| それ以外の文字を含む | JavaScript の正規表現(anchor 無し) |
- 正規表現経路では
RegExp.prototype.testで判定されるため値のどこかに一致すれば成功する。Edit.*はEditとNotebookEditの両方に一致する。全体一致には^Edit$のように anchor する - カンマ区切りと前後空白の許容は v2.1.191 以降が必要
- 完全一致集合でのハイフンは v2.1.195 以降が必要。それ以前は
code-reviewerが anchor 無し正規表現として扱われsenior-code-reviewerにも発火する FileChangedとStopFailureは英数字・_・|のみの狭い完全一致集合を使う。ハイフン・スペース・カンマがあると正規表現経路に残り、区切りは|のみ
イベントごとの matcher 対象:
| イベント | matcher が絞るもの | 値の例 |
|---|---|---|
PreToolUse, PostToolUse, PostToolUseFailure, PermissionRequest, PermissionDenied | ツール名 | Bash, Edit|Write, mcp__.* |
SessionStart | セッションの開始方法 | startup, resume, clear, compact, fork |
Setup | どの CLI フラグが setup を起こしたか | init, maintenance |
SessionEnd | セッション終了の理由 | clear, resume, logout, prompt_input_exit, bypass_permissions_disabled, other |
Notification | 通知の種類 | permission_prompt, idle_prompt, auth_success, elicitation_dialog, elicitation_complete, elicitation_response, agent_needs_input, agent_completed |
SubagentStart / SubagentStop | agent 種別 | general-purpose, Explore, Plan、カスタム agent 名、^my-plugin:reviewer$ のような plugin スコープ名 |
PreCompact / PostCompact | compaction のトリガー | manual, auto |
ConfigChange | 設定のソース | user_settings, project_settings, local_settings, policy_settings, skills |
DirectoryAdded | 追加方法 | slash_command, register_repo_root |
FileChanged | 監視するリテラルなファイル名 | .envrc|.env |
StopFailure | エラー種別 | rate_limit, overloaded, authentication_failed, oauth_org_not_allowed, billing_error, invalid_request, model_not_found, server_error, max_output_tokens, unknown |
InstructionsLoaded | 読み込み理由 | session_start, nested_traversal, path_glob_match, include, compact |
UserPromptExpansion | コマンド名 | skill / コマンド名 |
Elicitation / ElicitationResult | MCP サーバー名 | 設定済みの MCP サーバー名 |
CwdChanged, UserPromptSubmit, PostToolBatch, Stop, TeammateIdle, TaskCreated, TaskCompleted, WorktreeCreate, WorktreeRemove, MessageDisplay | matcher 非対応 | 常に発火する |
- matcher 非対応のイベントに
matcherを書いても黙って無視される
MCP ツールへの一致
- MCP ツールは通常のツールとしてツールイベントに現れる。命名は
mcp__<server>__<tool> - サーバーの全ツールに一致させるには
.*を付ける。mcp__memoryのような形は完全一致文字だけなので文字列比較となり何にも一致しない - plugin バンドルの MCP サーバーのツールは
mcp__plugin_<plugin-name>_<server-name>__<tool>。素のサーバーキーで書いた matcher は発火しない
hook handler の種類
| 種類 | 説明 |
|---|---|
command | シェルコマンドを実行する。JSON 入力を stdin で受け取り、終了コードと stdout で結果を返す |
http | JSON 入力を URL への HTTP POST として送る。レスポンスボディで command hook と同じ JSON 出力形式を返す |
mcp_tool | 接続済み MCP サーバーのツールを呼ぶ。ツールのテキスト出力が command hook の stdout として扱われる |
prompt | 単発評価のため Claude モデルへプロンプトを送る。モデルは yes/no の判断を JSON で返す |
agent | Read / Grep / Glob などのツールを使って条件を検証する subagent を起動する。実験的 |
- 一致したすべての hook は並列に実行される。同じ handler を複数の settings ファイルで定義しても 1 回だけ動く。plugin や skill の同じ handler は別扱い
- handler は現在のディレクトリで Claude Code の環境で動く。リモートの web 環境では
$CLAUDE_CODE_REMOTEが"true"になる。v2.1.199 以降、Remote Control 接続中は$CLAUDE_CODE_BRIDGE_SESSION_IDが設定される
共通フィールド
| フィールド | 必須 | 説明 |
|---|---|---|
type | はい | "command" / "http" / "mcp_tool" / "prompt" / "agent" |
if | いいえ | permission rule 構文で発火を絞る("Bash(git *)"、"Edit(*.ts)")。ツールイベント(PreToolUse、PostToolUse、PostToolUseFailure、PermissionRequest、PermissionDenied)でのみ評価される。それ以外のイベントでは if 付きの hook は決して動かない |
timeout | いいえ | キャンセルまでの秒数。既定は command / http / mcp_tool が 600、prompt が 30、agent が 60。UserPromptSubmit は前 3 者の既定を 30 に、MessageDisplay は 10 に下げる。SessionEnd の hook は 1.5 秒の予算を共有する(settings のフックごとの timeout がより長ければ最大 60 秒まで引き上げられる) |
statusMessage | いいえ | 実行中に表示するスピナーメッセージ |
once | いいえ | true でセッションに 1 回だけ実行して削除される。skill frontmatter で宣言した hook でのみ有効で、settings ファイルと agent frontmatter では無視される |
ifは permission rule をちょうど 1 つだけ持つ。&&や||やリスト構文は無い。複数条件には handler を分ける- ファイルツールの
ifで"Edit(src/**)"のような単一セグメントのディレクトリパターンは、作業ディレクトリのsrcとその配下のみに一致する。任意の深さには"Edit(**/src/**)"。v2.1.214 より前は任意の深さに一致した
Bash パターンの if の挙動(先頭の VAR=value 代入は照合前に取り除かれる):
if パターン | Bash コマンド | hook が動くか | 理由 |
|---|---|---|---|
Bash(git *) | FOO=bar git push | はい | 先頭の代入が取り除かれ git push が一致 |
Bash(git *) | npm test && git push | はい | 各サブコマンドが確認され git push が一致 |
Bash(rm *) | echo $(rm -rf /) | はい | $() とバッククォート内のコマンドも確認される |
Bash(rm *) | echo $(date) | いいえ | rm * に一致するサブコマンドが無い |
Bash(git push *) | echo $(date) | はい | コマンド名以上を指定したパターンは $()・バッククォート・$VAR があるととにかく hook を動かす |
- Bash コマンドを解析できない場合もフィルタは fail open して hook を動かす。
ifは best-effort なので、確実な許可・拒否には permission system を使う
command hook のフィールド
| フィールド | 必須 | 説明 |
|---|---|---|
command | はい | 実行するシェルコマンド。args があるときは直接起動する実行ファイル |
args | いいえ | 引数リスト。あると command は実行ファイルとして解決され、シェルを介さず args を引数ベクタとして直接起動される |
async | いいえ | true でブロックせずバックグラウンド実行する |
asyncRewake | いいえ | true でバックグラウンド実行し、終了コード 2 で Claude を起こす。async を含意する。hook の stderr(空なら stdout)が system reminder として Claude に見せられる |
shell | いいえ | この hook に使うシェル。"bash" または "powershell"。既定は "bash"、Git Bash が無い Windows では "powershell"。CLAUDE_CODE_USE_POWERSHELL_TOOL は不要(hook は PowerShell を直接起動するため)。args を設定すると無視される |
exec form と shell form:
- exec form(
argsあり):commandをPATH上の実行ファイルとして解決し、argsを引数ベクタとして直接起動する。シェルが無いため各args要素はそのまま 1 引数になり、${CLAUDE_PLUGIN_ROOT}などのパスプレースホルダはプレーン文字列として置換される。アポストロフィ・$・バッククォートはそのまま通る - shell form(
args無し):command文字列がシェル(macOS / Linux はsh -c、Windows は Git Bash、Git Bash が無ければ PowerShell)に渡される。トークン化・変数展開・パイプ・&&・リダイレクト・glob が解釈される - パスプレースホルダを参照する hook では exec form を推奨する。shell form では各プレースホルダをダブルクォートで囲む
- Windows の exec form では
commandが.exeのような実際の実行ファイルに解決される必要がある。node_modules/.binの.cmd/.batshim はシェル無しでは起動できない - どちらの form も
CLAUDE_PROJECT_DIR/CLAUDE_PLUGIN_ROOT/CLAUDE_PLUGIN_DATAを起動プロセスの環境変数としてエクスポートする - plugin hook は exec form でのみ
${user_config.*}の値を置換する。shell form で参照するとエラーになる。代わりに$CLAUDE_PLUGIN_OPTION_<KEY>環境変数を読むかargsを設定して exec form にする
HTTP hook のフィールド
| フィールド | 必須 | 説明 |
|---|---|---|
url | はい | POST 先の URL |
headers | いいえ | 追加の HTTP ヘッダー。値は $VAR_NAME / ${VAR_NAME} の環境変数補間に対応する。allowedEnvVars に載る変数のみが解決される |
allowedEnvVars | いいえ | ヘッダー値に補間してよい環境変数名の一覧。載っていない変数の参照は空文字列に置き換えられる。環境変数の補間にはこの指定が必須 |
- JSON 入力は
Content-Type: application/jsonの POST ボディとして送られる
MCP tool hook のフィールド
| フィールド | 必須 | 説明 |
|---|---|---|
server | はい | 設定済み MCP サーバーの名前。plugin バンドルのサーバーでは plugin:<plugin-name>:<server-name> のスコープ名。サーバーは既に接続済みである必要があり、hook が OAuth や接続フローを起こすことはない |
tool | はい | そのサーバーで呼ぶツール名 |
input | いいえ | ツールに渡す引数。文字列値は hook の JSON 入力からの ${path} 置換に対応する("${tool_input.file_path}" など) |
- ツールのテキストコンテンツは command hook の stdout として扱われる。JSON 出力として妥当なら決定として処理され、そうでなければプレーンテキストとして表示される
- サーバーが未接続、またはツールが
isError: trueを返すと、非ブロッキングエラーになり実行は続く SessionStartとSetupは通常サーバー接続完了より前に発火するため、初回は「未接続」エラーになりうる
prompt / agent hook のフィールド
| フィールド | 必須 | 説明 |
|---|---|---|
prompt | はい | モデルに送るプロンプト。$ARGUMENTS が hook 入力 JSON のプレースホルダ。リテラルにはバックスラッシュでエスケープする |
model | いいえ | 評価に使うモデル。既定は高速なモデル |
パスプレースホルダ
${CLAUDE_PROJECT_DIR}: プロジェクトルート。stdio MCP サーバーと plugin の LSP サーバーの環境にも設定される${CLAUDE_PLUGIN_ROOT}: plugin のインストールディレクトリ。plugin 更新ごとに変わる${CLAUDE_PLUGIN_DATA}: plugin の永続データディレクトリ
skill / agent の frontmatter で定義する hook
- すべての hook イベントをサポートする。subagent では
Stophook が自動的にSubagentStopに変換される - 設定形式は settings ベースの hook と同じで、コンポーネントの生存期間にスコープされ終了時に片付けられる
- project subagent の frontmatter hook は、agent ファイルのあるフォルダの workspace trust ダイアログを承認した後にのみ動く(v2.1.218 以降)
/hooks メニュー
- 設定済み hook の読み取り専用ブラウザ。イベントごとの hook 数、matcher、各 handler の詳細を表示する
- 5 種類すべての hook タイプを表示し、
[type]接頭辞と出所(User Settings/Project Settings/Local Settings/Plugin Hooks/Session Hooks/Built-in Hooks)が付く - 読み取り専用。追加・変更・削除は settings JSON を直接編集する
無効化・削除
- 削除は settings JSON からエントリを消す
- 一時的にすべて無効にするには
"disableAllHooks": true。個別の hook だけを無効化する方法は無い - managed policy settings で設定された hook は、user / project / local の
disableAllHooksでは無効化できない。managed settings レベルのdisableAllHooksのみが可能 - settings ファイルの hook の直接編集は通常ファイル監視で自動的に反映される
共通の入力フィールド
| フィールド | 説明 |
|---|---|
session_id | 現在のセッション識別子 |
prompt_id | 処理中のユーザープロンプトを識別する UUID。OpenTelemetry の prompt.id と一致する。最初のユーザー入力までは存在しない。v2.1.196 以降 |
transcript_path | 会話 JSON のパス。非同期に書かれるためメモリ上の会話に遅れることがある。現在ターンの最終アシスタントテキストが必要な hook は Stop / SubagentStop の last_assistant_message を使う |
cwd | hook 呼び出し時の作業ディレクトリ |
permission_mode | 現在の permission mode("default" / "plan" / "acceptEdits" / "auto" / "dontAsk" / "bypassPermissions")。Manual と表示されるモードは "default" として届く。すべてのイベントに入るわけではない |
effort | level フィールドを持つオブジェクト("low" / "medium" / "high" / "xhigh" / "max")。ultracode は "xhigh" として報告される。$CLAUDE_EFFORT 環境変数からも読める |
hook_event_name | 発火したイベント名 |
agent_id | subagent の一意な識別子。subagent 内で発火したときのみ存在する |
agent_type | agent 名。--agent 使用時、または subagent 内での発火時に存在する。subagent ではその型がセッションの --agent 値より優先される |
modelフィールドを受け取れるのはSessionStarthook だけで、存在は保証されない。$CLAUDE_MODEL環境変数は無い- Claude Code は起動するすべてのサブプロセス(hook を含む)から
OTEL_*の exporter 変数を取り除く
終了コードによる出力
- Exit 0: 成功。stdout を JSON 出力フィールドとして解析する。JSON 出力は exit 0 のときのみ処理される。多くのイベントで stdout はデバッグログに書かれトランスクリプトには出ない。例外は
UserPromptSubmit、UserPromptExpansion、SessionStartで、stdout が Claude の見るコンテキストとして追加される - exit 0 の hook の stderr はデバッグログのみに行き、Claude は見ない
- Exit 2: ブロッキングエラー。stdout とその中の JSON は無視され、stderr のテキストがエラーメッセージとして Claude に返される
- exit 2 で JSON 出力のスキーマ検証に失敗する JSON を出した場合もブロックする。stderr をブロック理由として使い、検証失敗はデバッグログに記録される(v2.1.214 以降)
- それ以外の終了コード: 多くのイベントで非ブロッキングエラー。処理は続き、トランスクリプトに
<hook name> hook errorと stderr の先頭行がFailed with non-blocking status code:付きで表示される - exit 1 は非ブロッキングエラーとして扱われる。ポリシーを強制するなら
exit 2を使う。例外はWorktreeCreateで、非ゼロ終了コードはすべて worktree 作成を中断する
exit 2 のイベント別の挙動
| イベント | ブロックできるか | exit 2 で起きること |
|---|---|---|
PreToolUse | はい | ツール呼び出しをブロックする |
PermissionRequest | はい | permission を拒否する |
UserPromptSubmit | はい | プロンプト処理をブロックしプロンプトを消す |
UserPromptExpansion | はい | 展開をブロックする |
Stop | はい | Claude の停止を防ぎ会話を続ける |
SubagentStop | はい | subagent の停止を防ぐ |
TeammateIdle | はい | teammate のアイドル化を防ぎ作業を続けさせる |
TaskCreated | はい | タスク作成をロールバックする |
TaskCompleted | はい | タスクの完了マークを防ぐ |
ConfigChange | はい | 設定変更の反映をブロックする(policy_settings を除く) |
PostToolBatch | はい | 次のモデル呼び出しの前に agentic loop を止める |
PreCompact | はい | compaction をブロックする |
Elicitation | はい | elicitation を拒否する |
ElicitationResult | はい | 応答をブロックする(decline になる) |
WorktreeCreate | はい | 非ゼロ終了コードで worktree 作成が失敗する |
StopFailure | いいえ | 出力と終了コードは無視される |
PostToolUse / PostToolUseFailure | いいえ | stderr を Claude に見せる(ツールは既に実行済み) |
PermissionDenied | いいえ | 終了コードと stderr は無視される。hookSpecificOutput.retry: true を使う |
Notification / SubagentStart / SessionStart / Setup / SessionEnd / CwdChanged / FileChanged / PostCompact | いいえ | stderr をユーザーにのみ表示する |
DirectoryAdded | いいえ | stderr はデバッグログへ。ディレクトリは既に追加済み |
WorktreeRemove | いいえ | 失敗は debug モードでのみ記録される |
InstructionsLoaded | いいえ | 終了コードは無視される |
MessageDisplay | いいえ | 元のテキストが表示される |
HTTP レスポンスの扱い
- 2xx + 空ボディ: 成功(exit 0 で出力なしと等価)
- 2xx + プレーンテキスト: 成功。テキストがコンテキストとして追加される
- 2xx + JSON: 成功。command hook と同じ JSON 出力スキーマで解析される
- 非 2xx: 非ブロッキングエラー。実行は続く
- 接続失敗・タイムアウト: 非ブロッキングエラー。実行は続く
- HTTP hook はステータスコードだけではブロッキングエラーを表せない。ブロックには 2xx + 適切な決定フィールドを含む JSON ボディを返す
JSON 出力
- 終了コードと JSON はどちらか一方を使う。JSON は exit 0 のときのみ処理され、exit 2 では無視される
- stdout には JSON オブジェクトだけを出す
additionalContext、systemMessage、プレーンな stdout を含む hook の出力文字列は 10,000 文字が上限。超えるとファイルに保存され、プレビューとファイルパスに置き換えられる
| フィールド | 既定 | 説明 |
|---|---|---|
continue | true | false で hook 実行後に Claude が処理を完全に停止する。イベント固有の決定フィールドより優先される |
stopReason | なし | continue が false のときユーザーに表示するメッセージ。Claude には見えない |
suppressOutput | false | true で hook の stdout をトランスクリプトから隠す(デバッグログには残る) |
systemMessage | なし | ユーザーに表示する警告メッセージ |
terminalSequence | なし | Claude Code が代わりに出力するターミナルエスケープシーケンス。OSC 0/1/2/9/99/777 と BEL に限られる。allowlist 外を含むとフィールドは無視される |
- hook は制御端末を持たずに動くため
/dev/ttyへのエスケープシーケンス書き込みは失敗する。代わりにterminalSequenceを返す。tmux / GNU screen 内でも、/dev/ttyの無い Windows でも動く。v2.1.141 以降が必要 - 許可されるのは OSC
0/1/2(ウィンドウ・アイコンタイトル)、OSC9(iTerm2 / ConEmu / Windows Terminal / WezTerm の通知、9;4のタスクバー進捗を含む)、OSC99(Kitty の通知)、OSC777(urxvt / Ghostty / Warp の通知)、素の BEL。終端は BEL か ST
additionalContext
hookSpecificOutputの中にhookEventNameとともに返す- Claude Code は文字列を system reminder で包み、hook が発火した位置で会話に挿入する。Claude は次のモデルリクエストで読むが、UI 上のチャットメッセージとしては現れない
- 挿入位置
SessionStart/Setup/SubagentStart: 会話の先頭、最初のプロンプトより前UserPromptSubmit/UserPromptExpansion: 送信されたプロンプトと並んでPreToolUse/PostToolUse/PostToolUseFailure/PostToolBatch: ツール結果の隣Stop/SubagentStop: ターンの末尾。会話は続き Claude はフィードバックに反応できる
- 同じイベントで複数の hook が返した場合、Claude はすべての値を受け取る。1 つの値が 10,000 文字を超えると、全文がセッションディレクトリのファイルに書かれ、パスと短いプレビューが渡される
- 命令的なシステム指示ではなく事実の記述として書く。out-of-band のシステムコマンドのように書かれたテキストは prompt-injection 防御を起こし、Claude がコンテキストとして扱わずユーザーに提示することがある
- 注入されたテキストはセッショントランスクリプトに保存される。
--continue/--resumeでは過去ターンの hook を再実行せず保存済みテキストを再生するため、タイムスタンプやコミット SHA のような値は古くなる。SessionStarthook は resume 時にsourceを"resume"(--fork-sessionなら"fork")として再実行される
decision control
| イベント | 決定のパターン | 主なフィールド |
|---|---|---|
UserPromptSubmit, UserPromptExpansion, PostToolUse, PostToolUseFailure, PostToolBatch, Stop, SubagentStop, ConfigChange, PreCompact | トップレベルの decision | decision: "block"、reason。Stop と SubagentStop は会話を続ける非エラーのフィードバックとして hookSpecificOutput.additionalContext も受け付ける |
TeammateIdle, TaskCreated, TaskCompleted | 終了コードまたは continue: false | exit 2 で stderr のフィードバック付きにブロックする。{"continue": false, "stopReason": "..."} でも停止する |
PreToolUse | hookSpecificOutput | permissionDecision(allow / deny / ask / defer)、permissionDecisionReason |
PermissionRequest | hookSpecificOutput | decision.behavior(allow / deny) |
PermissionDenied | hookSpecificOutput | retry: true でモデルに再試行可能と伝える |
WorktreeCreate | パスの返却 | command hook は stdout にパスを出力、HTTP hook は hookSpecificOutput.worktreePath を返す。失敗またはパス欠落で作成が失敗する |
Elicitation | hookSpecificOutput | action(accept / decline / cancel)、content(accept 時のフォーム値) |
ElicitationResult | hookSpecificOutput | action、content(フォーム値の上書き) |
MessageDisplay | hookSpecificOutput | displayContent が画面表示テキストを置き換える。表示のみで、トランスクリプトと Claude が見る内容は元のまま |
SessionStart, Setup, SubagentStart | コンテキストのみ | hookSpecificOutput.additionalContext。SessionStart は加えて initialUserMessage / watchPaths / sessionTitle / reloadSkills |
WorktreeRemove, Notification, SessionEnd, PostCompact, InstructionsLoaded, StopFailure, CwdChanged, DirectoryAdded, FileChanged | 無し | 決定制御は無い。ログや後片付けなどの副作用に使う |
内容の書き換えができるイベント:
-
PreToolUse:hookSpecificOutput直下のupdatedInputがツールの引数を実行前に置き換える -
PermissionRequest:decisionオブジェクト内のupdatedInput -
PostToolUse:updatedToolOutputがツールの結果を置き換える -
UserPromptSubmit: プロンプトは置き換えられず、additionalContextを並べて注入するだけ -
トップレベル
decisionの唯一の値は"block"。許可するにはdecisionを省くか、JSON 無しで exit 0 する
PreToolUse の decision control
| フィールド | 説明 |
|---|---|
permissionDecision | "allow" は permission prompt を飛ばす(user interaction を要するツールと、組織が ask に設定した connector ツールを除く)。"deny" はツール呼び出しを防ぐ。"ask" はユーザーに確認を求める。"defer" は後で再開できるよう正常終了する。deny と ask のルールは hook の戻り値に関わらず評価される |
permissionDecisionReason | "allow" と "ask" ではユーザーにのみ表示され Claude には見えない。"deny" では Claude に表示される。"defer" では無視される |
updatedInput | 実行前にツールの入力パラメータを変更する。入力オブジェクト全体を置き換えるため変更しないフィールドも含める。"defer" では無視される |
additionalContext | ツール結果と並んで Claude のコンテキストに追加される文字列。"defer" では無視される |
- 複数の
PreToolUsehook が異なる決定を返した場合の優先順位はdeny>defer>ask>allow - hook が
"ask"を返すと、permission prompt に出所のラベル([User]/[Project]/[Plugin]/[Local])が付く - hook の
"ask"は auto mode でも permission prompt を強制する。classifier は拒否できるが黙って承認することはできない(v2.1.211 以降) AskUserQuestionとExitPlanModeは user interaction を要し、-pの非対話モードでは通常ブロックされる。permissionDecision: "allow"とupdatedInputを併せて返すとその要件を満たす。"allow"だけでは不十分- v2.1.199 以降、
_meta["anthropic/requiresUserInteraction"]が付いた MCP ツールは、updatedInputの有無に関わらず hook の"allow"で承認プロンプトを飛ばせない PreToolUseの旧来のトップレベルdecision/reasonは非推奨。"approve"は"allow"、"block"は"deny"に対応する
"defer":
claude -pをサブプロセスとして実行しその JSON 出力を読む統合(Agent SDK アプリやカスタム UI)向け。-pの非対話モードでのみ尊重され、対話セッションでは警告を記録して無視される- 流れ: hook が
"defer"を返す → ツールは実行されずstop_reason: "tool_deferred"で終了し保留中のツール呼び出しがトランスクリプトに保持される → 呼び出し元がdeferred_tool_useを読み自前 UI で回答を集める →claude -p --resume <session-id>で同じツール呼び出しが再びPreToolUseを発火 → hook がupdatedInputに回答を入れて"allow"を返す deferred_tool_useはツールのid、name、inputを持つ- タイムアウトも再試行上限も無い。セッションは
cleanupPeriodDays(既定 30 日)の保持期間までディスクに残る - そのターンで Claude がツール呼び出しを 1 つだけ行う場合のみ機能する。複数同時のときは警告付きで無視され通常の permission フローに進む
- resume 時に deferred なツールが利用できない場合、hook 発火前に
stop_reason: "tool_deferred_unavailable"とis_error: trueで終了する --resumeは deferred 時の permission mode を復元する。例外はplanとbypassPermissions(決して引き継がれない)とauto(アカウントが要件を満たす場合のみ復元)
SessionStart の decision control
| フィールド | 説明 |
|---|---|
additionalContext | 会話の先頭、最初のプロンプトより前に追加される文字列 |
initialUserMessage | セッションの最初のユーザーメッセージとして使う文字列。-p の非対話モードで有効で、プロンプトが無くても最初のターンになる。プロンプトがあればその次のターンになる |
sessionTitle | セッションタイトルを設定する(/rename と同じ効果)。source が "startup" / "resume" / "fork" のときに適用され、"clear" と "compact" では無視される |
watchPaths | このセッション中に FileChanged イベントで監視する絶対パスの配列 |
reloadSkills | true で、SessionStart hook 完了後に skill とコマンドのディレクトリを再スキャンし、hook がインストールした skill を同じセッションで使えるようにする |
- このイベントでは stdout がそのまま Claude に届くため、コンテキストを読み込むだけの hook は JSON を組み立てず stdout に出力してよい
hook タイプ別の対応イベント
- 5 種類すべて(
command/http/mcp_tool/prompt/agent)に対応:PermissionDenied、PermissionRequest、PostToolBatch、PostToolUse、PostToolUseFailure、PreToolUse、Stop、SubagentStop、TaskCompleted、TaskCreated、TeammateIdle、UserPromptExpansion、UserPromptSubmit command/http/mcp_toolのみ(promptとagent非対応):ConfigChange、CwdChanged、DirectoryAdded、Elicitation、ElicitationResult、FileChanged、InstructionsLoaded、Notification、PostCompact、PreCompact、SessionEnd、StopFailure、SubagentStart、WorktreeCreate、WorktreeRemoveSessionStartとSetupはcommandとmcp_toolのみ(http/prompt/agent非対応)
prompt hook
- hook 入力とプロンプトを Claude モデル(既定は Haiku)に送る
- LLM が決定を含む構造化 JSON を返す
- Claude Code が決定を自動処理する
| フィールド | 必須 | 説明 |
|---|---|---|
type | はい | "prompt" |
prompt | はい | LLM に送るプロンプト。$ARGUMENTS が hook 入力 JSON のプレースホルダ。無い場合は入力 JSON がプロンプト末尾に追加される |
model | いいえ | 評価に使うモデル。既定は高速なモデル |
timeout | いいえ | 秒。既定 30 |
continueOnBlock | いいえ | プロンプトが ok: false を返したとき、停止せず理由を Claude に返してターンを続ける。既定 false |
レスポンススキーマ: {"ok": true | false, "reason": "..."}。ok が false のとき reason は必須。
ok: false のイベント別の挙動:
Stop/SubagentStop: 理由が Claude の次の指示としてフィードバックされターンが続くPreToolUse: ツール呼び出しが拒否される。既定ではターンが終わり拒否理由が警告行として表示される。continueOnBlock: trueで理由をツールエラーとして Claude に返すPostToolUse: 既定ではターンが終わり理由が警告行として表示される。continueOnBlock: trueでフィードバックしターンを続けるPostToolBatch/UserPromptSubmit/UserPromptExpansion:continueに関わらずターンが終わり理由が警告行になるPostToolUseFailure/TaskCreated:continueOnBlockに関わらず理由がツールエラーとして返されターンが続くTaskCompleted: ターン中にタスクが完了マークされて発火した場合はツールエラーとして返しターンが続く。teammate 停止で発火した場合はTeammateIdleと同様に既定で teammate を止めるTeammateIdle: 既定で teammate が止まり理由が警告行になる。continueOnBlock: trueでフィードバックし作業を続けさせるPermissionRequest:ok: falseは効果が無い。拒否には command hook のhookSpecificOutput.decision.behavior: "deny"を使うPermissionDenied:ok: falseは効果が無い。このイベントが読むのはhookSpecificOutput.retryだけで、prompt / agent hook はそれを設定できない
agent hook(実験的)
- プロンプトと hook の JSON 入力を持つ subagent を起動する
- subagent は Read / Grep / Glob などのツールで調査できる
- 最大 50 ターンの後、構造化された
{ "ok": true/false }の決定を返す - Claude Code は prompt hook と同じように決定を処理する
| フィールド | 必須 | 説明 |
|---|---|---|
type | はい | "agent" |
prompt | はい | 何を検証するかのプロンプト。$ARGUMENTS が hook 入力 JSON のプレースホルダ |
model | いいえ | 使うモデル。既定は高速なモデル |
timeout | いいえ | 秒。既定 60 |
async hook
- command hook に
"async": trueを付けるとブロックせずバックグラウンドで動く。このフィールドはtype: "command"でのみ使える - async hook は Claude の挙動をブロック・制御できない。
decision、permissionDecision、continueなどのレスポンスフィールドは効果が無い - hook プロセスは同じ JSON 入力を stdin で受け取る
- バックグラウンドプロセスの終了後、
additionalContextを含む JSON レスポンスがあれば、その内容が次の会話ターンでコンテキストとして Claude に届く。systemMessageはユーザーに表示される - レスポンスは同期 hook と同じ出力スキーマで検証され、型の合わないフィールドは配信されず落とされる。
--debugで落とされたフィールド名の警告が見える - 完了通知は既定で抑止される。
Ctrl+Oの verbose モードまたは--verboseで表示される - 制約
- 出力は次の会話ターンで配信される。セッションがアイドルなら次のユーザー操作まで待つ。例外は終了コード 2 の
asyncRewakehook で、アイドルでも即座に Claude を起こす - 実行ごとに別のバックグラウンドプロセスが作られる。同じ async hook の複数回発火に対する重複排除は無い
- 出力は次の会話ターンで配信される。セッションがアイドルなら次のユーザー操作まで待つ。例外は終了コード 2 の
Windows の PowerShell
- command hook に
"shell": "powershell"を設定すると個別の hook を PowerShell で実行できる。pwsh.exe(PowerShell 7 以降)を自動検出し、無ければpowershell.exe(Windows PowerShell 5.1)にフォールバックする - PowerShell の shell form でプロジェクトルートを参照するには
${CLAUDE_PROJECT_DIR}または$env:CLAUDE_PROJECT_DIRと書く。v2.1.198 以降、${CLAUDE_PROJECT_DIR}/${CLAUDE_PLUGIN_ROOT}/${CLAUDE_PLUGIN_DATA}は PowerShell の${env:NAME}形式に書き換えられる。ダブルクォート内では展開されるがシングルクォート内では展開されない - 素の
$CLAUDE_PROJECT_DIRは書かない。PowerShell は未定義のローカル変数として$nullに解決する。Claude Code は書き換えず debug log に警告を記録する
デバッグ
- どの hook が一致したか、終了コード、stdout と stderr の全文はデバッグログに書かれる。
claude --debug-file <path>で任意の場所へ、claude --debugで~/.claude/debug/<session-id>.txtに書く。--debugはターミナルには出力しない CLAUDE_CODE_DEBUG_LOG_LEVEL=verboseで hook の matcher 数やクエリ照合などの詳細ログが追加される
設定
{ "hooks": { "PreToolUse": [ { "matcher": "Bash", "hooks": [ { "type": "command", "if": "Bash(rm *)", "command": "${CLAUDE_PROJECT_DIR}/.claude/hooks/block-rm.sh", "args": [] } ] } ] }}{ "hookSpecificOutput": { "hookEventName": "PreToolUse", "permissionDecision": "deny", "permissionDecisionReason": "Destructive command blocked by hook" }}{ "hooks": { "PostToolUse": [ { "matcher": "Write|Edit", "hooks": [ { "type": "command", "command": "${CLAUDE_PROJECT_DIR}/.claude/hooks/run-tests-async.sh", "args": [], "async": true, "timeout": 300 } ] } ] }}{ "hooks": { "PreToolUse": [ { "matcher": "Bash", "hooks": [ { "type": "http", "url": "http://localhost:8080/hooks/pre-tool-use", "timeout": 30, "headers": { "Authorization": "Bearer $MY_TOKEN" }, "allowedEnvVars": ["MY_TOKEN"] } ] } ] }}---name: secure-operationsdescription: Perform operations with security checkshooks: PreToolUse: - matcher: "Bash" hooks: - type: command command: "./scripts/security-check.sh"---制約・注意点
- command hook はユーザーの完全な権限でシェルコマンドを実行する。設定に追加する前にレビューとテストを行う
- 公式に挙げられているベストプラクティス: 入力を検証・サニタイズする、シェル変数は常にクォートする(
"$VAR")、パストラバーサル(..)をブロックする、絶対パスを使う、.envや.git/や鍵などの機微なファイルを避ける - macOS と Linux では、v2.1.139 以降 command hook は制御端末を持たない独自のセッションで動く。hook プロセスとその子プロセスは
/dev/ttyを開けず、エスケープシーケンスを直接 UI に送れない。ユーザーへのメッセージはsystemMessage、通知やタイトルやベルはterminalSequenceを使う
関連
facts/claude-code/settings.mdfacts/claude-code/permissions.mdfacts/claude-code/permission-modes.mdfacts/claude-code/skills.mdfacts/claude-code/sub-agents.mdfacts/claude-code/mcp.mdfacts/claude-code/tools-reference.mdfacts/claude-code/worktrees.mdfacts/claude-code/statusline.mdfacts/claude-code/env-vars.md