3ヶ月間。Claude Code Hooks についてドキュメントを読まずに放置しながら、AI がフォーマット規約を無視したコードを生成し続けることに不満を言っていました。Claude Code を1月に立ち上げ、すぐに機能をリリースし始め、「Hooks のことは後でやろう」と思い込んでいました。典型的なミスです。
Hooks は余計な機能ではなく、Claude Code を実際のエージェンシーワークフローに組み込むために不可欠なピースだったのです。ESLint を時々無視する高性能オートコンプリートではなく、真の価値を発揮するツールに変わりました。
Claude Code Hooks の正体(曖昧な抽象化なし)
Hooks はシェルコマンドで、Claude Code が自身の操作の特定のポイントで実行します。Git Hooks のようなライフサイクルイベントと考えてください。Pre-commit スクリプトを書いたことがあれば、それと同じような概念ですが、Git のコミットパイプラインではなく AI のツール使用ループに組み込まれています。
現在、4つのイベントタイプがあります:
PreToolUse。Claude がツール(ファイル編集、Bash コマンドなど)を呼び出す前に実行されますPostToolUse。ツール呼び出しが完了した後に実行されますNotification。Claude が通知を送信するときにトリガーされますStop。Claude が完全なレスポンスターンを終了するときに実行されます
これらはプロジェクトの .claude/ フォルダ内の settings.json ファイルで設定するか、グローバルに ~/.claude/settings.json で設定します。各 Hook に matcher(ツールまたはイベントのトリガー)と hooks 配列(実行するシェルコマンド)を指定します。
Hook の出力は Claude のコンテキストにフィードバックされます。この最後の部分が、単なる凝ったクロンジョブではなく、本当に価値のある機能にしています。
なぜこれは手動でスクリプトを実行するのとは異なるのか
Claude の編集後に毎回 Prettier を手動で実行することはできます。2週間やってみましたが、締め切りが迫った際に忘れてしまい、47個のフォーマット違反を含む PR をプッシュしてしまいました。Hooks はセッション内で自動実行され、Claude はその出力を読めます。だから Linter が警告を出すと、Claude はそれを見て、同じセッション内で対応できるのです。このフィードバックループが全てです。
Seahawk プロジェクトで実際に機能した設定
ここは具体的に説明したいです。大半の記事にある「設定に Hooks を追加しろ」というアドバイスは、文脈がないと無意味だからです。
Seahawk では、仕事の大きな部分が WordPress ビルドと WooCommerce カスタマイズです。また Headless セットアップ用の React フロントエンドも手がけており、2022年以降は Next.js を多用しています。私が辿り着いた Hook 設定は、こうしたスタックに固有の問題に対応しています。
Next.js プロジェクトで使用している settings.json の構造は以下の通りです:
`` { "hooks": { "PostToolUse": [ { "matcher": "Write|Edit|MultiEdit", "hooks": [ { "type": "command", "command": "npx prettier --write $CLAUDE_FILE_PATHS && npx eslint --fix $CLAUDE_FILE_PATHS" } ] } ], "Stop": [ { "matcher": ".*", "hooks": [ { "type": "command", "command": "npx tsc --noEmit 2>&1 | head -20" } ] } ] } } ``
PostToolUse Hook は Claude がファイルに触れた直後に Prettier と ESLint を実行します。Stop Hook はターン終了時に TypeScript 型チェックを実行し、エラーの最初の20行を表示します。Claude がその出力を読み、型エラーがあれば、私が レスポンスを見る前に修正します。
その TypeScript チェックだけで、先月の厳しい noImplicitAny 設定を有するクライアント向けの決済ダッシュボードプロジェクトで、おそらく4時間を節約しました。Claude はユーティリティ関数で any 型を生成し続けていたのです。Stop Hook を追加した後、同じターン内で自己修正を始めました。
WordPress / PHP プロジェクトで使用しているHook
WordPress は異なる獣だ。明らかに TypeScript はないが、WordPress Coding Standards ルールセットを備えた PHP_CodeSniffer が物事を正常に保つ。2022年に WooCommerce プロジェクトでジュニア開発者がいて、彼は2週間 PHPCS を実行しなかった。コードレビューは...楽しいものではなかった。
PHP が大量のプロジェクトでは、PostToolUse hook が実行される:
`` vendor/bin/phpcs --standard=WordPress $CLAUDE_FILE_PATHS 2>&1 | tail -30 ``
そして bash コマンドの PreToolUse hook とペアにしている:
`` { "matcher": "Bash", "hooks": [ { "type": "command", "command": "echo 'Bash tool triggered' >> ~/.claude/audit.log && date >> ~/.claude/audit.log" } ] } ``
2つ目は純粋な杞憂だ。Claude が実行するすべての bash コマンドを監査ログに記録する。ライブのステージング環境で Claude Code を実行している場合(はい、やったことがある、はい少しリスキーだ)、正確にどのシェルコマンドが実行されたかを知ることは、本当に安心できる。
Exit コードでの動作ブロック
ドキュメントのこの部分は、見つけるのに少し時間がかかった。hook が exit code 2 で終了する場合、Claude Code はそれをブロックとして扱い、ツール呼び出しを続行しない。Exit code 0 は成功で、0 以外(ただし 2 ではない)は stderr をコンテキストとしてフィードバックするだけだ。
つまり、実際に Claude が何かするのを防ぐ PreToolUse hook を書くことができる。migrations/ ディレクトリがあり、Claude が自律的に触れてほしくないプロジェクトでこれを使用する:
`` #!/bin/bash if echo "$CLAUDE_FILE_PATHS" | grep -q "migrations/"; then echo "Migrations folder is protected. Do not edit migration files autonomously." exit 2 fi exit 0 ``
そのスクリプトは .claude/hooks/guard-migrations.sh に存在する。Claude が migrations/ 下のものに書き込もうとすると、ブロックされ、メッセージが表示される。その後、続行前に私に確認を求める。シンプルで効果的だ。
これは「このAIにコードベースをある程度信頼している」から「実際にコードベースを信頼している」への違いを作る制御の種類だ。
盗む価値のある実用的な Hook パターン
これらは理論的ではない。それぞれ特定の問題点から生まれた。
- ファイル編集後のテスト自動実行。PostToolUse hook で
npx jest --testPathPattern=$CLAUDE_FILE_PATHS --passWithNoTestsを実行する。スイート全体ではなく、Claude が編集したファイルに関連するテストだけを実行する。十分に高速で、うっとうしくない。 - コミット準備完了フォーマットスナップショット。git diff --stat を実行し、概要を Claude にフィードバックする
Stophook。セッション全体で何が変更されたかを正確に確認できるため、依頼されればコミットメッセージを書くのに役立つ。 - 環境変数セーフティチェック。Write 上の
PreToolUsehook で、ハードコードされたシークレットパターン(API キーやパスワードのように見えるもの)をグリップする。疑わしいものが見つかった場合、exit2。このビルドは約18ヶ月前にするべきだった。 - 長いタスク用の通知 hook。Claude が通知を送信する場合(
Notificationイベント)、Pushover エンドポイントにcurl呼び出しを実行するため、電話でプッシュ通知を受け取る。大規模なリファクタリングをキックオフしてお茶を飲みに行く場合に非常に役立つ。 - bash 前の PHP 構文チェック。WordPress プロジェクトでは、bash 実行前に
php -l $CLAUDE_FILE_PATHSをすばやく実行する。ステージングサーバーを破壊する前に致命的な構文エラーを捕捉する。
公式の Claude Code hooks ドキュメントには、hook スクリプト内で利用可能な環境変数の完全なリファレンスがある。ブックマークする価値がある。
Hook が修正しないもの
ここは正直さが重要だ。Hook は Claude が論理的に間違ったコードを生成することの解決策ではない。処理の問題を修正する:フォーマット、リント、タイプ安全性、テストカバレッジ。Claude がデータモデルを誤解し、間違った機能を構築する場合、編集後のリントがそれをキャッチすることはない。
Hook も遅延を追加する。Prettier + ESLint パスが4秒かかる場合、すべてのファイル編集は4秒長くなる。セッション中に200個のファイル編集があるプロジェクトでは、13分の待機時間だ。hook コマンドをプロファイルする。高速に保つ。単一の高速パスが低速パスに続く第2の修正パスより優れているため、--fix バリアント(ファイルをインプレースで変更)ではなく、レポートのみのバリアントを実行する。
また、プロジェクトの障害モードについて事前に実際に考える必要がある。Claude が間違ったファイルを編集した場合、何が悪くなる可能性があるか。絶対に実行する必要がある基準は何か。その思考は関係なく価値があるが、hook は経験豊富な開発者よりも初心者にはより多くの報酬を与えることを意味する。
Hook の設定:ステップバイステップ
ゼロから始める人のために:
- プロジェクトルートに
.claude/フォルダを作成します(存在しない場合)。 settings.jsonファイルを追加して、フックの設定を記述します(構成は上記の通り)。- 1行以上のコードの場合は、別のシェルスクリプト(.claude/hooks/your-script.sh)を作成し、chmod +x を実行してから、コマンドをインライン化せずに設定から呼び出します。
- プロジェクトで
claudeを実行してフック条件を意図的にトリガーし、セッションコンテキストに返されたものを読みます。 - 予期したとおりに動作していない場合は、
~/.claude/logs/でフック実行ログを確認します。
Anthropic 開発者ドキュメントには完全な設定スキーマが記載されており、フックがより広い AI コーディングワークフローにどのように適合するかについて考えたい場合は、Simon Willison のブログが実際のプロジェクトでのエージェント AI ツールについて詳しく考えたい人の参考先です。
最初に間違えたこと:すべてのフックをグローバルな ~/.claude/settings.json に入れて、PHP フックが JavaScript プロジェクトで動作している理由を不思議に思いました。プロジェクトレベルの設定がグローバル設定をオーバーライドします。スタック固有のフックをプロジェクトの .claude/settings.json に配置し、グローバル設定は監査ログと通知フックのようにどこでも適用すべき設定に使用します。
FAQ
Claude Code フックは Windows で動作しますか?
フックコマンドはシステムが使用するシェルで実行されます。Windows では PowerShell または CMD がデフォルトなので、bash スタイルのスクリプトはネイティブには動作しません。実用的な答えは WSL2 です。自分は macOS と Ubuntu の開発マシンを使用しているため、個人的には経験していませんが、Anthropic のドキュメントではシェル依存を明示的に記載しています。
フックは Claude の会話コンテキストにアクセスできますか?
直接はできません。フックはシェルコマンドとして実行され、CLAUDE_FILE_PATHS や CLAUDE_TOOL_NAME のような環境変数を受け取りますが、完全な会話トランスクリプトは取得できません。できることは、stdout に出力を書き込むことで、Claude がフック実行後のコンテキストとしてそれを読み込みます。
フックは Claude Code セッションに顕著な遅延をもたらしますか?
フックが実行する内容に完全に依存します。単一ファイルの php -l 構文チェックは 100ms 以下です。ファイル編集のたびに Jest スイート全体を実行すると、ストレスになります。個々のフックコマンドを 2~3 秒以下に保つ限り、ほぼ気づきません。
フックは本番環境で安全に使用できますか?
その質問は別の方向で考えるべきです:本番環境で直接 Claude Code を実行していますか? はい の場合、フックはあなたの懸念の最小事項です。ステージングで使用し、PreToolUse ブロッキングパターンを使用して機密ディレクトリを保護し、Claude を本番データベースから完全に遠ざけます。
プロジェクトレベルとグローバルフックの違いは何ですか?
グローバルフックは ~/.claude/settings.json に置かれ、マシン上のすべての Claude Code セッションに適用されます。プロジェクトレベルのフックは特定のプロジェクト内の .claude/settings.json に置かれ、そのプロジェクト内にいるときのみ動作します。両方が同じイベントを定義する場合、プロジェクトレベルが優先されます。
---
率直な要約:フックは地味なものです。殺風景なシェルスクリプト(Prettier を実行するなど)の美しいアーキテクチャについてブログ記事を書く人はいません。しかし、Claude Code がプロトタイプのおもちゃであることと、実際にクライアント案件で信頼できるものであることの違いです。1日目に設定すべきでした。おそらく、あなたもそうすべきです。
