The Orchestrator Pattern for Claude Agents: Delegating Everything, Owning Nothing
by Mozi Mohidien
The most common mistake when building multi-agent systems with Claude is turning the orchestrator into a worker. It reads files. It edits code. It calls APIs directly. Within twenty turns, the orchestrator's context is bloated with tool output noise, the session is slow, and every response costs more than it should.
The fix is a strict rule: the orchestrator never acts. It only plans, delegates, and reviews.
The Core Rule
The orchestrator does exactly three things:
- Understand the task and break it down
- Brief and spawn agents to execute
- Review what comes back and surface the result to the user (or re-brief if it's wrong)
Everything else β file edits, terminal commands, API calls, deployments, web searches, browser navigation β goes through a spawned agent. The orchestrator touches nothing directly.
This sounds simple. It requires discipline to maintain, because the temptation to "just do it inline" is constant. One inline file read feels harmless. Ten turns later, the session context contains 40KB of raw file content that gets re-read on every subsequent turn.
Why Context Cost Matters More Than You Think
For Fable (claude-fable-5), cost hits from two directions.
Input: every turn re-reads the entire session context. A conversation that has accumulated tool outputs from twelve previous turns re-reads all of that on turn thirteen. Context does not get cheaper as the session grows β it gets more expensive per turn.
Output: Fable's thinking tokens bill as output. Even a short response with a thinking budget burns output tokens. The longer the session, the more the model thinks to navigate the accumulated context.
This is why the orchestrator rule has financial weight, not just architectural weight. An orchestrator that stays clean β no inline tool calls, no accumulated raw output β keeps per-turn cost low throughout the session. An orchestrator that acts directly starts cheap and gets expensive fast.
Handling Context Overflow
Sessions eventually get long. The right response is not to keep going β it is to hand off cleanly and restart.
The pattern:
- Append relevant updates to the brain files (MOZI.md, operate_with_intelligence.md, the relevant brief β whichever apply)
- Write
HANDOFF.mdβ the baton pass document - Touch a signal file that the watcher daemon is polling
- The watcher sees the signal file, kills the current session, starts a fresh one
# Trigger the restart
touch ~/mozi/second_brain/.restart_laptop
The watcher picks this up within 30 seconds. The new session starts with zero tool noise in context. Brain files carry forward the relevant state.
HANDOFF.md: Baton Pass, Not Log
HANDOFF.md has one job: give the next session exactly what it needs to continue, nothing more.
Hard constraints: under 30 lines, three fields only.
# Handoff
## Done this session
- Rebuilt the oper8 bot start.sh after model env var broke Telegram server mode
- Updated LEARNING_PATH.md with new MCP module completion
- Cleaned stale files from /mozi/university/
## Next step
Deploy the updated general_fable bot and verify it processes messages
## Urgent
None
That is the entire document. No audit lists. No issue inventories. No historical context. No "also worth noting" sections.
The reason for the constraint: HANDOFF.md gets read on every session start. Every line is input tokens. A 200-line HANDOFF becomes a tax on every single turn of the next session. Keep it short.
The next session overwrites it entirely. It is never accumulated. It is never a log of what has happened over time. It tells the next session exactly one thing: where to pick up.
The Quality Gate
The orchestrator is the last reviewer before output reaches the user. If an agent's output is incomplete, wrong, or mediocre, the user should never see it.
When an agent returns:
- Read the output critically
- Ask: does this fully achieve what was asked?
- If yes, surface it
- If no: diagnose exactly why it failed, refine the brief, re-spawn
Common failure modes to check for: agent completed the task technically but missed the actual goal; output is correct but needs synthesizing with another agent's output before it's useful; agent hit a blocker and returned a partial result without flagging it clearly.
"I couldn't do it" from an agent is never an acceptable final answer without investigation. The orchestrator probes: what specifically failed? Was it a missing credential? Wrong file path? Tool error? Then it fixes the brief and tries again, or finds a different approach.
Only when all paths are genuinely exhausted does the orchestrator surface to Mozi: here is what was tried, here is the blocker, here is what he needs to do.
Model Selection for Spawned Agents
Not every agent needs the same model. Over-provisioning burns budget. Under-provisioning produces worse results.
The decision matrix:
- Haiku β single-file reads, classification, simple lookups, anything with a short deterministic answer
- Sonnet β coding, file edits, multi-step execution, most tasks
- Opus β complex reasoning, architecture decisions, deep multi-step analysis requiring judgment
- Fable β only when the agent itself needs orchestration capability (rare; spawning a Fable agent to orchestrate sub-agents is usually the wrong design)
# Spawning examples
# Quick lookup β haiku
Agent(
model="haiku",
description="Look up contact number",
prompt="Read /Users/mozimohidien/mozi/second_brain/contacts.json and return the phone number for Ayesha Kader."
)
# Code edit β sonnet
Agent(
model="sonnet",
description="Edit start.sh model env var",
prompt="Edit /path/to/sessions/oper8/start.sh. Change ANTHROPIC_MODEL from claude-sonnet-4-6 to claude-fable-5. Test that the file is valid bash syntax after."
)
# Architecture review β opus
Agent(
model="opus",
description="Review MCP server design",
prompt="Review the design of the Telegram bridge MCP server at ~/.claude/plugins/telegram_bridge/server.ts. Identify any race conditions or failure modes in the polling loop."
)
The WhatsApp Flow Example
A concrete example of the full pattern: Mozi says "send a WhatsApp to Bilal saying the meeting is confirmed for Thursday at 3pm."
The orchestrator does not send the message. It does not look up the contact. Here is the flow:
Step 1: Read contacts.json to find Bilal's number. This is a simple lookup β haiku agent.
Agent(haiku): Read contacts.json, return phone number for "Bilal"
Result: +27821234567
Step 2: Brief a sonnet agent with everything it needs. No back-and-forth.
Agent(
model="sonnet",
description="Send WhatsApp to Bilal",
prompt="""
Send a WhatsApp message to +27821234567 (Bilal).
Message: "Hey β meeting confirmed for Thursday at 3pm."
Use this approach:
osascript -e 'open location "whatsapp://send?phone=27821234567&text=Hey%20%E2%80%94%20meeting%20confirmed%20for%20Thursday%20at%203pm."'
Run it and confirm it opens WhatsApp. Report back with success or failure and the exact error if it fails.
"""
)
Step 3: Review the result. Did WhatsApp open? Did the message send? If yes, tell Mozi it is done. If no, diagnose and try another approach (Playwright, direct API if configured).
The orchestrator never touched the terminal. It never read the contacts file directly. It planned, delegated both tasks cleanly, reviewed results, and reported.
Screen Lock Pattern
Some agents need to control the screen β browser navigation, clicking, form submission. Only one agent can do this at a time or they race each other.
Lock file: /Users/mozimohidien/mozi/second_brain/.screen_agent_active
Acquire before starting screen work:
# Check if another agent has the lock
if [ -f "/Users/mozimohidien/mozi/second_brain/.screen_agent_active" ]; then
echo "Screen already locked by another agent. Aborting."
exit 1
fi
# Acquire
touch /Users/mozimohidien/mozi/second_brain/.screen_agent_active
Release when done (always β even on failure):
# Release
rm -f /Users/mozimohidien/mozi/second_brain/.screen_agent_active
The orchestrator must never spawn two screen-active agents simultaneously. Before spawning an agent that needs screen access, check that no other screen agent is running. If the lock file exists, either wait or queue the task.
Cost Discipline Summary
Keep Fable orchestrators cheap:
-
CLAUDE_CODE_EFFORT_LEVEL=lowin every Fable bot'sstart.sh. Never remove it. - Restart sessions early β after heavy agent cycles, not just when approaching context limits. A short session with a tight handoff costs less per turn than a long one.
- No inline tool calls in the orchestrator β keep its context clean.
- Write tight briefs. Every line in a CLAUDE.md or HANDOFF.md is re-read on every turn. Ruthlessly cut anything stale.
The orchestrator's job is thinking, not doing. Keep its context lean so the thinking stays sharp.













