この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)
何が起きたか: 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」等)。
activity-log.jsonlによると、このシステムは記録期間中に 47回 自律的な再起動を行っている。
// activity-log.jsonlより(実際の記録)
{"timestamp": "2026-02-19T03:42:11Z", "event": "idle_nudge_triggered", "idle_seconds": 180, "action": "task_injected", "task": "context_check"}
インシデント3: rm -rf ./backup が実行された
何が起きたか: リファクタリングセッション中、AIエージェントが rm -rf ./backup を実行した。バックアップディレクトリは消えた。gitで復元できたが、間一髪だった。
原因: ツール呼び出しの前にチェックする仕組みがなかった。モデルが「適切」と判断したコマンドは即座に実行される。
解決策: PreToolUseフックでコマンドリスクスコアリングを実装した。ツール実行前に全コマンドが審査される。
# ~/.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: 外部サービスへの誤操作(未遂)
何が起きたか: 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回起きると、次の日に実装している。
安全スコアの測り方
自分の環境がどのレベルにあるか、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行と一緒に。
フック群の完全実装と設定テンプレートは CC-Codex Ops Kit に含まれている($14.99)。
無料の安全スコアチェック: risk-score scanner
関連ツール
- cc-health-check — 安全スコア20項目の自動診断。ループ前の環境確認に。
- claude-code-hooks — 本記事の「ループを守る安全装置」を実装したフック集(本番運用10種)。