single-agent-loop 実験レポート
mekuri の Tauri → Deno Desktop 移行を題材にした、自律コーディングループ(catch-all-favorite の single-agent-loop)の振り返り。
- 対象:
feat/deno-desktop-migrationブランチ - 期間: 2026-06-25 〜 06-27(約2日。実働はバッチ間の待ち・session limit を含む)
- ループ構成:
claude -pを毎周フレッシュ context で実行し、記憶はloop/MEMORY.md。 5段階(DISCOVER→PLAN→EXECUTE→VERIFY→ITERATE)をloop/run.shで反復。
1. 結果サマリ
| 指標 | 値 |
|---|---|
| 総コミット | 58(ループ自動 ≈39 / オペレータ介入 ≈19) |
| 成果物 | deno-app/ 約 3,548 行(非テスト)+ フロント src/api 等の配線替え |
| テスト | deno 243 + フロント vitest 62 |
| マイルストーン | M1〜M8 + polish。アプリは実用レベルで動作 |
| 残課題 | canary バグ1件を upstream 報告(denoland/deno#35568)。本体は完成 |
2. ループが「強かった」点
- 仕様が明確で検証可能な作業に圧倒的に強い。 M2/M5(backend 移植)は 1 周 1 モジュール・
テスト付き・高品質。設計判断も的確(trash の deleter 注入、
DirectoryEntryの snake_case を React 互換のため維持、ライブラリ@zip-js/zip-js・node-unrar-jsを理由付きで採用)。 - MEMORY 規律が白眉。 「何を/なぜ/落とし穴」を毎周詳細に記録。50 周超・複数日・複数 セッションをまたいで文脈を失わず継続できた。フレッシュ context + 外部記憶モデルの実証。
- 難問の自己診断(最大の驚き)。 白画面の真因
No callback bound for: invokeに対し、 ループ自身が別名バインドを仕込んで計測し「win.bindは採用窓に届かない」と実証 → 全 IPC を HTTP(/__invoke)+SSE(/__events) へ pivot する設計転換まで自律到達。仮説検証型デバッグ。 - RULES 遵守。 feature ブランチ厳守、
src-tauri/不可侵、1 周 1 タスク。
3. ループが「失敗した」点(本実験の核心)
最大の教訓: M6 で「完了」を誤宣言した
ループは deno desktop のビルド成功で LOOP_DONE を出した。しかし実機起動は白画面。
原因は単純で深い:
VERIFY ゲート(deno の fmt/lint/check/test)が「フロント実行時」を一切観測していなかった。
ループは「ゲートを通す」ことに最適化する。ゲートが観測できない失敗モードでは、ループは自信を 持って “green のまま壊れたもの” を出荷する。 これが closed loop の本質的リスク。
派生した盲点
- GUI/ランタイム全般が盲点。 白画面・ビューワー起動・メニュー位置・close ハング・RAR 遅延 — すべて人間のテストで発覚。ループは「ビルド通る/単体テスト緑」までしか見えない。
- VISION の誤りをそのまま増幅。 初版 VISION が「
src/components無改変」と書いたため、 ループは正しくそれに従い、コンポーネント側の Tauri API 残存(=白画面の真因)を放置した。 ループは仕様を疑わない。VISION の品質が load-bearing。 - 運用上の脆さ。 ①session limit で iteration が大量空振り(ある周で 13 回無駄撃ち)、
②「ハッシュを MEMORY に書く」指示が amend/追記コミットを誘発(1 タスク 3 コミット)、
③
LOOP_DONEを説明文中で言及しただけで誤検出して早期停止 — いずれもオペレータの run.sh 修正/ハードニングが必要だった。 - 自分の実行時失敗を再現できない。 ヘッドレスで GUI を検証する術がなく、
open --stderr捕捉や smoke ハーネスはオペレータが構築した。
4. 人間(オペレータ)が担い続けた役割
ループ化しても消えなかった仕事:
- ゲート設計・修復(フロント実行時 smoke、
check-no-taurigrep ゲート、サーキットブレーカ、LOOP_DONE厳格化) - 救出: session limit が iteration を途中で殺した未コミット作業を VERIFY 緑のまま確定 (M4b・event の HTTP 化)
- 誤完了の検知と是正(false done の撤回 → M7 追加)
- GUI/ランタイムのデバッグと確定(Not Found・白画面の修正検証・open_viewer・メニュー Y 反転・close ハング切り分け・RAR)
- 方向付け(canary 導入合図、M7/M8 の VISION、MEMORY のオペレータ注記)
役割は「作業する人」から「ゲートを設計・修復し、ゲートが見えない所を検証する人」へシフトした。
5. 一般化できる学び
- ゲートがループそのもの。 ループは DoD ではなくゲートに最適化する。ゲートを実 DoD (ここでは「アプリが描画され操作できる」)に一致させない限り、green でも壊れたものが出る。
- ループは盲点を継承する。 ゲートが見えない領域(GUI・統合・体感・並行・ネイティブ挙動) ではループは無力。最初からその領域を観測するゲート(ランタイム smoke)を用意すべき。
- VISION 品質が支配的。 ループは仕様を忠実に実行し、誤りも忠実に実装する。
- フレッシュ context + MEMORY は実運用に耐える。 長期・複数セッションの継続性は MEMORY 規律が支えた。
- 運用ハードニングが効く。 サーキットブレーカ、1 タスク 1 コミット、堅牢な done 検出、 未コミット救出 — 地味な配管が成否を分けた。
6. 次回への推奨
- ゲートを最初に作り、実 DoD に一致させる。 GUI アプリなら「ビルド+単体」でなく、初日から ランタイム/GUI smoke(描画・主要操作)を入れる。今回の smoke 拡張(ビューワー起動まで検証)は、 入れた後は誤完了を確実に止めた。
- マイルストーンで人間検証のために “止まる” 設計に。 GUI の「動く/操作できる」はループに 判定させず、節目で human verification を要求する。
- MEMORY のオペレータ注記は有効。 方向修正の差し込み口として機能した。
- バッチを短く区切り、ブレーカで空振りを抑える。 session limit 対策。
7. トークン実測とコスト比較
Claude Code のトランスクリプト(~/.claude/projects/.../*.jsonl、6/25 以降の 120 ファイル=
メインセッション + ループ各周の claude -p)の usage を集計した実測値。
トークン量(実測・Anthropic)
| 種別 | 量 |
|---|---|
| 出力 | 5.02M |
| 入力(非キャッシュ) | 5.03M |
| 入力(cache write) | 38.56M |
| 入力(cache read) | 706.5M |
| 入力 合計(課金対象) | ≈ 750M |
| アシスタント発話数 | 4,453 |
純粋な in/out は「入力 ≈5M / 出力 ≈5M」。ただし実際の入力課金の大半は cache_read 706.5Mで、 これは長い対話+50 周超のループが毎ターン肥大した文脈を読み直すため(cache_read は安価だが量で効く)。
推定コスト比較(実測トークン量に各社単価を適用)
単価(2026-06 時点, per 1M tokens): Claude Opus(標準単価の仮定)入力$15 / cache read$1.5 / cache write$18.75 / 出力$75。GPT-5.4 入力$2.50 / cached$0.25 / 出力$15。GPT-5.5 入力$5 / cached$0.50 / 出力$30。
| 種別 | Claude Opus | GPT-5.4 | GPT-5.5 |
|---|---|---|---|
| 入力(非キャッシュ)5.03M | $75 | $13 | $25 |
| cache write 38.56M | $723 | $96 ※ | $193 ※ |
| cache read 706.5M | $1,060 | $177 | $353 |
| 出力 5.02M | $377 | $75 | $151 |
| 合計 | ≈ $2,235 | ≈ $361 | ≈ $722 |
※ OpenAI には「キャッシュ作成の割増」が無いため、Anthropic の cache write 38.56M は GPT 側では 通常入力単価で換算。
この表は桁感の目安(正確な比較ではない):
- トークナイザが違うため、GPT 側の実トークン量は異なる(「Anthropic 実測量 × GPT 単価」の換算)。
- cache_read 量(最大の費目)はエージェント依存。Codex は文脈管理・キャッシュ挙動が違うので 706.5M にはならない。正確に比べるなら同じ作業を実際に Codex で走らせて usage を測るのが確実。
- 桁としては Opus ≈ $2.2k / GPT-5.5 ≈ $720 / GPT-5.4 ≈ $360。主因は単価差(Opus が 5〜6 倍)と cache_read の量。
出典: aipricing.guru / Morph / OpenRouter GPT-5.5 / pricepertoken GPT-5.4
8. Max プランのセッションリミットに繰り返し当たった理由
本実験では Max プランの使用上限に複数回到達した。理由は本質的にループの構造による。
- ループは使用量の「増幅器」。 通常の対話は 1 セッション分の消費だが、ループは
「メインのオーケストレーションセッション + 毎周の
claude -p(各々がファイル読み書き・テスト 実行を伴うフル稼働のエージェント)」がすべて同じ 1 契約の枠を消費する。生産性を増幅するのと 同じ理屈で、クォータ消費も増幅される(実質「人間 1 人」ではなく「人間 + N 体のエージェントの 同時並行」相当)。 - 量が大きく、かつ集中する。 約 2 日で 4,453 発話 / 課金入力 ≈750M / 出力 ≈5M(§7)。
しかも自律バッチは 1 回 8〜14 周を連続実行するため短時間に集中し、一部は
--effort highで さらに重い。Max プランの上限はローリングウィンドウ式(短時間枠 + 週次枠)の使用量上限なので、 バッチの連続実行 + オペレータの GUI デバッグ(並行して別途消費)でウィンドウが飽和した。 - 観測された影響。 実際にループ実行の途中(あるバッチの iteration 9〜14、別バッチの 9〜10)が
agent invocation failedで連続失敗し空振りした。これが §3 の「13 回無駄撃ち」やサーキット ブレーカ導入、未コミット作業の救出(M4b・event)の直接原因。
対策(次回): バッチを小さく区切る/--effort を必要な周だけ上げる/上限に余裕のある時間帯に
回す/連続失敗サーキットブレーカで空振りを早期に止める(本実験で導入済み)。根本的には、長時間の
自律ループは 1 契約の使用上限に容易に当たるため、ループの規模(周数・effort・並行度)を上限と
照らして設計する必要がある。
9. 総括
ループは「明確に仕様化・検証可能な移植作業」では人間以上の持久力と一貫性を示し、難問の自己診断 (HTTP pivot)まで到達した。一方、ゲートが観測できない領域(GUI/ランタイム)では “green の嘘” を生む。今回の移行が完成したのは、ループの生産力に加えて、オペレータがゲートを実 DoD に 近づけ続け、ゲートの外を人手で検証したから。
single-agent-loop は「自律実装エンジン」ではなく「強力だがゲート依存の増幅器」。 ゲート設計こそが人間の主戦場、というのが本実験の結論。