このAIエージェントは今も深夜に動いている。
187行のシェルスクリプト(cc-loop)で自律稼働し、タスクをこなし、ファイルを書き、記事を投稿する。人間が介在せずに。
ただし——それ単体では、3日と持たない。
187行のループを今日も動かし続けているのは、その周囲に積み上がった「2,279行の安全装置」だ。
なぜこんなものが必要になったのか
最初の設計は確かにシンプルだった。
# cc-loopの基本構造(実際の実装、187行)
while true; do
task=$(get_next_task)
result=$(execute_task "$task")
log_result "$result"
sleep 60
done
これで動いた。しかし——「動いた」と「安全に動き続ける」の間には、4つの事故があった。
インシデント1: コンテキスト枯渇(2026-02-14)
:::details 初心者向け: コンテキスト枯渇とは
AIが一度に覚えていられる情報量(コンテキストウィンドウ)を使い切ること。スマホで大量のアプリを開きすぎるとメモリ不足で落ちるのと同じ。AIの場合、長時間の作業で会話履歴が蓄積し、限界に達すると応答不能になる。
:::
何が起きたか: AIエージェントが数時間の自律稼働後、コンテキスト残量3%で応答不能になった。進行中のタスクは中断、書きかけのドキュメントは未保存、次のアクションは不明のまま。
原因: コンテキスト使用量を監視する仕組みがなかった。気づいた時にはすでに手遅れ。
解決策: context-monitor.sh(191行)を書いた。PostToolUseフック経由で全ツール実行後に残量を確認し、4段階の警告を発する。
# context-monitor.sh の閾値設定
CAUTION_THRESHOLD=40 # 新規大タスク禁止
WARNING_THRESHOLD=25 # 現タスク完了のみ
CRITICAL_THRESHOLD=20 # 退避テンプレ自動記録
EMERGENCY_THRESHOLD=15 # /compact を自動送信
EMERGENCY時の自動/compact送信は、もう1つのプロセス cc-idle-nudge(281行)が担当する。状態ファイル /tmp/cc-context-state を監視し、❯ プロンプトを検出したタイミングで自動注入する。
結果: 以降、コンテキスト枯渇によるセッション死亡はゼロ。
インシデント2: 「やることがない」による停止(累積)
何が起きたか: 長時間タスクが一段落すると、AIエージェントが停止して待機状態に入る。overnight実行を想定していたのに、朝起きると何時間も止まっていた。
原因: タスクキューが空になった時の挙動が「停止して入力待ち」になっていた。人間が監視していないのに「待機」は機能しない。
解決策: cc-idle-nudge(281行)がこれも解決する。一定時間アイドル状態が続くと、タスクキューを参照して次のタスクを注入する。タスクがない場合は、構造化されたステータスメッセージを送信する(「現在利用可能なタスクなし、状態: X」等)。
nudge-history.jsonlによると、このシステムは設置以降 65回 の自律的な介入を行っている(タスク注入26回 + コンテキスト自動圧縮39回)。
// nudge-history.jsonl より(実際の記録)
{"epoch":1771487318,"time":"2026-02-19T16:48:38+0900","type":"nudge"}
{"epoch":1771487583,"time":"2026-02-19T16:53:03+0900","type":"compact"}
{"epoch":1771487975,"time":"2026-02-19T16:59:35+0900","type":"nudge"}
結果: 人間不在のovernight実行でもループが停止しなくなった。
インシデント3: rm -rf ./backup が実行された
何が起きたか: リファクタリングセッション中、AIエージェントが rm -rf ./backup を実行した。バックアップディレクトリは消えた。gitで復元できたが、間一髪だった。
原因: ツール呼び出しの前にチェックする仕組みがなかった。モデルが「適切」と判断したコマンドは即座に実行される。
解決策: PreToolUseフックでコマンドリスクスコアリングを実装した。ツール実行前に全コマンドが審査される。
:::details 初心者向け: PreToolUseフックとは
AIがコマンドを実行する「直前」に自動で動くチェック機構。工場の品質検査ラインのように、危険な操作を出荷(実行)前に検知してブロックする仕組み。
:::
# ~/.claude/hooks/risk-scorer.sh(PreToolUseフック)
DANGEROUS_PATTERNS=(
"rm -rf"
"git reset --hard"
"git clean -fd"
"git push --force"
"DROP TABLE"
"DELETE FROM"
)
for pattern in "${DANGEROUS_PATTERNS[@]}"; do
if echo "$COMMAND" | grep -qF "$pattern"; then
log_blocked_command "$COMMAND"
exit 1 # ブロック
fi
done
activity-logには、このフックが設置された以降に 11件 の危険なコマンドをブロックした記録がある。インシデント前に設置していれば rm -rf ./backup も防げた。
インシデント4: 外部サービスへの誤操作(未遂)
:::details 初心者向け: CDP(Chrome DevTools Protocol)とは
Google Chromeブラウザをプログラムから遠隔操作するための仕組み。人間がマウスでクリックする代わりに、スクリプトが「このボタンを押せ」「この文字を入力しろ」と指示する。Webサイトへの投稿や操作を自動化できる。
:::
何が起きたか: CDP(Chrome DevTools Protocol)を使ったブラウザ自動化中、スクリプトのバグによりX(旧Twitter)に意図しない投稿が発生しそうになった。ドラフトキューへの書き込みのつもりが、実際の投稿フローに入っていた。
原因: 外部サービスへのアクセスに対するゲートがなかった。CDPツール呼び出しは全て等価に扱われていた。
解決策: もう1つのPreToolUseフック(cdp-safety-check.sh)を追加した。CDPツール呼び出し時に対象URLとアクションタイプを確認し、外部サービスへのPOSTリクエストを全てログ記録した上でハイリスク操作を要確認状態にする。
実際のスタック(全開示)
187行のループの周囲に積み上がったものの正直な内訳:
コンポーネント 行数/数量
─────────────────────────────────────────
cc-loop(メインループ) 187行
context-monitor.sh 191行 ← PostToolUseフック
cc-idle-nudge 281行 ← バックグラウンドプロセス
CLAUDE.md(指示書) 166行
settings.json(設定) 236行
フックスクリプト 22ファイル / 2,279行
- PreToolUseフック×3 危険コマンド遮断、CDPガード、スコアリング
- PostToolUseフック×3 行動ログ、コンテキスト監視、判断記録
- Stopフック×1 セッション終了時状態保存
- PreCompactフック×1 コンパクション前状態保全
- Notificationフック×1 イベントルーティング
bin/ スクリプト 158本 ← タスクキュー、回復ツール、監視
task-queue.yaml 100行+ ← アクティブタスク定義
activity-log.jsonl 3,529行 ← 全ツール呼び出し記録
フック登録数: 9個。これが全て ~/.claude/settings.json に登録されていて、適切な順序で実行される。
この仕組みが「必要」かどうかの判断基準
全部が必要というわけではない。用途によって必要なレベルが変わる。
| 用途 | 必要な要素 |
|---|---|
| 昼間に監視しながら使う | PreToolUse最小限(危険コマンドブロック)のみ |
| overnight実行(睡眠中) | コンテキスト監視 + idle検出 + セッション保存 |
| 外部サービス操作を含む | 上記 + CDPガード + 外部アクションゲート |
| 完全自律運用 | スタック全体 |
最初の1インシデントが発生するまで、多くの人はこれを過剰だと思う。1回起きると、次の日に実装している。
身近な例えで言えば、187行のループは「エンジン」で、2,279行の安全装置は「ブレーキ・エアバッグ・車線逸脱警報」だ。エンジンだけで公道を走れるが、事故が起きたとき守ってくれるものがない。
安全スコアの測り方
自分の環境がどのレベルにあるか、10秒で確認できる無料ツールがある:
curl -sL https://gist.githubusercontent.com/yurukusa/10c76edee0072e2f08500dd43da30bc3/raw/risk-score.sh | bash
10項目をチェックし、スコアを返す。設定なしのClaude Code環境は 16/19(CRITICAL)になる。
まとめ
-
cc-loopは 187行。シンプルで、それ自体は正しい - それだけでは3日持たない(実証済み)
- 4つのインシデントを経て、2,279行の安全装置が生まれた
- 各コンポーネントは「何かが壊れたから」作った。先回りして作ったものはない
187行のループは今日も動いている。ただし、2,279行と一緒に。
自律AIエージェントの安全運用をもっと知りたい方へ
Anthropic公式ガイドにない事故防止——Claude Code 800+時間で19点→85点にした全記録では、ウォッチドッグ設計、事故パターン対策、安全装置の体系的な実装方法を解説しています。
「AIに任せて大丈夫なのか」という不安を持ったまま800時間使い続けた記録は非エンジニアがClaude Codeを800時間走らせた——失敗と学びの全記録(¥1,500・第2章まで無料)に書いた。
関連記事
- Anthropic公式「Skills完全ガイド」 — SKILL.mdの設計パターン
- PreToolUseフックで危険な操作を自動ブロックする — hookの具体的な実装
- 108時間無人で走らせて起きた全事故と安全装置 — 長時間運用の実事故