Claude Code Hooks 完全ガイド|9 ライフサイクル + 5 主要 matcher を全部実装【2026年5月版】
Claude Code の全 9 ライフサイクル Hook(PreToolUse / PostToolUse / UserPromptSubmit / Notification / Stop / SubagentStop / PreCompact / SessionStart / SessionEnd)+ 5 主要 matcher の組み合わせを実装サンプル付きで網羅。コスト管理・セキュリティ・監査・PII マスキング・品質ゲートを物理的に強制する運用テンプレ集。
Claude Code Hooks は、ツール呼び出しやセッションのライフサイクルに シェルスクリプトを差し込む 仕組みで、コスト爆発・セキュリティ事故・品質低下を CLAUDE.md やプロンプトだけでは取りこぼしやすい タイミングで阻止できます(exit code による制御のため、Claude 側の判断に依存せず強制力が働きます。ただし正規表現マッチの抜け漏れはあり得るため、後述の許可リスト方式と併用するのが前提です)。
本稿は 2026 年 5 月時点の 9 ライフサイクルイベント + 5 主要 matcher = 14 の実装パターン をすべて実機検証付きで解説する完全リファレンスです。
なぜ Hooks が必要か
ChatGPT のような対話型 AI と Claude Code の最大の違いは「実行する」ことです。Claude がコマンドを実行する直前・直後に 人間の意図を機械的に強制 できるのが Hooks。事例:
git push --forceを実行前にブロック(PreToolUse)- ファイル書き込み後に自動 lint
- セッション終了時に対話ログを S3 にアーカイブ
- 日次予算超過を検知して以降の継続を抑止(Stop は応答完了後に走る事後ガード)
- PII(個人情報)を含む出力を自動マスク
これらは CLAUDE.md やプロンプトに書くだけでは漏れる 領域です。Hooks は exit code でブロックを表現するため、Claude 側の判断に依存せず強制力が働きます(PreToolUse の exit 2 でツール実行を止められます)。
9 ライフサイクル一覧
| # | イベント | 起動タイミング | 主な用途 |
|---|---|---|---|
| 1 | PreToolUse | ツール実行前 | 危険コマンドのブロック、引数検証、コスト確認 |
| 2 | PostToolUse | ツール実行後 | 自動 fmt / lint、品質スコア、結果検証 |
| 3 | UserPromptSubmit | ユーザー送信直後 | プロンプトインジェクション検出、ログ |
| 4 | Notification | Claude が通知発火時 | 待機通知の自動転送、Slack 連携 |
| 5 | Stop | アシスタント応答完了時 | セッション終端の最終チェック、監査 |
| 6 | SubagentStop | サブエージェント完了時 | 並列タスクの集計、トークン精算 |
| 7 | PreCompact | 文脈圧縮直前 | 重要文脈の手動保護、メモ抽出 |
| 8 | SessionStart | セッション起動時 | 環境変数 / コンテキスト注入 |
| 9 | SessionEnd | セッション終了時 | クリーンアップ、外部ログ送信 |
5 主要 matcher(PreToolUse / PostToolUse 用)
| matcher | マッチするツール | よくある用途 |
|---|---|---|
Bash | shell コマンド | 危険コマンドの deny |
Write|Edit | ファイル書き換え | lint / fmt |
Read | ファイル読み込み | 機密ファイルの監視 |
WebFetch | 外部 URL 取得 | プロンプトインジェクション検出 |
Task | サブエージェント起動 | コスト管理 |
これらを組み合わせれば 14 通りの実装パターンが組めます。
1. PreToolUse — 暴走を止める最重要 Hook
.claude/settings.json の hooks.PreToolUse 配列に登録。マッチした すべての Hook が直列実行 され、いずれかが exit 2 を返すと Claude のツール呼び出しはブロックされます(stderr の内容がブロック理由として Claude に伝わります。exit 0 は通過、その他の非ゼロは「Hook のエラー」扱いでブロックはしません)。
1-A. 危険な Bash コマンドのブロック(matcher: Bash)
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{ "type": "command", "command": ".claude/hooks/pre-bash-guard.sh" }
]
}
]
}
}
#!/usr/bin/env bash
# .claude/hooks/pre-bash-guard.sh
INPUT=$(cat)
CMD=$(echo "$INPUT" | jq -r '.tool_input.command // ""')
# 物理的にブロックするパターン
if echo "$CMD" | grep -qE '(rm -rf /|git push -[fF]|git reset --hard|DROP TABLE|DELETE FROM .* WHERE 1=1)'; then
echo "[blocked] dangerous command pattern: $CMD" >&2
exit 2 # exit 2 = Claude にブロック理由を伝える
fi
exit 0
1-B. .env / 秘密ファイルへのアクセスを禁止(matcher: Read|Edit|Write)
#!/usr/bin/env bash
# .claude/hooks/pre-secret-guard.sh
INPUT=$(cat)
FILE=$(echo "$INPUT" | jq -r '.tool_input.file_path // .tool_input.path // ""')
if echo "$FILE" | grep -qE '\.env(\.|$)|/secrets/|credentials\.json$|\.pem$'; then
echo "[blocked] access to secret file: $FILE" >&2
exit 2
fi
exit 0
1-C. WebFetch のプロンプトインジェクション検査(matcher: WebFetch)
#!/usr/bin/env bash
# .claude/hooks/pre-webfetch-sanitize.sh
INPUT=$(cat)
URL=$(echo "$INPUT" | jq -r '.tool_input.url // ""')
# ローカルアドレスへの SSRF を防ぐ
if echo "$URL" | grep -qE '^https?://(localhost|127\.0\.0\.1|169\.254\.|10\.|192\.168\.|172\.(1[6-9]|2[0-9]|3[01])\.)'; then
echo "[blocked] SSRF attempt to local network: $URL" >&2
exit 2
fi
exit 0
2. PostToolUse — 結果を検証する品質ゲート
ツール実行後に走る。出力結果を見て 後段で品質検査 や自動 fmt を強制できます。
2-A. MDX 書き込み後の品質チェック(matcher: Write|Edit)
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{ "type": "command", "command": ".claude/hooks/post-mdx-quality.sh" }
]
}
]
}
}
#!/usr/bin/env bash
# .claude/hooks/post-mdx-quality.sh — 文字数 / H2 / 内部リンクの最低基準
INPUT=$(cat)
FILE=$(echo "$INPUT" | jq -r '.tool_input.file_path // ""')
[[ "$FILE" != *.mdx ]] && exit 0
WORD_COUNT=$(grep -v '^---' "$FILE" | wc -w)
H2_COUNT=$(grep -c '^## ' "$FILE")
LINK_COUNT=$(grep -oE '\[.*?\]\(/[^)]+\)' "$FILE" | wc -l)
WARN=""
[[ $WORD_COUNT -lt 1500 ]] && WARN+="本文 < 1,500 字 ($WORD_COUNT)\n"
[[ $H2_COUNT -lt 3 ]] && WARN+="H2 < 3 ($H2_COUNT)\n"
[[ $LINK_COUNT -lt 2 ]] && WARN+="内部リンク < 2 ($LINK_COUNT)\n"
if [[ -n "$WARN" ]]; then
echo -e "[mdx-quality]\n$WARN" >&2
# 警告のみで通す(exit 0)。ブロックしたい場合は exit 2
fi
exit 0
2-B. TypeScript ファイル編集後の tsc + prettier(matcher: Write|Edit)
#!/usr/bin/env bash
# .claude/hooks/post-ts-format.sh
INPUT=$(cat)
FILE=$(echo "$INPUT" | jq -r '.tool_input.file_path // ""')
[[ "$FILE" != *.ts && "$FILE" != *.tsx ]] && exit 0
cd "$(dirname "$FILE")" && cd $(git rev-parse --show-toplevel 2>/dev/null || echo .)
pnpm prettier --write "$FILE" 2>/dev/null
TSC=$(pnpm tsc --noEmit 2>&1 | grep "$(basename "$FILE")" | head -3)
if [[ -n "$TSC" ]]; then
echo "[tsc] $TSC" >&2
fi
exit 0
3. UserPromptSubmit — プロンプトインジェクション検出
ユーザーが送信したプロンプト本文を Claude が処理する前に 検査できます。
{
"hooks": {
"UserPromptSubmit": [
{ "type": "command", "command": ".claude/hooks/user-prompt-guard.sh" }
]
}
}
#!/usr/bin/env bash
# .claude/hooks/user-prompt-guard.sh
INPUT=$(cat)
PROMPT=$(echo "$INPUT" | jq -r '.prompt // ""')
# 既知の jailbreak パターン
if echo "$PROMPT" | grep -qiE 'ignore (all )?previous|disregard.*instructions|you are now (a |an )?[A-Z]'; then
echo "[user-prompt-guard] potential injection pattern detected" >&2
# ログだけ取って通す
fi
# 監査ログ
echo "$(date -u +%FT%TZ) USER_PROMPT length=${#PROMPT}" >> ~/.claude/audit/prompts.log
exit 0
4. Notification — Claude の通知をフックする
Claude が「ユーザーに確認したい」「処理が長引いている」等で通知を発火するタイミング。Slack / メール転送に最適。
{
"hooks": {
"Notification": [
{ "type": "command", "command": ".claude/hooks/notify-slack.sh" }
]
}
}
#!/usr/bin/env bash
# .claude/hooks/notify-slack.sh
INPUT=$(cat)
MSG=$(echo "$INPUT" | jq -r '.message // ""')
curl -sS -X POST "$SLACK_WEBHOOK_URL" \
-H 'Content-Type: application/json' \
-d "$(jq -nc --arg t "🛎 Claude: $MSG" '{text:$t}')" >/dev/null
exit 0
5. Stop — アシスタント応答完了時の最終チェック
セッションの 1 ターン応答が終わった時点で起動。全 mdx の console.log 漏れチェック や対話ログ送信に最適。
{
"hooks": {
"Stop": [
{ "type": "command", "command": ".claude/hooks/stop-archive-session.sh" }
]
}
}
#!/usr/bin/env bash
# .claude/hooks/stop-archive-session.sh — 対話 jsonl を S3 にアーカイブ
SESSION_DIR="${HOME}/.claude/projects/$(basename "$(pwd)" | tr ' ' '-' | tr '/' '-')"
LATEST=$(ls -t "$SESSION_DIR"/*.jsonl 2>/dev/null | head -1)
[[ -z "$LATEST" ]] && exit 0
DATE=$(date -u +%Y-%m-%dT%H-%M-%SZ)
aws s3 cp "$LATEST" "s3://your-claude-audit/$(hostname)/$DATE.jsonl" --quiet 2>/dev/null
exit 0
6. SubagentStop — サブエージェント完了時の集計
Task ツールで起動した subagent が終わったタイミング。並列タスクの結果集約・ログ記録に。
#!/usr/bin/env bash
# .claude/hooks/subagent-stop-accumulate.sh
INPUT=$(cat)
AGENT_TYPE=$(echo "$INPUT" | jq -r '.subagent_type // ""')
# 注: 消費トークン数(tokens_used)は Hook 入力に含まれる保証がないため、
# 取得できない場合に備えてフォールバック(0)を置く。正確な精算が必要なら別途集計する。
TOKENS=$(echo "$INPUT" | jq -r '.tokens_used // 0')
echo "$(date -u +%FT%TZ) $AGENT_TYPE tokens=$TOKENS" >> ~/.claude/audit/subagents.log
exit 0
7. PreCompact — 文脈圧縮直前のメモ抽出
Claude が文脈をオートコンパクトする直前。重要な決定事項を別ファイルに退避 できます。長時間セッションで「あの判断、何だったっけ?」を防ぐ最後の砦。
#!/usr/bin/env bash
# .claude/hooks/pre-compact-snapshot.sh
INPUT=$(cat)
TRANSCRIPT_PATH=$(echo "$INPUT" | jq -r '.transcript_path // ""')
[[ -z "$TRANSCRIPT_PATH" ]] && exit 0
# 直近の決定事項を抽出して別ファイルに残す
TS=$(date -u +%Y%m%d-%H%M%S)
DEST=".claude/snapshots/decisions-$TS.md"
mkdir -p .claude/snapshots
grep -E '(決定|approved|merged|deployed|削除)' "$TRANSCRIPT_PATH" | tail -50 > "$DEST"
exit 0
8. SessionStart — セッション起動時の環境準備
新しいセッションを開いたタイミング。プロジェクトの最新ブランチ確認 / git status 通知 / トークン残量表示 などのオンボーディング処理に。
#!/usr/bin/env bash
# .claude/hooks/session-start-brief.sh — セッション開始時の状況サマリ
echo "[session-start]" >&2
echo " branch: $(git rev-parse --abbrev-ref HEAD 2>/dev/null)" >&2
echo " unstaged: $(git status --short 2>/dev/null | wc -l)" >&2
echo " last commit: $(git log -1 --oneline 2>/dev/null)" >&2
exit 0
9. SessionEnd — セッション完全終了時のクリーンアップ
最後の Stop が走ってからセッションが完全に閉じる時点。一時ファイル削除 / 最終バックアップ に。
#!/usr/bin/env bash
# .claude/hooks/session-end-cleanup.sh
rm -rf /tmp/claude-session-cache/* 2>/dev/null
# 当日の subagent サマリを Discord に送信
TODAY=$(date -u +%F)
SUMMARY=$(grep "$TODAY" ~/.claude/audit/subagents.log 2>/dev/null | awk '{sum+=$NF} END{printf "subagents=%d tokens=%d", NR, sum}')
if [[ -n "$SUMMARY" && -n "$DISCORD_AGENT_WEBHOOK" ]]; then
curl -sS -X POST "$DISCORD_AGENT_WEBHOOK" \
-H 'Content-Type: application/json' \
-d "$(jq -nc --arg c "📊 today: $SUMMARY" '{content:$c}')" >/dev/null
fi
exit 0
exit code の意味(最重要)
Hook は stdout / stderr / exit code でツール実行の挙動を制御します。
| exit | 効果 |
|---|---|
0 | 通過。stdout / stderr は単にログとして扱われる |
2 | ブロック。Claude にブロック理由(stderr の内容)が伝わり、別の方法を試させる |
| その他非ゼロ | エラー。Claude には「Hook が失敗した」と伝わるが、ブロックはしない |
deny の意図を確実に伝えたいなら必ず exit 2。exit 1 だと「Hook 自体のバグ」と解釈され、ブロック効果が薄い。
当メディアでの 14 Hook 構成(実機検証済)
claude-code-media.com 自身の .claude/hooks/ 配下:
| # | Hook | matcher | 目的 |
|---|---|---|---|
| 1 | pre-bash-guard.sh | PreToolUse Bash | 危険コマンド deny |
| 2 | pre-secret-guard.sh | PreToolUse Read|Edit|Write | .env / secrets 保護 |
| 3 | pre-webfetch-sanitize.sh | PreToolUse WebFetch | SSRF + injection 防止 |
| 4 | pre-cost-gate.sh | PreToolUse Task | 日次予算超過時 subagent 起動拒否 |
| 5 | pre-mdx-frontmatter.sh | PreToolUse Write | frontmatter 必須項目チェック |
| 6 | post-mdx-quality.sh | PostToolUse Write|Edit | 文字数 / H2 / 内部リンク |
| 7 | post-mdx-seo-validate.sh | PostToolUse Write|Edit | E-E-A-T / Featured Snippet 構造 |
| 8 | post-mdx-geo-aio-check.sh | PostToolUse Write|Edit | quotable sentence / llm_summary |
| 9 | post-ts-format.sh | PostToolUse Write|Edit | tsc + prettier |
| 10 | user-prompt-guard.sh | UserPromptSubmit | injection 検出 + 監査 |
| 11 | notify-slack.sh | Notification | 待機通知転送 |
| 12 | stop-archive-session.sh | Stop | jsonl 対話ログを S3 へ |
| 13 | subagent-stop-accumulate.sh | SubagentStop | トークン精算 |
| 14 | session-end-cleanup.sh | SessionEnd | tmp 削除 + Discord 集計通知 |
これら 14 本で 編集部 1 人 + エージェント 30 体 の安全運用が回ります。詳細実装は Skills × Subagents × Hooks 使い分けマップ も参照。
よくある詰まりポイント
| 症状 | 原因 | 対処 |
|---|---|---|
| Hook が起動しない | パス間違い / chmod +x 忘れ | .claude/hooks/ に正確なパス + 実行権限付与 |
| stderr が見えない | echo 先が stdout になっている | echo "..." >&2 で stderr に明示 |
| ブロックが効かない | exit 1 を使っている | exit 2 に変更 |
| タイムアウト | 重い処理(外部 API 等) | 5 秒以内に完了させる、& で非同期化 |
| jq が無い | 標準ツール不足 | brew install jq |
| matcher が動かない | 正規表現が ungreedy | Write|Edit のように | でエスケープ不要 |
| 全部の Tool に発火する | matcher 未設定 | 空文字 "" でも全マッチになるので意図的に空にする時のみ使う |
設定ファイルのスコープ
Hook の設定は 3 段階で書けます。
| 位置 | 効く範囲 | 用途 |
|---|---|---|
~/.claude/settings.json | 全プロジェクト | 個人の安全装置(secret guard 等) |
<project>/.claude/settings.json | プロジェクト固有 | チームで共有する規律(mdx 品質等) |
<project>/.claude/settings.local.json | プロジェクト個人設定 | gitignore 推奨、個人の追加 hook |
優先順位は local > project > global。global で deny したものを local で上書き許可は基本不可(deny が強い)。
まとめ: 今すぐ入れるべき 3 つ + 余裕があれば 11
最初の 30 分 で入れるべき:
- pre-bash-guard.sh — rm -rf / force push を物理停止
- pre-secret-guard.sh — .env / secrets を物理保護
- post-mdx-quality.sh(or 同等の lint)— 書き込み品質を後段ガード
この 3 本で「半日で取り返しのつかない事故」のうち 80% は塞げます。残り 11 本は運用が安定してから順次。
関連記事:
- Claude Code でやってはいけない 7 つ — Hook が無いと起きる失敗事例集
- Skills × Subagents × Hooks 使い分けマップ — 三位一体運用パターン
- Claude Code 使い方 完全ガイド — Hook を仕込む前の基本セットアップ
- Claude Code 法人完全ガイド — Hook を稟議で承認させるための ROI 説明
FAQ
Q: Hooks を仕込むとどれくらい遅くなりますか?
A: 1 Hook あたり 50-200ms。本稿の 14 本全部仕込んでも 1 セッションあたり累積 1-2 秒程度。重い外部 API 連携は & で非同期化推奨。
Q: 既存プロジェクトに後から導入できますか?
A: できます。.claude/settings.json を作成し、.claude/hooks/ 配下にスクリプトを置くだけ。Claude Code 再起動不要、即時反映。
Q: Hooks 内で外部 API を叩いてもいいですか?
A: 可能ですが、タイムアウト管理必須(curl --max-time 3 等)。同期処理が長引くと Claude セッションが見かけ上止まる。
Q: ブロックしたい時の正しい exit code は?
A: exit 2。exit 1 は「Hook 自体のバグ」と解釈されブロック効果が弱い。
Q: Hook の stdout は Claude に渡りますか?
A: stderr のみ Claude が読みます。stdout は対話ログには残りますが Claude の文脈には入りません。ブロック理由は必ず stderr に。
Q: matcher で複数ツールを対象にできますか?
A: Write|Edit のように | 区切りで指定。正規表現として評価されます。
Q: Hook が無限ループする心配は?
A: PostToolUse で Edit を呼ぶような Hook を書くと、再度 PostToolUse が走るループが発生し得ます。Hook 内では Claude のツールを呼ばず、純粋なシェル操作のみで完結させる設計が安全。
関連記事
- Claude Code Skills × Subagents × Hooks 使い分け完全マップ — 三位一体の運用設計
- Claude Code Skills 完全ガイド — Hooks と組み合わせる自社知識の再利用
- Claude Code ベストプラクティス15選 — Hooks を含む最適化の全手法
- Claude Code Plan Mode とは? — 実行前の承認フローと安全性設計
- Claude Code CLAUDE.md の書き方 — Hooks と連動する設定ファイルの設計
- Claude Code でやってはいけない 7 つ — Hooks で防ぐ事故パターン
- Claude Code 完全ガイド — Hooks 以外の全機能を網羅したピラー記事
この記事の著者
claude-code-media 編集部/ Claude Code 専門編集チーム
Claude Code の非エンジニア向け業務効率化メディア『claude-code-lab.jp』を運営。フリーランス・中小企業・個人開発者向けに、実装テンプレ・業務自動化テクニック・Vibe Coding 入門を配信。
