Claude Code を 10 並列で動かして、PR が 7 本同時に上がった日 — Windows スクショツール開発記 #1
先に結論
検索でたどり着いた方向けに、要点だけ。
- 個人で作っている Windows 向けのスクショツールの開発で、Claude Code を「同時に 10 個」並列で動かした話
- その結果、1 セッションで PR が 7 本同時に上がった ので、ぶつからない順にマージする組み立てが必要だった
- モデルは Opus と Sonnet を、タスクの「噛み合わせの難しさ」で振り分けた
- 同じブランチ名で 2 つ目を作ろうとすると怒られるので、リトライ時は名前を少し変える
- 途中で止まったエージェントの作業内容は残るので、翌日続きから救えるケースが多い
連載の他記事
- #1 Claude Code を 10 並列で動かして、PR が 7 本同時に上がった日(この記事)
- #2 バーが消える / 隣のモニタにはみ出す / 撮影中に画面が固まる
- #3 「撮ったのに見えない」を構造で防ぐ — アーキテクチャの話
- #4 40MB を諦めた話と、リリース準備の取捨選択
何を作っているか
個人で作っているのは、Windows 向けの軽量スクショツールです。リリース前なのでツール名はまだ伏せておきますが、雰囲気としては、
- 画面の端に小さなバーが出てきて、ボタンで領域・ウィンドウ・スクロール撮影ができる
- 撮ったあとは右下にサムネが出て、その場で編集や保存・コピーができる
- 過去のスクショはローカルのワークスペースで一覧できる
- 外部に通信しない / キー入力を覗き見しない、というセキュア寄りの方針
というあたりを揃えていく予定です。
技術スタックは C# / WPF / .NET 9 で、配布は単一の実行ファイル(.NET ランタイム同梱の self-contained 構成)を想定しています。普段は WSL2 でコードを書いて、動作確認は Windows 側でやる、という二重環境です。
リポジトリは Private のまま で進めるつもりなので、この連載はソースコードよりも、開発の流れと判断の話を中心に書いていきます。
なぜ並列で動かすか
GitHub の Issue が 50 件以上たまっていて、シリアルに 1 件ずつ片付けていくと、それなりに時間がかかります。Claude Code は 1 セッションでも複数のタスクをこなせるのですが、ひとつの会話のなかで色々なファイルを触ろうとすると、思考の混線も起きやすくなります。
そこで、1 タスク = 1 ブランチ = 1 作業ディレクトリ、と分けて同時に走らせる構成を試すことにしました。git の worktree という仕組みを使うと、1 つのリポジトリに対して複数の作業ディレクトリを並べられるので、これをエージェントごとに割り当てるイメージですね。
10 個のタスクをまとめて投げた
ある日のセッションでは、10 件の Issue をエージェントに 1 件ずつ割り当てて同時にディスパッチしました。
モデルの振り分けは Opus を 5 件、Sonnet を 5 件にしました。Opus が重めのタスク向け、Sonnet が軽めのタスク向け、というのがざっくりした使い分けの目安ですね。判断基準は 「タスクの読みづらさ・噛み合わせの難しさ」 です。たとえば、
- マルチモニタ環境で表示位置がズレる問題
- バーの表示と非表示のタイミングが噛み合わないバグ
- 撮影中に他の処理が固まる問題
このあたりは、原因が一見ではわかりにくいので、Opus に任せておくほうが安心でした。
逆に「ある画面に設定項目を 1 つ足す」「ある経路を削除する」みたいな、やることがはっきりしているものは Sonnet で十分回ってくれます。
実装の規模ではなく 「読みづらさ」で振り分けてみると、自分の中では振り分けに迷う場面が少なかった気がしています。
PR が 7 本同時に上がった日
並列で動かした結果、その日のうちに 7 本の PR が同時に上がりました。
これを取り込んでいくのですが、PR 番号順にマージしようとすると衝突が発生します。同じファイルを触っている PR が複数あって、後から来たものが「もう変わってますよ」とぶつかる、というやつですね。
なので、マージする順番を先に設計しました。考え方としては、
- ほかの PR と無関係な単独のものから先に
- 同じファイル群を触っているグループは、後ろの作業に影響しにくいものから先に
という並べ方。これで衝突を抑えながら、順々に main に取り込めました。
「並列で動かせばラク」という単純な話ではなくて、並列で動かしたあとの取り込みのほうに頭を使うことになった、というのが今回の自分なりの手応えでした。
同じブランチ名は同時に使えない
並列で走らせていると、リトライや再投入のときに、つい同じブランチ名で 2 回目を作ろうとしてしまうことがあります。これをすると「そのブランチはもう別のところで使われてますよ」と怒られます。
対処はシンプルで、リトライ時は名前を少し変えます。たとえば最初が feature-x なら、リトライは feature-x-v2 にする、というだけで衝突は避けられました。エラーとしては is already checked out at ... のようなメッセージが出るので、見覚えがあれば「あ、worktree が残ってるな」と気づきやすいです。
AI エージェントを並列で動かすときの細かい運用ノウハウとして、ここはテンプレに入れておくとあとで楽です。
エージェントが「自分の居場所」を見失う
10 個並列で走らせていると、なかには途中で止まってしまうエージェントもいました。
調べると、自分が今どのフォルダで作業しているかをきちんと把握できていなくて、相対的にファイルを操作しようとした結果、別のエージェントの作業フォルダを触りそうになって、安全側で止まる、という流れだったようです。
並列で動かすときは、最初の指示で 「あなたの作業フォルダは絶対パスでここです」とハッキリ伝えるのが大事そうでした。エージェントへのプロンプトの先頭に「カレントディレクトリは <絶対パス> です」と書いておくだけで、似たトラブルがぐっと減るので、毎回テンプレ化しておくと安心です。
力尽きたエージェントの作業内容は救える
長時間 10 個を並列で動かしていると、セッションの容量にぶつかって、まだ仕事が終わっていないエージェントが止まることがあります。あるセッションでは、4 つのエージェントが「あと一歩でコミット」のところで止まりました。
ここで「全部やり直し」になると気持ちが折れますが、幸いそうではありませんでした。
各エージェントの作業フォルダの中身はそのまま残っているので、翌日そこに入って状態を確認すれば、続きから再開できます。具体的には .claude/worktrees/agent-<id>/ の下にそれぞれの作業状態が残っている、という感じです。テストは通っているけど、まだコミットだけしていない、というケースが多くて、ふつうにコミットして PR にする、というだけの作業で済みました。
振り返り
10 個並列で動かしてみての所感はこんなあたりです。
- 並列で動かすこと自体は、自分が想像していたほど大変ではなかった。ただし、取り込み側のほうに時間を使った
- モデルの振り分けは「タスクの読みづらさ」で判断してみたら、自分にとっては感覚が掴みやすかった
- ブランチ名の重複や、エージェントの作業フォルダ認識、はテンプレで対処したい
- セッションが落ちても、作業の中身は救えるケースが多い
その日のうちに、最終的に複数の PR が main に取り込まれて、テストもすべて通る状態に揃いました。1 人で 1 日やる量としては、ふだんとはだいぶ違う密度になっていた気がします。
次の #2 では、この日に上がった機能のなかから、振り返りが面白かったものをいくつか取り上げます。バーの表示と非表示が噛み合わないバグ、マルチモニタではみ出す表示問題、撮影中に画面が固まる問題、あたりを書く予定です。