M

Claude isn't your best model, It's your best manager.

10 min readView source ↗

Cover image

Everyone's fighting over which LLM is smartest, that's the wrong fight, in a serious system, the model that matters most isn't a worker - it's the one deciding what the workers do, and judging whether they did it.

Call that role the meta-controller. Below is the first-principles case for why Claude fits it better than it fits the worker seat - and the full code to build one that plans, delegates to Grok / GPT / Llama, critiques the results, and then rewrites its own strategy.

The question everyone asks is the wrong one

"Which model is best?" assumes one model does everything. Real systems don't work that way. They have a division of labor: cheap models for bulk work, fast models for latency, specialized models for narrow domains, frontier models for hard reasoning.

Once you have many models, a new job appears - one that didn't exist when you had one. Someone has to decide what goes where, check what comes back, and fix the plan when it fails. That's not a worker. That's a manager.

Stop asking "which model is best." Ask "which model for which role." The scarce, high-leverage role isn't the smartest worker - it's the controller that routes, judges, and revises.

First principle: the controller is the bottleneck

Here's the math nobody puts on the slide. Errors compound in multi-step systems. If each step is 90% reliable and you chain five of them with no correction:

A pipeline of excellent models still produces mediocre results, because small failures multiply. The only thing that breaks the compounding is a step that catches and corrects - a controller that inspects each result and re-runs what failed.

Article image

In a chain, quality is capped by verification, not by the strongest link. A fleet of great workers with a weak controller loses to average workers with a strong one.

So the controller's work is different in kind from the workers'. Workers need knowledge and skill. The controller needs reasoning, memory of the whole task, reliability, and honest judgment. Those are the selection criteria - not trivia benchmarks.

What the controller role actually demands

Derive the requirements from the job, then pick the model. The controller must:

Decompose and plan - Turn a fuzzy objective into a routed graph of subtasks. Pure reasoning.

Hold the whole system in context - Every sub-result, every failure, the running plan. Long context is non-negotiable.

Follow the protocol exactly - Emit valid routing decisions every time. A controller that "gets creative" with its own output format takes the system down.

Judge honestly - Say "this failed" about work it just orchestrated. Calibrated self-critique, not cheerleading.

Stay steerable under pressure - Not drift, not go rogue, not quietly change the objective across a long run.

Why Claude fits the manager seat

Article image

Map those requirements onto what Claude is built for, and the fit is not an accident:

Steerability and reliability. Constitutional AI trains the model to follow a stated set of principles consistently. For a controller, "does exactly what the protocol says, run after run" is worth more than a few points of raw capability. A brilliant controller that ignores your output schema 5% of the time is a broken controller.

Reasoning depth. Decomposition, routing, and critique are reasoning tasks. This is where you want your strongest thinker and it's the one seat where paying frontier prices is justified, because there's only one controller and many workers.

Long context. The controller has to see the entire run - plan, every worker output, every verdict - to make the next decision. It's the most context-hungry seat in the system.

Willingness to say no. A good critic fails work that should fail. A model that flatters its own plan is useless as a judge. (More on the trap of self-judgment below.)

This is an argument about a role, not brand loyalty. Other models often make better workers - cheaper, faster, or stronger in a niche. Grok for fresh-web takes, a small local model for bulk classification, a code-specialized model for generation. The claim is narrow: Claude fits the controller seat well. Benchmark your own routing before you trust anyone's.

The architecture

One brain, many hands. Claude wears four hats - planner, router, critic, synthesizer. Everything else is a swappable worker.

Code - one interface over many models

Start with the boring part that makes everything else clean: hide every provider behind one call. (Model IDs here are examples - check each provider's current docs.)

Article image

Code - Claude plans and routes

The controller turns the objective into a routed list of subtasks. Force JSON so the output is machine-usable, and strip code fences (the one gotcha everyone hits):

"Return JSON only" works, but it can still drift. For anything real, force the schema with tool use - define the plan as a tool and let Claude fill the arguments. Then the structure can't break, and you delete strip_fences entirely.

Code - dispatch to the workers, in parallel

Code - Claude critiques the results

This is the load-bearing step. The controller reads every output and returns a verdict per subtask: keep it, retry it, or send it to a different model.

Claude critiquing a plan Claude wrote shares the same blind spots - exactly the weakness we hit with any self-review. So where ground truth exists, use it instead of opinion: run the tests, execute the code, check the number against a source. Reserve model-critique for the genuinely subjective calls (clarity, synthesis quality) - not as the only gate.

Code - the inner loop (fix the outputs)

The recursive move - Claude rewrites its own strategy

The inner loop fixes bad outputs. But sometimes the outputs are fine and the plan was wrong - bad decomposition, wrong model for the job, a missing step. A worker loop can't fix that. Only the controller, looking back at the whole attempt, can.

The distinction that makes it recursive

Inner loop: "this answer failed - redo it." Outer loop: "this approach failed - redesign it." The second one is the controller improving its own architecture, not just its outputs. That's the meta-controller.

Read the flow once and the whole idea clicks:

The part that will bite you

A meta-controller is not free. The controller sees everything, so its context and its bill - grows with the run. Every critique and every replan is another frontier-model call on top of the workers.

Guardrails, not vibes

Cap it hard: a token/dollar budget for the whole run, a max on inner rounds and outer attempts, and a rule that it hands off to a human when it hits either. Watch for two failure modes the controller over-decomposing a simple task into ten calls, and two workers contradicting each other with no ground truth to break the tie. Log the trace so you can see which it was.

When NOT to build this

Skip the controller

One-shot tasks. Anything a single strong model handles in one call. Here a meta-controller only adds latency, cost, and new ways to fail.

Build the controller

Multi-step work, mixed task types, real cost pressure (route cheap work to cheap models), or output you can't ship unverified. That's where routing + critique pays for itself.

The mental model to keep

Don't hire the smartest genius and make them do everything. Hire a great manager, give them a team of specialists, and let the manager plan the work, check it, and rethink the plan when it fails.

The workers are interchangeable. Swap Grok for the next hot model next month. The controller is the part you invest in - because it's the one seat where reasoning, memory, reliability, and honest judgment decide whether the whole system works.

One line

Pick your models for the worker seats. Engineer your controller for the manager seat. They're not the same job and confusing them is why most multi-model systems underperform a single good model.

You build your own life - so choose the right path. If this was useful - follow.

Prompts

class Budget:
    def __init__(self, usd): self.left = usd
    def charge(self, model, tok_in, tok_out):
        self.left -= cost(model, tok_in, tok_out)
        if self.left <= 0:
            raise RuntimeError("budget exhausted — handing off to human")
def execute(objective, prior=None, max_rounds=3):
    subtasks = plan(objective, prior)["subtasks"]
    results  = dispatch(subtasks)
 
    for _ in range(max_rounds):
        verdicts = critique(results)
        failing  = [v for v in verdicts if v["verdict"] != "PASS"]
        if not failing:
            break
        for v in failing:                       # retry or reroute only what failed
            t = next(r for r in results if r["id"] == v["id"])
            t["worker"] = v["reroute_to"] or t["worker"]
            t["output"] = call_model(t["worker"], WORKER_SYSTEM, t["goal"])
 
    return synthesize(objective, results), results
 
def synthesize(objective, results):
    prompt = f"Objective: {objective}\n\nParts:\n" + json.dumps(results, ensure_ascii=False)
    return call_model("claude", "Merge the parts into one coherent answer.", prompt)
import json, re
 
def strip_fences(s):                       # models love wrapping JSON in json
    return re.sub(r"^(json)?|$", "", s.strip(), flags=re.M).strip()
 
PLANNER_SYSTEM = """You are the controller of a multi-model system.
Decompose the objective into the FEWEST subtasks that solve it.
For each, pick the best worker and justify the choice by capability,
not habit. Respond with JSON only — no prose, no fences."""
 
WORKERS = """grok  — real-time web, current events (medium cost)
gpt   — general reasoning, broad knowledge (high cost)
llama — bulk text, classification, drafts (near-zero cost)"""
 
def plan(objective, prior=None):
    prompt = f"""OBJECTIVE:
{objective}
 
WORKERS:
{WORKERS}
"""
    if prior:                              # outer loop feeds last critique back in
        prompt += f"\nLAST ATTEMPT FAILED BECAUSE:\n{prior}\nFix the STRATEGY.\n"
    prompt += """
Return: {"subtasks":[
  {"id":"t1","goal":"...","worker":"grok","reason":"..."}]}"""
    return json.loads(strip_fences(call_model("claude", PLANNER_SYSTEM, prompt)))
ARCHITECT_SYSTEM = """You are reviewing your own orchestration strategy.
Look past individual outputs. Did the DECOMPOSITION or ROUTING itself fail?
Return JSON: {"good_enough":bool, "diagnosis":"...", "fix":"..."}"""
 
def meta_loop(objective, max_attempts=2):
    lesson = None
    for attempt in range(max_attempts):
        answer, trace = execute(objective, prior=lesson)      # plan is informed by last lesson
        review = json.loads(strip_fences(call_model(
            "claude", ARCHITECT_SYSTEM,
            f"Objective: {objective}\nWhat we tried:\n{json.dumps(trace, ensure_ascii=False)}")))
        if review["good_enough"]:
            break
        lesson = review["diagnosis"] + " → " + review["fix"]   # feeds back into plan()
    return answer
 
from concurrent.futures import ThreadPoolExecutor
 
WORKER_SYSTEM = "Do exactly the task. Be concise. State assumptions."
 
def dispatch(subtasks):
    def run(t):
        out = call_model(t["worker"], WORKER_SYSTEM, t["goal"])
        return {**t, "output": out}
    with ThreadPoolExecutor(max_workers=4) as pool:   # independent subtasks run at once
        return list(pool.map(run, subtasks))
meta_loop
  └─ plan            Claude designs the architecture
       └─ dispatch   workers (Grok / GPT / Llama) execute in parallel
            └─ critique   Claude judges each result   ← inner loop ↺
       └─ review     Claude judges the STRATEGY       ← outer loop ↺
  └─ replan with the lesson, or stop
0.90 ^ 5  =  0.59      # five good models, 59% end-to-end
0.95 ^ 5  =  0.77      # even great models decay when chained
 
                   ┌─────────────────────────┐
                    │   CLAUDE (controller)   │
                    │  plan · route · judge   │
                    └───────────┬─────────────┘
              ┌─────────────────┼─────────────────┐
              ▼                 ▼                 ▼
        ┌──────────┐      ┌──────────┐      ┌──────────┐
        │  Grok    │      │  GPT     │      │  Llama   │
        │ web/now  │      │ general  │      │ cheap    │
        └────┬─────┘      └────┬─────┘      └────┬─────┘
             └─────────────────┼─────────────────┘

                    ┌─────────────────────────┐
                    │  CLAUDE critiques ↺      │
                    │  pass / retry / reroute  │
                    └─────────────────────────┘
CRITIC_SYSTEM = """You are the critic. You did NOT produce these outputs.
Judge each against its goal. Be strict: a false PASS is the worst outcome.
For each subtask return verdict = PASS | RETRY | REROUTE.
If REROUTE, name a better worker. JSON only."""
 
def critique(results):
    prompt = ("Judge each result:\n\n"
              + json.dumps(results, ensure_ascii=False, indent=2)
              + """\n\nReturn: {"verdicts":[
  {"id":"t1","verdict":"PASS","reason":"...","reroute_to":null}]}""")
    return json.loads(strip_fences(call_model("claude", CRITIC_SYSTEM, prompt)))["verdicts"]
rom anthropic import Anthropic
from openai import OpenAI   # OpenAI, xAI, and local vLLM/Ollama all speak this shape
 
anthropic = Anthropic()
clients = {
    "openai": OpenAI(),
    "xai":    OpenAI(base_url="https://api.x.ai/v1"),
    "local":  OpenAI(base_url="http://localhost:11434/v1"),
}
 
MODELS = {
    "claude": {"provider":"anthropic", "id":"claude-opus-4-8"},   # the controller
    "gpt":    {"provider":"openai",    "id":"gpt-5.1"},
    "grok":   {"provider":"xai",       "id":"grok-4"},
    "llama":  {"provider":"local",     "id":"llama-4-70b"},
}
 
def call_model(name, system, prompt, max_tokens=2000):
    m = MODELS[name]
    if m["provider"] == "anthropic":
        r = anthropic.messages.create(
            model=m["id"], max_tokens=max_tokens, system=system,
            messages=[{"role":"user", "content":prompt}],
        )
        return r.content[0].text
    r = clients[m["provider"]].chat.completions.create(
        model=m["id"],
        messages=[{"role":"system","content":system},
                  {"role":"user","content":prompt}],
    )
    return r.choices[0].message.content

Related articles