What Are AI Agent Subagents? Context Isolation for Complex Tasks
My AI agent kept running out of context. Every time I asked it to search a codebase, it would read dozens of files, filling the message history with irrelevant content. The main task got lost in the noise.
I tried limiting file reads. I tried summarizing more aggressively. Nothing worked well.
Then I discovered subagents.
The Context Pollution Problem
When an agent explores a codebase, it generates massive context:
User: "Find where authentication is handled"Agent: "Let me search..."[reads auth.py] - 200 tokens[reads middleware.py] - 300 tokens[reads routes/login.py] - 400 tokens[reads utils/jwt.py] - 250 tokens[reads tests/test_auth.py] - 500 tokens...After 20 files, your context window is polluted. The actual task - understanding authentication - is buried in file contents that may or may not be relevant.
The parent agent’s message array grows unbounded:
messages = [ {"role": "user", "content": "Find authentication code"}, {"role": "assistant", "content": "I'll search..."}, {"role": "user", "content": "File: auth.py\n...[500 lines]..."}, {"role": "assistant", "content": "Now let me check..."}, # ... 50+ messages later]Every subsequent decision must process all this accumulated noise.
The Subagent Pattern
A subagent is a child agent spawned with a fresh messages=[] array. It works in its own isolated context, shares the filesystem, then returns only a summary to the parent.
Parent agent Subagent+------------------+ +------------------+| messages=[...] | | messages=[] | <-- fresh| | dispatch | || tool: task | ---------->| while tool_use: || prompt="..." | | call tools || description="" | | append results || | summary | || result = "..." | <--------- | return last text |+------------------+ +------------------+ |Parent context stays clean.Subagent context is discarded.This pattern appears in Claude Code’s implementation with a simple motto: “Break big tasks down; each subtask gets a clean context.”
How Subagents Work
The implementation is straightforward but powerful:
def run_subagent(prompt: str) -> str: sub_messages = [{"role": "user", "content": prompt}] # fresh context for _ in range(30): # safety limit response = client.messages.create( model=MODEL, system=SUBAGENT_SYSTEM, messages=sub_messages, tools=CHILD_TOOLS, max_tokens=8000, ) sub_messages.append({"role": "assistant", "content": response.content})
if response.stop_reason != "tool_use": break
results = [] for block in response.content: if block.type == "tool_use": handler = TOOL_HANDLERS.get(block.name) output = handler(**block.input) if handler else f"Unknown tool: {block.name}" results.append({ "type": "tool_result", "tool_use_id": block.id, "content": str(output)[:50000] }) sub_messages.append({"role": "user", "content": results})
# Only the final text returns to the parent -- child context is discarded return "".join(b.text for b in response.content if hasattr(b, "text")) or "(no summary)"Key observations:
- Fresh context:
sub_messagesstarts with only the prompt - Tool access: Child gets tools to explore (read, write, bash)
- Summary return: Only the final text returns to parent
- Context discarded: Child’s entire message history is thrown away
Tool Filtering: Preventing Recursion
Subagents need tools but not all tools. You don’t want a subagent spawning its own subagents infinitely:
# Child gets all base tools except task (no recursive spawning)CHILD_TOOLS = [ {"name": "bash", ...}, {"name": "read_file", ...}, {"name": "write_file", ...}, {"name": "edit_file", ...},]The parent keeps the task tool (which spawns subagents), but children don’t. This creates a hierarchy:
Parent (has task tool) └── Subagent A (no task tool) └── Subagent B (no task tool)No recursion possible.
When to Use Subagents
Use subagents when:
- Exploration tasks: Searching codebases, reading many files
- Parallel work: Independent tasks that don’t need parent context
- Context preservation: You need the parent conversation clean for later work
Don’t use subagents when:
- Sequential dependencies: Later steps need earlier context
- Simple queries: Just reading one file doesn’t justify the overhead
- Context sharing needed: Child needs parent’s conversation history
Subagent vs Teammate Pattern
Claude Code distinguishes between two patterns:
| Pattern | Lifecycle | Use Case |
|---|---|---|
| Subagent | spawn -> execute -> return -> destroyed | One-shot exploration tasks |
| Teammate | spawn -> work -> idle -> work -> … -> shutdown | Long-running collaboration |
Subagents are fire-and-forget. Teammates persist across multiple interactions.
A subagent is like hiring a consultant: they do the job, give you a report, and leave. A teammate is like hiring an employee: they stick around for multiple projects.
Practical Example
Let’s say I want to understand how authentication works in a project:
Parent: "Use a subagent to analyze the authentication flow"
[Subagent spawned with fresh context]Subagent reads: auth.py, middleware.py, routes/login.py, utils/jwt.pySubagent builds understanding internallySubagent returns: "Authentication uses JWT tokens. The flow is: 1. User posts credentials to /login 2. validate_credentials() checks against database 3. generate_jwt() creates token with 24h expiry 4. Token stored in httpOnly cookie 5. Middleware validates token on protected routes"
[Subagent context discarded]
Parent: "Great, now implement 2FA"[Parent has clean context, can proceed with 2FA implementation]The parent never saw the 20 files read. It only received the concise summary.
Key Takeaways
Subagents solve context pollution through isolation:
- Fresh
messages=[]: Each subagent starts with no history - Tool filtering: Children can explore but not spawn their own subagents
- Summary-only return: Parent receives conclusions, not process
- Discarded context: Child’s entire exploration history is thrown away
This pattern scales agents to handle complex, multi-phase work. The parent orchestrates; the children explore. Context stays clean.
As one codebase puts it: “Process isolation gives context isolation for free.”
Final Words + More Resources
My intention with this article was to help others share my knowledge and experience. If you want to contact me, you can contact by email: Email me
Here are also the most important links from this article along with some further resources that will help you in this scope:
Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!
Comments