Skip to content

Subagents

Subagents give agents the ability to spawn, delegate to, and merge results from child agents — each with its own model, capability set, and memory isolation scope. This is multi-agent orchestration without a proprietary message bus: the subagent protocol is standardized, so any A2E-compatible host can run it.

Overview

The subagents capability provides multi-agent orchestration — spawning, delegating tasks to, communicating with, and merging results from child agents. Subagents run as independent agent instances with their own model, system prompt, capabilities, and execution scope.

Key concepts:

  • Spawn — Create a new subagent with a specific configuration
  • Delegate — Assign a task to a spawned subagent
  • Await — Block until a subagent completes its task
  • Message — Send inter-agent messages between subagents
  • Merge — Combine results from multiple subagents
  • Cancel/Terminate — Stop a running subagent gracefully or forcefully

Isolation Model

Each subagent operates within a configurable isolation boundary:

Memory Scope

ScopeDescriptionUse Case
sharedSubagent shares parent's memoryCollaborative tasks needing shared context
isolatedSubagent has its own memory namespaceIndependent tasks with no cross-contamination
snapshotSubagent gets a copy of parent's memory at spawn timeTasks that need initial context but produce independent results

Tool Scope

ScopeDescriptionUse Case
sharedFull access to parent's toolsTrusted subagents that need all capabilities
restrictedLimited tool access (host policy)Default — safe for most tasks
isolatedCompletely separate tool namespaceSandboxed execution with custom tool sets

Protocol Messages (12 types)

Type StringModelDirection
SUBAGENT_SPAWN_REQSubagentSpawnRequestParent → Host
SUBAGENT_SPAWN_RESPSubagentSpawnResponseHost → Parent
SUBAGENT_DELEGATE_REQSubagentDelegateRequestParent → Host
SUBAGENT_DELEGATE_RESPSubagentDelegateResponseHost → Parent
SUBAGENT_AWAIT_REQSubagentAwaitRequestParent → Host
SUBAGENT_AWAIT_RESPSubagentAwaitResponseHost → Parent
SUBAGENT_MESSAGE_REQSubagentMessageRequestAgent → Host
SUBAGENT_MESSAGE_RESPSubagentMessageResponseHost → Sender
SUBAGENT_LIST_REQSubagentListRequestAgent → Host
SUBAGENT_LIST_RESPSubagentListResponseHost → Agent
SUBAGENT_CANCEL_REQSubagentCancelRequestAgent → Host
SUBAGENT_TERMINATE_REQSubagentTerminateRequestAgent → Host
SUBAGENT_MERGE_REQSubagentMergeRequestAgent → Host
SUBAGENT_MERGE_RESPSubagentMergeResponseHost → Agent
SUBAGENT_EVENTSubagentEventHost → Agent (streaming)

SubagentConfig

FieldTypeRequiredDefaultDescription
namestrYesSubagent name
rolestrNoNoneRole descriptor
modelstrYesLLM model identifier
system_promptstrNoNoneCustom system prompt
capabilitieslist[str]No[]Enabled capabilities
memory_scopeMemoryScopeNosharedMemory isolation level
tool_scopeToolScopeNorestrictedTool access level
max_stepsintNo40Maximum agent steps
timeout_secondsintNo600Execution timeout
metadatadictNo{}Additional metadata

TaskDefinition

FieldTypeRequiredDefaultDescription
namestrYesTask name
instructionstrYesTask instruction for the subagent
success_criterialist[str]No[]Criteria for task completion
metadatadictNo{}Additional task metadata

SubagentInfo

FieldTypeDescription
subagent_idstrSubagent identifier
namestrDisplay name
statusSubagentStatusCurrent status
parent_agent_idstr or NoneParent agent
root_agent_idstr or NoneRoot agent
depthintNesting depth
configSubagentConfigFull configuration

SubagentStatus

ValueDescription
READYSpawned but not yet executing a task
RUNNINGActively executing a delegated task
WAITINGWaiting for input or another subagent
COMPLETEDTask finished successfully
FAILEDTask finished with error
CANCELLEDTask was gracefully cancelled
TERMINATEDTask was forcefully terminated

Merge Strategies

StrategyDescription
hierarchical_summaryParent summarizes child results
votingMajority vote across results
customHost-defined merge strategy

SubagentPlugin

python
from a2e.caps.subagents.plugin import SubagentPlugin, SubagentRuntime

class SubagentPlugin:
    def __init__(self):
        self.subagents: Dict[str, SubagentRuntime] = {}

    async def spawn(self, request: SubagentSpawnRequest) -> SubagentSpawnResponse: ...
    async def delegate(self, request: SubagentDelegateRequest) -> SubagentDelegateResponse: ...
    async def await_result(self, subagent_id: str) -> SubagentAwaitResponse: ...
    async def list_subagents(self) -> list[SubagentInfo]: ...
    async def terminate(self, subagent_id: str) -> None: ...

SubagentRuntime

Each subagent is managed by a SubagentRuntime instance:

FieldTypeDescription
subagent_idstrUnique identifier
configSubagentConfigConfiguration
parent_agent_idstr or NoneParent reference
root_agent_idstr or NoneRoot reference
depthintNesting depth
statusSubagentStatusCurrent status
resultdict or NoneTask result
task_handleasyncio.Task or NoneRunning task handle

Lifecycle

  1. Spawn: Create runtime, set status = READY
  2. Delegate: Create asyncio.Task for run_task(), set status = RUNNING
  3. Execute: Agent adapter runs the task
  4. Complete: Set status = COMPLETED, store result
  5. Fail: Set status = FAILED, store error
  6. Cancel: Cancel asyncio.Task, set status = CANCELLED
  7. Terminate: Cancel asyncio.Task, set status = TERMINATED

SubagentClient (Client)

python
from a2e.caps.subagents.client import SubagentClient

subagents = SubagentClient(transport)

# Spawn a new subagent
spawn_resp = await subagents.spawn(
    name="researcher",
    model="claude-3.5-sonnet",
    role="research",
    system_prompt="You are a research assistant",
    capabilities=["tools", "memory"],
)

# Delegate a task
delegate_resp = await subagents.delegate(
    subagent_id=spawn_resp.subagent_id,
    task_name="research_topic",
    instruction="Research the latest developments in quantum computing",
    success_criteria=["Include at least 3 recent papers"],
)

# Await the result
result = await subagents.await_result(spawn_resp.subagent_id)
print(result.status)   # "COMPLETED"
print(result.result)   # {"summary": "...", "papers": [...]}

# Convenience: spawn + delegate + await in one call
result = await subagents.run(
    name="coder",
    model="gpt-4",
    task_name="implement_feature",
    instruction="Implement the login API endpoint",
)

Convenience Method

MethodDescription
run(name, model, task_name, instruction)Spawn + delegate + await in one call

Security Considerations

  1. Depth limiting: Host must enforce maximum nesting depth to prevent recursive spawning
  2. Memory isolation: isolated and snapshot scopes prevent cross-agent data leakage
  3. Tool restriction: restricted and isolated scopes limit dangerous tool access
  4. Timeout enforcement: timeout_seconds prevents runaway subagents
  5. Step limiting: max_steps prevents infinite agent loops
  6. Cancellation propagation: Cancel requests must propagate to all child subagents
  7. Resource quotas: Host should enforce per-session subagent count limits

See Security & Trust for the full security model.

Relationship to Other Capabilities

  • memory: memory_scope controls whether subagents share, isolate, or snapshot parent memory
  • tools: tool_scope controls tool access; restricted subagents see a filtered tool list
  • chains: Chains orchestrate tools/data within one agent; subagents orchestrate across multiple agents
  • mcp: Subagents with shared tool scope can access MCP-bridged tools

For a complete walkthrough of building a subagent orchestration plugin and client, see Subagent Orchestrator (Plugin & Client).

A2E Protocol v1.0 — Released under the MIT License.