「PreToolUse と PostToolUse の違いが分からない」で止まる人へ
Claude Code Hooks を触り始めると、多くの人が最初に詰まるのは設定ファイルの書き方そのものではありません。 PreToolUse と PostToolUse をどう使い分けるか が曖昧なまま、何となくサンプルをコピペしてしまうことです。
たとえば Prettier を必ず実行したい、.env は触らせたくない、CI の最後に型チェックを走らせたい。この3つは全部 Hooks で実現できますが、発火タイミングを間違えると意図どおりに動きません。実際、直近の検索でも claude code pretooluse のような具体クエリが出始めており、Hooks の「概念」よりも「どのイベントに何を書くか」の需要が高まっています。
CLAUDE.md のルールは「お願い」に過ぎません。LLM は確率的にテキストを生成する以上、長い会話の中でコンテキストが薄れれば、どんなに明確に書いたルールも無視されます。筆者も以前は pnpm run format を CLAUDE.md に書いていましたが、10回に2〜3回は実行されないまま作業が進んでいました。
Hooks はこの問題を根本的に解決します。 CLAUDE.md が「こうしてほしい」という希望文なのに対して、Hooks は「こうする」という決定論的なルールです。ツール実行の前後にシェルコマンドを自動で走らせ、100% の確率で処理を強制します。
この記事では、「Claude Code Hooks の使い方」を調べている人向けに、まず PreToolUse / PostToolUse を理解し、その上で通知・自動フォーマット・危険操作ブロック・品質ゲートへ広げる順番で整理します。単なるサンプル集ではなく、実務でどこに効くかまで踏み込みます。
Claude Code 全体の導入順や CLAUDE.md、権限設計、Auto-Fix まで含めた全体像から掴みたい場合は、先に Claude Code 実践ガイド を読むと、Hooks をどこで効かせるべきかが整理しやすくなります。CLAUDE.md 側の設計を詰めたい人は CLAUDE.md の書き方 設計パターン集 も前提知識になります。
Hooks の全体像 — まず PreToolUse / PostToolUse から理解する
Hooks は settings.json に設定を書くことで、Claude Code のライフサイクルの特定のタイミングで処理を自動実行する仕組みです。
4つのハンドラタイプ
command → シェルコマンドを実行(最も基本的)
http → HTTPエンドポイントにPOST送信
prompt → LLMに単発の評価を依頼
agent → サブエージェントを起動(ファイル読み取り等が可能)
ほとんどの用途では command 型で十分です。prompt 型と agent 型は品質ゲートやコードレビュー自動化など、判断を伴う処理に使います。http 型はチームでの監査ログ送信や外部サービス連携に便利です。
主要なイベント
2026年3月時点で Hooks がサポートするイベントは 21 に増えていますが、実務でよく使うのは以下の 6 つです。
| イベント | 発火タイミング | ブロック可能 | 主な用途 |
|---|---|---|---|
| PreToolUse | ツール実行の直前 | Yes | 危険操作のブロック、ファイル保護 |
| PostToolUse | ツール実行の成功後 | No | 自動フォーマット、テスト実行 |
| Notification | 通知送信時 | No | デスクトップ通知 |
| Stop | Claude の応答完了時 | Yes | 品質ゲート、最終チェック |
| SessionStart | セッション開始・再開時 | No | コンテキスト注入 |
| UserPromptSubmit | プロンプト送信時 | Yes | 入力バリデーション |
PreToolUse と PostToolUse が最重要です。この2つだけでも、開発体験は大きく変わります。
PreToolUse / PostToolUse を最初にどう覚えるか
ここは丸暗記でよいです。
- PreToolUse: ツール実行の前に走る。危険操作を止めたいときに使う
- PostToolUse: ツール実行の後に走る。整形や通知など後処理に使う
つまり、.env 編集や rm -rf を防ぎたいなら PreToolUse、prettier --write やテスト実行を自動化したいなら PostToolUse です。PostToolUse は「実行後」なので、ここでエラーを返しても元の操作自体は取り消せません。
Hooks の使い方で迷う人の多くは、実は matcher や JSON 構文ではなく、この順番を誤解しています。まずは 止めるものは Pre、付け足すものは Post と覚えてください。
設定ファイルの場所
~/.claude/settings.json → 全プロジェクト共通(個人用)
.claude/settings.json → プロジェクト固有(Git管理可)
.claude/settings.local.json → プロジェクト固有(gitignore対象)
チームで共有したいルールは .claude/settings.json に、個人の好みは ~/.claude/settings.json に書くのがベストです。
段階的導入ロードマップ — Day 1 から Month 1 まで
Hooks を一気に設定しようとすると、デバッグが大変です。筆者の経験上、段階的に導入するのが最も効率的でした。
Day 1: デスクトップ通知(効果を体感する)
まずは最もシンプルな Notification Hook から始めましょう。Claude が長時間の処理を終えた際にデスクトップ通知が届くようになります。
{
"hooks": {
"Notification": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "MSG=$(cat | jq -r '.message // \"Task completed\"'); osascript -e \"display notification \\\"$MSG\\\" with title \\\"Claude Code\\\"\""
}
]
}
]
}
}
Command Hooks では、イベントの情報は stdin に JSON として渡されます。Notification イベントの場合、message フィールドに通知内容が含まれます。$CLAUDE_NOTIFICATION のような環境変数ではない点に注意してください。
これだけで「Hooks が動いている」ことを実感できます。Claude がビルドやテストを実行している間、別の作業に集中して、終わったら通知で気づく。地味ですが生産性への貢献は大きいです。
Week 1: 自動フォーマット(最大の効果)
次に導入すべきは PostToolUse による自動フォーマットです。これが Hooks の最大のキラーユースケースだと筆者は考えています。
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write|MultiEdit",
"hooks": [
{
"type": "command",
"command": "jq -r '.tool_input.file_path // empty' | xargs -I{} npx prettier --write '{}' 2>/dev/null || true"
}
]
}
]
}
}
重要なポイント: matcher に Edit|Write|MultiEdit を指定することで、ファイル編集系のツールが実行された時だけ発火します。Bash や Read では発火しません。
筆者はこの Hook を導入してから、CLAUDE.md から prettier を実行すること の記述を完全に削除しました。CLAUDE.md の「指示バジェット」を1行節約できたことになります。
ここでいう「CLAUDE.md から削除してよいルール」と「文章で残すべきルール」の判断に迷うなら、CLAUDE.md の書き方 設計パターン集を先に読むと整理しやすいです。Hooks は CLAUDE.md の代替ではなく、違反コストが高い処理だけを機械的に引き受ける補助輪だと考えると設計が崩れません。
実務では、Edit|Write|MultiEdit に加えて NotebookEdit のような新しい編集系ツールが増える可能性もあります。matcher を固定文字列として覚えるのではなく、自分が普段使う編集操作が何かを一度ログで確認しておくと、設定の見落としを減らせます。
Week 2: 危険操作のブロック(安全性の確保)
PreToolUse で危険な操作をブロックします。
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "INPUT=$(cat); if echo \"$INPUT\" | jq -r '.tool_input.command' | grep -qE '(rm -rf|git push --force|DROP TABLE)'; then echo 'Blocked: destructive command detected' >&2; exit 2; fi"
}
]
},
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "INPUT=$(cat); if echo \"$INPUT\" | jq -r '.tool_input.file_path' | grep -qE '(\\.env|credentials|secrets)'; then echo 'Blocked: sensitive file modification' >&2; exit 2; fi"
}
]
}
]
}
}
終了コードの仕組みがここで重要になります:
- exit 0: 成功。処理を続行する
- exit 2: ブロッキングエラー。Claude に stderr の内容がフィードバックされ、ツール実行がキャンセルされる
- その他: 非ブロッキングエラー(ログに記録されるが処理は続行)
exit 2 で stderr にメッセージを出力すると、Claude はそれを読んで「なぜブロックされたか」を理解し、代替手段を提案してくれます。
個人開発では .env 保護や git push --force ブロックから始めれば十分ですが、チーム利用ではここに 依存関係追加、外部送信、特定ディレクトリの編集禁止 を追加したくなります。その場合の判断基準は AIコーディングツールの社内ガイドライン と揃えておくと、ローカル運用と組織ルールがねじれません。
Month 1: 品質ゲート(Stop Hook)
ある程度 Hooks に慣れたら、Stop Hook で品質ゲートを設けます。Claude の応答が完了するたびに自動でチェックが走ります。
{
"hooks": {
"Stop": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "INPUT=$(cat); if echo \"$INPUT\" | jq -e '.stop_hook_active' >/dev/null 2>&1; then exit 0; fi; cd \"$CLAUDE_PROJECT_DIR\" && npx tsc --noEmit 2>&1 | head -20 | jq -Rs '{\"decision\": \"block\", \"reason\": .}' || exit 0"
}
]
}
]
}
}
注意: stdin JSON の stop_hook_active フィールドのチェックは必須です。Stop Hook がブロックすると Claude は修正を試みて再度応答を完了しますが、その完了でまた Stop Hook が発火します。このガードがないと無限ループに陥ります。
CLAUDE.md vs Hooks — 使い分けの判断フロー
「このルールは CLAUDE.md に書くべきか、Hooks で実装すべきか?」という判断に悩むことがあると思います。筆者が使っている判断基準はシンプルです。
Hooks に向いているもの:
- 例外なく毎回実行すべき処理(フォーマッタ、リンター)
- 絶対に防ぎたい操作(本番データの削除、機密ファイルの編集)
- 通知やログなどの副作用
- 成功/失敗が機械的に判定できるもの
CLAUDE.md に向いているもの:
- 判断を伴うガイドライン(「コンポーネントは小さく保つ」)
- プロジェクトの背景説明(「なぜこのアーキテクチャか」)
- コマンドの選択(「npm ではなく pnpm を使え」)
- コーディングスタイルの好み
一言でまとめると、「機械的に判定できるルールは Hooks、判断が必要なガイドラインは CLAUDE.md」 です。
よくある失敗パターンとして、CLAUDE.md に「Prettier を実行せよ」と書きつつ Hooks でも実行する二重設定があります。これは CLAUDE.md 側を削除すべきです。Hooks で 100% 実行されるなら、CLAUDE.md に書く必要はありません。指示バジェットの無駄遣いです。
また、権限承認の摩擦そのものを減らしたいなら、Claude Code Auto Mode 徹底解説も補助線になります。Hooks が「実行前後の処理を強制する仕組み」なのに対して、Auto Mode は「その操作を自動承認してよいか」を判定する機能で、役割がずれています。
実務補足: チーム運用で最初に決める3項目
個人開発では「便利になった」で終わりがちですが、チームで Claude Code Hooks を共有し始めると別の論点が出ます。私なら最初に次の3つを固定します。
1. どこまでを共通 Hooks にするか
全員に配る .claude/settings.json には、通知のような好みが分かれる設定より、事故防止と最低限の品質担保 に絞った方がよいです。具体的には .env 保護、危険コマンドのブロック、整形や build など再現性が必要なものです。個人の通知やローカル補助は ~/.claude/settings.json 側に逃がした方が運用が荒れません。
2. Hook が失敗したときの扱い
フォーマット失敗を非ブロッキングにするのか、型チェック失敗で Stop Hook を止めるのかは、チームごとに決める必要があります。ここが曖昧だと、ある人の環境では止まり、別の人の環境では素通りする状態になります。品質ゲートを厳格にしたいなら、Auto-Fix や CI 側の運用とセットで設計した方が安全です。Claude Code Auto-Fix 実践ガイド はその補助線になります。
3. 外部接続と監査をどう見るか
Hooks 自体はローカル自動化の仕組みですが、HTTP Hook や MCP と組み合わせると監査や外部送信の論点が出ます。会社で使うなら「どの SaaS に、誰の権限で、どこまで送るか」を先に決めるべきです。ここを後回しにすると、便利なローカル自動化がそのまま統制不能な抜け道になります。組織配布や allowlist を含めた論点は MCP エンタープライズ運用ガイド に整理しています。
実際にハマった5つの落とし穴
1. .zshrc の echo が JSON パースを壊す
Hooks のシェルコマンドはログインシェルで実行されます。.zshrc に装飾的な echo や fortune コマンドがあると、その出力が Hook の stdout に混入し、JSON パースが失敗します。
# .zshrc でこういう記述があると Hooks が壊れる
echo "Welcome back!"
fortune | cowsay
対策: .zshrc のインタラクティブ限定処理を適切にガードする。
# インタラクティブシェルの場合のみ実行
if [[ $- == *i* ]]; then
echo "Welcome back!"
fi
2. チルダ (~) が展開されない
// NG: チルダは展開されない
{ "command": "~/.claude/hooks/my-script.sh" }
// OK: 環境変数を使う
{ "command": "\"$HOME\"/.claude/hooks/my-script.sh" }
// OK: プロジェクトルート相対パス
{ "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/my-script.sh" }
3. フォアグラウンドプロセスのハング
Hook 内で dev サーバーなどの長時間プロセスを起動すると、Claude が永遠に待ち続けます。
# NG: Claude がハングする
npm run dev
# OK: バックグラウンドで起動して即座に返す
npm run dev &>/dev/null &
disown
4. PostToolUse ではツール実行を止められない
PostToolUse はツール実行 後 に発火するため、exit 2 を返してもツールの実行結果は取り消せません。ファイル保護や危険操作のブロックは必ず PreToolUse で行ってください。
5. stderr と stdout の混同
Hook スクリプトの中で使用するツールが、エラーメッセージを stdout に出力するケースがあります。これが Hook の JSON 出力と混ざってパースエラーを引き起こします。
# 外部コマンドの stderr を適切にリダイレクト
result=$(some-command 2>/dev/null)
# デバッグ出力は必ず stderr に
echo "Debug: checking file..." >&2
実践例: 筆者の Astro プロジェクトでの Hooks 設定
最後に、このブログサイト(nidoneko.dev)で実際に使っている Hooks 設定の考え方を紹介します。大事なのは「何でも自動化する」ことではなく、Claude が忘れやすいが、人間が毎回レビューしたくない処理だけを Hook に寄せることです。
{
"hooks": {
"Notification": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "MSG=$(cat | jq -r '.message // \"Task completed\"'); osascript -e \"display notification \\\"$MSG\\\" with title \\\"Claude Code\\\"\""
}
]
}
],
"PostToolUse": [
{
"matcher": "Edit|Write|MultiEdit",
"hooks": [
{
"type": "command",
"command": "jq -r '.tool_input.file_path // empty' | xargs -I{} npx prettier --write '{}' 2>/dev/null || true"
}
]
}
],
"PreToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "INPUT=$(cat); if echo \"$INPUT\" | jq -r '.tool_input.file_path' | grep -qE '\\.env'; then echo 'Blocked: .env file is protected' >&2; exit 2; fi"
}
]
}
]
}
}
この設定は 3 つの Hook で構成されていますが、これだけで以下の効果が得られています:
- 通知: 長時間のビルドやテスト実行後にデスクトップ通知
- 自動フォーマット: ファイル編集後に Prettier が自動で走り、CLAUDE.md からフォーマット指示を削除できた
- ファイル保護:
.envの誤編集を事前にブロック
筆者のポジションとしては、Hooks は「少数精鋭」で始めるべきです。設定ファイルに 20 個の Hook を並べる必要はありません。上記の 3 つだけでも、CLAUDE.md のルール遵守率で悩んでいた問題の大半が解消しました。逆に、いきなりチーム共通設定へ大量投入すると、誰の環境で何が止まったのか分からなくなります。
まとめ
- Claude Code Hooks の使い方は PreToolUse / PostToolUse の切り分けから覚える。止める処理は Pre、後処理は Post
- CLAUDE.md は「お願い」、Hooks は「強制」。機械的に判定できるルールは Hooks に移行する
- 段階的に導入する: Day 1 は通知、Week 1 で自動フォーマット、Week 2 で危険操作ブロック、Month 1 で品質ゲート
- 落とし穴を知っておく:
.zshrc干渉、チルダ非展開、Stop Hook の無限ループは頻出トラブル - 少数精鋭で始める: 3 つの Hook(通知・フォーマット・ファイル保護)だけでも十分な効果がある
- Hooks で自動化した処理は CLAUDE.md から削除し、「指示バジェット」を節約する
Hooks は 2026 年に入ってから急速にイベント数が増えており、TaskCreated や FileChanged など、マルチエージェント対応やファイル監視の新イベントも追加されています。今のうちに基本的な Hooks 運用を確立しておけば、こうした新機能にもスムーズに対応できるはずです。
導入全体の判断基準を先に掴みたいなら Claude Code 実践ガイド、CI 修正まで自動化したいなら Claude Code Auto-Fix 実践ガイド、組織ルールまで広げたいなら AIコーディングツールの社内ガイドライン を続けて読むと、Hooks の役割をより立体的に理解できます.