192 lines
5.5 KiB
Markdown
192 lines
5.5 KiB
Markdown
# Agent and Subagent Definition Patterns
|
|
|
|
This guide covers how to define agents and subagents programmatically using the Claude Agent SDK.
|
|
|
|
## Core Concepts
|
|
|
|
**AgentDefinition** - Defines a specialized agent with specific tools, prompts, and model configuration.
|
|
|
|
**Programmatic Definition** - SDK best practice is to define agents programmatically using the `agents` parameter in `ClaudeAgentOptions`, not filesystem auto-discovery.
|
|
|
|
## Basic Agent Definition
|
|
|
|
```python
|
|
from claude_agent_sdk import AgentDefinition, ClaudeAgentOptions
|
|
|
|
options = ClaudeAgentOptions(
|
|
agents={
|
|
"agent-name": AgentDefinition(
|
|
description="When to use this agent",
|
|
prompt="System prompt defining role and behavior",
|
|
tools=["Read", "Grep", "Glob"],
|
|
model="sonnet" # or "opus", "haiku", "inherit"
|
|
)
|
|
}
|
|
)
|
|
```
|
|
|
|
## AgentDefinition Fields
|
|
|
|
| Field | Type | Required | Description |
|
|
|-------|------|----------|-------------|
|
|
| `description` | `str` | Yes | Natural language description of when to use this agent |
|
|
| `prompt` | `str` | Yes | Agent's system prompt defining role and behavior |
|
|
| `tools` | `list[str]` | No | Array of allowed tool names. If omitted, inherits all tools |
|
|
| `model` | `str` | No | Model override: "sonnet", "opus", "haiku", or "inherit" |
|
|
|
|
## Common Patterns
|
|
|
|
### Read-Only Analyzer Agent
|
|
|
|
For code review, architecture analysis, or documentation review:
|
|
|
|
```python
|
|
"code-reviewer": AgentDefinition(
|
|
description="Reviews code for best practices, security, and performance",
|
|
prompt="""You are a code reviewer. Analyze code for:
|
|
- Security vulnerabilities
|
|
- Performance issues
|
|
- Best practice adherence
|
|
- Potential bugs
|
|
|
|
Provide constructive, specific feedback.""",
|
|
tools=["Read", "Grep", "Glob"],
|
|
model="sonnet"
|
|
)
|
|
```
|
|
|
|
### Code Modification Agent
|
|
|
|
For implementing features or fixing bugs:
|
|
|
|
```python
|
|
"code-writer": AgentDefinition(
|
|
description="Implements features and fixes bugs",
|
|
prompt="""You are a code implementation specialist.
|
|
Write clean, tested, well-documented code.
|
|
Follow project conventions and best practices.""",
|
|
tools=["Read", "Write", "Edit", "Grep", "Glob"],
|
|
model="sonnet"
|
|
)
|
|
```
|
|
|
|
### Test Execution Agent
|
|
|
|
For running tests and analyzing results:
|
|
|
|
```python
|
|
"test-runner": AgentDefinition(
|
|
description="Runs tests and analyzes results",
|
|
prompt="""You are a testing specialist.
|
|
Execute tests, analyze failures, and provide clear diagnostics.
|
|
Focus on actionable feedback.""",
|
|
tools=["Bash", "Read", "Grep"],
|
|
model="sonnet"
|
|
)
|
|
```
|
|
|
|
### Multiple Agents Pattern
|
|
|
|
Orchestrator with specialized subagents:
|
|
|
|
```python
|
|
options = ClaudeAgentOptions(
|
|
system_prompt="claude_code", # Orchestrator needs Task tool knowledge
|
|
allowed_tools=["Bash", "Task", "Read", "Write"],
|
|
agents={
|
|
"analyzer": AgentDefinition(
|
|
description="Analyzes code structure and patterns",
|
|
prompt="You are a code analyzer. Examine structure, patterns, and architecture.",
|
|
tools=["Read", "Grep", "Glob"]
|
|
),
|
|
"fixer": AgentDefinition(
|
|
description="Fixes identified issues",
|
|
prompt="You are a code fixer. Apply fixes based on analysis results.",
|
|
tools=["Read", "Edit", "Bash"],
|
|
model="sonnet"
|
|
)
|
|
}
|
|
)
|
|
```
|
|
|
|
## Loading Agent Definitions from Files
|
|
|
|
While programmatic definition is recommended, you can still store agent prompts in markdown files:
|
|
|
|
```python
|
|
import yaml
|
|
|
|
def load_agent_definition(path: str) -> AgentDefinition:
|
|
"""Load agent definition from markdown file with YAML frontmatter."""
|
|
with open(path) as f:
|
|
content = f.read()
|
|
|
|
parts = content.split("---")
|
|
frontmatter = yaml.safe_load(parts[1])
|
|
system_prompt = parts[2].strip()
|
|
|
|
# Parse tools (can be comma-separated string or array)
|
|
tools_value = frontmatter.get("tools", [])
|
|
if isinstance(tools_value, str):
|
|
tools = [t.strip() for t in tools_value.split(",")]
|
|
else:
|
|
tools = tools_value
|
|
|
|
return AgentDefinition(
|
|
description=frontmatter["description"],
|
|
prompt=system_prompt,
|
|
tools=tools,
|
|
model=frontmatter.get("model", "inherit")
|
|
)
|
|
|
|
# Load and register programmatically
|
|
investigator = load_agent_definition(".claude/agents/investigator.md")
|
|
|
|
options = ClaudeAgentOptions(
|
|
agents={"investigator": investigator}
|
|
)
|
|
```
|
|
|
|
## Best Practices
|
|
|
|
1. **Use programmatic registration** - Define agents via `agents` parameter, not filesystem auto-discovery
|
|
2. **Set orchestrator system_prompt** - Main agent needs `system_prompt="claude_code"` to use Task tool
|
|
3. **Specific descriptions** - Agent descriptions determine when they're used
|
|
4. **Restrict tools** - Limit agent tools to minimum needed for safety and clarity
|
|
5. **Match agent names** - Ensure agent names in `agents={}` match what orchestrator references
|
|
|
|
## Anti-Patterns
|
|
|
|
❌ **Relying on filesystem auto-discovery**
|
|
|
|
```python
|
|
# SDK will auto-discover .claude/agents/*.md but this is NOT recommended
|
|
options = ClaudeAgentOptions() # Missing explicit agents={}
|
|
```
|
|
|
|
✅ **Programmatic registration**
|
|
|
|
```python
|
|
options = ClaudeAgentOptions(
|
|
agents={"agent-name": AgentDefinition(...)}
|
|
)
|
|
```
|
|
|
|
❌ **Missing orchestrator system prompt**
|
|
|
|
```python
|
|
options = ClaudeAgentOptions(
|
|
agents={...}
|
|
# Missing system_prompt="claude_code"
|
|
)
|
|
```
|
|
|
|
✅ **Proper orchestrator configuration**
|
|
|
|
```python
|
|
options = ClaudeAgentOptions(
|
|
system_prompt="claude_code", # Orchestrator knows how to use Task tool
|
|
agents={...}
|
|
)
|
|
```
|