Hookはブロックにしか使えませんか?会話に情報を能動的に追加することもできますか?
できる。Hookはインターセプトやブロックだけでなく、情報を能動的に注入するのにも使える。例えばSessionStartというイベントは毎回のセッション開始時に発動し、コマンドを紐づけて現在のgitブランチ名を自動取得し、追加の背景情報として会話の冒頭に組み込むことができる。毎回「今どのブランチにいるか」を手動で伝える必要がなくなる。
これはPreToolUse/PostToolUseのインターセプト型の使い方と同じ仕組みで、方向性が異なるだけだ。インターセプト型は「起きるべきでない時に止める」、注入型は「常に存在すべき情報を自動的に補う」というものであり、どちらも「安定して起きるべきこと」を口頭での念押しに頼らず、仕組みによる保証に変えている。
なぜCLAUDE.mdのルールをすべてHookに変えて、実行漏れの問題を一気に解決してしまわないのですか?
両者が適した扱うルールの性質が異なるからだ。Hookの強みは「判断条件が明確で、動作が固定されている」ルールにある。例えば「特定の文字列を検知したらブロックする」「ファイル書き込み後にフォーマットコマンドを実行する」など。この種のルールは文脈の理解や判断力を必要とせず、純粋に条件が一致すれば実行するだけなので、スクリプトに書きやすい。
しかし「プロジェクトのスタイルに合っているか」「このコードの命名がわかりやすいか」といった判断が必要なルールもあり、これらは意味の理解を要し、絶対的な正解のないルールで、シンプルなシェルスクリプトで判断させるのは非常に難しい。この場合はCLAUDE.mdに残してClaudeの理解力で判断させる方が、無理にルールを固定化するより適している。実務上のより良い役割分担は、機械的で白黒はっきりしたルールはHookに任せ、意味的判断が必要なルールはCLAUDE.mdに残す——両方を組み合わせて使うのであり、どちらか一方を選ぶものではない。
Hookの設定は複雑で、高度な技術的背景が必要ですか?
ハードルは実はそれほど高くない。最も基本的なHookは、シェルコマンドと紐づけたいイベントタイプを設定ファイルに書くだけだ。最もよくある自動フォーマットを例に挙げると、「PostToolUseイベント」を指定し、「WriteやEditといったツールに一致」させ、「フォーマッターを実行するコマンド」を紐づければよく、複雑なプログラムロジックを書く必要はない。よくある場面の多くは、実際には公式ドキュメントやコミュニティで共有されている例をコピーし、パスとツール名を微調整するだけで使える。
本当に少し工夫が必要なのは「インターセプト型」のHookだ。例えばコマンドに危険な文字列が含まれているか判定するような場合、少し条件分岐のロジックを書く必要がある。しかしそれでも深いプログラミングの背景が必要なレベルではなく、ネット上にはすでに大量の既存の例があり、それを直接参考にして自分のプロジェクトのニーズに合わせて調整すればよく、ゼロから設計する必要はない。
Hookを設定した後、気が変わって例えば今回だけフォーマットを実行したくない場合、回避するのは難しいですか?
それは設計次第だ。PostToolUseに紐づけたフォーマットコマンドの場合、通常は後から手動で元に戻したり、そのHookを一時的に設定ファイルから外して続行したりできる。Hookが保証するのは「条件が一致すれば実行される」ことであり、「実行後は人が調整できない」ということではない。しかしPreToolUseに紐づけたブロック型のHook(削除コマンドを遮断するなど)の場合、そのHookが存在する意味自体が「簡単に回避されたくない」ことにあるため、通常は簡単な例外スイッチも用意されていない。本当にそのブロックされた動作を実行したいなら、対話でClaudeと相談するのではなく、設定ファイル自体を手動で変更する必要がある。
これはHookを設計する際に事前に考えておく価値がある点だ。このルールを「ほとんどの場合自動的に有効で、時々柔軟に調整できる」ものにしたいのか、「どんな状況でも回避されるべきではない」ものにしたいのか。この2つの心構えによって、Hookを異なる厳格さで設計することになる。
CLAUDE.mdに「コードを変更するたびにPrettierでフォーマットする」と書いても、Claudeはほとんどの場合それに従うが、時々漏れることがある——これはClaudeがわざと怠けているのではなく、CLAUDE.mdは本質的に「指示」であり、Claudeはできる限り従おうとするが、それでもモデル自身が実行するかどうかを判断する一文であり、シェルスクリプトに書いてコンピューターが必ず実行することを保証するコマンドとは、まったく別次元の信頼性だからだ。Hooksが解決するのはまさにこのギャップだ。特定のタイミングであるアクションが確実に実行されるようにする——「Claudeが覚えていればやる」のではなく、「Claudeがどう判断しようと、これは必ず起きる」のである。
Hookは設定ファイルで定義するシェルコマンドで、Claude Codeのライフサイクル内の特定のイベント——「ツール呼び出しの前」「ツール呼び出しの後」「セッション開始時」など——に紐づけられる。そのイベントが実際に発生すると、紐づけたコマンドが自動的に実行され、Claudeが自ら実行するかどうかを判断する必要はない。この概念はGit hooksによく似ている。Gitにはコミットの前後に固定のトリガーポイントがあり、そこに自分のスクリプトを組み込むことができる。HooksはClaude Codeの操作ライフサイクルにおいても同じ論理で動く。
PreToolUseはClaudeがあるツールを実行する「前」に発動し、危険な操作をブロックするのに使える——例えばコマンドにrm -rfのような削除構文が含まれていることを検知し、実際に実行される前にその実行をブロックする。PostToolUseはツール実行の「後」に発動し、最も一般的な使い方は自動フォーマットだ。Claudeがファイルを書き込んだり編集したりした瞬間に、すぐ自動的にPrettierや普段使っているフォーマッターを実行し、CLAUDE.mdで「フォーマットを忘れずに」と繰り返し念押しする必要がなくなる。
CLAUDE.mdやプロンプトに書かれたルールは、会話が長くなってルールが薄まったり、タスクの内容から「今回は必要なさそうだ」とClaudeが判断したりして、スキップされる可能性がある。Hookにはこの問題がない。なぜならClaudeの判断を一切経由しないからだ——イベントが発動すれば、コマンドが実行される。これは説得のレベルの依頼ではなく、仕組みのレベルの保証だ。この違いは「毎回必ず成立しなければならない」場面で特に重要になる。例えば機密ファイルが誤って上書きされないよう保護したり、変更のたびにテストが実際に実行されることを確実にしたりすることは、「たいてい」起きてほしいことではなく、「毎回」起きてほしいことだ。
すべてのイベントタイプを一度に学ぶ必要はない。最も実用的な3つの組み合わせから始めれば十分だ。自動フォーマット(PostToolUseをフォーマッターに紐づける)、機密ファイルの保護(PreToolUseで.envのようなファイルへの書き込みを遮る)、危険なコマンドの遮断(PreToolUseで削除系コマンドを検知して止める)。この3つは初心者が最もよく経験する「確かに伝えたのに漏れる」という悩みをカバーしている。慣れてきたら、自分のワークフローに合わせて少しずつ追加していけばよい。
Claudeが明確に伝えたつもりのルールを漏らすたびに、その代償は一度きりの見落としだけでなく、問題を発見し、ルールを説明し直し、修正を求めるための追加の対話ターンにも及ぶ——これらはすべて実質的なトークン消費であり、しかもプロジェクトがすでに半ばまで進み、修正コストが最も高い時点で発見されることが多い。本当に妥協できないルールを「CLAUDE.mdに書いたお願い」から「Hookで保証された仕組み」へと格上げすることは、初期の設定にかかる時間と引き換えに、同じことを何度も指摘し直し、対話ターンを繰り返し無駄にすることがなくなるという長期的な節約を得ることになる。