factsClaude Codehooks

stable4 日前 · 2026-08-09

Hooks reference

概要

Claude Code のライフサイクルの特定の時点で自動実行される、ユーザー定義のシェルコマンド・HTTP エンドポイント・LLM プロンプト。ターミナル、IDE 拡張、デスクトップアプリ、Claude Code on the web のいずれでも同じ hook イベントが発火する。

仕様

実行の流れ

  • イベントが発火し matcher が一致すると、イベントの JSON コンテキストが hook ハンドラに渡される。command hook では stdin、HTTP hook では POST のリクエストボディ
  • イベントのカデンス
    • セッションに 1 回: SessionStartSessionEnd
    • ターンに 1 回: UserPromptSubmitStopStopFailure
    • agentic loop 内のツール呼び出しごと: PreToolUsePostToolUseEndConversation の呼び出しは両方をスキップする)

イベント一覧

イベント発火するタイミング
SessionStartセッションの開始・再開時
Setup--init-only での起動時、または -p モードでの --init / --maintenance
UserPromptSubmitプロンプト送信時、Claude が処理する前
UserPromptExpansionユーザーが打ったコマンドがプロンプトに展開されるとき、Claude に届く前。展開をブロックできる
PreToolUseツール呼び出しの実行前。ブロックできる
PermissionRequestツール呼び出しに permission の判断が必要なとき
PermissionDeniedauto mode の classifier がツール呼び出しを拒否したとき。{retry: true} でモデルに再試行可能と伝える
PostToolUseツール呼び出しの成功後
PostToolUseFailureツール呼び出しの失敗後
PostToolBatch並列ツール呼び出しのバッチ全体が解決した後、次のモデル呼び出しの前
NotificationClaude Code が通知を送るとき
MessageDisplayアシスタントメッセージのテキストが表示される間
SubagentStartsubagent が起動されたとき
SubagentStopsubagent が終了したとき
TaskCreatedTaskCreate でタスクが作られるとき
TaskCompletedタスクが完了としてマークされるとき
StopClaude が応答を終えたとき
StopFailureAPI エラーでターンが終わったとき。出力と終了コードは無視される
TeammateIdleagent team の teammate がアイドルになろうとするとき
InstructionsLoadedCLAUDE.md や .claude/rules/*.md がコンテキストへ読み込まれたとき。セッション開始時と遅延読み込み時に発火する
ConfigChangeセッション中に設定ファイルが変わったとき
CwdChanged作業ディレクトリが変わったとき(Claude が cd を実行したときなど)
DirectoryAdded/add-dir や SDK の register_repo_root で作業ディレクトリがセッション中に追加されたとき
FileChanged監視対象のファイルがディスク上で変わったとき。matcher で監視するファイル名を指定する
WorktreeCreate--worktreeisolation: "worktree"、バックグラウンドセッションのために worktree が作られるとき。既定の git 挙動を置き換える
WorktreeRemoveセッション終了時、subagent 終了時、バックグラウンドセッション削除時に worktree が削除されるとき
PreCompactcontext compaction の前
PostCompactcontext compaction の完了後
ElicitationMCP サーバーがツール呼び出し中にユーザー入力を要求したとき
ElicitationResultユーザーが MCP の elicitation に応答した後、サーバーへ返す前
SessionEndセッション終了時

設定の構造

JSON の settings ファイルで 3 段のネストとして定義する。

  1. 反応する hook イベントを選ぶ
  2. 発火条件を絞る matcher group を追加する
  3. 一致したときに動く 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.jsonplugin が有効なときはい
Skill / agent の frontmatterそのコンポーネントがアクティブな間はい
  • settings ファイル、managed policy settings、plugin の hooks は subagent 内でも動く。subagent がツールを呼ぶと PreToolUse / PostToolUse などがメイン会話と同じ hook を発火させ、入力に agent_idagent_type が入る
  • 管理者は allowManagedHooksOnly で user / project / plugin の hook をブロックできる。managed settings の enabledPlugins で強制有効化した plugin の hook は除外される
  • hook のエントリは settings のレベル間で置き換えではなくマージされる。disableAllHooks は managed settings の外からは managed hook を無効化できない
  • HTTP hook の allowlist(allowedHttpHookUrlshttpHookAllowedEnvVars)は managed policy settings を含むすべてのソースの hook に適用される
  • Claude Code on the web の cloud session はローカルの ~/.claude/settings.json を読まない

matcher パターン

matcher の値評価のされ方
"*"""、省略すべてに一致
英数字、_-、スペース、,| のみ完全一致、または | / ,(前後の空白は許容)区切りの完全一致リスト
それ以外の文字を含むJavaScript の正規表現(anchor 無し)
  • 正規表現経路では RegExp.prototype.test で判定されるため値のどこかに一致すれば成功する。Edit.*EditNotebookEdit の両方に一致する。全体一致には ^Edit$ のように anchor する
  • カンマ区切りと前後空白の許容は v2.1.191 以降が必要
  • 完全一致集合でのハイフンは v2.1.195 以降が必要。それ以前は code-reviewer が anchor 無し正規表現として扱われ senior-code-reviewer にも発火する
  • FileChangedStopFailure は英数字・_| のみの狭い完全一致集合を使う。ハイフン・スペース・カンマがあると正規表現経路に残り、区切りは | のみ

イベントごとの 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 / SubagentStopagent 種別general-purpose, Explore, Plan、カスタム agent 名、^my-plugin:reviewer$ のような plugin スコープ名
PreCompact / PostCompactcompaction のトリガー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 / ElicitationResultMCP サーバー名設定済みの MCP サーバー名
CwdChanged, UserPromptSubmit, PostToolBatch, Stop, TeammateIdle, TaskCreated, TaskCompleted, WorktreeCreate, WorktreeRemove, MessageDisplaymatcher 非対応常に発火する
  • 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 で結果を返す
httpJSON 入力を URL への HTTP POST として送る。レスポンスボディで command hook と同じ JSON 出力形式を返す
mcp_tool接続済み MCP サーバーのツールを呼ぶ。ツールのテキスト出力が command hook の stdout として扱われる
prompt単発評価のため Claude モデルへプロンプトを送る。モデルは yes/no の判断を JSON で返す
agentRead / 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)")。ツールイベント(PreToolUsePostToolUsePostToolUseFailurePermissionRequestPermissionDenied)でのみ評価される。それ以外のイベントでは 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 formargs あり): commandPATH 上の実行ファイルとして解決し、args を引数ベクタとして直接起動する。シェルが無いため各 args 要素はそのまま 1 引数になり、${CLAUDE_PLUGIN_ROOT} などのパスプレースホルダはプレーン文字列として置換される。アポストロフィ・$・バッククォートはそのまま通る
  • shell formargs 無し): 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 / .bat shim はシェル無しでは起動できない
  • どちらの 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 を返すと、非ブロッキングエラーになり実行は続く
  • SessionStartSetup は通常サーバー接続完了より前に発火するため、初回は「未接続」エラーになりうる

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 では Stop hook が自動的に 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 / SubagentStoplast_assistant_message を使う
cwdhook 呼び出し時の作業ディレクトリ
permission_mode現在の permission mode("default" / "plan" / "acceptEdits" / "auto" / "dontAsk" / "bypassPermissions")。Manual と表示されるモードは "default" として届く。すべてのイベントに入るわけではない
effortlevel フィールドを持つオブジェクト("low" / "medium" / "high" / "xhigh" / "max")。ultracode は "xhigh" として報告される。$CLAUDE_EFFORT 環境変数からも読める
hook_event_name発火したイベント名
agent_idsubagent の一意な識別子。subagent 内で発火したときのみ存在する
agent_typeagent 名。--agent 使用時、または subagent 内での発火時に存在する。subagent ではその型がセッションの --agent 値より優先される
  • model フィールドを受け取れるのは SessionStart hook だけで、存在は保証されない。$CLAUDE_MODEL 環境変数は無い
  • Claude Code は起動するすべてのサブプロセス(hook を含む)から OTEL_* の exporter 変数を取り除く

終了コードによる出力

  • Exit 0: 成功。stdout を JSON 出力フィールドとして解析する。JSON 出力は exit 0 のときのみ処理される。多くのイベントで stdout はデバッグログに書かれトランスクリプトには出ない。例外は UserPromptSubmitUserPromptExpansionSessionStart で、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 オブジェクトだけを出す
  • additionalContextsystemMessage、プレーンな stdout を含む hook の出力文字列は 10,000 文字が上限。超えるとファイルに保存され、プレビューとファイルパスに置き換えられる
フィールド既定説明
continuetruefalse で hook 実行後に Claude が処理を完全に停止する。イベント固有の決定フィールドより優先される
stopReasonなしcontinuefalse のときユーザーに表示するメッセージ。Claude には見えない
suppressOutputfalsetrue で 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(ウィンドウ・アイコンタイトル)、OSC 9(iTerm2 / ConEmu / Windows Terminal / WezTerm の通知、9;4 のタスクバー進捗を含む)、OSC 99(Kitty の通知)、OSC 777(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 のような値は古くなる。SessionStart hook は resume 時に source"resume"--fork-session なら "fork")として再実行される

decision control

イベント決定のパターン主なフィールド
UserPromptSubmit, UserPromptExpansion, PostToolUse, PostToolUseFailure, PostToolBatch, Stop, SubagentStop, ConfigChange, PreCompactトップレベルの decisiondecision: "block"reasonStopSubagentStop は会話を続ける非エラーのフィードバックとして hookSpecificOutput.additionalContext も受け付ける
TeammateIdle, TaskCreated, TaskCompleted終了コードまたは continue: falseexit 2 で stderr のフィードバック付きにブロックする。{"continue": false, "stopReason": "..."} でも停止する
PreToolUsehookSpecificOutputpermissionDecision(allow / deny / ask / defer)、permissionDecisionReason
PermissionRequesthookSpecificOutputdecision.behavior(allow / deny)
PermissionDeniedhookSpecificOutputretry: true でモデルに再試行可能と伝える
WorktreeCreateパスの返却command hook は stdout にパスを出力、HTTP hook は hookSpecificOutput.worktreePath を返す。失敗またはパス欠落で作成が失敗する
ElicitationhookSpecificOutputaction(accept / decline / cancel)、content(accept 時のフォーム値)
ElicitationResulthookSpecificOutputactioncontent(フォーム値の上書き)
MessageDisplayhookSpecificOutputdisplayContent が画面表示テキストを置き換える。表示のみで、トランスクリプトと Claude が見る内容は元のまま
SessionStart, Setup, SubagentStartコンテキストのみhookSpecificOutput.additionalContextSessionStart は加えて 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" では無視される
  • 複数の PreToolUse hook が異なる決定を返した場合の優先順位は deny > defer > ask > allow
  • hook が "ask" を返すと、permission prompt に出所のラベル([User] / [Project] / [Plugin] / [Local])が付く
  • hook の "ask" は auto mode でも permission prompt を強制する。classifier は拒否できるが黙って承認することはできない(v2.1.211 以降)
  • AskUserQuestionExitPlanMode は 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 はツールの idnameinput を持つ
  • タイムアウトも再試行上限も無い。セッションは cleanupPeriodDays(既定 30 日)の保持期間までディスクに残る
  • そのターンで Claude がツール呼び出しを 1 つだけ行う場合のみ機能する。複数同時のときは警告付きで無視され通常の permission フローに進む
  • resume 時に deferred なツールが利用できない場合、hook 発火前に stop_reason: "tool_deferred_unavailable"is_error: true で終了する
  • --resume は deferred 時の permission mode を復元する。例外は planbypassPermissions(決して引き継がれない)と auto(アカウントが要件を満たす場合のみ復元)

SessionStart の decision control

フィールド説明
additionalContext会話の先頭、最初のプロンプトより前に追加される文字列
initialUserMessageセッションの最初のユーザーメッセージとして使う文字列。-p の非対話モードで有効で、プロンプトが無くても最初のターンになる。プロンプトがあればその次のターンになる
sessionTitleセッションタイトルを設定する(/rename と同じ効果)。source"startup" / "resume" / "fork" のときに適用され、"clear""compact" では無視される
watchPathsこのセッション中に FileChanged イベントで監視する絶対パスの配列
reloadSkillstrue で、SessionStart hook 完了後に skill とコマンドのディレクトリを再スキャンし、hook がインストールした skill を同じセッションで使えるようにする
  • このイベントでは stdout がそのまま Claude に届くため、コンテキストを読み込むだけの hook は JSON を組み立てず stdout に出力してよい

hook タイプ別の対応イベント

  • 5 種類すべて(command / http / mcp_tool / prompt / agent)に対応: PermissionDeniedPermissionRequestPostToolBatchPostToolUsePostToolUseFailurePreToolUseStopSubagentStopTaskCompletedTaskCreatedTeammateIdleUserPromptExpansionUserPromptSubmit
  • command / http / mcp_tool のみ(promptagent 非対応): ConfigChangeCwdChangedDirectoryAddedElicitationElicitationResultFileChangedInstructionsLoadedNotificationPostCompactPreCompactSessionEndStopFailureSubagentStartWorktreeCreateWorktreeRemove
  • SessionStartSetupcommandmcp_tool のみ(http / prompt / agent 非対応)

prompt hook

  1. hook 入力とプロンプトを Claude モデル(既定は Haiku)に送る
  2. LLM が決定を含む構造化 JSON を返す
  3. Claude Code が決定を自動処理する
フィールド必須説明
typeはい"prompt"
promptはいLLM に送るプロンプト。$ARGUMENTS が hook 入力 JSON のプレースホルダ。無い場合は入力 JSON がプロンプト末尾に追加される
modelいいえ評価に使うモデル。既定は高速なモデル
timeoutいいえ秒。既定 30
continueOnBlockいいえプロンプトが ok: false を返したとき、停止せず理由を Claude に返してターンを続ける。既定 false

レスポンススキーマ: {"ok": true | false, "reason": "..."}okfalse のとき 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(実験的)

  1. プロンプトと hook の JSON 入力を持つ subagent を起動する
  2. subagent は Read / Grep / Glob などのツールで調査できる
  3. 最大 50 ターンの後、構造化された { "ok": true/false } の決定を返す
  4. Claude Code は prompt hook と同じように決定を処理する
フィールド必須説明
typeはい"agent"
promptはい何を検証するかのプロンプト。$ARGUMENTS が hook 入力 JSON のプレースホルダ
modelいいえ使うモデル。既定は高速なモデル
timeoutいいえ秒。既定 60

async hook

  • command hook に "async": true を付けるとブロックせずバックグラウンドで動く。このフィールドは type: "command" でのみ使える
  • async hook は Claude の挙動をブロック・制御できない。decisionpermissionDecisioncontinue などのレスポンスフィールドは効果が無い
  • hook プロセスは同じ JSON 入力を stdin で受け取る
  • バックグラウンドプロセスの終了後、additionalContext を含む JSON レスポンスがあれば、その内容が次の会話ターンでコンテキストとして Claude に届く。systemMessage はユーザーに表示される
  • レスポンスは同期 hook と同じ出力スキーマで検証され、型の合わないフィールドは配信されず落とされる。--debug で落とされたフィールド名の警告が見える
  • 完了通知は既定で抑止される。Ctrl+O の verbose モードまたは --verbose で表示される
  • 制約
    • 出力は次の会話ターンで配信される。セッションがアイドルなら次のユーザー操作まで待つ。例外は終了コード 2 の asyncRewake hook で、アイドルでも即座に Claude を起こす
    • 実行ごとに別のバックグラウンドプロセスが作られる。同じ async hook の複数回発火に対する重複排除は無い

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-operations
description: Perform operations with security checks
hooks:
  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.md
  • facts/claude-code/permissions.md
  • facts/claude-code/permission-modes.md
  • facts/claude-code/skills.md
  • facts/claude-code/sub-agents.md
  • facts/claude-code/mcp.md
  • facts/claude-code/tools-reference.md
  • facts/claude-code/worktrees.md
  • facts/claude-code/statusline.md
  • facts/claude-code/env-vars.md