Back to Writing
AI Engineering 2026-05-01

Specialist Subagents: When One Agent Isn't Enough

A single agent trying to explore code, write implementations, review diffs, and generate tests simultaneously performs worse at all of them. Specialist subagents with narrow scopes, distinct tool subsets, and separate token budgets produce better results.


The jack-of-all-trades agent is a comfortable abstraction. One loop, one system prompt, one model that handles everything. It’s easy to reason about and easy to build.

It’s also worse at everything it does than a team of specialists.

When a single agent has to explore a codebase, write a fix, review its own diff, and generate tests, its context becomes cluttered with the artifacts of all four activities simultaneously. Exploration results interfere with code-writing focus. Self-review is compromised by the same blindspots that produced the code being reviewed. Test generation relies on the same assumptions the implementation was built on.

Subagents fix this by giving each activity its own scope.


What a Subagent Is

A subagent is a fresh agent instance with:

  • A focused system prompt describing exactly one job
  • A subset of tools appropriate to that job
  • Its own token budget independent of the parent agent
  • Its own turn limit

The parent agent spawns a subagent with a task, waits for the result, and incorporates the summary into its own reasoning. The subagent’s internal reasoning, tool calls, and intermediate results don’t pollute the parent’s context — only the final summary does.


The Specialist Roster

Explorer: reads the codebase. Searches for relevant files, reads them, and returns a structured summary of what it found. Tools: grep_search, read_file, list_directory. No write tools. Max 15 turns.

Parallel Explorer: runs multiple Explorer instances concurrently against different parts of the codebase. Returns aggregated findings. Used when the relevant code is distributed across subsystems that can be explored independently.

Code Writer: implements a specific change described in a plan. Tools: read_file, edit_code, write_file. No search tools — it shouldn’t be re-investigating, just implementing. Max 10 turns.

Reviewer: reads a diff and checks for regressions, style violations, and missing edge cases. Tools: read_file, grep_search. No write tools. Returns a structured review with pass/fail verdict and specific issues.

Test Writer: reads the changed code and generates targeted unit tests. Tools: read_file, write_file. Returns the test file path and a summary of what’s covered.

Analyst: reads ticket data, prior runs, and existing code to produce a structured analysis. No write tools. Returns a confidence score and a summary of findings.


Tool Subset Isolation

The tool subset isn’t just about preventing accidents — it’s about focus. A code-writer subagent that has no search tools cannot start re-investigating the problem. It has the plan, it has file access, its only job is to implement.

This is the same principle behind phase gating: remove the option to do the wrong thing, and the agent does the right thing more reliably.

const explorerTools = new ToolRegistry([
  new GrepSearchTool(),
  new ReadFileTool(),
  new ListDirectoryTool(),
]);

const codeWriterTools = new ToolRegistry([
  new ReadFileTool(),
  new EditCodeTool(),
  new WriteFileTool(),
]);

The parent agent’s ToolRegistry includes a spawn_subagent tool. The subagent never sees the parent’s full tool set.


Context Isolation

A subagent receives exactly the context it needs for its task — not the full conversation history of the parent run.

When the parent spawns an explorer:

const result = await runSubAgent(provider, {
  name: 'explorer',
  model: config.model,
  systemPrompt: explorerSystemPrompt,
  task: `Find all files that call the function calculateInvoiceTotal() in ${repoPath}. 
         Return a structured summary: file paths, line numbers, and how each call site uses the function.`,
  tools: explorerTools,
  maxTurns: 15,
});

The explorer starts fresh. It doesn’t know about the Jira ticket. It doesn’t know about the refine phase findings. It has one question and the tools to answer it.

The parent receives result.summary — a compact, structured description of what was found — and incorporates it into its own reasoning without any of the explorer’s intermediate tool results.


Parallel Exploration

When the relevant code is distributed across independent subsystems, spawn multiple explorer subagents concurrently:

const [controllerFindings, modelFindings, testFindings] = await Promise.all([
  runSubAgent(provider, { task: `Find ${symbol} in controllers/`, ... }),
  runSubAgent(provider, { task: `Find ${symbol} in models/`, ... }),
  runSubAgent(provider, { task: `Find ${symbol} in tests/`, ... }),
]);

Three parallel exploration threads, each returning a focused summary. The parent merges the three summaries and proceeds with a complete picture of the codebase in roughly the time it would have taken one explorer to cover one subsystem.


When to Use Subagents vs. Just More Turns

Subagents add coordination overhead. Don’t use them for tasks that a single focused turn can handle.

Use subagents when:

  • The task produces output that would clutter the parent’s context if done inline (exploration results, test files)
  • The task can be done in parallel with other tasks (parallel exploration)
  • The task benefits from a fresh context without the parent’s accumulated assumptions (review, testing)
  • The task is self-contained and reusable across multiple parent workflows

The signal is “would I rather have this as a clean summary in my context, or as 20 turns of tool calls?” For exploration and review, the answer is almost always the summary.