止める仕組みが判定を返さなかったとき、規程は何と書くか
はじめに
この稿は、AI エージェントにコマンド実行やファイル編集を任せ、その直前に自社製の「止めるスクリプト」を挟んでいる現場の方への答えです。問いは、そのスクリプトが判定を返さなかったとき、規程のどこを根拠に実行を許すのか、です。
多くの規程は「危険な操作は止める」と書きます。対象も、主体も、記録の残し方も書きます。書かれていないのは、止めるスクリプトが落ちたとき、起動しなかったとき、判定を返さなかったときです。規程の外では実行環境の既定が働き、その既定はたいてい「進む」の側にあります。
事例が示した構造
2026 年 10 月 28 日、Zenn に kazuki_okura さんの記事が公開されました。自分の Claude Code の設定を Claude 自身に点検させた記録です。中心は、git push の前にレビュー済みかを確認する PreToolUse フックが、実際には push を通していたという発見でした。
norman6464 さんの 2026 年 11 月 2 日の記事が、この経路を著者の記述として要約しています。コマンド文字列から cd <dir> を切り出し、git -C "$dir" rev-parse HEAD で確かめる設計でした。cd "$HOME/dev/project" && git push が来たとき、フックは $HOME を展開しません。存在しないディレクトリを見て「リポジトリではない」と判断し、早期に戻ります。その経路の終了コードが 0 だったため、push は通りました。絶対パスで書いた同じ push は止まりました。
注目したいのは $HOME そのものではありません。止める層が「判定できない」と「問題なし」を、同じ終了コードで返していたという構造です。
合図の意味は、事象ごとに決まる
Claude Code のフックの契約は、2026 年 11 月 3 日時点の公式リファレンスに書かれています。ブロックするエラーは終了コード 2 です。それ以外の終了コード、起動の失敗、タイムアウトは、ブロックしないエラーとして扱われ、操作は進みます。例外で落ちたスクリプトは 1 で終わり、「落ちたら止まる」にはなりません。リファレンスは、方針を強制したいフックは 2 を使うべきだと明記しています。
規程の言葉でいえば、止める層の合図のうち「止める」と読まれるのは 1 種類だけです。「異常があった」「判定できなかった」「時間切れになった」は、いずれも「進めてよい」と同じ欄に集められます。
終了コードの意味は事象ごとに定義されます。実行の後の事象では 2 は警告で、実行はすでに終わっています。規程に「終了コード 2 で止める」と書いても、どの事象の話かが決まりません。
規程の側で分けられていない 3 つ
1 つ目は、止める相手の取り違えです。 規程は「担当者が確認する」と書きます。しかし確認を求める相手は、担当者ではなくモデルです。モデルは拒否の理由を読み、別の書き方で同じ操作をやり直します。規程が想定する確認と、実際に起きる再試行は別の出来事で、再試行の上限はどの規程にも書かれていません。
2 つ目は、止まらなかったことの記録です。 止めた操作はログに残ります。判定が返らなかった操作は、止めた記録にも止めなかった記録にも残りません。監査で問われるのは「止めなかったときに誰が知ったか」ですが、この欄が規程にありません。
3 つ目は、層の順序です。 権限の一覧、分類器、フック、サンドボックスは、1 つの権限の別名ではありません。決まった順序で解決され、手前の層が許可を返すと奥の層が呼ばれないことがあります。「フックを入れたから安心」という書き方は、この順序を見ていません。
規程に足す 4 つの欄
1 つ目、判定なしの扱い。 止める層が判定を返さなかったときに、実行を許すのか止めるのかを欄として書きます。例外、時間切れ、スクリプトの不在、入力の空の 4 つを列挙し、それぞれの既定を書きます。欄が空なら、既定は実行環境が決めます。
2 つ目、拒否の理由の宛先。 止めたときに、理由を誰が読むのかを書きます。モデルに読ませて自己修正させるのか、人にだけ見せて判断を待つのか。モデル向けには次に試すことを 1 つだけ、人向けには起きたことを時系列で書きます。
3 つ目、対象の事象と実行の形。 フックが、どの事象で、どの実行の形のときに発火するのかを書きます。ツールの前か後か、無人実行か対話実行か。この 2 つがない規程は、「フックを入れた」を「どの経路でも止まる」と読み替えてしまいます。
4 つ目、二重化の確認。 止める層を 2 つ重ねたら、片方を外して、もう片方が同じ操作を止めるかを確かめた記録を残します。外しても止まらないなら、2 つは 1 つです。監査で最も見つけにくい欠陥です。
まとめ
10 月 28 日の事例は、フックの $HOME 展開の失敗として読まれがちです。規程の側から読むと、別の失敗が見えます。異常も問題なしも、実行の側では同じ合図になっていた、という失敗です。
規程に書くべきは「止める仕組みを入れる」ではなく、「その仕組みが判定を返さなかったときに、何が起きるか」です。答えは道具の説明書に書いてあり、規程の側では誰も決めていません。
本稿は事実の整理と欄の提案までです。終了コードの意味は版で変わるため、導入の前に使っている版のリファレンスを確認してください。
参考情報
- kazuki_okura「Claude Code の個人設定を Claude 自身に点検させたら、フックに抜け穴が見つかった」、Zenn、2026 年 10 月 28 日公開。本稿の出発点となった事例の一次記述である。本稿執筆時点では原文に直接当たっておらず、経路の記述は次の記事を経由している
- norman6464「git push を止める hook は要らなかった:無人 claude -p には push の権限を渡さない、という置き方」、Zenn、2026 年 11 月 2 日公開。上の事例を著者の記述として要約し、3 層の比喩を示している。本稿が扱う事例の経路はこの記事で確認した
- y_ukai(azarashi)「Auto mode時代のClaude Codeを守る。検証済み10キットで始めるセキュリティ対策【全員・チーム・組織別】」、Zenn、2026 年 10 月 28 日公開。2026 年 10 月に 12 の操作を権限モードごとに試した記録である。キットなしの auto mode で、強制 push と設定ファイルの書き換えが確認の画面なしに実行されたとの記述を参照した。結果は著者の環境での値であり、途中経過にあたる
- Anthropic「Claude Code hooks リファレンス」、code.claude.com/docs/en/hooks、2026 年 11 月 3 日参照。終了コード 2 をブロックとし、それ以外をブロックしないエラーとする記述、事象ごとに意味が定まること、方針を強制するフックは 2 を使うべき旨を参照した。原文は英語である
本稿は AI の支援を受けて執筆されました。事実の確認と内容の責任は筆者にあります。