Skip to main content

Custom Agents

Creating specialized subagents with curated tool sets.

Overview

ClaudeBox enables a powerful pattern: the main Claude Code agent can spawn specialized subagents, each with their own curated set of MCP tools. This allows for:

  • Separation of Concerns - Each agent focuses on what it does best
  • Tool Curation - Give agents only the tools they need
  • Parallel Work - Multiple specialized agents working together
  • Expertise Abstraction - "Ask Venus for design help" vs knowing which tools to use

Why ClaudeBox, Not Claude Code's Task Tool?

Claude Code has a built-in Task tool for spawning subagents. So why do we need ClaudeBox?

The Limitation

Claude Code's Task tool has predefined subagent types with fixed configurations:

Subagent TypeWhat It DoesCustomizable?
ExploreSearch codebaseNo
PlanDesign implementationNo
general-purposeGeneral tasksNo
claude-code-guideDocumentation lookupNo

These are hardcoded into Claude Code. You cannot:

  • Add custom MCP servers (like magic-mcp or context7)
  • Restrict which tools the subagent can use
  • Define a custom system prompt
  • Choose a different model

The Solution: Claude Agent SDK

The Claude Agent SDK is the underlying library that powers Claude Code itself. It provides full programmatic control over agent configuration:

from claude_code_sdk import query, ClaudeAgentOptions

options = ClaudeAgentOptions(
mcp_servers={"magic": {...}, "context7": {...}}, # Any MCP servers
allowed_tools=["Read", "mcp__magic__*"], # Tool restrictions
system_prompt="You are Venus...", # Custom personality
model="claude-sonnet-4-20250514" # Model choice
)

async for message in query("Find a button component", options):
print(message)

ClaudeBox = Agent SDK Over HTTP

ClaudeBox wraps the Agent SDK and exposes it via HTTP with SSE streaming. This lets Claude Code (or any HTTP client) spawn fully customized subagents:

┌────────────────────────────────────────────────────────────────┐
│ Claude Code │
│ │
│ Built-in Task Tool ClaudeBox HTTP Call │
│ ┌─────────────────┐ ┌─────────────────┐ │
│ │ subagent_type= │ │ POST /chat │ │
│ │ "Explore" │ │ {mcp_servers, │ │
│ │ │ │ allowed_tools, │ │
│ │ Fixed config │ │ system_prompt} │ │
│ │ No customization│ │ │ │
│ └────────┬────────┘ └────────┬────────┘ │
│ │ │ │
│ ▼ ▼ │
│ ┌─────────────────┐ ┌─────────────────┐ │
│ │ Predefined │ │ ClaudeBox │ │
│ │ Subagent │ │ (Agent SDK) │ │
│ │ │ │ │ │
│ │ Tools: fixed │ │ Tools: custom │ │
│ │ MCP: none │ │ MCP: any │ │
│ └─────────────────┘ └─────────────────┘ │
└────────────────────────────────────────────────────────────────┘

Comparison

CapabilityTask ToolClaudeBox
Spawn subagentsYesYes
Custom MCP serversNoYes
Tool restrictionsNoYes
Custom system promptNoYes
Model selectionLimitedFull
Works from Claude CodeYesYes (via HTTP)

When to Use Each

Use Task Tool when:

  • You need basic exploration (Explore)
  • You want implementation planning (Plan)
  • The predefined types fit your needs

Use ClaudeBox when:

  • You need custom MCP tools (magic-mcp, context7, etc.)
  • You want to restrict what tools the agent can use
  • You need a specialized personality (Venus, Athena, etc.)
  • You're building reusable agent patterns

The Subagent Pattern

┌─────────────────────────────────────────────────────────────┐
│ Main Claude Code Agent │
│ │
│ "I need a React component for user settings" │
│ │
└──────────────────────────┬──────────────────────────────────┘
│ HTTP call to ClaudeBox API

┌─────────────────────────────────────────────────────────────┐
│ Venus (Design Agent) │
│ │
│ Brain: Claude Sonnet │
│ Tools: │
│ - magic-mcp (21st.dev component library) │
│ - context7 (documentation lookup) │
│ │
│ "Here's a polished settings component with these files..." │
│ │
└──────────────────────────┬──────────────────────────────────┘
│ Returns design + code

┌─────────────────────────────────────────────────────────────┐
│ Main Claude Code Agent │
│ │
│ Implements the design Venus provided │
│ (Write, Edit, Bash tools) │
│ │
└─────────────────────────────────────────────────────────────┘

Example: Venus (Design Agent)

Venus is a design-specialized subagent that finds and adapts UI components.

Configuration

venus_request = {
"prompt": "Find a user settings component with dark mode toggle",
"system_prompt": """You are Venus, a UI/UX design specialist.

Your job is to:
1. Search for relevant component designs using magic-mcp
2. Look up framework documentation with context7
3. Return complete, ready-to-use component code

Always consider:
- Accessibility (ARIA labels, keyboard nav)
- Responsive design
- Dark mode support
- Consistent styling with existing components

Return the component code and explain any dependencies needed.""",

"model": "claude-sonnet-4-20250514",

"mcp_servers": {
"magic": {
"command": "npx",
"args": ["-y", "@anthropic/magic-mcp"]
},
"context7": {
"command": "npx",
"args": ["-y", "@anthropic/context7-mcp"]
}
},

# Only design-related tools, no file writing
"allowed_tools": [
"mcp__magic__21st_magic_component_builder",
"mcp__magic__21st_magic_component_inspiration",
"mcp__magic__21st_magic_component_refiner",
"mcp__magic__logo_search",
"mcp__context7__resolve-library-id",
"mcp__context7__query-docs"
]
}

Invoking Venus

From Claude Code (main agent), call the ClaudeBox HTTP API:

import httpx
import json

async def ask_venus(prompt: str) -> str:
"""Call Venus subagent for design help."""
venus_request["prompt"] = prompt

async with httpx.AsyncClient() as client:
async with client.stream(
"POST",
"http://localhost:8765/chat",
json=venus_request,
timeout=300.0
) as response:
result = ""
async for line in response.aiter_lines():
if line.startswith("data: "):
event = json.loads(line[6:])
if event["type"] == "text":
result += event["data"]["text"]
elif event["type"] == "done":
return result
return result

# Usage
design = await ask_venus("Find a settings panel component with user preferences")

The main agent receives the design and implements it using its own Write/Edit tools.

What Venus Returns

Venus provides ready-to-implement designs:

## Settings Panel Component

Based on 21st.dev's settings-panel pattern, here's a component
that matches your app's style:

### Dependencies
- @radix-ui/react-switch
- lucide-react

### Component Code
```tsx
// SettingsPanel.tsx
export function SettingsPanel() {
// ... complete implementation
}

Usage

<SettingsPanel
user={currentUser}
onSave={handleSave}
/>

The main agent then implements this using its Write/Edit tools.

Creating Your Own Agents

Step 1: Define the Specialty

What does this agent do better than a general-purpose agent?

AgentSpecialtyKey Tools
VenusUI/UX designmagic-mcp, context7
AthenaResearchweb search, context7
HephaestusTestingtest runners, coverage
HermesAPI integrationHTTP tools, schema validators

Step 2: Select MCP Tools

Choose tools that match the specialty:

# Research agent
research_tools = {
"context7": {"command": "npx", "args": ["-y", "@anthropic/context7-mcp"]},
"web": {"command": "web-search-mcp"}
}

# Testing agent
testing_tools = {
"coverage": {"command": "coverage-mcp"},
"playwright": {"command": "playwright-mcp"}
}

Step 3: Craft the System Prompt

Define the agent's personality and constraints:

research_system_prompt = """You are Athena, a research specialist.

Your role:
1. Search documentation thoroughly before answering
2. Cite sources for all claims
3. Distinguish between facts and opinions
4. Acknowledge when information is uncertain

You do NOT:
- Write or modify code
- Make implementation decisions
- Execute commands

Return research findings in structured format with citations."""

Step 4: Set Tool Restrictions

Limit tools to prevent scope creep:

# Research agent can only read and search
allowed_tools = [
"Read",
"Glob",
"Grep",
"mcp__context7__query-docs",
"mcp__web__search"
]
# Note: No Write, Edit, or Bash

Step 5: Create a Helper Function

Wrap the HTTP call for easy reuse:

# agents.py - reusable agent helpers

VENUS_CONFIG = { ... } # Full config from above
ATHENA_CONFIG = { ... }

async def ask_venus(prompt: str) -> str:
"""Get design help from Venus."""
return await call_claudebox_agent(VENUS_CONFIG, prompt)

async def ask_athena(prompt: str) -> str:
"""Get research from Athena."""
return await call_claudebox_agent(ATHENA_CONFIG, prompt)

async def call_claudebox_agent(config: dict, prompt: str) -> str:
"""Generic ClaudeBox agent caller."""
config["prompt"] = prompt
async with httpx.AsyncClient() as client:
async with client.stream("POST", "http://localhost:8765/chat",
json=config, timeout=300.0) as response:
result = ""
async for line in response.aiter_lines():
if line.startswith("data: "):
event = json.loads(line[6:])
if event["type"] == "text":
result += event["data"]["text"]
elif event["type"] == "done":
return result
return result

Best Practices

1. Single Responsibility

Each agent should do one thing well:

  • Venus: Find and adapt designs
  • Athena: Research and cite
  • Hephaestus: Test and validate

Don't create a "do everything" agent.

2. Clear Handoffs

Define what the subagent returns:

# Good: Clear deliverable
"Return the component code, required dependencies, and usage example"

# Bad: Vague
"Help with the UI"

3. Tool Minimization

Fewer tools = more focused agent:

# Good: Just what's needed
allowed_tools = ["Read", "mcp__context7__query-docs"]

# Bad: Everything
allowed_tools = None # All tools available

4. Stateless Design

Subagents should be stateless between calls:

# Good: Self-contained request
{"prompt": "Find a button component matching this style: {...}"}

# Bad: Assumes prior context
{"prompt": "Now make it blue"} # What is "it"?

Agent Composition

Combine multiple agents for complex tasks:

Main Agent: "Build a user dashboard"

├─► Venus: "Design the layout"
│ Returns: Component structure

├─► Athena: "Research dashboard best practices"
│ Returns: UX guidelines, accessibility requirements

└─► Main Agent: Implements using both inputs
Uses: Write, Edit, Bash

Future: Agent Registry

Planned features:

  • Agent Catalog - Browse available specialized agents
  • Agent Metrics - Track performance and usage
  • Agent Composition - Define pipelines of agents
  • Agent Versioning - Pin to specific agent configurations

See Also

  • Agent HTTP API - How to invoke agents
  • Janus - Infrastructure orchestration with second opinion pattern