サブエージェント

サブエージェントは既存のエージェント実行からスポーンされるバックグラウンドエージェント実行です。独自のセッション(agent:<agentId>:subagent:<uuid>)で動作し、完了すると結果をリクエスターのチャットチャンネルにアナウンスします。

スラッシュコマンド

/subagents現在のセッションのサブエージェント実行を検査・制御できます:

  • /subagents list
  • /subagents kill <id|#|all>
  • /subagents log <id|#> [limit] [tools]
  • /subagents info <id|#>
  • /subagents send <id|#> <message>
  • /subagents steer <id|#> <message>
  • /subagents spawn <agentId> <task> [--model <model>] [--thinking <level>]

スレッドバインディング制御:

これらのコマンドは永続的なスレッドバインディングに対応するチャンネルで動作します。後述のスレッド対応チャンネルを参照。

  • /focus <subagent-label|session-key|session-id|session-label>
  • /unfocus
  • /agents
  • /session idle <duration|off>
  • /session max-age <duration|off>

/subagents infoは実行メタデータ(ステータス、タイムスタンプ、セッションID、トランスクリプトパス、クリーンアップ)を表示します。

スポーンの動作

/subagents spawnはユーザーコマンドとしてバックグラウンドサブエージェントを開始し(内部リレーではない)、実行完了時にリクエスターチャットに1つの最終完了アップデートを送信します。

  • スポーンコマンドはノンブロッキングで、即座にrun IDを返します。
  • 完了すると、サブエージェントはリクエスターチャットチャンネルにサマリー/結果メッセージをアナウンスします。
  • 手動スポーンの場合、配信は耐障害性を持ちます:
    • OpenClawはまず安定した冪等性キー付きで直接agent配信を試行。
    • 直接配信が失敗した場合、キュールーティングにフォールバック。
    • キュールーティングも利用できない場合、短い指数バックオフでリトライし最終的に断念。
  • リクエスターセッションへの完了ハンドオフはランタイム生成の内部コンテキスト(ユーザー作成テキストではない)で、以下を含みます:
    • Resultassistant返信テキスト、またはアシスタント返信が空の場合は最新のtoolResult
    • Statuscompleted successfully / failed / timed out / unknown
    • コンパクトなランタイム/トークン統計
    • リクエスターエージェントに通常のアシスタントの声で書き直すよう指示する配信指示(内部メタデータをそのまま転送しない)
  • --model--thinkingはその特定の実行のデフォルトをオーバーライドします。
  • 完了後の詳細と出力の確認にはinfo/logを使用。
  • /subagents spawnはワンショットモード(mode: "run")です。永続的なスレッドバウンドセッションにはsessions_spawnthread: truemode: "session"を使用してください。
  • ACPハーネスセッション(Codex、Claude Code、Gemini CLI)にはsessions_spawnruntime: "acp"を使用。ACPエージェントを参照。

主な目的:

  • 「リサーチ/長時間タスク/遅いツール」の作業をメイン実行をブロックせずに並列化。
  • サブエージェントをデフォルトで分離(セッション分離+オプションのサンドボックス化)。
  • ツールサーフェスを誤用しにくく: サブエージェントにはデフォルトでセッションツールを付与しない
  • オーケストレーターパターンのための設定可能なネスト深度をサポート。

コストに関する注意: 各サブエージェントは独自のコンテキストとトークン使用量を持ちます。負荷の高いまたは反復的なタスクでは、サブエージェントに安価なモデルを設定し、メインエージェントに高品質モデルを維持してください。 agents.defaults.subagents.modelまたはエージェント単位のオーバーライドで設定可能です。

ツール

sessions_spawnを使用:

  • サブエージェント実行を開始(deliver: false、グローバルレーン: subagent
  • その後アナウンスステップを実行し、リクエスターチャットチャンネルにアナウンスリプライを投稿
  • デフォルトモデル: agents.defaults.subagents.model(またはエージェント単位のagents.list[].subagents.model)が設定されていない限り呼び出し元を継承。明示的なsessions_spawn.modelが優先。
  • デフォルト思考レベル: agents.defaults.subagents.thinking(またはエージェント単位のagents.list[].subagents.thinking)が設定されていない限り呼び出し元を継承。明示的なsessions_spawn.thinkingが優先。
  • デフォルト実行タイムアウト: sessions_spawn.runTimeoutSecondsが省略された場合、agents.defaults.subagents.runTimeoutSecondsが設定されていればそれを使用。未設定の場合はデフォルト0(タイムアウトなし)。

ツールパラメータ:

  • task(必須)
  • label?(オプション)
  • agentId?(オプション、許可されている場合に別のエージェントIDでスポーン)
  • model?(オプション、サブエージェントモデルをオーバーライド。無効な値はスキップされ、サブエージェントはデフォルトモデルで実行、ツール結果に警告付き)
  • thinking?(オプション、サブエージェント実行の思考レベルをオーバーライド)
  • runTimeoutSeconds?(設定されている場合はagents.defaults.subagents.runTimeoutSecondsがデフォルト、未設定なら0。設定するとN秒後にサブエージェント実行を中止)
  • thread?(デフォルトfalsetrueでこのサブエージェントセッションのチャンネルスレッドバインディングをリクエスト)
  • mode?run|session
    • デフォルトはrun
    • thread: truemode省略の場合、デフォルトはsession
    • mode: "session"にはthread: trueが必要
  • cleanup?delete|keep、デフォルトkeep
  • sandbox?inherit|require、デフォルトinheritrequireはターゲットの子ランタイムがサンドボックス化されていない場合にスポーンを拒否)
  • sessions_spawnはチャンネル配信パラメータ(targetchanneltothreadIdreplyTotransport)を受け付けません。配信にはスポーンされた実行からmessage/sessions_sendを使用。

スレッドバウンドセッション

チャンネルのスレッドバインディングが有効な場合、サブエージェントをスレッドにバインドして、そのスレッド内の後続のユーザーメッセージが同じサブエージェントセッションにルーティングされるようにできます。

スレッド対応チャンネル

  • Discord(現在唯一の対応チャンネル): 永続的なスレッドバウンドサブエージェントセッション(sessions_spawnthread: true)、手動スレッド制御(/focus/unfocus/agents/session idle/session max-age)、アダプターキーchannels.discord.threadBindings.enabledchannels.discord.threadBindings.idleHourschannels.discord.threadBindings.maxAgeHourschannels.discord.threadBindings.spawnSubagentSessionsに対応。

クイックフロー:

  1. sessions_spawnthread: true(およびオプションでmode: "session")を使用してスポーン。
  2. OpenClawがアクティブチャンネルでスレッドを作成またはバインドし、そのセッションターゲットに紐付け。
  3. そのスレッド内のリプライとフォローアップメッセージはバインドされたセッションにルーティング。
  4. /session idleで非アクティブ自動アンフォーカスの確認/更新、/session max-ageでハード上限を制御。
  5. /unfocusで手動でデタッチ。

手動制御:

  • /focus <target>で現在のスレッド(または新規作成したスレッド)をサブエージェント/セッションターゲットにバインド。
  • /unfocusで現在のバインドされたスレッドのバインディングを解除。
  • /agentsでアクティブな実行とバインディング状態(thread:<id>またはunbound)を一覧表示。
  • /session idle/session max-ageはフォーカスされたバインドスレッドでのみ動作。

設定スイッチ:

  • グローバルデフォルト: session.threadBindings.enabledsession.threadBindings.idleHourssession.threadBindings.maxAgeHours
  • チャンネルオーバーライドとスポーン自動バインドキーはアダプター固有。上記のスレッド対応チャンネルを参照。

設定リファレンススラッシュコマンドで現在のアダプター詳細を確認してください。

許可リスト:

  • agents.list[].subagents.allowAgents: agentIdでターゲットにできるエージェントIDのリスト(["*"]で任意を許可)。デフォルト: リクエスターエージェントのみ。
  • サンドボックス継承ガード: リクエスターセッションがサンドボックス化されている場合、sessions_spawnはサンドボックス化されずに実行されるターゲットを拒否。

ディスカバリー:

  • agents_listsessions_spawnに現在許可されているエージェントIDを確認。

自動アーカイブ:

  • サブエージェントセッションはagents.defaults.subagents.archiveAfterMinutes(デフォルト: 60)経過後に自動アーカイブ。
  • アーカイブはsessions.deleteを使用し、トランスクリプトを*.deleted.<timestamp>にリネーム(同じフォルダ)。
  • cleanup: "delete"はアナウンス後に即座にアーカイブ(リネームによりトランスクリプトは保持)。
  • 自動アーカイブはベストエフォート。保留中のタイマーはGateway再起動で失われます。
  • runTimeoutSecondsは自動アーカイブを行いません。実行を停止するのみ。セッションは自動アーカイブまで残ります。
  • 自動アーカイブは深度1と深度2のセッションに等しく適用されます。

ネストされたサブエージェント

デフォルトでは、サブエージェントは独自のサブエージェントをスポーンできません(maxSpawnDepth: 1)。maxSpawnDepth: 2に設定すると1レベルのネストが有効になり、オーケストレーターパターンが可能になります: メイン → オーケストレーターサブエージェント → ワーカーサブサブエージェント。

有効化方法

{
  agents: {
    defaults: {
      subagents: {
        maxSpawnDepth: 2, // サブエージェントに子のスポーンを許可(デフォルト: 1)
        maxChildrenPerAgent: 5, // エージェントセッションごとの最大アクティブ子数(デフォルト: 5)
        maxConcurrent: 8, // グローバル同時実行レーンの上限(デフォルト: 8)
        runTimeoutSeconds: 900, // sessions_spawn省略時のデフォルトタイムアウト(0 = タイムアウトなし)
      },
    },
  },
}

深度レベル

深度セッションキーの形式役割スポーン可能?
0agent:<id>:mainメインエージェント常に可能
1agent:<id>:subagent:<uuid>サブエージェント(深度2許可時はオーケストレーター)maxSpawnDepth >= 2の場合のみ
2agent:<id>:subagent:<uuid>:subagent:<uuid>サブサブエージェント(リーフワーカー)不可

アナウンスチェーン

結果はチェーンを遡って伝播:

  1. 深度2のワーカーが完了 → 親(深度1のオーケストレーター)にアナウンス
  2. 深度1のオーケストレーターがアナウンスを受信、結果を統合、完了 → メインにアナウンス
  3. メインエージェントがアナウンスを受信してユーザーに配信

各レベルは直接の子からのアナウンスのみ参照します。

深度別のツールポリシー

  • 役割と制御スコープはスポーン時にセッションメタデータに書き込まれます。これにより、フラットまたは復元されたセッションキーが偶発的にオーケストレーター権限を再取得することを防ぎます。
  • 深度1(オーケストレーター、maxSpawnDepth >= 2の場合): 子を管理するためにsessions_spawnsubagentssessions_listsessions_historyを取得。他のセッション/システムツールは拒否のまま。
  • 深度1(リーフ、maxSpawnDepth == 1の場合): セッションツールなし(現在のデフォルト動作)。
  • 深度2(リーフワーカー): セッションツールなし — sessions_spawnは深度2では常に拒否。さらなる子のスポーンは不可。

エージェント単位のスポーン制限

各エージェントセッション(あらゆる深度)は最大maxChildrenPerAgent(デフォルト: 5)のアクティブな子を持てます。これにより単一のオーケストレーターからの暴走的なファンアウトを防ぎます。

カスケード停止

深度1のオーケストレーターを停止すると、そのすべての深度2の子が自動的に停止:

  • メインチャットでの/stopはすべての深度1エージェントを停止し、その深度2の子にカスケード。
  • /subagents kill <id>は特定のサブエージェントを停止し、その子にカスケード。
  • /subagents kill allはリクエスターのすべてのサブエージェントを停止しカスケード。

認証

サブエージェントの認証はセッションタイプではなくエージェントIDで解決:

  • サブエージェントのセッションキーはagent:<agentId>:subagent:<uuid>
  • 認証ストアはそのエージェントのagentDirからロード。
  • メインエージェントの認証プロファイルはフォールバックとしてマージ。エージェントプロファイルが競合時にメインプロファイルをオーバーライド。

注: マージは加算的なので、メインプロファイルは常にフォールバックとして利用可能。エージェントごとの完全に分離された認証はまだサポートされていません。

アナウンス

サブエージェントはアナウンスステップで結果を報告:

  • アナウンスステップはサブエージェントセッション内で実行(リクエスターセッションではない)。
  • サブエージェントがANNOUNCE_SKIPと正確に返信した場合、何も投稿されません。
  • それ以外の場合、配信はリクエスターの深度に依存:
    • トップレベルのリクエスターセッションは外部配信付きのフォローアップagent呼び出し(deliver=true)を使用
    • ネストされたリクエスターサブエージェントセッションは内部フォローアップインジェクション(deliver=false)を受け、オーケストレーターがセッション内で子の結果を統合可能
    • ネストされたリクエスターサブエージェントセッションが存在しない場合、OpenClawは利用可能ならそのセッションのリクエスターにフォールバック
  • ネストされた完了のファインディング構築時の子の完了集約は現在のリクエスター実行にスコープされ、古い以前の実行の子出力が現在のアナウンスに漏洩することを防ぎます。
  • アナウンスリプライはチャンネルアダプターで利用可能な場合、スレッド/トピックルーティングを維持します。
  • アナウンスコンテキストは安定した内部イベントブロックに正規化:
    • ソース(subagentまたはcron
    • 子セッションキー/ID
    • アナウンスタイプ+タスクラベル
    • ランタイム結果から導出されるステータス行(successerrortimeout、またはunknown
    • アナウンスステップからの結果コンテンツ(存在しない場合は(no output)
    • 返信すべきか沈黙すべきかを示すフォローアップ指示
  • Statusはモデル出力から推論されるのではなく、ランタイム結果シグナルから取得されます。

アナウンスペイロードには(ラップされている場合でも)末尾に統計行が含まれます:

  • ランタイム(例: runtime 5m12s
  • トークン使用量(input/output/total)
  • モデル価格が設定されている場合の推定コスト(models.providers.*.models[].cost
  • sessionKeysessionId、トランスクリプトパス(メインエージェントがsessions_historyで履歴を取得するか、ディスク上のファイルを検査するため)
  • 内部メタデータはオーケストレーション用。ユーザー向けリプライは通常のアシスタントの声で書き直すべきです。

ツールポリシー(サブエージェントツール)

デフォルトでは、サブエージェントはセッションツールとシステムツールを除くすべてのツールを取得:

  • sessions_list
  • sessions_history
  • sessions_send
  • sessions_spawn

maxSpawnDepth >= 2の場合、深度1のオーケストレーターサブエージェントは子を管理するためにsessions_spawnsubagentssessions_listsessions_historyを追加で取得します。

設定でオーバーライド:

{
  agents: {
    defaults: {
      subagents: {
        maxConcurrent: 1,
      },
    },
  },
  tools: {
    subagents: {
      tools: {
        // denyが優先
        deny: ["gateway", "cron"],
        // allowが設定されている場合、許可リストモードになる(denyは引き続き優先)
        // allow: ["read", "exec", "process"]
      },
    },
  },
}

同時実行

サブエージェントは専用のインプロセスキューレーンを使用:

  • レーン名: subagent
  • 同時実行数: agents.defaults.subagents.maxConcurrent(デフォルト8

停止

  • リクエスターチャットで/stopを送信すると、リクエスターセッションを中止し、そこからスポーンされたアクティブなサブエージェント実行を停止。ネストされた子にもカスケード。
  • /subagents kill <id>は特定のサブエージェントを停止し、その子にカスケード。

制限事項

  • サブエージェントのアナウンスはベストエフォート。Gatewayが再起動すると、保留中の「アナウンスバック」作業は失われます。
  • サブエージェントは同じGatewayプロセスリソースを共有。maxConcurrentをセーフティバルブとして扱ってください。
  • sessions_spawnは常にノンブロッキング: 即座に{ status: "accepted", runId, childSessionKey }を返します。
  • サブエージェントのコンテキストにはAGENTS.md + TOOLS.mdのみが注入されます(SOUL.mdIDENTITY.mdUSER.mdHEARTBEAT.mdBOOTSTRAP.mdは含まれません)。
  • 最大ネスト深度は5(maxSpawnDepthの範囲: 1〜5)。ほとんどのユースケースには深度2を推奨。
  • maxChildrenPerAgentはセッションごとのアクティブな子を制限(デフォルト: 5、範囲: 1〜20)。