Tutorials · Claude Agent SDK · examples / python / 08_subagents.pyExample code

Example code · python

08_subagents.py

Programmatic subagents with AgentDefinition, plus SubagentStart/Stop hooks.

Raw fileDownload all examples (zip)See its output →

Used in Part 2 §4 · Subagents: splitting work

"""08: Programmatic subagents with AgentDefinition, plus SubagentStart/Stop hooks."""

import asyncio

from claude_agent_sdk import (
    AgentDefinition,
    AssistantMessage,
    ClaudeAgentOptions,
    HookMatcher,
    ResultMessage,
    ToolUseBlock,
    query,
)
from demo_util import PROJECT


async def on_subagent_start(input_data, tool_use_id, context):
    print(f"  [hook SubagentStart] type={input_data['agent_type']} id={input_data['agent_id']}")
    return {}


async def on_subagent_stop(input_data, tool_use_id, context):
    print(f"  [hook SubagentStop]  type={input_data['agent_type']} transcript={input_data['agent_transcript_path']}")
    return {}


async def main():
    options = ClaudeAgentOptions(
        cwd=PROJECT,
        allowed_tools=["Read", "Grep", "Glob", "Agent"],
        max_turns=10,
        agents={
            "security-reviewer": AgentDefinition(
                description="Security code reviewer. Use for finding vulnerabilities in source files.",
                prompt="You are a security reviewer. Report each vulnerability as file:line and one sentence. "
                       "Be brief. Never edit files.",
                tools=["Read", "Grep", "Glob"],   # read-only
                model="haiku",                     # cheaper model for the subtask
            ),
        },
        hooks={
            "SubagentStart": [HookMatcher(hooks=[on_subagent_start])],
            "SubagentStop": [HookMatcher(hooks=[on_subagent_stop])],
        },
    )

    async for message in query(
        prompt="Use the security-reviewer agent to review src/app.py, then repeat its findings verbatim.",
        options=options,
    ):
        if isinstance(message, AssistantMessage):
            inside = " (inside subagent)" if message.parent_tool_use_id else ""
            for block in message.content:
                if isinstance(block, ToolUseBlock):
                    if block.name in ("Agent", "Task"):
                        print(f"Subagent invoked: subagent_type={block.input.get('subagent_type')} "
                              f"model={block.input.get('model')}")
                    else:
                        print(f"  tool{inside}: {block.name}")
        elif isinstance(message, ResultMessage):
            print("\nFinal result:\n", message.result)
            print("\nPer-model usage:")
            for model, usage in (message.model_usage or {}).items():
                print(f"  {model}: in={usage['inputTokens']} out={usage['outputTokens']} cost=${usage['costUSD']:.4f}")


asyncio.run(main())

68 lines · Back to the folder