Chapter 14 — Hierarchical Agents and Subtasks
ShopOps now runs four agents — Intake, Resolution, Policy, Outreach — but four prompts are not a hierarchy. If Intake mounts Outreach’s send_email because every worker shares one tool list, Intake can send despite its role. That is shared authority with labels, not design.
Supervisor–worker means modularity with contracts: delegate a bounded task, grant only needed capabilities, verify before advancing.
supervisor → TaskContract → worker run → schema verify → accept | reject | fail upward
This chapter adds task contracts — worker id, input/output schema, step budget, capability set, verification rule — and a capability firewall so O-1001 handoffs stay accountable.
First principles
A task contract makes the boundary concrete:
- who runs it (
worker) - input / output schema
- step and token budgets
- capabilities (read / propose / draft / send / …)
- verification rule (schema + optional semantic checks)
For O-1001, Intake reads the customer profile and returns structured facts. Resolution classifies the order issue. Policy issues a verdict. Outreach creates a draft—or sends only when separately authorized. Each handoff has an expected result, allowed tools, and a failure path.
The supervisor:
- Assigns a contract
- Runs the worker (or refuses capability violations)
- Validates the result
- Accepts, rejects (verify-reject loop), or fails upward
Recursive delegation needs a depth limit; otherwise a worker can spend the case budget spawning more workers. Hierarchy does not increase intelligence. It adds isolation, review points, and explicit accountability when those costs are justified.
Concrete example
Intake worker for O-1001 may read CRM and write profile facts to the ledger. It must not send messages. In code, assigning capabilities={"read","send"} to worker="intake" fails immediately with capability_violation — before any model call.
Resolution returns {track, required_evidence}. If it omits required_evidence, supervisor status is REJECTED, not “close enough.”
Diagram
flowchart TB
Sup[Supervisor] -->|TaskContract| W1[Intake worker]
Sup -->|TaskContract| W2[Resolution worker]
W1 -->|result JSON| V{schema verify}
V -->|ok| Sup
V -->|reject| Sup
W1 -.->|no send capability| FW[context / capability firewall]
Context firewall (ASCII):
┌──────── supervisor state ────────┐
│ case_id, budgets, assignments │
└─────────────┬────────────────────┘
│ minimal input only
▼
┌──────── Intake worker ───────────┐
│ tools: get_customer, ... │
│ tools NOT mounted: send_* │
└──────────────────────────────────┘
Implementation
Reference module: shopops/orchestrator.py (Supervisor, workers).
from shopops.ledger import Ledger
from shopops.orchestrator import Supervisor, intake_worker, resolution_worker
from shopops.types import CaseState
sup = Supervisor({"intake": intake_worker, "resolution": resolution_worker})
state = CaseState(case_id="O-1001", order_total_cents=240_00)
ledger = Ledger("O-1001")
task = sup.assign(
"O-1001",
"intake",
{"stage": "intake"},
{"required": ["customer_id", "preferred_channel"]},
capabilities=frozenset({"read"}),
)
task = sup.run_task(task, state, ledger)
assert task.status.value == "done"
assert task.result["preferred_channel"] == "whatsapp"
# Capability split
bad = sup.assign(
"O-1001",
"intake",
{},
{"required": ["customer_id"]},
capabilities=frozenset({"read", "send"}),
)
bad = sup.run_task(bad, state, ledger)
assert bad.error == "capability_violation"
Verify-reject path: hand Resolution a schema requiring track and omit it from a stub worker — status REJECTED. Budget exhaustion is the worker’s problem to surface; the supervisor should fail the task when budget_steps would be exceeded (extend the stub in exercises).
Failure modes
- More agents = more intelligence — usually more race conditions (Ch 17).
- Prompt-only roles — same tool mount, different system text.
- Unbounded delegation — depth and fanout without caps.
- Accepting invalid JSON “to keep the pipeline moving.”
- Supervisor as mega-model — LLM invents workers each run; prefer closed worker registry.
Production considerations
- Mount tools per worker identity (Ch 27). Contracts are necessary but not sufficient without authz.
- Trace each task as a span with
task_id(Ch 23). - Reject loops need a max iterations → human.
- Share beliefs via ledger (Ch 16), not by dumping full supervisor chat into every worker.
- For many teams, hierarchy is plain functions with schemas until isolation requirements appear.
Failure propagation
When a worker fails, the supervisor must choose an explicit policy:
| Worker result | Supervisor default (ShopOps teaching code) |
|---|---|
| DONE + schema ok | accept; merge facts; continue |
| REJECTED schema | fail task (optionally one retry) |
| exception | fail task; do not invent filler facts |
| depth exceeded | fail closed |
Never “heal” a missing preferred_channel by asking the Resolution model to guess. Escalate or re-run Intake with a refresh flag. Hierarchy without failure propagation rules becomes a rumor mill: each layer polishes the last layer’s uncertainty into false confidence.
Budgets travel with the contract. A Intake task with budget_steps=4 that tries to spawn Enrichment must still fit inside the remaining budget or fail — recursive spend without accounting is how token burn appears “nowhere” in the parent dashboards.
Chapter summary
- Hierarchy = contracts + capabilities + verification, not job titles in prompts.
- Intake must not send — enforce in capability checks and tool mounts.
- Schema reject is a valid outcome.
- Delegation depth is budgeted.
- Supervisor schedules and verifies; it is not “the smart one.”
- Closed worker registries beat invented topologies.
- Context firewalls limit what each worker sees.
- Split only when Ch 15 reasons apply.
Exercises
- Implement budget exhaustion: worker that no-ops until
budget_steps, supervisor fails withbudget_exhausted. - Build a verify-reject loop that retries Resolution once on schema reject, then escalates.
- Add an
enrichmentworker and show depth-2 delegation; assert depth-3 fails. - Refactor a “three prompt agents” design doc into one module with three functions — note what you lost and what you gained.
References
- Multi-agent survey selections for taxonomy of roles vs processes. [VERIFY SOURCE]
- Anthropic. Building Effective Agents. 2024 — caution on multi-agent complexity. [VERIFY URL]
- Ch 5 (executor permissions) and Ch 27 (authz) — hierarchy without authz is theatre.