Post

Conversation

Anthropicが「Claude Codeを16体チームで並列に走らせて、人間がほぼ介入せずにCコンパイラを作らせた」という記事を公開した。 結果も面白いけど、それよりも中身が「Claude Codeを自律的に長時間動かすための実践Tipsの塊」になっていて、普段のClaude Code運用にそのまま転用できる知見が大量にあるので、整理してみた。 ━━━━━━━━━━━━━━━━━━━━ 【前提:何を作ったのか】 Opus 4.6を使い、Rust製のCコンパイラをゼロから構築。約2,000セッション、API費用2万ドル(約300万円)、2週間で完成。 このプロジェクトはClaude 4シリーズ全体を通じたベンチマークとして設計されている。以前のOpus 4モデルではまともなコンパイラすら作れず、Opus 4.5で初めて機能するコンパイラが可能になり、Opus 4.6で大規模プロジェクトのコンパイルまで到達した。 成果物のスペック: ・10万行のRustコード ・Linux 6.9をx86, ARM, RISC-Vでブート可能 ・QEMU, FFmpeg, SQLite, PostgreSQL, Redis もコンパイルできる ・GCC torture test 99%パス ・DOOMもビルド&実行できた クリーンルーム実装で、Claudeはインターネットアクセスなし。Rust標準ライブラリのみ使用。 ━━━━━━━━━━━━━━━━━━━━ 【仕組み①:Claude Codeを「止まらないエージェント」にするハーネス】 通常のClaude Codeは、人間と一緒に作業する前提で設計されている。長く複雑な問題を渡しても、途中で止まって「質問していいですか?」「次はどうしますか?」と人間の入力を待つ。これだと寝ている間に作業を進めてもらう、ということができない。 Carlini氏はこれを解決するために、コンテナ内でClaude Codeを無限ループで回すハーネスを作った(Ralph-loopと呼ばれる手法の応用): #!/bin/bash while true; do COMMIT=$(git rev-parse --short=6 HEAD) LOGFILE="agent_logs/agent_${COMMIT}.log" claude --dangerously-skip-permissions \ -p "$(cat AGENT_PROMPT.md)" \ --model claude-opus-X-Y &> "$LOGFILE" done やっていることはシンプルで: ① claude コマンドが起動し、AGENT_PROMPT.mdの指示に従って作業する ② 作業が完了(またはセッション上限に到達)するとclaudeプロセスが終了する ③ while trueなので即座に次のclaudeが起動する ④ 新しいセッションはgit logやREADME、progressファイルから現状を把握し、次のタスクに取りかかる ⑤ これが永遠に繰り返される --dangerously-skip-permissions で権限確認を全スキップしているので、人間への問い合わせで止まることがない(※だからこそ必ずコンテナ内で実行する)。ログは agent_logs/ に保存されるので、あとから全セッションの行動を追跡できる。 肝心のAGENT_PROMPT.mdには「問題を小さく分解して、進捗を追跡して、次に取り組むべきものを自分で判断して、完璧になるまで続けろ」と書く。Claudeに選択肢がないのがポイントで、ループは永遠に回るからやめることができない。 (ただし一度だけ、Claudeが誤って pkill -9 bash を実行してしまい、自分自身を殺してループごと止めたことがあったらしい。元記事では "on accident" と明記されており、意図的な行動ではなく偶発的な事故。) 💡個人的な考察: 大規模リファクタリングや型移行のような「やること自体は明確だが量が多い」タスクに向いている。AGENT_PROMPT.mdに方針を書き、テストで品質を担保し、コンテナ内で一晩回す。朝起きたらPRが出来上がっている、という運用ができる。ただし、テストがないプロジェクトでこれをやると破壊的な変更を延々コミットし続ける危険があるので、仕組み④のCI連携とセットで使うべき。 ━━━━━━━━━━━━━━━━━━━━ 【仕組み②:16並列エージェントの協調メカニズム】 1体のClaudeでは1つのことしかできない。16体を並列で走らせることで、複数の問題を同時にデバッグできる。 並列化の実装はシンプル: ・bare gitリポジトリを作成 ・各エージェントごとにDockerコンテナを起動 ・各コンテナ内でリポジトリをcloneして作業 ・終わったらpush → 他のエージェントがpullで同期 タスクの重複防止は「テキストファイルロック」: ・エージェントAが current_tasks/parse_if_statement.txt を作成 → ロック取得 ・エージェントBが同じタスクを取ろうとする → gitの同期で弾かれ、別タスクへ ・作業完了 → ロックファイル削除 マージコンフリクトは頻発するが、Claudeは自力で解決できる。 重要なのは、オーケストレーションエージェント(司令塔)を使っていない点。各Claudeが自律的に「次に最も明らかな問題」を拾って動く。行き詰まったときは、失敗したアプローチと残タスクのメモを自分で残す。 💡個人的な考察: 個人開発でも、Claude Codeを2-3セッション並列で走らせるとき、git worktree+テキストファイルのタスク管理で重複を避けられる。Boris Cherny氏も5-15セッション並列運用していたが、あの手法とこのロック機構を組み合わせるとより安定しそう。 ━━━━━━━━━━━━━━━━━━━━ 【仕組み③:Claudeの認知的限界を設計で回避する】 ここが一番実用的。Claudeには言語モデル特有の弱点があり、テストやフィードバックの設計でそれを回避している。 ■ Context window pollution(文脈汚染) テスト出力が何千行も流れるとClaudeが混乱する。 対策: ・テスト結果は数行だけ表示、詳細はログファイルへ出力 ・エラーがあれば ERROR を理由と同一行に出力し、grepで即座に拾えるようにする ・集計統計を事前計算しておく(Claudeに毎回再計算させない) ■ Time blindness(時間感覚の欠如) Claudeは時間がわからないので、放置すると何時間もテストを回し続けて進捗しない。 対策: ・--fast オプションで1%〜10%のランダムサンプルだけ実行 ・サンプルはエージェントごとに決定的だが、VM間ではランダム(=全体ではカバレッジ確保しつつ各エージェントはリグレッション検知可能) ・進捗表示は低頻度に(文脈汚染防止) ■ 自己位置把握の困難 各エージェントは毎回新しいコンテナに投入され、文脈ゼロの状態から始まる。 対策: ・READMEとprogressファイルを頻繁に更新させる指示をプロンプトに含める ・新しいセッションが起動したとき、まずこれを読んで現状把握できるようにする 💡個人的な考察: これは明日から使える。テストの出力設計(grepしやすいフォーマット)、進捗ファイルの更新指示、--fastオプション的な「まず一部だけ確認」の仕組み。どれもClaude Codeを日常使いする人に直接効く。特にcontext window汚染対策は、長めのセッションで品質が落ちてくる原因の1つなので意識するだけで変わる。 ━━━━━━━━━━━━━━━━━━━━ 【仕組み④:CIパイプラインで「壊さない」を担保する】 プロジェクト後半、Claudeが新機能を実装するたびに既存機能を壊す問題が頻発。対策としてCIパイプラインを構築し、新しいコミットが既存テストを壊さないことを自動検証するようにした。 💡個人的な考察: これはBoris Cherny氏が強調していた「Claudeに自分の仕事を検証する手段を与える」と完全に同じ原則(※Boris Cherny氏は元記事には登場しない)。検証手段の質がそのまま成果物の品質に直結する。 Claude Codeに長めの作業を任せるなら、テストスイートの充実度が成果物の品質を決める。テストがないプロジェクトでは、まずClaude自身にテストを書かせてからコード変更に入る、という順序を徹底するだけで品質が上がる。 ━━━━━━━━━━━━━━━━━━━━ 【仕組み⑤:巨大タスクを並列化可能にする工夫】 テストが多数ある段階では並列化は簡単(各エージェントが別のテストを担当するだけ)。 問題は「Linuxカーネルのコンパイル」のような1つの巨大タスク。16体全員が同じバグに突撃して、互いの修正を上書きし合い、並列の意味がなくなった。 解決策:GCCを「正解のオラクル」として使う ・カーネルのほとんどのファイルをGCCでコンパイル、残りだけClaude製コンパイラで処理 ・カーネルが動けば→Claude側のファイルは問題なし ・壊れたら→ファイルを絞り込んで原因特定 ・これで各エージェントが別のファイルのバグを並列で修正できるようになった さらに「単独では動くが組み合わせると壊れる」ペアの検出にはデルタデバッギングも使用。 💡個人的な考察: 大規模プロジェクトのマイグレーションで「全部一気にやると何が壊れたかわからない」問題。既存の動作するコードをオラクルにして、変更箇所を少しずつ入れ替えていく手法はそのまま使える。 ━━━━━━━━━━━━━━━━━━━━ 【仕組み⑥:エージェントの役割分担】 並列化は専門化も可能にする。全員が同じことをやるのではなく、役割を振る: ・メインタスク担当:コンパイラ本体の実装 ・重複コード検出担当:LLMが書くコードは同じ処理を再実装しがち。それを統合する係 ・パフォーマンス改善担当:コンパイラ自体の実行速度を上げる係 ・コード品質担当:Rust開発者の視点で構造改善 ・ドキュメント担当:設計文書の整備 ・出力コード効率担当:コンパイルされたコードの効率を上げる係 💡個人的な考察: 個人開発でも、機能実装のセッションと別に「コード品質レビュー専用セッション」「ドキュメント更新セッション」を分けて走らせるのは有効。1つのセッションに全部やらせると文脈が膨れて品質が落ちるので、役割分離は理にかなっている。 ━━━━━━━━━━━━━━━━━━━━ 【現時点の限界】 完璧ではない。正直に書かれている制限: ・16-bit x86コンパイラは未実装(ここだけGCCに頼る) ・アセンブラとリンカは未完成でバギー ・全プロジェクトがビルドできるわけではない(drop-in replacementではない) ・生成コードは非効率(GCCの最適化OFFよりも遅い) ・Rustコードの品質は及第点だがエキスパートレベルではない ・新機能やバグ修正が頻繁に既存機能を壊す Carlini氏は「Opus 4.6の限界にほぼ到達した」と述べており、修正を何度も試みたが完全には成功しなかったとのこと。 ━━━━━━━━━━━━━━━━━━━━ 【Carlini氏の所感と自分の感想】 Carlini氏(Nicholas Carlini、AnthropicのSafeguardsチーム研究者、元ペンテスター)は「開発者が自分で検証したことのないソフトウェアをデプロイする世界」への懸念を率直に書いている。この実験に興奮しつつも不安を感じている、と。 個人的に思ったのは、この記事の本質は「Cコンパイラを作った」という結果ではなく、「LLMエージェントをチームとして機能させるための設計パターン」が体系的に示されたこと。 context window汚染対策、テスト出力設計、タスクロック、progressファイル運用、役割分担、オラクル比較による並列化。これらは全部、明日からの自分のClaude Code運用に使える。 コンパイラのソースコードも公開されている。Carlini氏は今もClaudeに改善を続けさせているとのことなので、経過も追う価値あり。 ━━━━━━━━━━━━━━━━━━━━ 動画: