The supervisor-worker pattern
Coordinate multiple specialized agents under a single supervisor agent with shared memory and archival storage.
Coordinate multiple specialized agents under a single supervisor. Workers maintain memory across sessions and share knowledge through common resources. The supervisor autonomously routes tasks to workers based on their expertise and tags.
When to use this pattern
Section titled “When to use this pattern”The supervisor-worker pattern works well when you need to:
- Distribute work across specialized agents (technical research, market analysis, content creation)
- Maintain shared context and knowledge across a team
- Scale task execution with parallel worker agents
- Keep workers coordinated with shared guidelines or priorities
Example use case
Section titled “Example use case”A research supervisor coordinates specialized workers (technical, market, and academic) to gather comprehensive information on a topic. The supervisor intelligently routes tasks to specific workers based on their expertise - sending technical questions to the technical worker, market analysis to the market worker. Each worker maintains context across research sessions, stores findings in a shared archive, and follows guidelines set by the supervisor.
How it works
Section titled “How it works”The pattern uses three key components:
- Agent tagging: Workers are tagged (for example,
["worker", "research", "technical"]) for organization and discovery by the supervisor. - Shared memory blocks: Memory blocks make the small coordination state visible to all agents (guidelines, priorities, status).
- Shared archival memory: Workers contribute findings to a large searchable knowledge base.
The supervisor autonomously:
- Analyzes tasks and decides which workers to use
- Routes tasks to specific workers using tag-based filtering (
match_allandmatch_some) - Receives responses from targeted workers
- Synthesizes results from worker contributions
Key feature - Intelligent routing: The supervisor uses match_all and match_some parameters to target specific workers. For example, to send a task only to the technical worker: match_all=["worker"] and match_some=["technical"]. This enables intelligent task assignment based on worker specialization.
Implementation
Section titled “Implementation”Step 1: Get the supervisor coordination tool
Section titled “Step 1: Get the supervisor coordination tool”The supervisor needs the send_message_to_agents_matching_tags tool to coordinate workers:
from letta_client import Lettaimport os
client = Letta(api_key=os.getenv("LETTA_API_KEY"))
# Get the broadcast coordination tooltools = client.tools.list(name="send_message_to_agents_matching_tags")broadcast_tool = tools.items[0]This tool allows the supervisor to send messages to agents matching specific tag criteria. It supports two filtering modes:
match_all: Tags that agents MUST have (required tags)match_some: Tags where agents need at least one (optional specialization tags)
This enables intelligent routing - the supervisor can target specific workers or broadcast to groups.
Step 2: Create shared resources
Section titled “Step 2: Create shared resources”First, create the shared memory block and archive:
# Shared memory block for guidelinesguidelines_block = client.blocks.create( label="research_guidelines", description="Research guidelines and priorities set by supervisor", value="Focus on accurate, well-sourced information from 2024-2025.")
# Shared archive for research findingsfindings_archive = client.archives.create( name="research_findings", description="Collaborative archive for all research findings")Step 3: Create the supervisor
Section titled “Step 3: Create the supervisor”Create the supervisor with the broadcast tool and shared resources:
supervisor = client.agents.create( name="research_supervisor", model="anthropic/claude-sonnet-4-5-20250929", memory_blocks=[{ "label": "persona", "value": """I am a research supervisor that coordinates specialized workers.
Available workers and their tags:- technical worker (tags: worker, research, technical) - Reviews code, APIs, implementation details- market worker (tags: worker, research, market) - Analyzes market trends, competitors, industry
I route tasks to appropriate workers using send_message_to_agents_matching_tags:- For technical questions: match_all=["worker"], match_some=["technical"]- For market questions: match_all=["worker"], match_some=["market"]- For broad questions: match_all=["worker", "research"]
I delegate to workers rather than answering directly.""" }], block_ids=[guidelines_block.id], tags=["supervisor", "research"], tool_ids=[broadcast_tool.id])
client.agents.archives.attach(findings_archive.id, agent_id=supervisor.id)The supervisor can now:
- Update shared guidelines
- Route tasks to specific workers using intelligent tag-based filtering
- Broadcast tasks to all workers when needed
- Search the shared archive for worker contributions
Step 4: Create worker agents
Section titled “Step 4: Create worker agents”Create specialized workers, each with their own expertise:
# Technical research workertech_worker = client.agents.create( name="technical_worker", model="anthropic/claude-sonnet-4-5-20250929", memory_blocks=[{ "label": "persona", "value": "I analyze technical documentation, APIs, and implementation details." }], block_ids=[guidelines_block.id], tags=["worker", "research", "technical"], tools=["archival_memory_insert", "archival_memory_search"])client.agents.archives.attach(findings_archive.id, agent_id=tech_worker.id)
# Market research workermarket_worker = client.agents.create( name="market_worker", model="anthropic/claude-sonnet-4-5-20250929", memory_blocks=[{ "label": "persona", "value": "I gather market trends, competitor information, and industry insights." }], block_ids=[guidelines_block.id], tags=["worker", "research", "market"], tools=["archival_memory_insert", "archival_memory_search"])client.agents.archives.attach(findings_archive.id, agent_id=market_worker.id)Key features:
- Each worker has a specialized persona.
- All share the
research_guidelinesmemory block. - All share the
research_findingsarchive. - Workers are tagged with
["worker", "research"]plus their specialty. - Workers automatically persist memory across sessions.
Step 5: Supervisor routes tasks intelligently
Section titled “Step 5: Supervisor routes tasks intelligently”The supervisor autonomously analyzes tasks and routes them to appropriate workers:
# Technical task - supervisor routes to technical workerresponse = client.agents.messages.create( agent_id=supervisor.id, messages=[{ "role": "user", "content": "Analyze the API documentation for Letta's agent creation endpoint and identify key parameters." }])# Supervisor autonomously uses: match_all=["worker"], match_some=["technical"]
# Market task - supervisor routes to market workerresponse = client.agents.messages.create( agent_id=supervisor.id, messages=[{ "role": "user", "content": "Research current trends in the AI agent framework market and identify top competitors." }])# Supervisor autonomously uses: match_all=["worker"], match_some=["market"]
# Comprehensive task - supervisor broadcasts to all workersresponse = client.agents.messages.create( agent_id=supervisor.id, messages=[{ "role": "user", "content": "Conduct a comprehensive analysis of Letta from technical, market, and competitive perspectives." }])# Supervisor autonomously uses: match_all=["worker", "research"] (all workers)How intelligent routing works
Section titled “How intelligent routing works”The supervisor autonomously:
- Analyzes the task content to understand what expertise is needed
- Decides routing strategy without explicit instructions:
- Technical questions → Routes to technical worker
- Market questions → Routes to market worker
- Comprehensive tasks → Broadcasts to all workers
- Uses the broadcast tool with appropriate
match_allandmatch_someparameters - Workers receive and process their assigned tasks
- Supervisor receives worker responses
- Supervisor synthesizes results from worker contributions
Minimal example
Section titled “Minimal example”Here’s a minimal end-to-end example:
from letta_client import Lettaimport os
client = Letta(api_key=os.getenv("LETTA_API_KEY"))
# Get broadcast tooltools = client.tools.list(name="send_message_to_agents_matching_tags")broadcast_tool = tools.items[0]
# Create shared resourcesguidelines = client.blocks.create( label="guidelines", value="Focus on quality sources.")archive = client.archives.create(name="findings")
# Create supervisor with broadcast toolsupervisor = client.agents.create( model="anthropic/claude-sonnet-4-5-20250929", memory_blocks=[{ "label": "persona", "value": """I am a research supervisor that coordinates specialized workers.
Available workers and their tags:- technical worker (tags: worker, technical) - Reviews code, APIs, implementation details
I route tasks to appropriate workers using send_message_to_agents_matching_tags:- For technical questions: match_all=["worker"], match_some=["technical"]
I delegate to workers rather than answering directly.""" }], block_ids=[guidelines.id], tags=["supervisor"], tool_ids=[broadcast_tool.id])client.agents.archives.attach(archive.id, agent_id=supervisor.id)
# Create technical workertech_worker = client.agents.create( model="anthropic/claude-sonnet-4-5-20250929", memory_blocks=[{ "label": "persona", "value": "I am a technical researcher." }], block_ids=[guidelines.id], tags=["worker", "technical"], tools=["archival_memory_insert", "archival_memory_search"])client.agents.archives.attach(archive.id, agent_id=tech_worker.id)
# Supervisor autonomously routes to technical workerresponse = client.agents.messages.create( agent_id=supervisor.id, messages=[{ "role": "user", "content": "Review this Python code for potential issues:\n\ndef process_data(items):\n return [item * 2 for item in items]" }])# Supervisor analyzes the code review request and routes to technical worker
# Cleanupclient.agents.delete(tech_worker.id)client.agents.delete(supervisor.id)client.archives.delete(archive.id)client.blocks.delete(guidelines.id)Best practices
Section titled “Best practices”-
Use descriptive tags: Tag workers by role, specialty, and team for flexible coordination.
-
Keep shared memory focused: Use shared memory blocks for guidelines and coordination, not large data.
-
Use archival memory: Store research findings, data, and historical context in archives.
-
Design clear personas: Give each worker a specific specialty and role definition.
-
Monitor worker state: Check worker memory and archive contributions to track progress.