Skip to content

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:

s04_subagent.py
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:

  1. Fresh context: sub_messages starts with only the prompt
  2. Tool access: Child gets tools to explore (read, write, bash)
  3. Summary return: Only the final text returns to parent
  4. 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:

s04_subagent.py
# 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:

PatternLifecycleUse Case
Subagentspawn -> execute -> return -> destroyedOne-shot exploration tasks
Teammatespawn -> work -> idle -> work -> … -> shutdownLong-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.py
Subagent builds understanding internally
Subagent 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:

  1. Fresh messages=[]: Each subagent starts with no history
  2. Tool filtering: Children can explore but not spawn their own subagents
  3. Summary-only return: Parent receives conclusions, not process
  4. 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