ガイド
Claude Code フック入門:フックの設定方法、イベントの選び方、すぐ使えるサンプル
フックは、Claude Code がライフサイクルの特定のタイミングで実行する、ユーザー定義のシェルコマンドです。実行するのはモデルではなくフックなので、その動作は必ず行われます。このページは使い方の解説で、フックの置き場所、フックのエントリの形、特に重要なイベント、貼り付けて使える 4 つのサンプル、終了コードで操作をブロックする仕組み、フックが何もしないときの確認点を説明します。内容は Anthropic の Automate actions with hooks と Hooks reference に沿っており、2026 年 10 月 30 日に両ページで確認しました。
- フックは設定ファイル内の
hooksブロックです。イベントを選び、matcher で絞り込み、実行するハンドラーを定義します。すべてのプロジェクトに適用するなら~/.claude/settings.json、リポジトリで共有するなら.claude/settings.jsonに置きます。 - Claude Code で
/hooksと入力すると、フックが正しいイベントに登録されているか確認できます。 - 終了コード 0 は成功です。終了コード 2 は、ブロックできるイベントで操作をブロックし、stderr の内容が理由になります。それ以外の終了コードは、ブロックしないエラーです。
- command フックは、あなたのユーザー権限のままシェルコマンドを実行します。追加する前に、すべてのフックコマンドを確認してテストしてください。
フックとは何か、いつ使うか
フックは、ユーザー定義のシェルコマンドです。Claude Code はライフサイクルの特定のタイミングでそれを実行するので、LLM が実行するかどうかを選ぶのに頼らず、特定の操作が必ず行われる確定的な制御ができます。プロジェクトのルールの徹底、繰り返し作業の自動化、Claude Code と既存ツールとの連携にフックを使います。
Anthropic の例には、編集後のファイル整形、実行前のコマンドのブロック、Claude が入力を待っているときの通知、セッション開始時のコンテキストの注入などがあります。確定的なルールではなく判断が必要なものについては、ガイドは Claude モデルで条件を評価する prompt ベースと agent ベースのフックを案内しています。セッションを開始するたびにコンテキストを注入したいなら、ガイドは代わりに CLAUDE.md を勧めています。Claude に追加の指示や実行可能なコマンドを与えたい場合は、スキルを参照してください。
セキュリティ:command フックは、あなたのユーザー権限のままシェルコマンドを実行します。そのユーザーアカウントがアクセスできるファイルなら、変更、削除、アクセスのすべてが可能です。設定に追加する前に、すべてのフックコマンドを確認してテストしてください。
フックの設定場所
フックは JSON の設定ファイルで定義します。どこに追加するかで、スコープが決まります。
| 場所 | スコープ | 共有できるか |
|---|---|---|
~/.claude/settings.json | すべてのプロジェクト | できない。マシンのローカルのみ |
.claude/settings.json | 単一のプロジェクト | できる。リポジトリにコミットできる |
.claude/settings.local.json | 単一のプロジェクト | できない。Claude Code が設定を保存するときに gitignore される |
| Managed policy settings | 組織全体 | できる。管理者が管理する |
プラグインの hooks/hooks.json | プラグインが有効なとき | できる。プラグインに同梱される |
| スキルの frontmatter | スキルを呼び出した後のセッションの残り | できる。スキルファイルで定義する |
| サブエージェントの frontmatter | そのサブエージェントの実行中 | できる。サブエージェントのファイルで定義する |
Claude Code で /hooks と入力すると、設定されているフックを閲覧できる読み取り専用の画面が開きます。一覧には、ユーザー設定、プロジェクト設定、ローカル設定、プラグイン、現在のセッションなど、各フックの出どころが表示されます。フックを無効にするには、設定ファイルに "disableAllHooks": true を設定します。Claude Code の実行中に設定ファイルを直接編集した場合は、通常はファイルウォッチャーがフックの変更を自動で検出します。
対話セッションでは、そのフォルダ、またはその信頼が及ぶ親ディレクトリのワークスペース信頼ダイアログを承認するまで、Claude Code は、あなた自身の ~/.claude/settings.json も含め、すべての設定ファイルのフックを保留します。
フックのエントリの構造
設定は 3 段階のネストになっています。まず PreToolUse や Stop のように反応するフックイベントを選び、次に「Bash ツールのときだけ」のように発火の条件を絞る matcher グループを追加し、最後に、一致したときに実行するフックハンドラーを 1 つ以上定義します。各イベント名は、単一の hooks オブジェクトの中のキーです。次は、Anthropic のガイドにある最初のフックで、macOS のデスクトップ通知です。
{
"hooks": {
"Notification": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "osascript -e 'display notification \"Claude Code needs your attention\" with title \"Claude Code\"'"
}
]
}
]
}
}
設定ファイルにすでに hooks キーがある場合は、オブジェクト全体を置き換えるのではなく、既存のイベントのキーと並べて新しいイベントを追加してください。
内側の hooks 配列の各オブジェクトが、フックハンドラーです。ほとんどのフックは、シェルコマンドを実行する "type": "command" を使います。ほかに 4 つのタイプがあります。"type": "http"、"type": "mcp_tool"、"type": "prompt"、"type": "agent" です。agent フックは実験的で、変更される可能性があります。共通のハンドラーのフィールドは次のとおりです。
| フィールド | 必須 | 内容 |
|---|---|---|
type | はい | "command"、"http"、"mcp_tool"、"prompt"、"agent" |
if | いいえ | このフックを実行する条件を絞る、権限ルールの構文。例:"Bash(git *)"、"Edit(*.ts)"。ツールイベントでのみ評価されます:PreToolUse、PostToolUse、PostToolUseFailure、PermissionRequest、PermissionDenied。それ以外のイベントでは、if を設定したフックは実行されません |
timeout | いいえ | キャンセルされるまでの秒数。デフォルト:command、http、mcp_tool は 600、prompt は 30、agent は 60 |
statusMessage | いいえ | フックの実行中に表示される、カスタムのスピナーメッセージ |
Matcher
matcher がないフックは、そのイベントが起きるたびに発火します。matcher フィールドで発火の条件を絞れます。評価の方法は、含まれる文字によって変わります。
| matcher の値 | 評価のされ方 | 例 |
|---|---|---|
"*"、""、または省略 | すべてに一致 | そのイベントが起きるたびに発火する |
英字、数字、_、-、スペース、,、| のみ | 完全一致の文字列、または | か , で区切った完全一致の文字列のリスト(前後の空白は可) | Bash は Bash ツールにだけ一致し、Edit|Write と Edit, Write はどちらも 2 つのツールのいずれかに完全一致します |
| それ以外の文字を含む | JavaScript の正規表現(アンカーなし) | ^Notebook は名前が Notebook で始まるすべてのツールに一致し、mcp__memory__.* は memory サーバーのすべてのツールに一致します |
イベントの種類ごとに、一致を見るフィールドが異なります。PreToolUse と PostToolUse ではツール名、SessionStart ではセッションの開始方法(startup、resume、clear、compact、fork)、Notification では通知の種類です。matcher は大文字と小文字を区別します。UserPromptSubmit、Stop などいくつかのイベントは matcher に対応しておらず、常に毎回発火します。
if フィールドは、グループ単位でツール名だけを絞る matcher より細かく絞れます。次の例は、すべての Bash コマンドではなく、Claude が git コマンドを使うときだけフックを実行します。
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"if": "Bash(git *)",
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/check-git-policy.sh"
}
]
}
]
}
}
この絞り込みはベストエフォートなので、確実な許可や拒否を強制したいときは、フックではなく権限システムを使うようガイドは述べています。
よく使うイベント
イベントが発火すると、Claude Code は一致するフックを並列で実行します。ガイドにはもっと多くのイベントが挙げられていますが、ここではこのページのサンプルが使うものと、よく使ういくつかを紹介します。
| イベント | 発火するタイミング | ブロックできるか |
|---|---|---|
SessionStart | セッションの開始時、または再開時 | できない。終了コード 2 は stderr をユーザーにだけ表示する |
UserPromptSubmit | プロンプトが送信されたとき(Claude が処理する前) | できる。プロンプトをブロックする |
PreToolUse | ツール呼び出しの実行前 | できる。ツール呼び出しをブロックする |
PermissionRequest | ツール呼び出しに権限の判断が必要なとき | できない。終了コード 2 は尊重されず、代わりに decision オブジェクトで拒否する |
PostToolUse | ツール呼び出しが成功した後 | できない。stderr を Claude に表示する。ツールはすでに実行済み |
Notification | Claude Code が通知を送るとき | できない。終了コードと stderr は無視される |
Stop | Claude が応答を終えたとき | できる。Claude が止まるのを防ぎ、会話を続ける |
ConfigChange | セッション中に設定ファイルが変更されたとき | できる。変更をブロックする(policy_settings を除く) |
CwdChanged | 作業ディレクトリが変わったとき(例:Claude が cd コマンドを実行したとき) | できない。stderr をユーザーにだけ表示する |
PreCompact | コンテキストのコンパクトの前 | できる。コンパクトをブロックする |
SessionEnd | セッションが終了したとき | できない。stderr をユーザーにだけ表示する |
貼り付けて使える 4 つのサンプル
それぞれ、Anthropic のガイドにある、そのまま使える設定ブロックです。Bash のサンプルは JSON の解析に jq を使います。macOS では brew install jq、Debian と Ubuntu では apt-get install jq でインストールするか、jq のダウンロードページを参照してください。
Claude が入力を待っているときに通知を受け取る
このフックは Notification イベントを使います。Claude Code は、Claude が入力や許可を待っているときにこのイベントを発火します。macOS 版は上のセクションにあります。こちらは notify-send を使う Linux 版です。~/.claude/settings.json に追加します。
{
"hooks": {
"Notification": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "notify-send 'Claude Code' 'Claude Code needs your attention'"
}
]
}
]
}
}
空の matcher は、すべての通知の種類で発火します。特定のイベントでだけ発火させたい場合は、通知の種類のいずれかを設定します。たとえば permission_prompt(Claude がツールの使用の承認を求めている)や idle_prompt(Claude が約 60 秒前に応答を終え、その後あなたが入力していない)です。macOS で通知が出ない場合、osascript は通知を組み込みのスクリプトエディタ(Script Editor)アプリ経由で出すため、Script Editor に通知の権限がないと、コマンドは何も言わずに失敗します。Linux では notify-send にデスクトップ通知のデーモンが必要ですが、ヘッドレスのサーバー、SSH セッション、ほとんどのコンテナにはありません。
編集後にコードを自動整形する
このフックは、Edit|Write の matcher を付けた PostToolUse イベントを使うので、ファイル編集ツールの後にだけ実行されます。コマンドは jq で編集されたファイルのパスを取り出し、Prettier に渡します。プロジェクトルートの .claude/settings.json に追加します。
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "jq -r '.tool_input.file_path' | xargs npx prettier --write"
}
]
}
]
}
}
試すには、JavaScript ファイルに単一引用符の文字列を含む行を追加するよう Claude に頼み、そのファイルを開いてください。Prettier のデフォルト設定なら、フックがそれを二重引用符に書き換えます。フックが成功しても、Claude Code は会話に何も表示しないので、編集したファイルが整形されたかどうかで確認してください。Bash コマンドもファイルを書き換えられます。どのように変更されたかにかかわらず特定のファイルを整形し直すには、代わりに FileChanged フックを使います。
保護されたファイルの編集をブロックする
これは、Claude が .env、package-lock.json、.git/ 内のものなどの機密ファイルを変更するのを防ぎます。Claude には編集がブロックされた理由を説明するフィードバックが届くので、やり方を調整できます。このフックは、対象のファイルパスを保護パターンの一覧と照合し、終了コード 2 で編集をブロックするスクリプトを呼び出します。スクリプトを .claude/hooks/protect-files.sh に保存します。
#!/bin/bash
# protect-files.sh
INPUT=$(cat)
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')
# Normalize Windows backslash separators so the patterns below match
FILE_PATH="${FILE_PATH//\\//}"
PROTECTED_PATTERNS=(".env" "package-lock.json" ".git/")
for pattern in "${PROTECTED_PATTERNS[@]}"; do
if [[ "$FILE_PATH" == *"$pattern"* ]]; then
echo "Blocked: $FILE_PATH matches protected pattern '$pattern'" >&2
exit 2
fi
done
exit 0
Claude Code がフックのスクリプトを実行するには、実行可能にしておく必要があります。macOS と Linux では次のとおりです。
chmod +x .claude/hooks/protect-files.sh
続いて、.claude/settings.json に、Edit または Write ツールの呼び出しの前にスクリプトを実行する PreToolUse フックを追加します。
{
"hooks": {
"PreToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/protect-files.sh"
}
]
}
]
}
}
試すには、.env ファイルにコメントを追加するよう Claude に頼みます。Claude Code は編集を実行前にブロックし、スクリプトの Blocked: メッセージをフィードバックとして Claude に渡します。
コンパクト後にコンテキストを再注入する
Claude のコンテキストウィンドウがいっぱいになると、コンパクトが会話を要約して空きを作りますが、重要な詳細が失われることがあります。compact の matcher を付けた SessionStart フックを使うと、コンパクトのたびに重要なコンテキストを再注入できます。Claude Code は、コマンドが stdout に書き出したプレーンテキストを Claude のコンテキストに追加します。プロジェクトルートの .claude/settings.json に追加します。
{
"hooks": {
"SessionStart": [
{
"matcher": "compact",
"hooks": [
{
"type": "command",
"command": "echo 'Reminder: use Bun, not npm. Run bun test before committing. Current sprint: auth refactor.'"
}
]
}
]
}
}
echo は、git log --oneline -5 で最近のコミットを表示するなど、動的な出力を生成する任意のコマンドに置き換えられます。
終了コードとブロックの仕組み
フックは、stdin、stdout、stderr、終了コードを通じて Claude Code とやり取りします。イベントが発火すると、Claude Code はイベント固有のデータを JSON としてスクリプトの stdin に渡します。Bash コマンドの場合、PreToolUse フックは session_id、cwd、hook_event_name、tool_name、tool_input などのフィールドを受け取り、tool_input.command にシェルコマンドが入っています。次のスクリプトは、コマンドをブロックします。
#!/bin/bash
INPUT=$(cat)
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command')
if echo "$COMMAND" | grep -q "drop table"; then
echo "Blocked: dropping tables is not allowed" >&2 # stderr becomes Claude's feedback
exit 2 # exit 2 = block the action
fi
exit 0 # exit 0 = no decision; the normal permission flow applies
- 終了コード 0 は成功を意味します。
PreToolUseフックから 0 で終了しても、終了コード 0 は承認ではないため、ツール呼び出しは通常の権限フローを通ります。UserPromptSubmit、UserPromptExpansion、SessionStart、PostModelSwitchのフックでは、Claude Code はプレーンテキストの stdout を Claude のコンテキストに追加します。それ以外のほとんどのイベントでは、stdout はデバッグログに出力され、トランスクリプトには表示されません。 - 終了コード 2 は、ブロックできるイベントで操作をブロックします。理由は stderr に書いてください。ブロックに付くメッセージが、フックの stderr です。イベントによって、Claude がフィードバックとして受け取って調整する、ユーザーに表示される、メッセージが何も出ない、のいずれかになります。ブロックできないイベントもあり、
SessionStartなどでは、終了コード 2 は stderr をユーザーに表示し、実行は続きます。 - それ以外の終了コードは、ブロックしないエラーです。操作は進みますが、失敗すると操作をブロックするフック(たとえば
onFailureを"block"に設定したフック)は例外です。PreToolUseなどのイベントでは、トランスクリプトに<hook name> hook errorという通知が表示されます。
0 で終了したフックの stderr は、Claude には一切見えません。PostToolUse フックから Claude に警告を伝えるには、代わりに終了コード 2 を使います。ツールがすでに実行済みでも、Claude が stderr を見られます。PostToolUse フックは、ツールがすでに実行されているため、その操作を取り消せません。
終了コードでできるのは、ブロックするか黙るかだけです。より細かく制御するには、0 で終了して JSON オブジェクトを stdout に出力します。フックごとにどちらか一方の方法を選んでください。stderr のメッセージ付きでブロックするなら終了コード 2、構造化された制御なら JSON 付きの終了コード 0 です。たとえば、PreToolUse フックは、ツール呼び出しを拒否して、その理由を Claude に伝えられます。
{
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "deny",
"permissionDecisionReason": "Use rg instead of grep for better performance"
}
}
"deny" を指定すると、Claude Code はツール呼び出しをキャンセルし、permissionDecisionReason を Claude にフィードバックします。permissionDecision: "deny" を返すフックは、bypassPermissions モードや --dangerously-skip-permissions を指定していても、そのツールをブロックします。同じイベントに複数のフックが一致する場合、Claude Code が結果を統合する前にすべてのフックのコマンドが最後まで実行されるので、1 つのフックが deny を返しても、並んだ他のフックの実行は止まりません。
フックのデバッグ方法
/hooksを実行して、フックが正しいイベントの下に表示されているか確認します。- サンプルの JSON をスクリプトにパイプで渡してテストし、終了コードを確認します(下のコマンドを参照)。
Ctrl+Oを押してトランスクリプトビューを開き、フックの結果を探します。成功した場合は、フックの JSON が何かを表示しない限り、何も表示されません。ブロックのエラーでは、ブロックに付いたメッセージが表示されます。ブロックしないエラーでは、短い説明付きの<hook name> hook error通知が表示されます。- フックの終了コード、stdout、stderr を含む実行の詳細は、デバッグログで確認します。
claude --debug-file /tmp/claude.logで Claude Code を起動して既知のパスに書き出し、別のターミナルでtail -f /tmp/claude.logを実行します。このフラグなしで起動した場合は、セッションの途中で/debugを実行すると、ログが有効になり、ログのパスも分かります。
echo '{"tool_name":"Bash","tool_input":{"command":"ls"}}' | ./my-hook.sh
echo $? # Check the exit code
claude --debug-file /tmp/claude.log
tail -f /tmp/claude.log
トラブルシューティング
| 症状 | 確認すること |
|---|---|
| フックが発火しない | /hooks を実行し、正しいイベントの下に表示されているか確認します。matcher のパターンがツール名と完全に一致しているか確認します。matcher は大文字と小文字を区別します。正しい種類のイベントを発火させているか確認します。PreToolUse はツールの実行前、PostToolUse は実行後に発火します。 |
/hooks にフックが表示されない | 数秒たっても表示されない場合は、セッションを再起動して再読み込みさせます。JSON が有効か確認します。末尾のカンマとコメントは使えません。ファイルが正しい場所にあるか確認します。プロジェクトのフックは .claude/settings.json、グローバルなフックは ~/.claude/settings.json です。 |
| トランスクリプトに「PreToolUse hook error: ...」と出る | スクリプトが想定外に 0 以外のコードで終了しました。サンプルの JSON をパイプで渡して手動でテストします。スクリプトがそもそも実行されていないなら、chmod +x ./my-hook.sh で実行可能にします。 |
| 「command not found」 | スクリプトの参照には、絶対パスか ${CLAUDE_PROJECT_DIR} を使います。 |
| 「jq: command not found」 | jq をインストールするか、JSON の解析に Python や Node.js を使います。 |
| フックが JSON を出力しているのに何も起きない | 別のものが先に stdout へ書き込んでいる可能性があります。多くはシェルのプロファイルにある無条件の echo で、出力が { で始まらなくなります。それらの echo は、対話シェルでのみ実行されるようにしてください。あるいは、フィールドの階層が誤っている可能性があります。permissionDecision は、トップレベルではなく hookSpecificOutput の中に置きます。claude --debug で Claude Code を起動し、デバッグログで Hook output does not start with { や Hook JSON output had unrecognized keys を検索してください。 |
| Claude が作業を続け、Stop フックのブロックが多すぎるという警告が出る | Claude Code は、間に Claude のツール呼び出しがないまま Stop フックが 8 回連続でブロックすると、そのフックを上書きします。JSON の入力から stop_hook_active フィールドを解析し、true なら早めに終了してください。 |
stop_hook_active のチェックは、次のようになります。
#!/bin/bash
INPUT=$(cat)
if [ "$(echo "$INPUT" | jq -r '.stop_hook_active')" = "true" ]; then
exit 0 # Allow Claude to stop
fi
# ... rest of your hook logic
FAQ
CLAUDE.md の指示ではなく、フックを使うのはどんなときですか?
ある操作が必ず行われなければならないときにフックを使います。フックは、Claude Code が特定のタイミングで実行するシェルコマンドなので、LLM が実行するかどうかを選ぶのに頼りません。セッションを開始するたびにコンテキストを注入したい場合は、Anthropic のガイドは代わりに CLAUDE.md を勧めています。コンパクト後にコンテキストを再注入する例としては、compact の matcher を付けた SessionStart フックがあります。
フックはどの設定ファイルに置くべきですか?
すべてのプロジェクトに適用し、自分のマシンだけに置くフックは ~/.claude/settings.json を使います。1 つのプロジェクトで、リポジトリにコミットして共有できるものは .claude/settings.json を使います。1 つのプロジェクトで共有しないものは .claude/settings.local.json を使います。フックのエントリは、設定のレベルをまたいで統合され、互いに置き換わることはありません。
bypass モードでも、フックで何かをブロックできますか?
はい。permissionDecision: "deny" を返す PreToolUse フックは、PreToolUse フックが権限モードのチェックより前に発火するため、bypassPermissions モードや --dangerously-skip-permissions を指定していても、そのツールをブロックします。"allow" を返すフックは、設定にある deny ルールをバイパスしません。
参考資料
- Claude Code: Automate actions with hooks(最初のフック、サンプル、matcher、トラブルシューティング。2026 年 10 月 30 日に確認)
- Claude Code: Hooks reference(フックの場所、ハンドラーのフィールド、終了コード、デバッグ、セキュリティ上の考慮事項。2026 年 10 月 30 日に確認)