Documentation Index
Fetch the complete documentation index at: https://springaicommunity.mintlify.app/llms.txt
Use this file to discover all available pages before exploring further.
Module 21: Subagents Introduction
Defining and spawning custom subagents.
What You’ll Learn
- Defining agents with JSON configuration
- Using the
--agents CLI option via CLIOptions
- Instructing Claude to spawn subagents via the Task tool
- Agent definition structure (description and prompt)
What are Subagents?
Subagents are specialized Claude instances with custom system prompts. When you define agents, Claude can spawn them using the Task tool to delegate specialized work.
Agents are defined in JSON:
{
"agent-name": {
"description": "What the agent does (shown to Claude)",
"prompt": "System prompt for the agent (its personality/role)"
}
}
Defining Agents with CLIOptions
Use CLIOptions.builder().agents() to define custom agents:
import org.springaicommunity.claude.agent.sdk.ClaudeClient;
import org.springaicommunity.claude.agent.sdk.ClaudeSyncClient;
import org.springaicommunity.claude.agent.sdk.config.PermissionMode;
import org.springaicommunity.claude.agent.sdk.transport.CLIOptions;
import java.nio.file.Path;
// Define a code reviewer agent
String agentsJson = """
{
"code-reviewer": {
"description": "Reviews code for best practices and potential issues",
"prompt": "You are a code reviewer. Analyze code for bugs, performance issues, security vulnerabilities, and adherence to best practices. Provide constructive feedback in a concise format."
}
}
""";
// Build CLI options with agents
CLIOptions options = CLIOptions.builder()
.model(CLIOptions.MODEL_HAIKU)
.permissionMode(PermissionMode.BYPASS_PERMISSIONS)
.agents(agentsJson)
.build();
// Use sync(options) pattern to include agents
try (ClaudeSyncClient client = ClaudeClient.sync(options)
.workingDirectory(Path.of("."))
.build()) {
// Tell Claude to use the agent
client.connect("Use the code-reviewer agent to review this code: ...");
// ...
}
ClaudeClient.sync(options) Pattern
When using agents, you must use the ClaudeClient.sync(CLIOptions) pattern:
// This pattern is required for agents
CLIOptions options = CLIOptions.builder()
.agents(agentsJson)
.build();
try (ClaudeSyncClient client = ClaudeClient.sync(options)
.workingDirectory(Path.of("."))
.build()) {
// ...
}
The fluent builder (ClaudeClient.sync().xyz()) does not have an .agents() method.
Complete Example
import org.springaicommunity.claude.agent.sdk.ClaudeClient;
import org.springaicommunity.claude.agent.sdk.ClaudeSyncClient;
import org.springaicommunity.claude.agent.sdk.config.PermissionMode;
import org.springaicommunity.claude.agent.sdk.parsing.ParsedMessage;
import org.springaicommunity.claude.agent.sdk.transport.CLIOptions;
import org.springaicommunity.claude.agent.sdk.types.AssistantMessage;
import java.nio.file.Path;
import java.util.Iterator;
String agentsJson = """
{
"code-reviewer": {
"description": "Reviews code for best practices and potential issues",
"prompt": "You are a code reviewer. Analyze code for bugs, performance, and security. Be concise."
}
}
""";
CLIOptions options = CLIOptions.builder()
.model(CLIOptions.MODEL_HAIKU)
.permissionMode(PermissionMode.BYPASS_PERMISSIONS)
.agents(agentsJson)
.build();
try (ClaudeSyncClient client = ClaudeClient.sync(options)
.workingDirectory(Path.of("."))
.build()) {
String prompt = """
Use the code-reviewer agent to review this Java code:
public class Example {
public static void main(String[] args) {
String password = "admin123";
for(int i=0; i<1000; i++) {
System.out.println(password);
}
}
}
Provide a brief review with 2-3 key issues.
""";
client.connect(prompt);
Iterator<ParsedMessage> response = client.receiveResponse();
while (response.hasNext()) {
ParsedMessage msg = response.next();
if (msg.isRegularMessage() && msg.asMessage() instanceof AssistantMessage am) {
am.getTextContent().ifPresent(System.out::println);
}
}
}
How It Works
- You define agents in JSON and pass to CLIOptions
- Claude receives the agent definitions
- When prompted to use an agent, Claude spawns it via the Task tool
- The subagent runs with its defined system prompt
- Results return to the main Claude instance
Main Claude → Task tool → Subagent (with custom prompt)
↓
Does work
↓
Main Claude ← Results ← Subagent
Agent Design Tips
| Aspect | Guidance |
|---|
| Description | Short, tells Claude when to use this agent |
| Prompt | System prompt defining the agent’s expertise |
| Naming | Use kebab-case: code-reviewer, security-auditor |
| Brevity | Ask agents to “be concise” to reduce response time |
Key Points
- Define agents as JSON with
description and prompt fields
- Use
CLIOptions.builder().agents(json) to configure
- Must use
ClaudeClient.sync(options) pattern (not fluent builder)
- Prompt Claude to “use the agent-name agent” to invoke
- Subagents run via Claude’s Task tool
Source Code
View on GitHub
Running the Example
mvn compile exec:java -pl module-21-subagents-intro
Next Module
Module 22: Subagents Parallel - Running multiple agents in parallel.