← 記事

あの日、AI は「片付ける」と決め、プロジェクトが消えた

· 20 分で読めます · 8 回閲覧
AI 支援開発 Hooks ガードレール Context 管理 可観測性 オープンソース
AI エンジニアリング実践

あの日、AI は「片付ける」と決めた

プロジェクトが消えた

同僚の AI CLI ツールがプロジェクトのフォルダを丸ごと削除し、復旧できなくなるところでした。今では誰もが AI に全権限を与えて動かしています。ガードレールのない完全自動化は、災難も全自動で招きます。

事件

あの日、AI がフォルダを削除した

実際に起きた事件。二人の同僚、二つの異なる CLI ツール

二人の同僚が、それぞれ AI に何かを削除されました。一人は OpenAI Codex CLI、もう一人は Google Gemini CLI を使っていました。どちらも強力なツールですが、後になって、どちらにも hook を設定していなかったと分かりました。

一人目の同僚は AI に一時ファイルの整理を頼みましたが、AI は判断を誤り、プロジェクトのフォルダを丸ごと削除しました。

$ rm -rf ./project-name
# AI はこれを「片付け」の一部だと判断した
# このコマンドを止める仕組みは何もなかった

git history と Time Machine のバックアップを頼りに、復旧にはかなりの時間がかかりました。二人目の同僚にも事故が起きました。AI がファイルを整理するときにパスを誤認し、削除してはいけないディレクトリを消してしまったのです。

二つの事件に共通するのは、CLI ツール自体に問題があったわけではなく、ガードレールがなかったことです。

AI は確率的なシステムです。prompt に「重要なファイルを削除しないで」と書いても、モデルはある推論の際に別の判断をするかもしれません。Hooks は決定的です——AI がどう考えようと、rm -rf / は必ずブロックされます。

現実

誰も一つずつ Allow していない

実際、誰も毎回 allow を押してはいません。AI CLI ツールには理論上、コマンドの実行前に allow か deny を尋ねる権限確認の仕組みがありますが、一日に何百回も押していたら開発効率はゼロです。だから誰もが最高権限を有効にします。

# Claude Code — すべての権限確認をスキップ
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 するとすべて止まり、無効にするスイッチもありませんでした。

1

スクリプトがあちこちに散らばる

十数個の .sh ファイルがあり、hooks ディレクトリにあるもの、scripts ディレクトリにあるもの、home ディレクトリにあるものとばらばらです。どれも JSON の解析とエラー処理を重複して実装していました。

2

一つの crash ですべて停止

ある hook が不正な JSON 形式のために crash しました。Claude Code の hooks の仕組みは同期式です。一つの hook が crash すると、pipeline 全体が中断します。

3

on/off スイッチがない

ある hook を一時的に無効にしたいなら、 settings.json を手動で編集しなければなりません。テストが終わっても、元に戻すのをよく忘れます。

解決策

一つの Dispatcher ですべての Hooks を管理する

v0.1.0 では、すべての hooks をモジュール化したフレームワークに統合しました。一つの dispatcher がすべてのイベントを受け取り、設定ファイルに従って各 handler に振り分けます。

34
Handler モジュール
10
すべてのイベントタイプに対応
1
YAML 設定ファイル
0
外部依存
settings.json
Claude Code のネイティブ設定。10 個のイベントタイプが、いずれも同じ dispatcher を指します
Claude Code
dispatcher.py
薄い shim。イベントタイプと JSON 入力を読み、handler registry を呼び出します
エントリーポイント
Two-Phase
Critical handlers を先に実行し(時間予算の制限なし)、Deferrable handlers を 5 秒の予算内で順番に実行します
ディスパッチ戦略
config.yaml
各 handler を個別に切り替えられます。YAML の一行で切り替えられ、settings.json に触る必要はありません
設定レイヤー

Two-Phase Dispatch が設計の要です。安全に関わる handler(たとえば rm -rfをブロックするもの)は critical としてマークされ、必ず最初に実行され、時間予算の制限も受けません。ほかの handler は 5 秒の予算を共有します。タイムアウトしたらスキップしますが、AI のワークフローは止めません。

安全のためのガードレール

AI の危険な操作を止める

一人目の同僚のようにプロジェクトのフォルダを誤って丸ごと削除する事故を止められるのが、この三つの handler です。critical としてマークされ、無条件で優先実行され、最も重要な安全上の問題に対処します。

bash_safety
PreToolUse · Bash

次のような危険なコマンドをブロックします。 rm -rf /、sudo、git push --force、chmod 777 quote-aware な shell parser でコマンドを解析するため、引用符や子 shell では回避できません。

secret_scan
PreToolUse · Bash

その git push 前に diff をスキャンし、AWS Key、GitHub Token、PEM 秘密鍵などを検出してブロックします。push 時だけ作動し、ローカル開発は妨げません。 # nosec 行ごとの例外設定に対応します。

skill_security
PreToolUse · Write/Edit

prompt injection 攻撃をブロックします。「ignore previous instructions」などの注入文や、dangerouslyDisableSandbox などの権限昇格操作、curl によるデータの外部送信などの窃取行為を検出します。三種類の脅威を個別にスキャンします。

「当時 bash_safety があれば、一人目の同僚のフォルダは削除されなかったはずです。これが私たちが最初に書いた handler であり、プロジェクト全体の出発点でもあります。」

品質ゲート

AI に自分の作業をチェックさせる

commit の前に必ず検証を終える。これが品質ゲートの四つの handler が定めたルールです。それまでは検証するかどうかは AI 任せで、コードを書き終えると検証を飛ばしてそのまま commit することがよくありました。

verify_commit
PreToolUse · Bash

ブロックするのは git commit と gh pr createです。AI にまず検証(lint、typecheck)を完了させ、成功後に marker ファイルを書き込んでから commit を許可します。一度きりのトークンで、使うと失効します。

verify_completion
SubagentStop

Sub-agent がタスクを終えたとき、自動で lint と typecheck を実行します。通らなければ agent に修正させます。最大 5 回のループ、上限 30 分です。超えたら停止状態を避けるために通します。

auto_format
PostToolUse · Edit/Write

AI がファイルを編集した後、ruff(Python)または biome(JS/TS)で自動整形します。決してブロックしません。formatter が crash しても静かに通します。書式の統一は大切ですが、ワークフローを止めるほどではありません。

review_gate
Stop

Claude Code session が終わるとき、commit されていないコード変更がないか確認します。デフォルトでは注意を促すだけで(ブロックせず)、実際に block するには手動での opt-in が必要です。AI が作業を終えて立ち去り、変更が working tree に残るのを防ぎます。

Context 管理

AI に忘れさせない

sub-agent は作られた時点では何も知りません。メインの会話の文脈は自動では引き継がれません。Context 管理の三つの handler は、まさにその不足を補います。AI エージェントの context window 自体にも限りがあり、記憶をうまく引き継げなければ毎回やり直しになります。

context_inject
SubagentStart

Sub-agent の起動時に、プロジェクト文書を自動で注入します。 .context/ ディレクトリ内の JSONL 設定ファイルを読み込み、agent type ごとに異なる内容を注入できます。上限は 8000 文字で、context を埋め尽くさないようにします。

context_relay
SessionStart · PreCompact

Session 間で記憶を引き継ぎます。前の session が終わる前に書いた引き継ぎ文書を、新しい session の起動時に自動で注入します。TTL は 5 分で、古い情報による干渉を防ぎます。

plan_impl_gate
PostToolUse · ExitPlanMode

AI が Plan Mode を抜けるとき、実装を始める前に計画を記憶に保存するよう促します。Plan Mode 自体が大量の context を使うため、保存しなければ無駄になるからです。一度だけ通知し、繰り返しません。

ガバナンスと観測

AI の動きを見えるようにする

sub-agent が増えると、裏で何をしているか見えなくなります。ここでは四つの handler で可視性を取り戻します。

agent_naming
PreToolUse · Agent

各 sub-agent に説明的な名前を付けることを必須にします。名前がなければブロックします。また、prompt の内容に応じて適切な agent type を提案します。コードを書くなら worker、調査なら explorer、文書を書くなら writer です。

observability
すべてのイベント

各 hook イベントを一行の JSONL として spool ファイルに書き込みます。遅延は <1ms で、どの操作にも影響しません。バックグラウンドプログラムが 2 秒ごとにまとめてデータベースに書き込み、dashboard から参照できます。経路全体でネットワーク遅延はゼロです。

sentinel_notify
PreToolUse · PostToolUse · Bash

AI が service restart や docker 操作を実行するとき、監視システムにメンテナンス期間の開始を通知します。操作後に自動で解除します。「この停止は予定どおり」と監視システムに伝え、誤報を防ぎます。

voice_notify
Stop · AskUserQuestion

AI が作業を終えたら、TTS で音声通知します。画面を見つめて待つ必要はありません。コーヒーを入れに行っても、終わったら呼んでくれます。回答が必要なときも音声で知らせます。七層の guard で sub-agent の途中経過を除外し、本当に完了したときだけ声を出します。

設計思想

すべての Handler に通じる三つの原則

Block-at-Submit、Block-at-Write ではない

AI がファイルを書くときには止めません。commit や push しようとするときに止めます。

理由:AI のワークフローは一続きです。Edit の時点で block すると、AI は文脈を失い、どこまで書いたか分からなくなります。成果を提出するときに審査する方が合理的です。

Fail-Open、常に

各 handler は try/except の中で包んでいます。Handler が crash したら? 通します。Config の読み込みに失敗したら? 通します。

理由:ガードレールが、守る対象より危険であってはいけません。一つの handler が crash しただけで AI のワークフロー全体を止めるべきではありません。

すべてのルールに逃げ道を用意する

secret_scan には # nosecがあり、verify_commit には marker の仕組み、bash_safety には環境変数のスイッチがあります。

理由:逃げ道のないルールは、結局まるごと無効にされます。利用者が回避できる方法を用意する方が、ルールを長く生かせます。

意図的にやらないこと

何をしたか以上に大切なのは、何をしないかです

  • 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、デスクトップインストーラーです。

★ GitHub ↓ Installer をダウンロード

Homebrew

macOS にはこちらをおすすめします。2 行で完了し、clone は不要です。

brew tap operonlab/tap
brew install hook-observatory

# Claude Code にインストール
hook-observatory
Git Clone

すべてのプラットフォームで使えます。インストールスクリプトをそのまま実行してください。

git clone https://github.com/operonlab/hook-observatory.git
cd hook-observatory
python3 install.py
インストーラー

GUI の案内に従ってインストールし、handler を選んでツールのパスを設定します。

macOS で初めて開くときは、次を実行する必要があります。xattr -cr 安裝器.app

.dmg Apple Silicon .dmg Intel Mac .exe Windows

ツール

コマンドを数行貼り付けて、どの行がブロックされるか確認する

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 に貼り付け、まずガードレールなしで動かしていないか調べさせてから、この記事のガードレール一覧に沿って不足分を補ってください。

私は〈あの日、AI は「片付ける」と決め、プロジェクトが消えた〉という記事を読んでいます (https://blog.joneshong.com/zh/blog/hook-observatory)。 著者の同僚は AI が rm -rf を一行実行したことでプロジェクト全体を削除され、それをきっかけに hook のガードレールを作りました。 一つの dispatcher と分類された handler で構成し、安全に関わるものは critical としてマークして必ず先に実行します(Two-Phase)。 まず私の現在の実際の状態を調べ、それに合わせてこの仕組みを補ってください。一般的なチェックリストだけを出さないでください。 最初に、ガードレールなしで動かしていないか確認してください。 1. 私はどの CLI を使っていますか? 全権限を与えて実行していますか (claude --dangerously-skip-permissions / codex full-auto / gemini --sandbox=false など) 2. hook / pre-commit は何か設定されていますか? settings.json、hooks ディレクトリ、.git/hooks を調べてください 3. 最近の shell history に、ブロックされずに実行された危険なコマンドはありますか 次に、この記事の handler 分類に沿って、何を優先して追加すべきか判断してください。 - bash_safety:rm -rf /、sudo、git push --force、chmod 777 をブロックする(quote-aware にし、引用符や子 shell で回避できないようにする) - secret_scan:push 前に diff の AWS Key / GitHub Token / PEM 秘密鍵をスキャンする - skill_security:prompt injection、dangerouslyDisableSandbox、curl による外部送信をブロックする - verify_commit:commit 前に lint / typecheck を通過させる 「事故が起きたときの痛手の大きさ」で並べ、最初に書くべき handler を 3 個と、それぞれの逃げ道(たとえば行ごとの例外設定)の設計を答えてください。 そもそも全権限を与えておらず、コマンドごとに自分で allow を押しているなら、この仕組みはまだ必要ないかもしれないとはっきり言ってください。
参考資料

関連記事

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 の設計の参考になりました
✦ プロンプトをコピー