Skip to content

16 min read

A second level buys a boundary, not a specialist

On this page

A market-intelligence team ships a competitive brief on six companies every Monday: Northbeam, Corveil and Palisade on the infrastructure side, Tessera, Marlowe and Aventine on the applications side. Two designs for the service that produces that brief are available. Design A is a single orchestrator that fans out six research workers, one per company, and writes the brief itself from what comes back. Design B puts a level in between — the orchestrator delegates to two sector supervisors, each of which runs three research workers and writes a sector summary, and the orchestrator assembles the brief from the two summaries.

Design B is a hierarchical agent system, more often called a supervisor tree: an arrangement in which the agent that receives a task splits it into pieces and hands each piece to another agent, and in which at least one of those delegates splits its piece again rather than doing the work itself. Sketch the calls a single run makes and the picture is a tree — one agent at the root, delegates hanging beneath it, and the actual fetching, reading and writing happening at the leaves. The number of delegation layers between the root and the work is the tree's depth. Orchestrator–worker, from the previous topic, is the depth-1 case, in which the root hands work straight to the agents that perform it, and a hierarchy is what you have as soon as a delegate is allowed to delegate.

The arrangement exists because a single agent that owns a whole task has to hold all of it at once — every worker's raw findings, every constraint it was handed, and the shape of the document it owes — in one context window while it writes. Both the care it takes when handing work out and the quality of what it writes degrade as that pile grows, and the standard remedy is to give each agent a slice small enough to hold. You will meet the pattern in most agent frameworks under slightly different names: LangGraph and LangChain expose supervisors with sub-agents and a configurable delegation depth, CrewAI calls the same idea a hierarchical process, coding assistants that let a sub-agent spawn its own sub-agents are offering it without the label, and the deep-research features in consumer assistants are typically three layers of it — a planner over section researchers over tools. All of them let you add a layer with a few lines of configuration, which is why the question comes up on nearly every such system: are the sector supervisors specialists who justify the layer they occupy?

Counting the delegation boundaries

A delegation boundary is one place where a task is handed from one agent to another and a result is handed back. It is the unit the rest of this topic is priced in, so it is worth counting precisely rather than eyeballing the diagram.

Counting is easier than it looks, because a tree has a property that makes the arithmetic mechanical. Every agent in the run except the root is reached by exactly one delegation — it was created by a parent handing it work, and no agent is handed work twice. So the number of boundaries is the number of agents below the root, and nothing else. Design A has six workers below its root, and therefore six boundaries, all identical in shape: orchestrator to worker, worker to orchestrator. Design B has two sector supervisors and six workers below its root, so eight. More importantly, the two new ones are not the same shape as the six old ones, because the payload crossing them is a sector summary rather than a set of raw findings.

That counting rule is worth holding onto, because it prices a level before anybody builds it. A proposed layer costs exactly as many new boundaries as it has delegates in it — two supervisors, two boundaries — and the workers beneath them keep the boundaries they already had, merely re-parented. Nothing about the count depends on how good the supervisors are or what their prompts say.

Flowchart: orchestrator → Northbeam] & w2[Corveil] & w3[Palisade; orchestrator → Tessera] & w5[Marlowe] & w6[Aventine; orchestrator → infra supervisor] & s2[apps supervisor; infra supervisor] & s2[apps supervisor → Northbeam] & x2[Corveil] & x3[Palisade; s2 → Tessera] & x5[Marlowe] & x6[Aventine.

Depth is the second number, and it is not the same as boundary count. Design A is depth 1: every result reaches the top after one hop. Design B is depth 2: a finding about Corveil crosses two boundaries and is rewritten once on the way. The two numbers come off the same picture and are computed differently. Boundary count is a total over the whole tree; depth is the length of one path through it, from the root down to a leaf. A tree can gain boundaries without gaining depth — add three more companies under an existing supervisor and the count rises while every finding still crosses two hops.

Keeping them apart matters because they scale different costs. Boundary count scales the number of places a handoff can go wrong at all. Depth scales how many rewrites a single piece of information survives before it reaches the answer, and each rewrite is a place where a number can be rounded, a caveat dropped, or a source URL lost.

The rewrite is not an accident that better prompting removes, and the reason is worth stating as a chain rather than asserted. A supervisor exists to shrink what its parent has to hold. Shrinking means choosing which of the material coming up is worth carrying further. Choosing means the material not chosen is absent from everything above that point. So a level converts the orchestrator can see all the findings into the orchestrator can see what two delegates decided to show it, and that conversion is the level working correctly rather than failing.

A brief going down and a contract coming up

The pair of artefacts at each boundary is the thing you are actually designing, so write them as types rather than as prose in a system prompt. The delegation brief is what the parent hands down: the scope of work, the constraints the parent is accountable for, and the identifiers that let you follow the handoff afterwards in a trace, meaning the ordered record of every call a run made, each hop tagged so it can be pulled up again by name. The return contract is the shape the parent will accept back, enforced rather than hoped for.

python
from dataclasses import dataclass, field

@dataclass(frozen=True)
class DelegationBrief:
    run_id: str            # one per weekly brief
    boundary_id: str       # e.g. "root>infra", "infra>corveil"
    parent_id: str | None  # boundary_id of the hop above, None at the root
    scope: list[str]       # the companies this delegate owns, enumerated
    constraints: list[str] # travels down unchanged at every hop
    return_schema: dict    # the contract the delegate must satisfy

BRIEF_CONSTRAINTS = [
    "Every numeric claim carries a source URL.",
    "Financial figures must be from FY2026 filings or later.",
    "Do not quote pricing that appears only in a press release.",
]

Each field of DelegationBrief answers a question somebody would otherwise have to answer by reading a prompt. scope says what this delegate owns. constraints says what it is held to. boundary_id and parent_id say where in the tree the handoff happened, so a record emitted at a leaf can be walked back up to the root. return_schema says what the parent will accept, which is the half that makes the boundary checkable at all.

The return schema is the half engineers most often leave implicit, and the reason it matters is a matter of what a caller can do with what it receives. A sector supervisor that returns three paragraphs of well-written prose has returned something no caller can validate; there is no predicate over English that says whether all three companies are present. A sector supervisor that returns the structure below has returned something the orchestrator can reject before it ever reaches the brief, because presence, sourcing and dating are all set membership and field checks.

python
SECTOR_RETURN_SCHEMA = {
    "type": "object",
    "additionalProperties": False,
    "required": ["boundary_id", "companies", "unresolved"],
    "properties": {
        "boundary_id": {"type": "string"},
        "companies": {
            "type": "array",
            "items": {
                "type": "object",
                "additionalProperties": False,
                "required": ["name", "positioning", "claims"],
                "properties": {
                    "name": {"type": "string"},
                    "positioning": {"type": "string"},
                    "claims": {
                        "type": "array",
                        "items": {
                            "type": "object",
                            "additionalProperties": False,
                            "required": ["statement", "source_url", "as_of"],
                            "properties": {
                                "statement": {"type": "string"},
                                "source_url": {"type": "string", "format": "uri"},
                                "as_of": {"type": "string", "format": "date"},
                            },
                        },
                    },
                },
            },
        },
        "unresolved": {"type": "array", "items": {"type": "string"}},
    },
}

additionalProperties: False appears at every level of that schema on purpose. Without it a delegate can satisfy the contract and also attach fields nobody asked for, and the parent has no way to tell an agreed field from an invented one. With it, the set of things that can cross the boundary is closed, which is what makes a later check a comparison against a known list rather than an inspection.

The call that a sector supervisor makes is then ordinary, and deliberately so — there is nothing exotic at a delegation boundary, which is part of why the extra cost is easy to overlook.

python
import anthropic

client = anthropic.Anthropic()

def run_sector_supervisor(brief: DelegationBrief, worker_reports: list[dict]) -> dict:
    response = client.messages.create(
        model="claude-opus-5",
        max_tokens=16000,
        system=(
            f"You supervise research on: {', '.join(brief.scope)}.\n"
            "You do no research yourself. Reconcile the worker reports you are "
            "given into one sector summary. Drop no constraint you were handed:\n"
            + "\n".join(f"- {c}" for c in brief.constraints)
        ),
        output_config={"format": {"type": "json_schema",
                                  "schema": brief.return_schema}},
        messages=[{"role": "user", "content": json.dumps(worker_reports)}],
    )
    return json.loads(response.content[0].text)

Two things in that function are decisions rather than requirements, and it is worth separating them. Enforcing the return schema at the boundary is a requirement: without it there is no contract, only a hope. Naming the scope in the system prompt while also carrying it in brief.scope is a decision — the same list is now in two places, which is redundancy bought deliberately so that the model sees the companies and the code can still check them.

The unresolved field is not decoration either. A delegate that could not satisfy the brief has exactly two honest options: fail the contract, or return successfully while saying what it could not establish. A contract with no room for the second option leaves a delegate that has hit a genuine dead end with nothing legal to return, and pushes it toward quiet invention, because a plausible-looking claim is the only shape the schema accepts.

The level buys context, and the invoice is in tokens

Design B does buy something real, and it is measurable. A research worker on this task returns roughly 4,200 tokens of raw findings — extracted filing text, quoted positioning language, a dozen URLs. In Design A all six of those land in the orchestrator's context before it writes anything, so multiplying one worker's output by the number of workers gives about 25,000 tokens of unstructured research in front of it, plus the system prompt. In Design B the orchestrator sees two sector summaries of roughly 1,100 tokens each, which is the same multiplication over a much smaller unit. Its writing step runs with about a tenth of the input, and the compression happened in two places that each had only three companies to hold in mind.

The invoice for that is three separate things, and only the first is obvious. Two extra inference calls, adding roughly 26,000 input and 1,100 output tokens between them, cost about $0.16 per run at Opus pricing of $5 per million input and $25 per million output. That figure is worth working rather than accepting, because the shape of the arithmetic explains why the number is small. Multiply the input tokens by the input rate, multiply the output tokens by the output rate, and add the two products. At $5 per million the input side carries most of the total, and the output side is a small addition on top of it even though its rate is the higher of the two, because there are so few output tokens to price. The cost row of the table below carries the same difference between the two designs, computed independently from the whole run, which is the check that the pair of calls is what accounts for it.

The second cost is that summarisation is lossy on purpose: the sector supervisor decides which of Corveil's twelve extracted claims are worth carrying up, and the orchestrator can no longer see the ten it dropped. The third is that BRIEF_CONSTRAINTS now has to survive two hops instead of one. In Design A the constraint about press-release pricing is in the same prompt as the work; in Design B it is in the supervisor's prompt, and the supervisor has to restate it in the worker's brief.

That third cost has a mechanism under it that is easy to skip past. A constraint is only in force where it is read. In Design B the agent that reads BRIEF_CONSTRAINTS is not the agent that does the fetching, so the constraint reaches the work only if the supervisor writes it into the brief it emits. A supervisor writing a brief is generating text, and generated text paraphrases. A supervisor that renders "do not quote pricing that appears only in a press release" as "prefer official sources" has produced a defensible summary that permits exactly the thing the original forbade, and it has quietly loosened the constraint for three companies at once. Passing the constraints as a list that travels unchanged, rather than as a sentence the supervisor rewrites, is what the constraints field in DelegationBrief exists to make possible.

The two designs, priced side by side

Putting them in one table makes the purchase concrete, and the rows are chosen so that each one is a quantity you can read off a trace rather than an impression formed in a review.

DimensionDesign A (depth 1)Design B (depth 2)
Delegation boundaries68
Times the task is restated before work starts12
Inference calls per run79
Tokens in front of the agent that writes the brief~25,400~2,600
Agents that ever hold all six companies at once10
Places a constraint can be paraphrased on the way down68
Research tool calls~54~54
Cost per run at Opus rates~$1.90~$2.06

Read the table by its gaps rather than its levels, and most of the rows turn out to be saying one thing twice. Boundaries, places a constraint can be paraphrased, and inference calls all move by the same small amount, because they are three views of the same two extra delegates. The tool-call row does not move at all. The cost row barely moves.

One row moves differently, and it is the row people do not expect: the count of agents that ever hold all six companies goes from one to zero. Every other row is a difference of degree; that one is a difference in kind, because zero is not a smaller version of one. In Design A the orchestrator has every company's findings in front of it at the moment it writes, so a question like which of these six has the cheapest entry tier is answerable by looking. In Design B no agent ever holds more than three, and the orchestrator holds two summaries that were each written without knowledge of the other. A cross-sector comparison in Design B is a comparison of two compressions rather than of the material underneath them, and those compressions were performed by delegates that did not know a comparison was coming. How much that costs depends on the output template: a brief that reports each company independently loses nothing, while a brief that opens with a positioning matrix across all six loses the evidence the matrix is built from.

The cost row is close enough between the designs to be uninteresting, which is worth stating plainly because it misdirects a lot of design discussion. Hierarchy is not expensive because supervisors are expensive. Six research workers making about nine web fetches each dominate the invoice in both designs, and the two supervisor calls add roughly 8% to it. The costs that actually separate the designs do not appear on an invoice at all: a rewrite that every finding must survive, a constraint that every supervisor must restate, and a boundary that every reliability metric must be attributed across.

Parallelism, domain knowledge and failure isolation

Each of the properties below gets attributed to the middle layer in reviews, and none of them comes from it. Naming them individually is what stops the argument from restarting.

It does not add parallelism. Design A already runs six workers concurrently, and Design B runs the same six, now in two groups of three. It does not add domain knowledge: the model weights are identical and the sector framing is a prompt, available to either design. It does not by itself isolate failures, which is a claim worth deferring rather than dismissing — a supervisor can catch a bad worker result before it reaches the top, but only if something in its prompt or its contract makes it check, and "there is a layer there" is not a check. And it does not reduce the number of research calls, which is where the money is; the cost curve of this service is dominated by six workers doing web fetches, and no arrangement of supervisors above them changes that.

The tempting belief underneath all four is that a supervisor is a more capable agent than the thing it supervises. It is tempting because the word carries that meaning everywhere else it is used, and because the tree drawn on a whiteboard looks like a chain of increasing authority. What is actually true is that the supervisor is the same model with a smaller slice, and the only quantity the level moves is how much material any single call is asked to hold.

The organisation chart is the metaphor that supplies most of the intuition for these designs. It is an analogy and not a description, and it is worth being careful with because it imports properties the software does not have. A human sector lead accumulates context across quarters, learns which analysts hand back figures that hold up, carries a relationship with the person who commissioned the brief, and can be asked in November why they made a call in June. A sector supervisor is instantiated at the start of the run, keeps nothing after it, and has no memory that last Monday's Corveil worker returned a figure that had to be corrected.

The place the analogy breaks is exactly where its persuasive force comes from. Arguments for hierarchy drawn from how human organisations scale are drawn from persistence, accountability and relationship — a lead who remembers, who can be held to a past decision, who knows the person asking. None of the three survives the translation into a stateless delegate invoked once per run, so an argument that leans on them is arguing for a thing the design does not contain.

What the level does is create two new places where a task is described by one agent and interpreted by another. That is the whole purchase, and whether it is worth making depends entirely on what those descriptions contain. Boundaries are countable before anything is built, depth is countable from the same picture, and both are properties of the arrangement rather than of any agent's expertise — which is why the review's forty minutes on roles produced nothing and one minute of counting produced the decision.

The scope field in DelegationBrief is a list of company names for a reason: it is an enumeration, not a theme, and the two enumerations must not intersect. Nothing in the code above enforces that. Two supervisors handed overlapping or vaguely-worded scopes will both do exactly what they were told, and the brief that comes out the top will contain Corveil twice with two different revenue figures — a failure written into the delegation rather than into the workers.

Hierarchical / supervisor trees — read the current version at https://daviddominguez.dev/learn/en/hierarchical-supervisor-trees/a-second-level-buys-a-boundary-not-a-specialist

Back to top