---
title: "Subagents"
description: "Hand a big task to a subagent with a clean context: it works in isolation and bubbles back only the conclusion, so noise never leaks into the main conversation."
source: https://vizlearn.app/ai/agents/subagent
access: premium (interactive player requires Lifetime; this doc is free)
---

# Subagents

A subagent is an agent loop your agent loop can call: the harness registers `Task` as one more tool, and when the model requests it, the handler runs the same call-inspect-dispatch-append cycle on a **fresh** `messages[]` seeded with nothing but the delegation prompt.

The child does its messy exploration in that private context, returns one line of text, and everything else it read is thrown away. That is the whole trick, and it has a name: context isolation.

Why bother? Because this append-only agent loop retains every tool result unless the harness removes or summarizes it. Ask a question that takes four archive searches and your conversation now carries four fat pages — a couple of thousand tokens — that remain in later model requests while this history is retained. Real runtimes may compact, truncate, or cache context. Delegate the same four searches to a subagent and your conversation grows by one result card (plus the Task call). In this lesson's run the difference is ~90 tokens versus ~2.1k for the identical work.

The catch is the same wall seen from the other side. The child's context contains the prompt and nothing else — not the conversation, not the user's earlier clarifications, not what you both agreed three messages ago. Whatever you didn't put in the prompt does not exist for the child. Half this lesson is watching that save you; the other half is watching it burn you.

This lesson builds directly on [the agent loop](https://vizlearn.app/ai/agents/agent-loop) (the child *is* that loop, run on a second array) and on [tool calling](https://vizlearn.app/ai/agents/tool-calling) (`Task` sits in the same dispatch map as `search`). The two lanes on screen are two `messages[]` arrays — the same accumulator the agent-loop lesson draws as a single column.

## How Subagents Work: One Line Builds the Wall

The main loop's side is three lines: the model returns `Task(prompt="…")` the way it returns any tool request, the harness calls `run_subagent(prompt)`, and the returned string is appended as an ordinary `tool_result`. The main loop cannot tell a subagent from a calculator.

```python
TOOLS["Task"] = run_subagent

def run_subagent(prompt: str) -> str:
    sub = [{"role": "user", "content": prompt}]
    while True:
        r = model.call(sub, tools=TOOL_SCHEMAS)
        sub.append(assistant(r.content))
        if r.stop_reason == "end_turn":
            return r.text
        sub.append(tool_results([TOOLS[c.name](**c.input) for c in tool_uses_of(r)]))
```

`run_subagent` is where the isolation happens, and it's one line: `sub = [{"role": "user", "content": prompt}]`. A brand-new array. The child's loop then runs exactly like the parent's — call the model, run the tool it asks for, append the result, repeat — but every append lands in `sub`, not in the main conversation. When the child's model finally answers with text, `return r.text` sends **only that string** back across. The `sub` array, with its thousands of tokens of search results, goes out of scope and dies.

Two consequences fall out of that one line, and they are the lesson:

**The ledger.** The main context grows by one result card per delegation (plus the Task call), no matter how much the child explored — O(1) result cards instead of O(k) tool-step records, assuming a bounded-size return; a card is not a fixed token count. And because each model call re-sends the whole conversation, inline pollution isn't a one-off cost: the 432-token search result appended at turn 1 remains input context at later turns; actual billing depends on the provider and caching. Keeping the trunk thin compounds too.

**The blind spot.** The prompt is the only channel in. The child doesn't inherit the conversation, so a constraint that lives earlier in the main thread — "I mean the 2011 original, not the 2024 remake" — is invisible to it unless the delegating model wrote it into the prompt. A subagent can answer its prompt perfectly and your question wrongly at the same time.

## Subagents Step by Step: Watch the Two Counters

The default run delegates a self-contained research task. The user asks: *Which year was the studio behind the original Aurora Run film founded?* Watch the two token counters — that's where the phenomenon lives.

1. **Init.** The main conversation holds one user card (~18 tok). `main = 18 tok`.
2. **Plan.** The main model answers with a tool request: `Task(prompt="Find the founding year of the studio that produced the original 2011 film Aurora Run.")`. Read that prompt carefully — it carries its own constraint ("the original 2011 film"), which is what makes this task self-contained. The request card joins the trunk: `main = 52 tok`.
3. **Fork.** The harness spawns `sub = [prompt]` — a second lane opens holding one ~26-token card. The trunk dims: the main conversation is now waiting, untouched.
4. **Child search 1.** `search["Aurora Run"]` returns the archive's index entry (~432 tok with the request): the primary title is the 2024 remake, with a see-also for the 2011 film. That lands in the *child's* lane. `main` hasn't moved.
5. **Child search 2.** The prompt says 2011, so the child follows the see-also: `search["Aurora Run (2011)"]` (~572 tok) — directed by Mara Voss, produced by Northlight.
6. **Child search 3.** `search["Northlight"]` (~392 tok) is a fork in the road: two companies match, Northlight Pictures and Northlight Films.
7. **Child search 4.** `search["Northlight Pictures"]` (~692 tok) settles it: founded in 1987, produced Aurora Run (2011). The child's context now holds ~2.1k tokens. The main counter still reads 52.
8. **Conclude.** The child's model answers with text: *"Northlight Pictures — founded in 1987."* Sixteen tokens. Of everything the child read, only this line will travel.
9. **Merge.** That one card crosses back into the trunk as a `tool_result`; the sub lane greys out — `sub = discarded`, ~2.1k tokens freed. `main = 68 tok`.
10. **Final.** The main model, seeing the result, answers the user: *"The studio was Northlight Pictures, founded in 1987."* `main = 90 tok`. Four searches happened; the main conversation contains none of them.

Now flip **mode** to `inline` and run the identical task. Same four searches, same pages — but every result appends to the one and only `messages[]`. The counter climbs 432, then 1,004, then 1,396, then 2,088 tokens of exploration, and the run ends with `main = 2,128 tok`. Same answer, ~24× the retained main-context count in this fixture. That flip is the cleanest A/B in the lesson: the *work* is identical, only the destination of `append` changed.

Then try the **Context-dependent** task, and this is where the wall bites back. The user asks the director-birth-year question and adds a second message: *"Careful — I mean the 2011 original, not the 2024 remake."* Delegated, the model writes `Task(prompt="Find the birth year of the director of the film Aurora Run.")` — and the clarification isn't in it. The child searches, resolves "Aurora Run" to the archive's primary title (the remake), chases its director, and returns *born 1989*, confident and wrong. Run the same task inline and the loop gets it right — *Mara Voss, born 1974* — because when the search surfaces both films, the clarification is sitting right there in the same `messages[]` the model re-reads on every call. Same task and archive, with scripted model choices; the only thing that changed is which side of the fork the constraint lived on.

## Edge Cases

- **A trivial delegation.** Fork a subagent for a one-search task and the overhead (the Task card, the result card, a whole extra loop) buys you almost nothing — the ledger only pays off when the child's exploration is bigger than its conclusion. Delegate journeys, not errands.
- **The child comes back empty or wrong.** The parent gets one opaque line. It can't audit the child's reasoning — the evidence was discarded with the lane. If the conclusion smells off, the parent's only move is to re-delegate with a sharper prompt or do the work inline; there is no transcript to inspect.
- **A prompt that should have carried context, and didn't.** The blind-spot run is the canonical case: nothing errors, nothing warns. The child returns a well-formed answer to the question as written. Isolation failures are silent — which is exactly why the delegating model, not the harness, is responsible for packing the prompt.
- **The child needs to ask the user something.** It can't. There is no channel from the child to the conversation except the final return value. A subagent that hits genuine ambiguity can only guess or report the ambiguity as its answer.

## Common Mistakes

- **Treating the subagent as special harness machinery.** It's `TOOLS["Task"] = run_subagent` — one more entry in the same dispatch map as `search`. The main loop doesn't branch on it, doesn't know it spawned a loop, and appends its result like any other `tool_result`.
- **Assuming the child sees the conversation.** It sees the prompt string. Anything the user said earlier — constraints, corrections, preferences — must be *written into the prompt* by the delegating model, or it's gone. When a subagent returns a confidently wrong answer, check the prompt before you blame the model.
- **Returning the transcript instead of the conclusion.** If the child sends back everything it read "to be safe," the merge imports all the noise delegation existed to exclude. The return value should be the distilled answer; the exploration is disposable by design.
- **Delegating to dodge the token bill and forgetting the bill compounds.** The win isn't just that main stays small at the merge — it's that every *later* model call re-sends a thin conversation instead of a fat one. Conversely, inline noise isn't paid once; it's rent.
- **Expecting the parent to catch the child's errors.** The parent sees one line and has no evidence to check it against. Delegation trades auditability for cleanliness — the [ReAct lesson](https://vizlearn.app/ai/agents/react-loop) is about exactly the grounding chain that a subagent's merge throws away.

## A Note on Simplification

The harness mechanics on screen — the fork, the fresh array, the single-line return, the token accounting — are real and deterministic; that's the part this lesson exists to teach. The model's utterances (the delegation prompt, the search choices, the conclusions) are scripted for clarity, not recorded from a live model; [tool-calling](https://vizlearn.app/ai/agents/tool-calling) and [react-loop](https://vizlearn.app/ai/agents/react-loop) show real recorded runs of the same loop machinery, and the 2011 film's facts here match react-loop's recorded trace. Token counts are illustrative sums over the conversation cards — a real run also carries a system prompt, tool schemas, and thinking tokens that this ledger omits. These isolation and communication limits belong to this fixture, not all subagent products. Production subagents add machinery too: they inherit tool definitions and a model choice, run under their own turn budgets, can execute in parallel, and often return structured output rather than a bare string. None of that changes the shape: fork a clean context, work in it, send one thing back.
