Feature Specification: Subagent Definitions & Multi-Agent Orchestration¶
Feature Branch: feature/007-claude-agent-features
Spec ID: 029-subagent-orchestration
Created: 2026-03-28
Status: Shipped (PR #309)
Input: Enable users to define full subagent specifications in YAML and wire them into the Claude SDK's agent orchestration system, allowing multi-agent teams to be configured without code.
Dependencies: 027-mcp-http-sse-transport (parent agent may use HTTP/SSE MCP servers; subagents inherit access to those servers via their tools allowlist)
User Scenarios & Testing (mandatory)¶
User Story 1 - Define a Multi-Agent Research Team (Priority: P1)¶
A user wants to create a research agent that delegates to specialized subagents: a Researcher that searches the web, a Data Analyst that processes findings, and a Report Writer that produces the final output. Each subagent has its own system prompt, model, and tool access. The user defines all of this in a single agent YAML file.
Why this priority: Multi-agent orchestration is the highest-value Claude SDK feature not yet exposed in HoloDeck. The demos repo shows this as the flagship pattern (Research Agent demo).
Independent Test: Define an agent.yaml with three subagent definitions under claude.agents, run a test case that requires delegation, and verify the SDK receives all three AgentDefinition objects.
Acceptance Scenarios:
- Given an agent.yaml with
claude.agentscontaining three named subagent definitions (researcher, analyst, writer), When the agent is initialized, Then the SDK options include all three asAgentDefinitionobjects with their respective prompts, models, and tool lists. - Given a subagent definition with
model: haiku, When the agent is initialized, Then the subagent's model override is set to "haiku" in the SDK config. - Given a subagent definition with
tools: [WebSearch, WebFetch], When the agent is initialized, Then only those tools are available to that subagent. - Given a subagent definition with no
toolsfield, When the agent is initialized, Then the subagent inherits all tools from the parent agent.
User Story 2 - Restrict Subagent Tool Access (Priority: P2)¶
A user wants a subagent to only see a subset of the parent agent's tools, including a subset of MCP-provided tools. For example, a "Database Analyst" subagent receives the database MCP server's tools (e.g., mcp__db__query) while a "Researcher" subagent does not — even though both subagents share the same MCP server registration on the parent.
Why this priority: Tool-level isolation is the core security and capability boundary the SDK provides for subagents. The SDK does not support per-subagent MCP server registration — all MCP servers register at the parent level, and isolation is enforced via each subagent's tools allowlist.
Independent Test: Define two subagents whose tools lists name different MCP tool identifiers (mcp__<server>__<tool>); initialize the agent and verify each subagent's AgentDefinition.tools contains only the named entries.
Acceptance Scenarios:
- Given a parent agent with an MCP server registered and a subagent definition whose
toolslist includesmcp__db__query, When the agent is initialized, Then the subagent'sAgentDefinition.toolscontainsmcp__db__queryand the SDK enforces that only those tools are usable from the subagent. - Given two subagents sharing one parent-level MCP server but with different
toolslists, When both are initialized, Then each subagent only has access to the tool names it explicitly enumerates.
User Story 3 - Define Subagent with Custom System Prompt (Priority: P1)¶
A user wants each subagent to have specialized instructions. They provide a prompt field (inline text or file path) for each subagent definition, giving each subagent a distinct personality and expertise area.
Why this priority: System prompts are what make subagents specialized. Without distinct prompts, subagents are just duplicates of the parent.
Independent Test: Define a subagent with prompt: "You are a data analyst. Only analyze data, never write code.", initialize the agent, and verify the SDK definition includes this prompt.
Acceptance Scenarios:
- Given a subagent with
prompt: "You are a financial analyst.", When the agent is initialized, Then the SDKAgentDefinitionincludes this prompt. - Given a subagent with
prompt_file: ./prompts/analyst.md, When the agent is initialized, Then the prompt is loaded from the file and set on the SDK definition. - Given a subagent with neither
promptnorprompt_file, When the config is loaded, Then the subagent uses no custom prompt (inherits parent behavior).
Edge Cases¶
- What happens when a subagent definition references a model not available to the user's API key? The SDK surfaces the error at runtime; HoloDeck should propagate it clearly.
- What happens when a subagent's tool list references tools not defined in the parent's tool configuration? Validation warning at config load time -- the tools may be built-in SDK tools (Read, Write, etc.), MCP-provided tools (
mcp__<server>__<tool>), or the user may have made a mistake. - What happens when subagent definitions are empty (no agents listed)? Treated the same as not having the
agentssection at all. - What happens when a subagent's
prompt_filepath doesn't exist? A validation error is raised at config load time. - What happens when neither
promptnorprompt_fileis provided? A validation error is raised at config load time -- the SDK requires a non-empty prompt on everyAgentDefinition. - What happens when a subagent's
modelvalue is outside{sonnet, opus, haiku, inherit}? A validation error is raised at config load time -- the SDK'sAgentDefinition.modelonly accepts those four literal values.
Requirements (mandatory)¶
Functional Requirements¶
- FR-001: System MUST accept an
agentssection underclaudein agent YAML containing named subagent definitions. - FR-002: Each subagent definition MUST support:
description(string, required),prompt(inline string, required-if-no-prompt_file),prompt_file(file path, required-if-no-prompt),tools(list of tool names, optional), andmodel(string, optional, restricted tosonnet | opus | haiku | inherit). - FR-003: System MUST translate each subagent definition into the Claude SDK's
AgentDefinitiondataclass with exactly its four supported fields:description,prompt,tools,model. - FR-004: System MUST validate that each subagent has a
descriptionfield (required by the SDK for routing decisions). - FR-005: System MUST resolve
prompt_filepaths relative to the agent YAML directory and load file contents as the prompt. - FR-006: System MUST validate that
promptandprompt_fileare not both specified on the same subagent (mutually exclusive) and that at least one of them is set (the SDK requires a non-empty prompt on everyAgentDefinition). - FR-007: When
toolsis omitted from a subagent, the subagent MUST inherit all tools from the parent agent (achieved by passingtools=Noneto the SDK). - FR-008: System MUST validate
modelagainst the SDK-allowed set{sonnet, opus, haiku, inherit}and surface a clear error for any other value. - FR-009: System MUST allow subagent
toolslists to reference parent-registered MCP tools by their fully qualified names (mcp__<server>__<tool>), so subagents share the parent's MCP server registrations but only see the tools enumerated in theirtoolslist. Per-subagent MCP server registration is not supported by the SDK and MUST NOT be modeled in YAML. - FR-010: System MUST treat the presence of one or more entries in
claude.agentsas the only gate for forwarding subagent definitions to the SDK. There is no separatesubagents.enabledflag; HoloDeck does not throttle SDK-internal subagent dispatch (the SDK manages that itself), and HoloDeck-side test concurrency continues to be controlled exclusively by the existing top-levelexecution.parallel_test_cases. - FR-011: System MUST remove the existing
claude.subagentsconfig block (enabled,max_parallel) entirely. The block has no remaining semantics under spec 029 —enabledis redundant withagentspresence, andmax_parallelwas never a meaningful SDK control. Removal is acceptable because the block is freshly introduced and not yet load-bearing in shipped configs.
Key Entities¶
- SubagentDefinition: A named subagent specification with
description,prompt/prompt_file,tools, andmodel. (Note: no per-subagent MCP servers — the SDK does not support that.) - ClaudeConfig.agents: A dictionary mapping subagent names to their definitions; translated 1-to-1 to
ClaudeAgentOptions.agentson the SDK side.
Success Criteria (mandatory)¶
Measurable Outcomes¶
- SC-001: Users can define multi-agent teams entirely in YAML with distinct prompts, models, and tool access per subagent.
- SC-002: Subagent definitions are correctly translated to SDK
AgentDefinitionobjects, verified by unit tests asserting on the four fields (description,prompt,tools,model) of the built options. - SC-003: Subagents with restricted
toolslists (including MCP tool names) only see those tools, verified by unit tests asserting on eachAgentDefinition.toolsvalue. - SC-004: Invalid subagent configurations (missing description, both prompt and prompt_file set, neither prompt nor prompt_file set, nonexistent prompt_file, model outside the allowed literal set) produce clear validation errors at config load time.
- SC-005: The
claude.subagentsconfig block is removed; loading anagent.yamlthat still containsclaude.subagentsproduces a clear validation error pointing users at the new model (presence ofclaude.agentsis the only gate).
Assumptions¶
- The Claude Agent SDK's
AgentDefinitiondataclass exposes exactly four fields:description: str(required),prompt: str(required),tools: list[str] | None,model: Literal["sonnet", "opus", "haiku", "inherit"] | None. There are noskills,memory,mcp_servers, orfallback_modelfields onAgentDefinition; these are top-levelClaudeAgentOptionsconcerns or are not exposed by the SDK at all. - The parent agent automatically delegates to subagents based on their
descriptionfields -- no explicit routing logic is needed in HoloDeck. - Subagent definitions are static (defined at config load time) -- dynamic subagent creation at runtime is out of scope.
- The
modelfield on subagent definitions is restricted to the SDK's literal set{sonnet, opus, haiku, inherit}; full model IDs are not accepted by the SDK type. - All MCP servers are registered at the parent (top-level
ClaudeAgentOptions.mcp_servers); subagents share that registration and use theirtoolsallowlist to scope which MCP tools they can call (mcp__<server>__<tool>). - The SDK manages subagent-dispatch concurrency internally; HoloDeck does not and cannot control how many subagents the SDK runs in parallel during a single agent session. HoloDeck-side test concurrency is controlled exclusively by
execution.parallel_test_cases; no separate subagent-specific knob is provided.