2026.05.18 · 19分で読める

Claude Code Hooks 完全実装ガイド|29イベントで品質ゲート・安全運用を仕組み化【2026年5月版】

Claude Code を「使う」と「安全に運用する」の間には深い溝があります。その溝を埋めるのが Hooks(フック) です。2026年5月時点で 全29種類のイベントが定義されており、PreToolUse でツール実行前に品質ゲートを走らせたり、Bash の rm -rf を強制ブロックしたり、SessionStart で本日の予定を自動表示したり、Stop で完了通知を Slack へ流したりと、AI の外側に仕組み化された守りを構築できます。本記事は自社で365日 quality-gate.sh を PostToolUse に組み込んで運用している筆者が、29イベントの全体像・6階層の設定ファイル・実装5パターン・exit code 2 の罠まで、2026年5月最新仕様で完全整理します。Subagents(5/15公開)と Components(5/16公開)と並んで、Claude Code 完全運用の3部作の最終章です。

目次

なぜ Hooks が「安全運用」を分けるのか

Claude Code は強力ですが、デフォルトのままで本番運用するとリスクが残ります。rm -rf を AI が判断ミスで実行する可能性、品質チェックを通さずに記事を公開する可能性、長時間セッションでコンテキストが汚れたまま重要操作に進む可能性などです。これらを人間の注意力だけで防ぐのは現実的ではありません。疲れている深夜にこそ事故は起きます。

そこで登場するのが Hooks です。Anthropic 公式 Hooks ドキュメントでは「Claude Code のライフサイクル各タイミングに、ユーザーが書いた処理を差し込める仕組み」と定義されています。これは 家のセキュリティシステムのようなもので、玄関のドアを開けた瞬間(SessionStart)、誰かが鍵を差し込もうとした瞬間(PreToolUse)、ドアを閉めた瞬間(Stop)に、それぞれ自動で動く警報やログ取得を仕込んでおけば、人間が一晩中見張る必要はありません。

Hooksは「AIの外側」に置く監視レイヤー AIの内側(プロンプト・思考・応答生成) Claude本体の判断ロジック CLAUDE.md / Subagents / Skills が効く層 Hooks の監視レイヤー(AIの外側) セッション SessionStart SessionEnd ターン UserPromptSubmit Stop / PreCompact ツール PreToolUse PostToolUse AIが何を考えているかに介入せず、起きたことに反応する

Subagents や Skills、Plugin(5/15・5/16 公開)はすべて AI の応答ロジック側に作用する仕組みでした。一方 Hooks は AI の応答とは独立に動く監視・制御レイヤーです。たとえるなら 運転手の隣に座るドライブレコーダーのようなもので、運転手の判断には口を出さず、危険なシーンを検知したら自動で警告音を鳴らす役割です。AI を信用しないわけではなく、信用とは別レイヤーで守りを置くのが Hooks の哲学です。2025年に Anthropic が Hooks 機構を導入して以降、2026年5月時点でイベントは 29種類に達しています。

29イベント早見表(4レイヤー分類)

Hooks は実行タイミングで 4つのレイヤーに分類できます。セッション単位・ターン単位・ツール単位・非同期です。家の防犯システムに例えるなら、セッション層は「家全体の警報セット/解除」、ターン層は「来客対応」、ツール層は「個別の鍵の開閉」、非同期層は「外周カメラの常時監視」のような関係です。

Claude Code Hooks 全29イベント・4レイヤー地図 セッション層 SessionStart SessionEnd Setup 用途: handoff自動表示 本日予定の注入 セッションログ ターン層 UserPromptSubmit UserPromptExpansion Stop / StopFailure PreCompact PostCompact TeammateIdle 用途: ルール動的注入 完了通知Slack compact前ログ ツール層 PreToolUse PostToolUse PostToolUseFailure PostToolBatch PermissionRequest PermissionDenied SubagentStart/Stop TaskCreated/Completed WorktreeCreate/Remove Elicitation ElicitationResult 用途: 品質ゲート連携 危険コマンド遮断 非同期層 Notification InstructionsLoaded ConfigChange CwdChanged FileChanged 用途: 外部監視・通知 .env 監視 ルール再読込 29イベントを4レイヤーで整理 — まず全体地図、次に9イベント深掘り

29イベントすべてを使う必要はありません。実運用で最初に触るべき 主要9イベントは、SessionStart・UserPromptSubmit・PreToolUse・PostToolUse・PreCompact・SessionEnd・Notification・Stop・SubagentStop です。これだけ押さえれば、品質ゲート連携・通知・ルール注入の3大用途は完成します。残り20イベントは特定の業界要件(金融のコンプライアンス、大企業の権限制御、MCP連携の細かい監査など)で必要になったときに追加すれば十分です。

設定ファイル6階層の使い分け

Hooks は 6種類の設定ファイルに書けます。最初に「どこに書くか」を間違えると、チーム配布や個人カスタムが噛み合わなくなります。たとえるなら 家・職場・カフェのWiFi設定のようなもので、どこに書いたかで効く範囲が決まります。

Hooks 設定ファイル6階層 ① ~/.claude/settings.json スコープ:全プロジェクト共通/個人専用/gitに上がらない ② .claude/settings.json スコープ:プロジェクト単位/リポジトリにcommit/チーム配布用 ③ .claude/settings.local.json スコープ:プロジェクト個人専用/gitignored/自分だけのカスタム ④ Managed policy(組織管理) スコープ:組織全体/管理者制御/allowManagedHooksOnlyで他層無効化可能 ⑤ Plugin hooks/hooks.json スコープ:Plugin有効時のみ/Marketplace配布/パッケージ同梱 ⑥ Skill / Agent フロントマター スコープ:コンポーネント利用時のみ/.claude/skills や agents 内に同梱 優先順位は重ね合わせ — 該当イベントの全層が同時並列実行される

初心者が混乱するのは、これらが 優先順位ではなく重ね合わせで動く点です。PreToolUse で Bash にマッチする Hooks を ②プロジェクト共有 と ③個人専用 の両方に書いた場合、両方が並列または逐次で実行されます。片方が exit 2 を返してブロックしたら、もう片方の結果に関係なくツール実行は止まります。「上書き」ではなく「全部足し合わせ」と覚えておきましょう。これは 家とオフィスのWiFi両方をPCにつなぐような関係のもので、両方アクティブだが優先するのは状況次第というイメージです。

実運用での使い分けの定石は次のとおりです。①個人共通の Hooks(rm -rf 全プロジェクト遮断など)は ~/.claude/settings.json、②チームに配布したい品質ゲートは .claude/settings.json、③自分だけの実験は .claude/settings.local.json、④組織のコンプライアンス要件は Managed policy、⑤汎用処理は Plugin として配布、⑥特定タスクに紐づく検証は Skill/Agent のフロントマターに同梱。Plugin 同梱 Hooks の構造は、5/16 公開の Claude Code Plugin・Skills・MCP・Subagents 4要素ガイドを参照してください。

最重要9イベント完全解説

ここからは実運用で必ず触る 主要9イベントを整理します。残り20イベントは特殊要件向けで、この9つはすべての Claude Code ユーザーの必修科目です。

4-1. SessionStart|開始時にコンテキスト動的注入

セッション開始または再開時に1回発火します。入力JSONの source で startup・resume・clear・compact を判別。最大の使い道は hookSpecificOutput.additionalContext で動的なテキストを注入することです。本日の予定・前回のhandoff・未完了タスクを毎セッションの先頭に自動表示できます。「あれ今日何するんだっけ」のロスがゼロになります。

4-2. UserPromptSubmit|送信前のルール注入

ユーザーがプロンプトを送信した直後、Claudeに渡される直前に発火します。入力JSONには promptpermission_mode が含まれます。decision: block で送信自体を止めることもできますが、一般的な用途は追加コンテキスト注入です。たとえば「リプ」「返信」が含まれていたらリプ作成3原則を強制注入する Hooks があれば、毎回 CLAUDE.md を読み込ませなくても確実にルールが効きます。timeout は30秒固定なので外部APIは避けましょう。

4-3. PreToolUse|ツール実行前の許可制御(最頻出)

Claude がツールを呼ぼうとする直前に発火する Hooks の主役です。入力JSONには tool_nametool_inputpermission_modeeffort.level が含まれ、出力の hookSpecificOutput.permissionDecisionallow / deny / ask / defer の4択を返します。

permissionDecision 挙動
allow 確認なしで即実行
deny 実行をブロック・理由をユーザーに表示
ask ユーザーに確認ダイアログを出す
defer 通常パーミッション判定に委ねる

典型例は 危険なコマンドの強制ブロックです。rm -rfgit push --force を含む場合は問答無用で deny を返す Hooks を入れれば、AI が一瞬気を抜いた瞬間の事故を防げます。判定の流れは次の通りです。

PreToolUse 判定木|4択の意思決定 ツール呼び出し受信 deny 禁止コマンド に該当 rm -rf git push -f ask 本番影響 の可能性 git push wp post create allow 安全な読み取り /ローカル編集 Read / Edit ls / cat defer 判定不能 通常判定へ 委ねる

シートベルトのようなもので、毎回意識しなくても自動で守ってくれる安心感が運用にとって大きいです。

4-4. PostToolUse|ツール成功後の検証(品質ゲートの主戦場)

ツール実行が成功した直後に発火します。失敗時は別イベント PostToolUseFailure が発火します。筆者の運用で最も価値を発揮しているのが、ここでの quality-gate.sh 連携です。記事ファイルを Edit/Write した直後に PostToolUse が発火し、tasks/articles/ 配下が変更されていれば quality-gate.sh を自動実行。文字数・SVG・JSON-LDの構造を即座に検証し、FAIL なら decision: block を返してClaudeに「ここで止まれ」と通知します。

4-5. PreCompact|コンテキスト圧縮前のセーフネット

コンテキストが自動コンパクションされる直前に発火します。matcher で manual(ユーザー手動)か auto(自動)かを判別できます。compact前にセッションログを退避させるのが主用途で、session-log.md にその日の学びを1〜3行で追記します。compact で文脈が薄くなる前に、後から自分が読み返せる形で残しておく仕組みです。

4-6. SessionEnd|セッション終了時の最終処理

セッション終了時に発火します。matcher は clearlogoutother の3種類です。典型用途はhandoff.mdへの自動書き出し、外部ダッシュボードへの作業ログ送信、ローカルバックアップなど。SessionEnd で書き残しを忘れない仕組みにしておくと、次セッション開始の SessionStart 側で読み込めて連続運用が成立します。

4-7. Notification|各種通知のフック

Claude Code が通知を出すときに発火します。type で permission_prompt・idle_prompt・auth_success・elicitation_dialog などを判別。Slack や macOS の通知センターに転送すれば、長時間タスクをバックグラウンド実行している時の気づき遅れを防げます。

4-8. Stop|ターン完了時のフック

Claude が応答を完了したときに発火します。入力JSONには effort.level(low/medium/high/xhigh/max)が含まれ、その応答にどれだけの計算量が使われたかが分かります。完了通知をSlack に流す、DB記録する、長時間処理後にBGMを停止するなど、ターン単位の後処理に最適です。

4-9. SubagentStop|サブエージェント完了時のフック

Subagent が処理を完了したときに発火します。ファクトチェックや自己評価のSubagentが終わった直後に結果ファイル(tasks/factchecks/factcheck-*.md)の構造を検証できます。Subagentの位置づけは Claude Code Subagents 実践ガイドを併読すると深まります。

Matcher 構文と if フィールド

Hooks は同じイベントでも matcher 構文で発火対象を絞り込みます。これを正しく書けないと「全Bashコマンドで毎回走る」など過剰実行でパフォーマンスを落とします。matcher は値の文字種類で 3種類のマッチング方式に自動切り替わります。食材の選別でいうところの「全部 vs 種類別 vs 細かい条件付き」のようなものです。

Matcher 構文の自動判定フロー matcher の値 “*” / 空 / 省略 → 全マッチ 全ツール対象 パフォーマンス注意 英数字・_・パイプのみ → 完全一致 Bash Edit|Write 特殊文字を含む → 正規表現 ^Notebook mcp__memory__.*

もうひとつ重要なのが if フィールドです。Claude Code のパーミッション規則構文で、ツール内の引数まで深掘りしてマッチを絞り込めます。"if": "Bash(git *)" なら git サブコマンドだけ、"if": "Edit(*.ts)" なら TypeScript 編集だけ、"if": "Bash(rm -rf *)" なら破壊的削除コマンドだけ発火させられます。matcher(ツール名)と if(引数内容)の2段絞り込みで過剰実行を最小化しましょう。

出力JSON仕様の3階層

Hooks が返すJSONには 3階層のフィールドがあります。トップレベル汎用・イベント別 decision・hookSpecificOutput です。玄関・各部屋・引き出しの3段階の鍵のようなものと覚えれば迷いません。

階層 代表フィールド 用途
トップレベル continue / stopReason / suppressOutput / systemMessage セッション全体への影響
イベント別decision decision: block / reason その動作をブロック
hookSpecificOutput permissionDecision / additionalContext イベント固有の細かい制御

たとえば PreToolUse で実行を拒否する場合:

{
  "hookSpecificOutput": {
    "hookEventName": "PreToolUse",
    "permissionDecision": "deny",
    "permissionDecisionReason": "rm -rf は全プロジェクトでブロックされています"
  }
}

SessionStartで動的コンテキストを注入する場合:

{
  "hookSpecificOutput": {
    "hookEventName": "SessionStart",
    "additionalContext": "本日のhandoff: ...\n未完了タスク: ..."
  }
}

自社運用5実装パターン|コード公開

ここからは実運用コードです。oishi-ai プロジェクトで 365日稼働させている5つのHooks実装を公開します。コピーするだけで Claude Codeの安全運用レベルが一段上がります。

パターン1:危険なBashコマンドの全プロジェクト共通ブロック

~/.claude/settings.json に書く全プロジェクト共通の防衛線です。シートベルトを全車両に標準装備するような位置づけです。

{
  "hooks": {
    "PreToolUse": [{
      "matcher": "Bash",
      "hooks": [{
        "type": "command",
        "command": "${HOME}/.claude/hooks/block-dangerous.sh",
        "timeout": 5
      }]
    }]
  }
}
#!/bin/bash
# ~/.claude/hooks/block-dangerous.sh
CMD=$(jq -r '.tool_input.command' < /dev/stdin)
PATTERNS='rm -rf|git push --force|git reset --hard|sudo |dd if=|mkfs\\.'
if echo "$CMD" | grep -E "$PATTERNS" > /dev/null; then
  jq -n --arg cmd "$CMD" '{
    "hookSpecificOutput": {
      "hookEventName": "PreToolUse",
      "permissionDecision": "deny",
      "permissionDecisionReason": ("禁止コマンドを検出: " + $cmd)
    }
  }'
fi
exit 0

パターン2:記事編集後の品質ゲート自動実行

記事HTMLを Edit/Write した直後に quality-gate.sh を走らせ、FAIL なら Claude に修正を促します。.claude/settings.json に書きプロジェクト全員で共有します。

{
  "hooks": {
    "PostToolUse": [{
      "matcher": "Edit|Write",
      "hooks": [{
        "type": "command",
        "command": "bash ${CLAUDE_PROJECT_DIR}/.claude/hooks/quality-gate-post.sh",
        "timeout": 120
      }]
    }]
  }
}
#!/bin/bash
# .claude/hooks/quality-gate-post.sh
FILE=$(jq -r '.tool_input.file_path' < /dev/stdin)
[[ ! "$FILE" =~ tasks/articles/.*\\.html$ ]] && exit 0

RESULT=$(bash "${CLAUDE_PROJECT_DIR}/scripts/quality-gate.sh" article "$FILE" 2>&1)
if echo "$RESULT" | grep -q 'FAIL: [1-9]'; then
  jq -n --arg r "$RESULT" '{
    "decision": "block",
    "reason": ("品質ゲート不合格:\\n" + $r)
  }'
fi
exit 0

パターン3:SessionStartで本日の文脈を動的注入

セッション開始時に handoff.md・週次スケジュール・未完了タスクを連結して additionalContext に返します。朝の打ち合わせ前にホワイトボードを見るようなものです。

{
  "hooks": {
    "SessionStart": [{
      "matcher": "startup|resume",
      "hooks": [{
        "type": "command",
        "command": "bash ${CLAUDE_PROJECT_DIR}/.claude/hooks/session-context.sh",
        "timeout": 30
      }]
    }]
  }
}
#!/bin/bash
# .claude/hooks/session-context.sh
CONTEXT=""
[ -f tasks/handoff.md ] && CONTEXT+="## 前回のhandoff\\n$(tail -50 tasks/handoff.md)\\n\\n"
[ -f tasks/weekly-schedule.md ] && CONTEXT+="## 本日の予定\\n$(grep "$(date '+%Y-%m-%d')" tasks/weekly-schedule.md)\\n"

jq -n --arg ctx "$CONTEXT" '{
  "hookSpecificOutput": {
    "hookEventName": "SessionStart",
    "additionalContext": $ctx
  }
}'

パターン4:UserPromptSubmitでルール強制注入

「リプ」「返信」が含まれていたらリプ作成3原則を強制注入します。CLAUDE.md だけだと毎回意識されないルールも、Hooks で強制すれば100%効きます。

#!/bin/bash
# .claude/hooks/reply-rules-injection.sh
PROMPT=$(jq -r '.prompt' < /dev/stdin)
if echo "$PROMPT" | grep -E 'リプ|返信|絡みたい' > /dev/null; then
  jq -n '{
    "hookSpecificOutput": {
      "hookEventName": "UserPromptSubmit",
      "additionalContext": "🔍 リプ大前提:①ファクトチェック必須 ②やんわり版のみ ③160-200字"
    }
  }'
fi
exit 0

パターン5:Stopで完了通知を macOS 通知センターに

長時間タスク完了の瞬間に通知を出します。Slack に流す場合は curl で Webhook を叩くだけで応用可能です。

{
  "hooks": {
    "Stop": [{
      "hooks": [{
        "type": "command",
        "command": "osascript -e 'display notification \\"完了\\" with title \\"oishi-ai\\"'",
        "timeout": 5,
        "async": true
      }]
    }]
  }
}

async: true をつけることで、通知処理が Claude の次ターン進行をブロックしません。軽い処理は async、重要な検証処理は同期と覚えておきましょう。

セキュリティ落とし穴8つ

Hooks は強力ですが、書き方を間違えると 動いてるつもりで動いてない状態に陥ります。実装でハマりやすい落とし穴を整理します。

No 落とし穴 対処
1 exit 1 はブロックされない exit 2 か JSON で deny を返す
2 stdout が JSON 以外を含むと全壊 デバッグ出力は stderr へ流す
3 HTTP は非2xxでブロック不可 2xx + decision block で返す
4 PermissionDenied で exit 2 無効 retry: true のみ有効
5 環境変数補間が黙って空文字に allowedEnvVars を必ず指定
6 シェル展開でパス破損 command と args を分離指定
7 MCP は接続済みサーバー限定 SessionStart で MCP 使わない
8 async のエラーは黙って消える 検証系は同期、通知系のみ async

最大の罠は exit 1 ではブロックされないこと。Unix の慣例だと「失敗=非ゼロ」ですが、Claude Code は exit 2 のみがブロック扱いです。初心者の9割がここで「ブロックしてるはずなのに実行される」とハマります。赤信号と黄信号で意味がまったく違う交通ルールのようなものと覚えておきましょう。

timeout / async / Managed Policy 運用判断

プロダクション運用で最後に整理しておきたいのが timeout・async・Managed Policy の3つの運用判断です。

Hook 型 デフォルト UserPromptSubmit
command 600秒 30秒
http 600秒 30秒
mcp_tool 600秒 30秒
prompt 30秒 30秒
agent 60秒 60秒

実運用では PreToolUse は5〜10秒、PostToolUse は60〜120秒、SessionStart は30〜60秒に設定。PreToolUse は毎ツール呼び出し前に走るため軽量バリデーション専用、PostToolUse は quality-gate.sh のような重い検証を許容、SessionStart は外部ファイル読み込みが主なので30秒で足りる、という棲み分けです。

async は通知系のみ、検証系は必ず同期。夜間警備員と監視カメラの違いのようなもので、警備員(同期)は判断して止める役割、カメラ(async)は記録するだけで止める権限はないという棲み分けです。

Managed Policy の allowManagedHooksOnly: true は組織統制の決定打です。これを true にすると ユーザー個人・プロジェクト・プラグインのすべての Hooks がブロックされ、管理者が指定した Hooks のみが有効になります。企業のAIガバナンス完全ガイドと組み合わせて運用する場面が増えています。

まとめ|3部作で組む安全運用

Claude Code を 「個人ツール」から「365日運用できるシステム」に押し上げるのが、Subagents(5/15公開)・Components(5/16公開)・Hooks(本記事)の3部作です。

要素 役割 主な使い道
Subagents 独立コンテキストで動く専用AIエージェント ファクトチェック・自己評価
Components Plugin・Skills・MCP・Subagents 4要素配布 能力配布・チーム共有
Hooks(本記事) AIの外側で動くイベント駆動スクリプト 品質ゲート・通知・安全制御

Subagents で 誰がやるかを分け、Components で 何を持たせるかを配布し、Hooks で どこで止めるかを仕組み化する。この3層が揃って初めて、Claude Code は深夜でも安全に動き続ける本物の運用基盤になります。本記事の5パターンはすべて自社365日稼働中。コピーして ~/.claude/ に置けば運用レベルが一段上がります。今のうちに Hooks を仕組み化できるかが、半年後の運用品質を決めます。

FAQ|よくある質問7問

Q1. Hooks の設定変更はリロード必要?

セッション中の設定変更は ConfigChange イベントが発火し、原則として次のターンから新しい設定が適用されます。即時反映を確実にしたい場合はセッションを再起動するのが安全です。

Q2. Hooks で Claude のプロンプト内容を改変できる?

UserPromptSubmit で additionalContext を返すことでコンテキストの追加は可能ですが、ユーザーが送信したプロンプト本体の改変はできません。改変ではなく 注入で対応するのが基本設計です。

Q3. async: true と asyncRewake: true の違いは?

async: true はバックグラウンド実行で完了通知なし。asyncRewake: true は完了時にClaudeを再起動して結果を渡せます。長時間検証用途に使います。

Q4. Hooks のテストはどうやる?

想定する入力JSONをファイルにして cat input.json | bash ~/.claude/hooks/foo.sh でstdoutを確認します。実セッションに組み込む前にJSON形式・終了コード・パフォーマンスを検証するのが定石です。

Q5. WorktreeCreate Hooks は git 外でも使える?

使えます。git リポジトリでない作業ディレクトリでも、WorktreeCreate/WorktreeRemove Hooks を設定すれば Claude Code に VCS非依存の分離環境を作る挙動を委譲できます。

Q6. Plugin 同梱と自前 Hooks が同じイベントで競合したら?

両方が並列または逐次で実行されます。どちらか1つでも exit 2decision: block を返せば最終的にブロック動作になります。「上書き」ではなく「足し合わせ」です。Managed Policy で allowManagedHooksOnly: true が立っている場合のみ例外です。

Q7. Hooks のログはどこに出る?

Claude Code 本体のデバッグログに記録されます。suppressOutput: true で stdout はログ除外できますが stderr は常時記録です。機密情報の出力には注意しましょう。

参考リンク

← Blog一覧へ