私のニーズがそもそも事後の記録や警告を残すことであって、本当に操作を止めたいわけではない場合、このPostToolUseの挙動はバグと言えますか?
厳密に言えば機能的なバグではなく、誤解を招くインターフェース表示に近い。報告者自身の主張もそうだ——彼はブロックメカニズム自体の修正を求めていたのではなく、表示テキストを「blocking error」からより正確な「hook warning」や「hook reported error」に変更することを提案していた。あなたのユースケースがそもそも事後のログ記録や通知であるなら、PostToolUseの現在の挙動はすでにあなたのニーズに合致している。ただ画面上の文言が「すでにブロックされた」と誤判断させやすいだけだ。
PreToolUseでさえissue #23284、#13744、#80039のような既知の失敗事例があるなら、hookは本当のセキュリティ管理には使えないということですか?
これらの事例は確かに一つのことを示唆している——特にセキュリティに関わるブロック要件については、hookを唯一の防衛線として扱うべきではないということだ。より現実的なアプローチは、hookを多層防御の中の一層として扱い、サンドボックスレベルの権限制限のような他のメカニズムと組み合わせて配置することで、一つの層が失敗しても他の層が機能している状態を保つことだ。
さらに重要な習慣は、書いたブロックルールをデプロイした後、実際に一度発火させて検証し、対象の操作が本当に起きていないことを自分の目で確認することだ——ターミナルにエラーメッセージが出たことだけを見て検証済みとみなしてはいけない。報告された3つの事例に共通するのは「exit 2は出たが、操作は実行された」という点であり、このギャップは実際のテストによってのみ発見できる。
exit codeとJSONのpermissionDecision、実務上どちらを使うべきですか?
公式ドキュメントの優先順位ルールがこの問いの一部にすでに答えている——ブロック可能なイベントタイプでは、exit 2が、同時に存在するJSONのpermissionDecision: "allow"出力よりも優先される。つまりexit codeの方がより直接的で、上書きされにくいシグナルだということだ。
hookのロジックがシンプルで、「許可」か「ブロック」かの2択だけでよいなら、裸のexit code(exit 0で通過、exit 2でブロック)で通常は十分であり、ミスも起きにくい。JSON出力の価値は、より細かい情報(Claudeに向けたメッセージの添付など)を表現できる点にある。ただし両方の出力方式を併用する場合は、exit codeの方が優先されることを必ず覚えておき、デバッグの際はJSONロジックが正しいかどうかだけでなく、まずexit codeを確認すること。
エンジニアではなく、ネット上のhook設定例をコピーして貼り付けただけです。それが本当に機能しているかどう確認すればいいですか?
コードの詳細を理解しなくてもできる3つの確認手順がある。第一に、設定ファイルを開き、イベント名がPreToolUseになっているかPostToolUseになっているかを確認する——目的が何かの動作を「阻止」することなのに、例がPostToolUseで書かれている場合、仕組み上そもそも阻止は不可能だ。第二に、ブロックロジック内のexit codeの数値を見つけ、それが1ではなく2になっているか確認する——これはコピー&ペーストで最もよく起きるミスの原因だ。第三に、そして最も重要なのは、そのルールが阻止しようとしている状況を意図的に一度発生させ、対象のファイルを実際に開くかコマンドの実行結果を確認して、本当に影響を受けたかどうかを自分の目で確かめること。ターミナルにエラー文字列が表示されたかどうかだけを見て検証済みとみなさないことだ。
PostToolUseイベントにhookを書き、変更してはいけないファイルを検知したらexit 2を返すようにした。ターミナルに赤い文字で「blocking error」と表示される。これで今回の変更はブロックされたはずだとほっとする——ところがファイルを開いてみると、内容はすでに変更されている。これはあなたの設定ミスではない。PostToolUseというイベントタイプそのものが、そもそも「ブロックする」能力を持っていないのだ。
このギャップはすでに明確なGitHub issue(#19009)として報告されている:あるユーザーのPostToolUse hookがEdit操作に対してexit 2を返し、インターフェース上には確かに「blocking error」という文字列が表示されたが、その編集はすでにディスクに書き込まれていた。報告者の提案は率直だ——ユーザーがこのメッセージを見て動作がブロックされたと誤解しないよう、「hook warning」や「hook reported error」といった表現に変えたほうが、実際に起きたことをより正確に反映できるというものだ。
なぜこうなるのかを理解するには、PreToolUseとPostToolUseの実行タイミングにおける根本的な違いを整理する必要がある。PreToolUseはツールが実際に実行される前に発火する。この時点ではClaudeはまだファイルシステムや外部環境に一切変更を加えていないため、ここでのexit 2には意味がある——Claudeにこの操作を完全に放棄するよう指示できるからだ。
PostToolUseが発火するタイミングはまったく異なる——ツールはすでに実行済みで、ファイルはすでに書き込まれ、コマンドはすでに送信され、副作用はすでに発生している。この時点でexit 2を返しても、できるのはstderrの内容をClaudeに伝え、「何か間違っていたかもしれない」と知らせることだけであり、すでにディスクに書き込まれた内容を自動的に元に戻す仕組みは存在しない。「blocking error」という表示は、実際には「このメッセージはClaudeが注意すべきエラーとしてフラグされた」ことを意味しているのであって、「この動作が阻止された」ことを意味しているわけではない。
もし次に「では全てのブロックロジックをPreToolUseに移せばいい」と考えたなら、知っておくべき既知の事例がいくつかある。issue #23284は、git pushコマンドに対するBashマッチャーとして設定されたPreToolUse hookが、exit 2を返した後もそのpushが実行されてしまったという報告だ。issue #13744は別のギャップを指摘している:同じPreToolUse、同じexit 2でも、Bashツールに対しては効果があったが、Write/Editツールに対しては実際には操作を止められなかった。
さらに厄介なのがissue #80039で、これはWindowsに限定された事例だ。ネストした引用符の解析が絡む特定のコマンド形式において、exit 2の処理とstderrの表示が同時に失敗するが、同じセッション内の他のhookは正常に発火する。これは、そのプラットフォーム上でhookの仕組み全体が失敗しているというより、特定のコマンド解析パスに障害があることを示している——診断する際は「このプラットフォームでhookが使えるかどうか」ではなく、「この特定のコマンド形式がこのプラットフォームで解析上の問題を引き起こすかどうか」を具体的に見る必要がある。
プラットフォームやイベントタイプの細部に踏み込む前に、より一般的で、しかも自分で引き起こしやすい問題を先に排除しておく価値がある。コミュニティ記事「5 Claude Code Hook Mistakes That Break Your Automation」(著者:yurukusa)は、高頻度で発生する失敗を記録している:本来exit 2を使うべきブロックロジックをexit 1で書いてしまうというものだ。exit 1はエラー内容をログに記録するだけで、実際のブロック効果は一切生まない。hookが本来ある操作を止めたいのにexit 1を使っている場合、イベントタイプの選択が正しかろうと間違っていようと、ブロックは発生しない。
公式ドキュメント(code.claude.com/docs/en/hooks)はもう一つの構造化された代替手段を提供している:hookはJSON形式のhookSpecificOutputを返すことができ、そこに含まれるpermissionDecisionフィールドで、単なる裸のexit codeに頼るのではなく、この操作の「許可」または「拒否」を表現できる。しかし同じドキュメントは優先順位についても明確に説明している——ブロック可能なイベントタイプにおいては、exit 2が、同時に存在するJSONのpermissionDecision: "allow"出力よりも優先される。つまり、あなたのJSONロジックが許可すると判断していても、exit codeが2を返している限り、Claudeはその操作をブロック対象として扱う。この優先順位のルール自体はシンプルだが、これは同時に、一つのhookロジックが両方の出力方式を混在させている場合、デバッグの際にはまずexit codeが実際に何を返しているかを確認すべきであり、JSONの内容が正しいかどうかだけを見てはいけないことを意味する。
PreToolUseでさえ既知の失敗事例があるなら、hookはセキュリティの砦として本当に使えるのだろうか?より現実的な答えは、使えるが、それを唯一の防衛線にしてはいけないというものだ。ブロック型のセキュリティ要件は、他のメカニズム(サンドボックスレベルの権限制限など)と組み合わせて配置し、hookはその中の一層として扱うべきであり、全てではない。さらに重要なのは、書いたブロックルールは実際に一度発火させ、ブロックされたはずの操作が本当に起きていないかを自分の目で確認するべきだということだ——ターミナルにエラーメッセージが出たかどうかだけを見て、検証済みとみなしてはならない。
誰かのhook設定例をコピーする前に、次の3つを確認しよう:イベント名がPostToolUseではなくPreToolUseになっているか、ブロックロジックがexit 1ではなくexit 2を使っているか、そして最も重要なのは、そのルールを実際に一度発火させて、対象のファイルやコマンドが本当に影響を受けたかどうかを確認することだ。画面に表示されるエラーメッセージが教えてくれるのは「Claudeが注意すべきシグナルを受け取った」ということだけであり、「リスクが排除された」ということではない。このギャップこそが、本当に検証すべき部分だ。