あの日、AI は「片付ける」と決めた
プロジェクトが消えた
同僚の AI CLI ツールがプロジェクトのフォルダを丸ごと削除し、復旧できなくなるところでした。今では誰もが AI に全権限を与えて動かしています。ガードレールのない完全自動化は、災難も全自動で招きます。
あの日、AI がフォルダを削除した
実際に起きた事件。二人の同僚、二つの異なる CLI ツール
二人の同僚が、それぞれ AI に何かを削除されました。一人は OpenAI Codex CLI、もう一人は Google Gemini CLI を使っていました。どちらも強力なツールですが、後になって、どちらにも hook を設定していなかったと分かりました。
一人目の同僚は AI に一時ファイルの整理を頼みましたが、AI は判断を誤り、プロジェクトのフォルダを丸ごと削除しました。
# AI はこれを「片付け」の一部だと判断した
# このコマンドを止める仕組みは何もなかった
git history と Time Machine のバックアップを頼りに、復旧にはかなりの時間がかかりました。二人目の同僚にも事故が起きました。AI がファイルを整理するときにパスを誤認し、削除してはいけないディレクトリを消してしまったのです。
二つの事件に共通するのは、CLI ツール自体に問題があったわけではなく、ガードレールがなかったことです。
AI は確率的なシステムです。prompt に「重要なファイルを削除しないで」と書いても、モデルはある推論の際に別の判断をするかもしれません。Hooks は決定的です——AI がどう考えようと、rm -rf / は必ずブロックされます。
誰も一つずつ Allow していない
実際、誰も毎回 allow を押してはいません。AI CLI ツールには理論上、コマンドの実行前に allow か deny を尋ねる権限確認の仕組みがありますが、一日に何百回も押していたら開発効率はゼロです。だから誰もが最高権限を有効にします。
claude --dangerously-skip-permissions
# OpenAI Codex CLI — YOLO モードですべてを自動承認
codex --approval-mode full-auto
# Google Gemini CLI — 同じく YOLO モード
gemini --sandbox=false
これは一部の人だけの行動ではなく、普通のことです。全権限を与えることが、AI エージェントに本来の効率を発揮させる唯一の方法です。ただし、その代償として AI は、ファイルの削除、force push、システムディレクトリへの書き込み、秘密鍵を含む commit の push など、あらゆるコマンドを実行できます。ガードレールのない完全自動化は、開発環境を「たいていは賢いけれど、ときどき間違える」システムに預けるのと同じです。
問題は「全権限を与えるかどうか」ではなく、「与えた後、その『ときどき』を誰が止めるのか」です。
散らばった Shell Scripts は制御できなくなる
そこで Claude Code に hooks を追加し始めました。最初は危険なコマンドを止める shell script をいくつか書いただけでしたが、三か月後には自分たちの仕組みが問題を起こしました。スクリプトはあちこちに散らばり、一つが crash するとすべて止まり、無効にするスイッチもありませんでした。
一つの Dispatcher ですべての Hooks を管理する
v0.1.0 では、すべての hooks をモジュール化したフレームワークに統合しました。一つの dispatcher がすべてのイベントを受け取り、設定ファイルに従って各 handler に振り分けます。
Two-Phase Dispatch が設計の要です。安全に関わる handler(たとえば rm -rfをブロックするもの)は critical としてマークされ、必ず最初に実行され、時間予算の制限も受けません。ほかの handler は 5 秒の予算を共有します。タイムアウトしたらスキップしますが、AI のワークフローは止めません。
AI の危険な操作を止める
一人目の同僚のようにプロジェクトのフォルダを誤って丸ごと削除する事故を止められるのが、この三つの handler です。critical としてマークされ、無条件で優先実行され、最も重要な安全上の問題に対処します。
次のような危険なコマンドをブロックします。 rm -rf /、sudo、git push --force、chmod 777 quote-aware な shell parser でコマンドを解析するため、引用符や子 shell では回避できません。
その git push 前に diff をスキャンし、AWS Key、GitHub Token、PEM 秘密鍵などを検出してブロックします。push 時だけ作動し、ローカル開発は妨げません。 # nosec 行ごとの例外設定に対応します。
prompt injection 攻撃をブロックします。「ignore previous instructions」などの注入文や、dangerouslyDisableSandbox などの権限昇格操作、curl によるデータの外部送信などの窃取行為を検出します。三種類の脅威を個別にスキャンします。
「当時 bash_safety があれば、一人目の同僚のフォルダは削除されなかったはずです。これが私たちが最初に書いた handler であり、プロジェクト全体の出発点でもあります。」
AI に自分の作業をチェックさせる
commit の前に必ず検証を終える。これが品質ゲートの四つの handler が定めたルールです。それまでは検証するかどうかは AI 任せで、コードを書き終えると検証を飛ばしてそのまま commit することがよくありました。
ブロックするのは git commit と gh pr createです。AI にまず検証(lint、typecheck)を完了させ、成功後に marker ファイルを書き込んでから commit を許可します。一度きりのトークンで、使うと失効します。
Sub-agent がタスクを終えたとき、自動で lint と typecheck を実行します。通らなければ agent に修正させます。最大 5 回のループ、上限 30 分です。超えたら停止状態を避けるために通します。
AI がファイルを編集した後、ruff(Python)または biome(JS/TS)で自動整形します。決してブロックしません。formatter が crash しても静かに通します。書式の統一は大切ですが、ワークフローを止めるほどではありません。
Claude Code session が終わるとき、commit されていないコード変更がないか確認します。デフォルトでは注意を促すだけで(ブロックせず)、実際に block するには手動での opt-in が必要です。AI が作業を終えて立ち去り、変更が working tree に残るのを防ぎます。
AI に忘れさせない
sub-agent は作られた時点では何も知りません。メインの会話の文脈は自動では引き継がれません。Context 管理の三つの handler は、まさにその不足を補います。AI エージェントの context window 自体にも限りがあり、記憶をうまく引き継げなければ毎回やり直しになります。
Sub-agent の起動時に、プロジェクト文書を自動で注入します。 .context/ ディレクトリ内の JSONL 設定ファイルを読み込み、agent type ごとに異なる内容を注入できます。上限は 8000 文字で、context を埋め尽くさないようにします。
Session 間で記憶を引き継ぎます。前の session が終わる前に書いた引き継ぎ文書を、新しい session の起動時に自動で注入します。TTL は 5 分で、古い情報による干渉を防ぎます。
AI が Plan Mode を抜けるとき、実装を始める前に計画を記憶に保存するよう促します。Plan Mode 自体が大量の context を使うため、保存しなければ無駄になるからです。一度だけ通知し、繰り返しません。
AI の動きを見えるようにする
sub-agent が増えると、裏で何をしているか見えなくなります。ここでは四つの handler で可視性を取り戻します。
各 sub-agent に説明的な名前を付けることを必須にします。名前がなければブロックします。また、prompt の内容に応じて適切な agent type を提案します。コードを書くなら worker、調査なら explorer、文書を書くなら writer です。
各 hook イベントを一行の JSONL として spool ファイルに書き込みます。遅延は <1ms で、どの操作にも影響しません。バックグラウンドプログラムが 2 秒ごとにまとめてデータベースに書き込み、dashboard から参照できます。経路全体でネットワーク遅延はゼロです。
AI が service restart や docker 操作を実行するとき、監視システムにメンテナンス期間の開始を通知します。操作後に自動で解除します。「この停止は予定どおり」と監視システムに伝え、誤報を防ぎます。
AI が作業を終えたら、TTS で音声通知します。画面を見つめて待つ必要はありません。コーヒーを入れに行っても、終わったら呼んでくれます。回答が必要なときも音声で知らせます。七層の guard で sub-agent の途中経過を除外し、本当に完了したときだけ声を出します。
すべての Handler に通じる三つの原則
Block-at-Submit、Block-at-Write ではない
AI がファイルを書くときには止めません。commit や push しようとするときに止めます。
理由:AI のワークフローは一続きです。Edit の時点で block すると、AI は文脈を失い、どこまで書いたか分からなくなります。成果を提出するときに審査する方が合理的です。
何をしたか以上に大切なのは、何をしないかです
- Edit / Write をブロックしない AI がファイルを書くときには介入しません。書き込みの途中で AI を止めると、ファイルが不完全な状態になりかねません。すべての審査を commit または push の時点まで遅らせます。
- ゲート内でテストを自動実行しない verify_completion が実行するのは lint と typecheck だけで、テストは意図的に除外しています。テストは遅く、副作用があり、データベースの状態を変えることもあります。自動ゲートに入れると、得られる利益よりリスクが大きいのです。
- 自動修復せず、ブロックして理由を説明する bash_safety は AI のために「より安全なコマンド」へ書き換えません。「このコマンドは X のためブロックされました」と伝えるだけです。次にどうするかは AI に判断させます。自動書き換えは、さらに奇妙な bug を招きかねません。
- context budget を採点しない かつて context_supervisor handler(800 行)を書き、context の使用量を計算して圧縮のタイミングを提案しようとしました。発想はよかったのですが、採点モデルが不正確でした。context の「重要性」はヒューリスティックなルールでは判断できません。現在は無効にしています。
- Fail-Closed にしない どの handler が crash しても通します。「それは危険では?」と聞かれるかもしれません。しかし、ガードレール自体がシステム全体を詰まらせる方が危険です。AI が動かなくなり、利用者にも理由が分かりません。
hook-observatory
MIT ライセンス、外部依存ゼロ。インストール後すぐに使えます。
インストール方法は三つ。Homebrew、Git Clone、デスクトップインストーラーです。
macOS にはこちらをおすすめします。2 行で完了し、clone は不要です。
brew install hook-observatory
# Claude Code にインストール
hook-observatory
すべてのプラットフォームで使えます。インストールスクリプトをそのまま実行してください。
cd hook-observatory
python3 install.py
GUI の案内に従ってインストールし、handler を選んでツールのパスを設定します。
macOS で初めて開くときは、次を実行する必要があります。xattr -cr 安裝器.app
コマンドを数行貼り付けて、どの行がブロックされるか確認する
bash_safety のカードでは、四種類のコマンドを挙げました。rm -rf、sudo、git push --force、chmod 777。自分で実行したコマンドを数行貼り付けてください。ここではその四種類と一行ずつ照合し、verify_commit や secret_scan に引っかかる行も示します。処理はすべてブラウザ内で行われ、外部への送信もコマンドの実行もありません。history 全体ではなく、数行だけで十分です。秘密鍵、内部ホスト名、非公開のパスを含む行は貼り付けないでください。
定数の根拠はすべてこの記事にあります。四種類の危険なコマンドと、「quote-aware な shell parser で解析するため引用符や子 shell では回避できない」という説明は bash_safety のカードから、git commit / gh pr create 許可する前に lint と typecheck を終える必要があるという条件は verify_commit のカードから、git push 事前に diff をスキャンするという条件は secret_scan のカードから取っています。ここでできないことは四つあります。① 判定するのは貼り付けた文字列であり、実際に自分のマシンで起こることではありません。外部への送信も実行もありません。② これは記事に挙げた四種類に基づく近似判定であり、hook-observatory の実際のルールではありません。記事には「などの危険なコマンド」とあり、リストはもともと網羅的ではありません。したがって「赤く表示されない」ことは安全を意味しません。③ 三つ目の critical handler(skill_security)は PreToolUse · Write/Edit にかかり、コマンドラインではなくファイルの内容を見るため、ここでは確認できません。④ 記事の「意図的にやらないこと」にあるとおり、ブロックされたときは理由だけを伝え、「より安全な書き方」は示しません。
自分の AI エージェントにコピーする
問題は「全権限を与えるか」ではなく、「与えた後、その『ときどき』を誰が止めるか」です。prompt に「重要なファイルを消さないで」と書いても効きません。AI は確率的で、ある推論のときに判断を変えることがあります。一方 hook は決定的で、rm -rf / を必ずブロックします。この記事の出発点は、一人目の同僚が AI にプロジェクトのフォルダを丸ごと削除されたことです。
以下を自分の AI に貼り付け、まずガードレールなしで動かしていないか調べさせてから、この記事のガードレール一覧に沿って不足分を補ってください。
関連記事
Blake Crosley の〈Why Each of My 95 Hooks Exists〉を読んで気づかされました。各 handler は実際の事故に対応すべきです。
| 資料 | 重要な理由 |
|---|---|
| operonlab/hook-observatory | この記事で取り上げたオープンソースプロジェクト |
| Blake Crosley: Why Each of My 95 Hooks Exists | incident-driven な hook の構築方法です。どの hook にも、その背景に事故があります。 |
| GitButler: Automate Your AI Workflows with Claude Code Hooks | 初期の設計に影響を与えた、hooks の実践的な紹介の一つです |
| aiorg.dev: Claude Code Hooks Complete Guide | 「決定性 vs 確率性」という枠組みの説明が、hooks の価値を的確に表しています |
| Jackle: Claude Code Voice Mode | hooks による音声通知の実装例で、voice_notify handler の設計の参考になりました |