The Supervisor That Should Have Been a For-Loop
Every night the same plan, a model call per dispatch, and about once a week it checked eleven services instead of twelve. A for-loop cannot skip an item; an agent orchestrating one eventually will.
A nightly ops pipeline had a supervisor agent. Its job: read the list of services to check, call a worker for each one, collect the results, and write a summary.
Every night it produced a plan that was identical to the previous night's plan. It spent a model call deciding what to do next before each dispatch. And roughly once a week it decided, for reasons visible only in the trace, to check eleven services instead of twelve.
The eleven-out-of-twelve nights are the point. A for loop cannot skip an item. An agent orchestrating that loop can, and eventually will.
Five responsibilities, one question
A supervisor is usually doing five things:
- Decompose the task into work items
- Dispatch each item to a worker
- Handle failures when an item comes back wrong
- Aggregate the results
- Decide it's finished
Ask of each: does this require judgment, given a policy I've already decided?
- Decompose — genuinely needs judgment when the work list isn't knowable in advance. Often the only one that does.
- Dispatch — iterate a list. No judgment.
- Handle failures — you already chose the policy: retry twice, then quarantine. Applying a policy is not judgment.
- Aggregate — collect, count, group. No judgment.
- Decide it's finished — every item has a terminal state. Arithmetic.
→ Four of the five are mechanics wearing an agent costume, and each one is a place where a nondeterministic component can make a decision you didn't want it making.
What you get by making the orchestrator code
It can't skip an item. The most valuable property, and the one the eleven-of-twelve nights were quietly costing.
The same input produces the same dispatch. Reruns are comparable; a difference in output means a difference in the work, not in the orchestration.
Failures follow the policy you wrote, not a policy improvised per run.
One model call per item instead of two. The dispatch decision was costing the same as the work.
It debugs with a stack trace. No trace-reading to find out why the third item never went out.
Resumption is trivial — the loop reads the ledger and continues, with no context to reconstruct.
The hybrid
Keep the model where judgment lives, and only there:
items = agent.decompose(task) # judgment — model
for item in items: # mechanics — code
result = agent.process(item) # judgment — model
if validate(result):
ledger.complete(item, result)
else:
ledger.retry_or_quarantine(item) # policy — code
summary = agent.summarize(ledger) # judgment — model
The model decomposes, does each item, and writes the summary. The loop dispatches, applies the failure policy, tracks state, and terminates. ✅ For a fixed nightly list, even decompose is unnecessary — the work list is configuration.
⚠️ What you actually give up
This isn't free, and the loss is specific: a code loop cannot react to what a worker found.
If checking service four reveals a database problem that makes checks five through twelve irrelevant, the loop keeps going. If a worker's finding should redirect the remaining work, code can't do that — you'd need to encode the branch explicitly, and if there are many such branches you're writing a rule engine badly.
That's the real dividing line, and it's about whether items are independent:
- Independent items — twelve unrelated health checks, forty documents, six accounts to reconcile. Code orchestrates.
- Items that inform each other — an investigation where each finding changes the next question. Model orchestrates.
🔍 The diagnostic
Read a week of your supervisor's traces and answer one question: did it ever dispatch a different set of work than the work list implied?
- No — it's a for-loop with a per-decision cost and a nonzero error rate. Convert it.
- Yes, and the deviation was correct — it's genuinely adaptive. Keep it, and make sure the adaptation is visible in the output rather than silent.
- Yes, and the deviation was wrong — you've found your eleven-of-twelve, and you now know what it costs.
That third answer is common and rarely looked for, because a supervisor that mostly does the right thing produces output that mostly looks right.
When a model supervisor earns its place
- The work list can't be known up front — investigation, exploration, debugging.
- Findings in one item change the handling of others.
- Failure handling needs a judgment per case rather than a policy.
- The number of items is unbounded and depends on what's discovered.
Those are real situations. They're a minority of the pipelines that currently have a supervisor agent.
The takeaway
Split a supervisor into its five jobs and check which need judgment. Decomposition sometimes does; dispatch, failure policy, aggregation and termination essentially never. Put the model at the ends — decompose, process, summarize — and let ordinary code run the middle. You lose the ability to adapt mid-run, which matters only when items inform each other, and you gain a pipeline that cannot quietly do eleven twelfths of the work.