Agents and orchestration patterns

The catalog of orchestration patterns for Claude-based agents — supervisor-worker, swarm, ReAct, Plan-and-Solve, handoff protocols — plus Anthropic’s own published guidance on building production agents. The headline insight from Anthropic’s engineering posts: most production agents should be simple LLM-plus-tools loops, not multi-agent systems. Multi-agent is an optimization for specific bottlenecks (context window, parallelism, expertise routing), not a default architecture. This note covers the building blocks (single-agent loop, subagents, agent teams, background agents), the named patterns (supervisor-worker, ReAct, Plan-and-Solve, handoff, swarm), the context-engineering rules (memory tool, just-in-time retrieval, compaction), and the production lessons.

See also

1. Anthropic’s published canon

Three engineering posts define Anthropic’s thinking on agents (cite them when you need the source):

  1. Building effective agents (Dec 2024) — the foundational piece. Distinguishes “workflows” (predefined steps with LLM in loops) from “agents” (LLM-directed). Argues most use cases want workflows.

  2. Effective context engineering for AI agents (2025) — the memory + just-in-time retrieval playbook. Introduces the pattern behind the memory tool.

  3. Effective harnesses for long-running agents (2025) — for multi-day software-engineering agents. Initializer + recovery pattern.

These are opinionated — Anthropic explicitly rejects some patterns popular in other camps (heavy multi-agent, blackboard architectures, MOA).

2. The single-agent loop (the baseline)

The unit of all agent architectures. Pseudo-code:

messages = [{"role": "user", "content": initial_prompt}]
while True:
    response = client.messages.create(model=..., tools=tools, messages=messages)
    messages.append({"role": "assistant", "content": response.content})
    
    if response.stop_reason == "end_turn":
        break
    
    if response.stop_reason == "tool_use":
        tool_uses = [b for b in response.content if b.type == "tool_use"]
        tool_results = [dispatch(tu) for tu in tool_uses]
        messages.append({"role": "user", "content": tool_results})
    
    if response.stop_reason == "max_tokens":
        # Continue or abort
        break

Bound the loop:

  • Max turns (max_turns in SDK, --max-turns in CLI)
  • Max dollars (--max-budget-usd)
  • Repeated-tool detection (same tool + same input N times → break)
  • Token budget across turns

This loop is the foundation of Claude Code, the Agent SDK, and every Anthropic example agent.

3. Building blocks Claude provides

PrimitiveWhereWhat for
SubagentsSame process, separate context windowSave context window; specialize roles; restrict tools
Background agentsSeparate subprocess (Claude Code daemon)Long-running tasks, parallel sessions
Agent teamsMultiple subagents communicatingCoordinated multi-role work
Task / Agent toolBuilt-in toolSpawn subagents
AskUserQuestion toolBuilt-in toolMultiple-choice user input mid-task
Memory toolTool primitivePersistent state across context resets
HooksSettings file or SDK callbacksDeterministic policy enforcement
CompactionBuilt-inServer-side context summarization
SkillsMarkdown + frontmatterReusable task playbooks

4. Named orchestration patterns

4.1 Workflow vs agent (Anthropic’s framing)

TypeDefinitionExample
WorkflowLLM and tools orchestrated through predefined code pathsChain: classify → extract → format → send
AgentLLM dynamically directs its own processes and tool usage”Find and fix the bug in auth.py”

Workflows are more predictable, easier to evaluate, cheaper. Agents are more flexible but harder to test and bound.

Per Anthropic: prefer workflows. Use agents only when:

  • The task can’t be decomposed in advance (unknown # of steps)
  • The agent needs to reason about results to decide next step
  • The work is open-ended (research, exploration)

4.2 Prompt chaining (workflow pattern)

Sequential LLM calls where each output feeds the next input. Optional gates check intermediate output before continuing.

Input → LLM 1 (extract) → gate (validate) → LLM 2 (transform) → LLM 3 (format) → Output

Use when: task naturally breaks into subtasks; subtasks are simpler than the whole.

4.3 Routing (workflow pattern)

Classify input → dispatch to specialized prompt.

Input → LLM 1 (classify intent) → ┬─ LLM A (handle refunds)
                                  ├─ LLM B (handle technical)
                                  └─ LLM C (handle billing)

Use when: distinct categories with different best handlers; one-size-fits-all is too generic.

4.4 Parallelization (workflow pattern)

  • Sectioning: split task into independent subtasks, run in parallel, aggregate. (“Read each file, summarize, then merge summaries.“)
  • Voting: same task N times, take majority. (Adversarial filtering, content moderation.)

Use when: parallelizable work and aggregation is cheap.

4.5 Orchestrator-workers (workflow pattern)

Central LLM dynamically breaks down task, delegates subtasks to worker LLMs, synthesizes results. Different from routing — the breakdown is dynamic, not predefined.

This is what Claude Code does with the Agent tool. Main thread = orchestrator; subagents = workers.

4.6 Evaluator-optimizer (workflow pattern)

One LLM generates, another evaluates and provides feedback, loop until acceptance. Useful for high-stakes generation (legal text, code, designs) when you have clear evaluation criteria.

4.7 ReAct (Reason + Act) — agent pattern

The classic pattern: model emits Thought → Action → Observation in a loop.

Implemented in Claude via:

  • Extended / adaptive thinking (thinking blocks) — handles “Thought”
  • Tool use — handles “Action”
  • Tool results — handles “Observation”

Out of the box. Don’t reimplement the ReAct paper — Claude does it natively.

4.8 Plan-and-Solve — agent pattern

Force explicit planning before execution:

Step 1: Generate a numbered plan (don't execute yet)
Step 2: Execute the plan step by step
Step 3: Verify final result

Claude Code’s plan mode (/plan or --permission-mode plan) bakes this in — Claude can only read until you approve the plan, then it executes.

Most useful when:

  • Stakes are high
  • The task has multiple correct paths and you want to choose
  • You want a chance to abort before mutation

4.9 Supervisor-Worker — multi-agent pattern

A supervisor agent (often Opus) coordinates worker agents (often Sonnet or Haiku) that execute subtasks.

In Claude Code: main thread is supervisor, subagents are workers. In SDK:

options = ClaudeAgentOptions(
    model="claude-opus-4-7",         # supervisor
    agents={
        "researcher": AgentDefinition(model="haiku", tools=["Read", "Grep"], ...),
        "implementer": AgentDefinition(model="sonnet", tools=["Edit", "Write", "Bash"], ...),
        "reviewer": AgentDefinition(model="opus", tools=["Read", "Grep"], ...),
    },
    allowed_tools=["Agent", "Read"],
)

Use when: clear functional decomposition + workers benefit from constrained context.

4.10 Swarm / handoff — multi-agent pattern (OpenAI’s framing)

Agents pass control to each other based on conditions. Each agent has its own tools and system prompt; explicit handoff tools route to peers.

Less common in Claude land — Anthropic generally prefers supervisor-worker because handoff is harder to reason about. Implementable in Agent SDK via shared session and --agent switching.

4.11 Background agents (parallelism via separate sessions)

Per agent view docs: Claude Code can run up to 12 background agents in parallel via a daemon (claude daemon). Each has its own session, independent of yours. Coordinate via:

  • Shared files
  • Memory tool (with shared paths)
  • A coordinator script that dispatches via claude --bg "task" --agent worker

Use when: truly parallel work; want to keep main session interactive.

4.12 Agent teams (in-session communication)

Per agent teams docs: multiple subagents that can message each other during a session via the SendMessage tool. Different from Task tool (one-shot dispatch with summary return).

Use when: agents need to negotiate or share intermediate results.

5. Context engineering for long-running agents

Per Effective context engineering for AI agents:

5.1 Just-in-time retrieval, not upfront dumping

Instead of stuffing the context window with everything you might need:

  • Store reference material in the memory tool (/memories directory)
  • Agent reads only what’s needed for the current step
  • Keeps active context focused

5.2 Memory tool patterns

Per the memory tool docs (see computer-use-and-code-execution §8):

Multi-session software-development pattern:

  1. Initializer session sets up:
    • Progress log (/memories/progress.md)
    • Feature checklist (/memories/features.md)
    • Reference to startup/init script
  2. Each subsequent session opens by reading these artifacts → recovers state in seconds.
  3. End-of-session update writes completion / what’s-next.
  4. Mark feature complete only after end-to-end verification.

Auto-injected system prompt when memory tool is enabled:

IMPORTANT: ALWAYS VIEW YOUR MEMORY DIRECTORY BEFORE DOING ANYTHING ELSE.
MEMORY PROTOCOL:
1. Use the `view` command of your `memory` tool to check for earlier progress.
2. ... (work on the task) ...
   - As you make progress, record status / progress / thoughts etc in your memory.
ASSUME INTERRUPTION: Your context window might be reset at any moment.

5.3 Compaction

Server-side conversation summarization when approaching context limit. Triggered automatically. Memory + compaction together = long-running agents survive across context resets.

Per code.claude.com/docs/en/how-claude-code-works#when-context-fills-up:

  • Skill content re-attached after compaction (first 5,000 tokens; 25,000 token combined budget for re-attached skills)
  • Recent tool results preserved
  • Older content summarized

5.4 Context editing

Client-side: explicitly clear specific tool results from context (e.g. large file contents that Claude no longer needs). See Context editing docs.

Memory + compaction + context editing form the long-running-agent stack.

6. Effective harnesses for long-running agents

Per Effective harnesses for long-running agents:

  1. Define done explicitly. The agent doesn’t get to decide what “complete” means; the harness does (test passes, build succeeds, user approves).
  2. Verify end-to-end. Code-passes-typecheck ≠ feature-works. Run the app.
  3. Recover from any state. Sessions can crash at any token. State must be reconstructable from disk (memory tool + git + your checklists).
  4. Bound iterations. Max turns per subtask, max retries per tool.
  5. Distinguish forward progress from churning. If feature N has been “in progress” for 3 sessions, escalate to a human.
  6. One feature at a time. Don’t let scope creep across sessions.

7. Production lessons

Distilled from Anthropic’s posts + Claude Code’s own codebase:

7.1 Simple > clever

Most agentic systems should be a single agent with good tools, not a swarm. Multi-agent complexity exists to solve specific problems (parallelism, context window, expertise routing); apply it only when those problems exist.

7.2 Evaluate constantly

You can’t have a serious agent without evals. Per Anthropic’s evals guidance:

  • Define success criteria up-front
  • Build a test set
  • Run on every prompt change
  • Track regressions per metric

7.3 Cost-aware routing

Run cheap models for cheap tasks. Common pattern: Haiku does extraction, Sonnet does reasoning, Opus does generation or critique. See claude-models-and-capabilities pricing table.

7.4 Determinism where possible

Hooks for hard rules (block rm -rf, auto-format on every edit). Skills for repeatable procedures. Subagents for constrained roles. Reserve LLM freedom for actually-judgement-required steps.

7.5 Human-in-the-loop for high-stakes actions

Per the computer-use safety floor: always require human confirmation for delete, payment, sign-out, ToS-accept, destructive shell commands. Use permissions.ask[] for the lighter version, prompt-injection classifiers for the heavier.

7.6 Observability

Use OpenTelemetry from Claude Code (per OTEL_* env vars in claude-code-cli) or instrument your Agent SDK code with traces/metrics/logs. Long-running agents fail in opaque ways without observability.

7.7 Sandbox aggressively

Per Claude Code sandbox: bash sandboxing via bubblewrap (Linux), filesystem allow/deny lists, network allow/deny lists. For agents that touch arbitrary user-provided URLs or content, sandbox is not optional.

8. Anti-patterns

  1. Multi-agent for solo work — coordination overhead exceeds benefit.
  2. Blackboard architectures — multiple agents read/write shared state. Race conditions; hard to reason about. Use one agent + memory tool.
  3. Stuffing everything in context — works until it doesn’t. Use just-in-time retrieval + memory tool.
  4. No bounding — unbounded loops on bad tools burn tokens fast. Always cap.
  5. No verification — generation without verification is hopeful, not effective.
  6. One giant prompt — break it into stages with explicit handoffs.
  7. Reimplementing ReAct from scratch — Claude does this natively; don’t add a parsing layer.
  8. MOA (Mixture of Agents) for everything — useful for specific tasks (debiased generation), not a default.
  9. Subagents as namespacing — if you’re just organizing prompts, use skills, not subagents.

9. Worked example: multi-day refactor agent

Combining all the above into a multi-day refactor of a large codebase:

# .claude/agents/refactor-coordinator.md
---
name: refactor-coordinator
description: Coordinates a multi-day refactor; maintains progress in memory
tools: Read, Glob, Grep, Bash, Agent, mcp__memory__view, mcp__memory__create, mcp__memory__str_replace
model: opus
memory: project
---
 
You coordinate a multi-day refactor. On every session:
1. View `/memories/refactor-plan.md` to see the plan.
2. View `/memories/progress.md` to see what's done.
3. Pick the next feature.
4. Dispatch the `refactor-implementer` subagent for the feature.
5. After it returns, dispatch the `refactor-reviewer` subagent.
6. If review passes, run the test suite via Bash.
7. If tests pass, update `/memories/progress.md`.
8. If anything fails, log to `/memories/blockers.md` and stop.
# .claude/agents/refactor-implementer.md
---
name: refactor-implementer
description: Implements one feature of the refactor
tools: Read, Edit, Write, Bash, Glob, Grep
model: sonnet
permissionMode: acceptEdits
maxTurns: 30
---
 
You implement one feature of the refactor. ...
# .claude/agents/refactor-reviewer.md
---
name: refactor-reviewer
description: Reviews the implementer's work
tools: Read, Grep, Bash(git diff *)
model: opus
disallowedTools: Write, Edit
maxTurns: 10
---
 
You review the implementer's changes. Focus on correctness, regressions, style. ...

Run on a schedule:

# .claude/settings.json schedule via routine, or cron:
0 9 * * * claude --bg --agent refactor-coordinator "continue the refactor"

The supervisor-worker pattern + memory tool + bounded subagent turns + cheap-model-for-implementer + expensive-model-for-reviewer = a robust multi-day agent.

10. Further reading