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:

  1. Decompose the task into work items
  2. Dispatch each item to a worker
  3. Handle failures when an item comes back wrong
  4. Aggregate the results
  5. 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.

Keep reading

Similar posts

Matched on shared tags and category — the more bars, the stronger the overlap with what you just read.