ずっと「お願い」していた
毎回 CLAUDE.md に「ファイルを編集したら必ず prettier をかけて」と書いていた。Claude は気が向くとやってくれるし、気が向かないと忘れる。私と犬のしつけが同じ進捗を辿っているのを見て、これは依頼ではなく自動化の話だと気づいた。
そこで出会ったのが Hooks(フック)だった。「Claude が動いた瞬間に、私の用意したスクリプトを横から差し込める」という、要するに 「お願い」を「実行」に格上げする仕組みである。
結論マップ(ビフォー/アフター)
| 場面 | Hooks を知る前 | Hooks を入れたあと |
|---|---|---|
| 編集後の整形 | 毎回「prettier かけて」と頼む | ファイル編集 → 自動で prettier が走る |
| 危ないコマンド | rm -rf を打つ前に祈る | 設定で問答無用ブロックされる |
| 終わったら通知 | 画面を見続けて待つ | 終了の瞬間にデスクトップ通知が出る |
3行で済んだ。Claude にいちいちお願いするより、Claude の周りに自動ドアを設置するほうが結局は早い、というだけの話だった。
Hooks って何
公式ドキュメントによれば、Hooks は Claude Code のライフサイクルの特定タイミングで自動的に走る、ユーザー定義のシェルコマンド・HTTP エンドポイント・LLM プロンプト のこと。日本語で言えば「Claude の動作の前後に、自分の処理を割り込ませる栓抜き」だ。
たとえばツール(Bash や Edit)を使う直前に走らせれば、危険なコマンドを止められる。直後に走らせれば、編集したファイルを自動で整形できる。会話が始まるとき、終わるとき、ユーザーがプロンプトを送ったとき、それぞれにフックポイントがある。
💡 似た言葉だが、いわゆる「Webhook(外部から呼ばれる仕組み)」ではない。Hooks は自分のマシンの中で動くしかけ。つまり LINE スタンプを送るのではなく、自分の家の玄関に自動センサーライトを付ける、くらいのスケール感。
どこに書くのか
設定ファイルは置き場所で 適用範囲(スコープ) が変わる。これは公式ドキュメントの記載どおり:
| 置き場所 | 適用範囲 | 共有 |
|---|---|---|
~/.claude/settings.json | 自分の全プロジェクト | 自分のマシン内のみ |
.claude/settings.json | そのプロジェクトのみ | git にコミット可 |
.claude/settings.local.json | そのプロジェクトのみ | gitignored |
このほか、プラグインに同梱したり、スキルやサブエージェントの frontmatter(YAML のメタ情報部分)に書く方法もある。「自分専用なら ~/.claude/、チームで共有するなら .claude/settings.json」と覚えると整理しやすい。
どんなイベントにフックできるのか
公式リファレンスに載っているイベントはかなり多いが、初心者がまず触りそうなのは以下:
SessionStart/SessionEnd— セッションの開始・終了UserPromptSubmit— 私が Enter を押した直後、Claude が読む前PreToolUse/PostToolUse— Claude がツール(Bash, Edit, Write, etc.)を呼ぶ直前・直後PostToolUseFailure— ツールが失敗したあとStop— Claude が応答を終えた瞬間Notification— Claude が通知を出すとき(権限確認など)PreCompact/PostCompact— 会話圧縮の前後FileChanged/CwdChanged— 監視対象ファイルが変わった/作業ディレクトリが変わった
このほかにも SubagentStart・InstructionsLoaded・WorktreeCreate など細かいものが並んでいて、要は 「Claude が何かする」ほぼ全タイミングに切れ目が用意されている。映画の隙にどこでも CM が入れられる、と思うと近い。
実例1:ファイル編集後に自動 prettier
公式ガイドにそのまま載っている、いちばん腑に落ちる例。.claude/settings.json に書く:
{ "hooks": { "PostToolUse": [ { "matcher": "Edit|Write", "hooks": [ { "type": "command", "command": "jq -r '.tool_input.file_path' | xargs npx prettier --write" } ] } ] }}
matcher で「Edit か Write のとき」と絞り込み、Claude が編集したファイルパスを jq(JSON を取り出すコマンド)で抜き出して prettier に渡す。「お願い」の文言を CLAUDE.md に何行書くより、これ1つ置くほうが効く。これは私の犬の食事よりも確実に動く。
💡 公式が
jqを前提にしているので、Mac ならbrew install jq、Ubuntu ならapt-get install jqを先に入れておく。私はここで30分溶かした(jqが入っていないと、フックは静かに失敗する)。
実例2:危ないコマンドを問答無用で止める
PreToolUse に「Bash で rm 系のコマンドが来たら止める」スクリプトを差し込む。.claude/hooks/protect-files.sh を作って中身は公式の例から拝借(exit 2 でブロックする):
#!/bin/bashINPUT=$(cat)COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command')if echo "$COMMAND" | grep -qE 'rm -rf'; then echo "Blocked: rm -rf は禁止です" >&2 exit 2fiexit 0
実行権限を付けて(chmod +x .claude/hooks/protect-files.sh)、.claude/settings.json に登録:
{ "hooks": { "PreToolUse": [ { "matcher": "Bash", "hooks": [ { "type": "command", "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/protect-files.sh" } ] } ] }}
ポイントは exit 2。終了コード 2 は「ブロッキングエラー」と決まっていて、これを返すとツール呼び出し自体が止まり、stderr の文字列が Claude にエラーとして渡る(公式ドキュメント「Exit code output」セクション)。Claude には「あ、それはダメだったのね」と伝わるので、別の手を考えてくれる。父親の「ダメ」と母親の「いいよ」が衝突したとき、強いほうが通るアレ、と説明したい。
実例3:Claude が止まった瞬間に通知
長いタスクを投げて待っている間、私は別の作業をしている。気がついたら Claude は10分前に終わっていた、というのを何度かやらかしたので、Stop イベント(Claude が応答を終えた瞬間)にデスクトップ通知を出す:
{ "hooks": { "Stop": [ { "matcher": "", "hooks": [ { "type": "command", "command": "osascript -e 'display notification \"Claude が応答を終えました\" with title \"Claude Code\"'" } ] } ] }}
これは Mac の例(osascript を使う)。Linux なら notify-send、Windows なら powershell.exe 経由でメッセージボックスを出す例が公式ガイドに載っている。要は 「終わり」の瞬間を取れるということ。私のスマホがピンと鳴るたび、Claude のタスクが終わっていて、Pavlov の犬のようになる未来が見えた。
ここで止まりそうなポイント
- 設定の置き場所を間違える:
~/.claude/settings.json(自分の全体)と.claude/settings.json(プロジェクト用)は別物。間違えるとフックが動かない or 全プロジェクトで暴走する。私は「家の鍵と会社の鍵を同じキーホルダーに付けたまま、うっかり会社の鍵で家を開けようとした」レベルで混乱した exit 2以外はブロックしない:終了コード1は「ノンブロッキングエラー」。Unix の慣習で1を返したくなるが、フックを「拒否」として使いたいなら必ず2にする。これは公式ドキュメントの「Exit code output」セクションに明記されている/hooksで確認できる:今どんなフックが効いているのか分からなくなったら、Claude Code 内で/hooksと打つと、設定済みのフックが一覧で読める。私はこれで「設定したつもりで動いていなかった」ことに気づいた
セキュリティの話(ここは飛ばさず読んでほしい)
公式ドキュメントの「Security considerations」に明記されているとおり、Hooks は私のユーザー権限で任意のシェルコマンドを実行する。つまり、信頼できないフック設定をうっかり共有リポジトリから取り込むと、ファイルを消されたり、認証情報を盗まれたりする可能性がある。
⚠️ 要するに、人がくれた
.claude/settings.jsonの中身は、見知らぬ人がくれた USB を挿す前と同じ気持ちで一度開いて読む。コマンドが読める範囲かどうか確認してから取り込むこと。便利な道具ほど、初対面の相手から黙って受け取ってはいけない。
公式が挙げているベストプラクティスは「入力を信用せず検証する」「シェル変数は必ずクォートする("$VAR")」「絶対パスを使う」「.env や .git/ には触らない」など。家の鍵を二重ロックするのと同じ感覚で、フックも二重に守る。
全部止めたいとき
設定を1個ずつ消す前に、disableAllHooks: true を settings.json に書けば、その階層のフックを丸ごと黙らせられる(公式リファレンス「Disable or remove hooks」セクション)。トラブルシュート時にまずこれで切り分けると早い。ブレーカーを落としてから配線を見る、あの感じ。
まとめ/次に試したいこと
Hooks は 「Claude が動く瞬間の前後に、自分の処理を差し込める仕組み」。お願い文を増やすより、設定1つで自動化したほうが早い場面が確実にある。
- PostToolUse + Edit|Write … 編集後の自動フォーマット
- PreToolUse + Bash … 危険コマンドのブロック
- Stop … 終了通知
- SessionStart + compact … 圧縮後にプロジェクトの大事なルールを再注入
私が次に試したいのは、コミット前に自動でテストを走らせる PostToolUse と、ログを残す SessionEnd の組み合わせ。気がつけばリポジトリの周りに自動ドアと監視カメラと宅配ロッカーが揃っていて、私は寝ていても進捗が出る家になっているはず(は、言いすぎた)。
なお、本記事の設定例・コマンド・イベント名は2026-04-27 時点の公式ドキュメントに基づく。Claude Code の更新頻度は高いので、実際に組む前に必ず一次情報を確認してほしい。
