Skip to main contentSkip to footer
ExamplescriptadvancedRunnableguided-flow

Level 5: Multi-Agent Orchestration — Delegated Autonomy

An orchestrator delegates to specialized subagents defined via the agent runtime SDK. Each subagent has its own prompt, tools, and model. The orchestrator coordinates.

Key Facts

Level
advanced
Runtime
Python • Pydantic + Python Dotenv
Pattern
Inspectable flow with visible system boundaries
Interaction
Live sandbox • Script
Updated
14 March 2026

Navigate this example

High-level flow

How this example moves from input to execution and reviewable output
Level 5: Multi-Agent Orchestration —… -> Coordinate staged execution -> Run the agent task -> Load environment keys -> Constrain output schema -> Register tool actions

Start

Level 5: Multi-Agent Orchestration —…

Checkpoint

Coordinate staged execution

Outcome

Run the agent task

Why this page exists

This example is shown as both real source code and a product-facing interaction pattern so learners can connect implementation, UX, and doctrine without leaving the library.

Visual flowReal sourceSandbox or walkthroughMCP access
How should this example be used in the platform?

Use the sandbox to understand the experience pattern first, then inspect the source to see how the product boundary, model boundary, and doctrine boundary are actually implemented.

UX pattern: Inspectable flow with visible system boundaries
Design for delegation rather than direct manipulation
Replace implied magic with clear mental models
Represent delegated work as a system, not merely as a conversation
Source references
Library entry
agents-agent-complexity-5-multi-agent
Source path
content/example-library/sources/agents/agent-complexity/5-multi-agent.py
Libraries
pydantic, python-dotenv
Runtime requirements
Local repo environment
Related principles
Design for delegation rather than direct manipulation, Replace implied magic with clear mental models, Represent delegated work as a system, not merely as a conversation, Optimise for steering, not only initiating

Model context

Model-dependentRequires native tool callingHigh reasoning requirement

Multi-agent coordination requires reliable tool calling and structured output across agent boundaries. Failure modes compound across hops.

5-multi-agent.py

python
"""
Level 5: Multi-Agent Orchestration — Delegated Autonomy
An orchestrator delegates to specialized subagents defined via the Claude Agent SDK.
Each subagent has its own prompt, tools, and model. The orchestrator coordinates.

NOTE: Run with `python 5-multi-agent.py` (not IPython/Jupyter).

https://platform.claude.com/docs/en/agent-sdk/python
"""

import asyncio
import json
from pathlib import Path

from pydantic import BaseModel
from claude_agent_sdk import (
    AssistantMessage,
    ClaudeAgentOptions,
    ClaudeSDKClient,
    ResultMessage,
    TextBlock,
    ToolUseBlock,
    tool,
    create_sdk_mcp_server,
)
from claude_agent_sdk.types import AgentDefinition
from dotenv import load_dotenv

load_dotenv()

KNOWLEDGE_DIR = Path(__file__).parent / "knowledge"


# --- External API tools (shared across agents via MCP) ---


@tool(
    "check_payment_gateway",
    "Check payment processor for transaction status and refund eligibility",
    {"transaction_date": str, "amount": str},
)
async def check_payment_gateway(args):
    return {
        "content": [
            {
                "type": "text",
                "text": (
                    f"Payment Gateway Response for {args['transaction_date']} — ${args['amount']}:\n"
                    "- Transaction ID: txn_8f3k2j1\n"
                    "- Status: SETTLED\n"
                    "- Refund eligible: YES\n"
                    "- Original payment method: Visa ending in 4242\n"
                    "- Settlement date: 2025-02-02"
                ),
            }
        ]
    }


@tool(
    "issue_refund",
    "Process a refund through the payment gateway",
    {"amount": str, "reason": str, "customer_id": str},
)
async def issue_refund(args):
    return {
        "content": [
            {
                "type": "text",
                "text": (
                    f"Refund processed successfully:\n"
                    f"- Customer: {args['customer_id']}\n"
                    f"- Amount: ${args['amount']}\n"
                    f"- Reason: {args['reason']}\n"
                    "- Refund ID: ref_9x2m4p7\n"
                    "- ETA: 3-5 business days"
                ),
            }
        ]
    }


# --- Subagent definitions ---


AGENTS = {
    "researcher": AgentDefinition(
        description="Investigates billing issues by reading customer files and checking the payment gateway.",
        prompt=(
            "You are a billing research specialist. You have access to a knowledge base "
            "with customer profiles, policies, and templates. Investigate the issue thoroughly:\n"
            "1. Read the customer file to understand their history\n"
            "2. Check the payment gateway to verify the transaction\n"
            "3. Read the refund policy to determine eligibility\n"
            "Return a clear, factual summary of your findings."
        ),
        tools=[
            "Read",
            "Glob",
            "Grep",
            "mcp__billing-api__check_payment_gateway",
        ],
        model="haiku",
    ),
    "drafter": AgentDefinition(
        description="Drafts customer-facing responses using templates from the knowledge base.",
        prompt=(
            "You are a customer communications specialist. Draft a professional, empathetic "
            "response based on the research findings you receive. Use the response templates "
            "in the knowledge base as a starting point, then personalize for the customer."
        ),
        tools=["Read", "Glob"],
        model="haiku",
    ),
    "compliance_reviewer": AgentDefinition(
        description="Reviews proposed actions and responses for policy compliance.",
        prompt=(
            "You are a compliance reviewer. Verify that the proposed refund action and "
            "customer response follow company policy. Check the escalation matrix and "
            "refund policy. Flag any issues or approve the action."
        ),
        tools=["Read", "Glob"],
        model="haiku",
    ),
}


# --- Orchestrator ---


class CustomerEmail(BaseModel):
    subject: str
    body: str


class OrchestratorOutput(BaseModel):
    research_summary: str
    duplicate_confirmed: bool
    refund_amount: float
    compliance_approved: bool
    final_action: str
    customer_email: CustomerEmail


async def run_orchestrator(task: str):
    server = create_sdk_mcp_server(
        name="billing-api",
        version="1.0.0",
        tools=[check_payment_gateway, issue_refund],
    )

    options = ClaudeAgentOptions(
        system_prompt=(
            "You are a senior case manager. Resolve customer issues by delegating "
            "to your specialized team using the Task tool:\n\n"
            "1. 'researcher' — investigates billing data and payment gateway\n"
            "2. 'drafter' — writes customer-facing responses from templates\n"
            "3. 'compliance_reviewer' — checks policy compliance before sending\n\n"
            "Coordinate the workflow: research first, then draft, then compliance review. "
            "Pass findings between agents. After all agents report back, synthesize "
            "a final decision and present the approved response.\n\n"
            f"Knowledge base location: {KNOWLEDGE_DIR}"
        ),
        allowed_tools=[
            "Task",
            "Read",
            "Glob",
            "mcp__billing-api__check_payment_gateway",
            "mcp__billing-api__issue_refund",
        ],
        agents=AGENTS,
        mcp_servers={"billing-api": server},
        output_format={
            "type": "json_schema",
            "schema": OrchestratorOutput.model_json_schema(),
        },
        permission_mode="acceptEdits",
        max_turns=20,
        max_budget_usd=1.00,
        model="sonnet",
        cwd=str(KNOWLEDGE_DIR),
    )

    async with ClaudeSDKClient(options=options) as client:
        await client.query(task)
        async for message in client.receive_response():
            if isinstance(message, AssistantMessage):
                for block in message.content:
                    if isinstance(block, TextBlock):
                        print(block.text)
                    elif isinstance(block, ToolUseBlock):
                        print(f"\n  [Tool] {block.name}({block.input})")
            elif isinstance(message, ResultMessage):
                cost = (
                    f"${message.total_cost_usd:.4f}"
                    if message.total_cost_usd
                    else "n/a"
                )
                print(f"\n--- Done in {message.num_turns} turns | cost: {cost} ---")
                if message.structured_output:
                    raw = (
                        json.loads(message.structured_output)
                        if isinstance(message.structured_output, str)
                        else message.structured_output
                    )
                    output = OrchestratorOutput.model_validate(raw)
                    print("\nStructured output:")
                    print(output.model_dump_json(indent=2))


if __name__ == "__main__":
    asyncio.run(
        run_orchestrator(
            "Customer cust_12345 reports a duplicate charge on their February bill. "
            "Delegate to your team: have the researcher investigate, the drafter prepare "
            "a response, and compliance review the final action before we send it."
        )
    )
What should the learner inspect in the code?

Look for the exact place where system scope is bounded: schema definitions, prompt framing, runtime configuration, and the call site that turns user intent into a concrete model or workflow action.

Look for output contracts and validation
Look for the exact execution call
Look for what the product could expose to the user
How does the sandbox relate to the source?

The sandbox should make the UX legible: what the user sees, what the system is deciding, and how the result becomes reviewable. The source then shows how that behavior is actually implemented.

Read the implementation summary.
Step through the user and system states.
Inspect the source code with the highlighted doctrine decisions in mind.
SandboxInspectable flow with visible system boundaries
Interaction walkthrough

Use the sandbox to step through the user-visible experience, the system work behind it, and the doctrine choice the example is making.

UX explanation

The sandbox explains what the user should see, what the system is doing, and where control or inspectability must remain explicit.

AI design explanation

The page turns raw source into a product-facing pattern: what the model is allowed to decide, what the product should expose, and where deterministic code or review should take over.

Interaction walkthrough

  1. 1Read the implementation summary.
  2. 2Step through the user and system states.
  3. 3Inspect the source code with the highlighted doctrine decisions in mind.

Visible to the user

Level 5: Multi-Agent Orchestration — Delegated Autonomy An orchestrator delegates to specialized subagents defined via the agent runtime SDK. Each subagent has its own prompt, tools, and model. The orchestrator coordinates.

System work

The product prepares a bounded model or workflow task.

Why it matters

The interface should make the delegated task legible before automation happens.

Used in courses and paths

This example currently stands on its own in the library, but it still connects to the principle system and the broader example family.

Related principles

Runtime architecture

Use this example in your agents

This example is also available through the blueprint’s agent-ready layer. Use the For agents page for the public MCP, deterministic exports, and Claude/Cursor setup.

Define triggers, context, and boundaries before increasing autonomy
Make control, observability, and recovery explicit in the runtime
Choose the right operational patterns before delegating to workflows