Claude Media
Claude Codeのサブエージェント並列設計 — fork既定化で何が変わるか

Claude Codeのサブエージェント並列設計 — fork既定化で何が変わるか

v2.1.232でforkが対話セッションの既定になり、サブエージェントはコンテキストとプロンプトキャッシュを引き継いで並列実行されます。深さ制限・並列数上限との相互作用も扱います。

Claude Code v2.1.232で、対話セッションのsubagent forkが既定onになりました。subagent_type: "fork"のサブエージェントは会話全体とプロンプトキャッシュを引き継ぎ、fork・非forkを問わずClaudeが起動したサブエージェントはバックグラウンドで動きます。並列タスクの組み方は「毎回フレッシュなコンテキストで投げる」から「同じ文脈を安く複製して投げる」へ重心が動いています。

forkと非forkサブエージェントの違い — 何を引き継ぐか

forkは、それまでの会話をまるごと引き継ぐサブエージェントです。システムプロンプト・ツール・モデル・メッセージ履歴のすべてがメインセッションと同一になるため、状況を説明し直さずに横道のタスクを任せられます。fork自身のツール呼び出しはメイン会話には出ず、最終結果だけが返るので、メインのコンテキストウィンドウは汚れません。

一方、非forkのサブエージェントは毎回フレッシュなコンテキストで始まります。会話履歴も、これまでに読んだファイルも、呼び出し済みのSkillも見えません。Claudeは委任メッセージを1つ組み立て、サブエージェントはそこから作業します。

項目fork非forkサブエージェント
コンテキストfork会話全体の履歴非forkサブエージェント委任メッセージのみの新規コンテキスト
システムプロンプト・ツールforkメインセッションと同一非forkサブエージェント定義ファイル由来(バックグラウンド実行時はさらに絞り込み)
モデルforkメインセッションと同一非forkサブエージェント定義ファイルのmodelフィールド
権限確認の出どころforkターミナルにそのまま出る非forkサブエージェントバックグラウンド実行時はメインセッションに出る
プロンプトキャッシュforkメインセッションと共有非forkサブエージェント別キャッシュ

ClaudeはAgentツールでforkというsubagent_typeを指定してforkを起動します。タイプを指定しなければgeneral-purposeサブエージェントが起動します。fork自体は、/subtaskに続けてタスクを書けば自分で開始することもできます(v2.1.161〜v2.1.211では/fork)。

/subtask パーサーの変更に対する単体テストを書いて

forkはプロンプト入力欄の下のパネルに表示され、バックグラウンドで走りながら作業を続けられます。完了すると結果がメイン会話にメッセージとして届きます。

メインの状態のうち、forkだけが引き継ぐもの

非forkのサブエージェントも、実は空っぽのコンテキストから始まるわけではありません。エージェント自身のシステムプロンプトと委任メッセージに加えて、次の4つが初期コンテキストに乗ります。

  • CLAUDE.mdの全階層(~/.claude/CLAUDE.md・プロジェクトルール・CLAUDE.local.md・管理ポリシー)
  • セッション開始時点のGitステータスのスナップショット
  • エージェント定義のskillsフィールドで指定したSkillの全文
  • SendMessageで名指しできる相手一覧(sibling roster)

ビルトインのExploreとPlanだけはCLAUDE.mdとGitステータスを省略します。

一方、メイン会話にあってもforkでなければ届かない状態が3つあります。出力スタイルは非forkサブエージェント自身のシステムプロンプトで動くため反映されません。自動メモリーも読み込まれず、サブエージェント自身に永続メモリーを持たせたい場合はmemoryフィールドを使います。コンテキストウィンドウのサイズもサブエージェント自身のモデルで決まり、親より小さいモデルに委任すればウィンドウも小さくなります。並列に投げたタスクの出力フォーマットや文体がメインと揃わないと感じたら、まずこの3点を疑うのが早道です。forkはメインセッションの状態をそのまま引き継ぐので、この3つも含めて全部揃います。

完了したforkに追いかけて指示を出す — SendMessageと自動再開

サブエージェントの呼び出しは毎回新しいインスタンスを作ります。既存の作業を続けさせたい場合、Claudeは完了したサブエージェントのエージェントIDか名前をtoに指定してSendMessageを送り、これがそのまま再開の合図になります。完了済みのサブエージェントは、新たなAgent呼び出しなしにバックグラウンドで自動的に再開します。ExploreとPlanは1回限りでエージェントIDを返さないため再開できません。

ただし、/tasksxを押すなど自分で止めたサブエージェントはこの自動再開の対象外です。Claudeがメッセージを送っても再開されず、キャンセル済みだと伝えられるだけなので、並列forkを意図的に止めたあとにClaudeが勝手に再開してしまう心配はありません。v2.1.199以降は、同じ名前が別のエージェントに使い回されていないかもSendMessage側でチェックされ、名前の取り違えによる誤送信を防ぎます。

サブエージェントのトランスクリプトはメイン会話とは別ファイルに保存されるため、メイン会話が/compactでコンパクションされてもサブエージェント側は影響を受けません。逆に、サブエージェント自身も同じロジックで自動コンパクションの対象になります。会話全体を引き継ぐforkは長時間動かすほどトークンを消費しやすいため、メインとは独立にコンパクションが走る設計は並列運用の前提として押さえておく価値があります。

既定化で対話セッションのバックグラウンド実行が標準になった

v2.1.232より前は、Claudeが結果をすぐ必要とするかどうかでフォアグラウンド・バックグラウンドを選んでいました。fork既定onの対話セッションでは、この判断そのものが変わります。ClaudeがAgentツールで起動するサブエージェントは、fork・非forkを問わずバックグラウンドで動き、Claude側からフォアグラウンド実行を要求することはできません。Agentツールのrun_in_backgroundパラメーター自体が取り除かれる設計です。

バックグラウンドのサブエージェントは、権限確認が必要なツール呼び出しに達するとメインセッション側にプロンプトが表示され、どのサブエージェントからの要求かが名前で示されます。承認すればサブエージェントは続行し、Escで個別のツール呼び出しだけを拒否できます。セッション全体に及ぶ許可(残りセッション中は許可、等)を答えた場合は、その判断がメイン会話を含むセッション全体に適用されます。

並列実行のコストはどう変わるか — プロンプトキャッシュ共有と深さ制限の相互作用

forkのシステムプロンプトとツール定義は親と完全に同一なので、最初のリクエストが親のプロンプトキャッシュをそのまま再利用します。同じ文脈を必要とするタスクを並列に投げる場合、毎回新規サブエージェントを立てるより安く済むのはこのためです。

ただし制約もあります。forkはさらにforkを起動できません。サブエージェントの入れ子は既定で3階層までです(CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTHで変更可能)。深さ上限に達すると、Agentツールはforkを除く全サブエージェントから取り上げられます。fork自身は上限に達してもAgentツールが定義上は残りますが、実際に呼び出すとエラーが返るだけで起動はしません。つまり深さ上限での挙動は、非forkが最初からツールを持たないのに対し、forkは持っているのに使えないという違いになります。

同時実行数の上限(既定20、CLAUDE_CODE_MAX_CONCURRENT_SUBAGENTSで変更可能)にも非対称があります。ClaudeがAgentツール経由で起動するforkは、この上限にカウントされます。一方、ユーザーが/subtaskで自分から開始したforkはセッション内で実行中の間ずっと枠を使いますが、上限のチェック対象にはなりません。上限に張り付くほど並列タスクを積む設計では、Claude任せのAgent呼び出しと/subtaskの直接起動とで、上限に引っかかるかどうかが変わってきます。

forkをisolation: "worktree"付きで起動すると、そのforkのファイル編集はメインの作業ツリーではなく別のgit worktreeに書き込まれます。同じリポジトリで複数の並列forkに実装を試させる場合、この分離を使わないと編集が競合します。

fork既定を切り替える・特定のforkだけ止める

fork既定onは対話セッションのみが対象です。非対話モード(-p)とAgent SDKでは既定offのままで、CLAUDE_CODE_FORK_SUBAGENT環境変数で個別に上書きできます。

効果
未設定効果対話セッションはon、非対話・Agent SDKはoff(既定)
1効果非対話モード・Agent SDKでもon
0効果すべてのセッションでoff
settings.jsonでの設定例
{
  "env": {
    "CLAUDE_CODE_FORK_SUBAGENT": "1"
  }
}

fork自体は残したまま、Claudeがforkを起動する経路だけを塞ぐこともできます。Agent(fork)ルールで拒否すれば、Claude Codeはforkを除く通常のサブエージェントをバックグラウンドで起動する挙動は維持したまま、fork起動だけを止められます。定義ファイルでcontext: forkを指定したSkillは、この既定on/offとは別のルールに従う点にも注意が必要です。

並列設計はどこを見直すべきか

fork既定化が変えたのは実装の細部ではなく、並列タスクを組むときの既定の選び方です。同じ文脈を必要とする作業は、general-purposeで新規コンテキストを渡すより、forkで会話を複製するほうが既定で安価な選択になりました。

一方で、上限に張り付くほど並列度を稼ぐ設計では話が変わります。Claude任せのAgent呼び出しは同時実行上限の対象ですが、/subtaskで自分から起動したforkは対象外です。並列ワークフローの再現性を上限の影響から切り離したいなら、Claudeに任せきりにせず/subtaskを併用するのが実務上の分かれ目になります。Agent Teamsのteammateはこの並列モデルの外側にあり、fork既定onでもフォアグラウンドで動く独自の扱いを持つ点も、設計を分けるときの判断材料になります。

まとめ

対話セッションでサブエージェントを多用するチームは、fork既定onによってバックグラウンド実行とプロンプトキャッシュ共有が標準の挙動になったことを踏まえて並列設計を見直す価値があります。非対話パイプラインやAgent SDKで同じ挙動を再現したい場合はCLAUDE_CODE_FORK_SUBAGENTを明示的に1にする必要があり、既定のままでは対話セッションと異なる挙動になります。

この記事を共有:XはてブLinkedIn