Skip to content
Sign up
Agents
Multi-agent patterns

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.

Supervisor-Worker Pattern Architecture

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

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.

The pattern uses three key components:

  1. Agent tagging: Workers are tagged (for example, ["worker", "research", "technical"]) for organization and discovery by the supervisor.
  2. Shared memory blocks: Memory blocks make the small coordination state visible to all agents (guidelines, priorities, status).
  3. 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_all and match_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.

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 Letta
import os
client = Letta(api_key=os.getenv("LETTA_API_KEY"))
# Get the broadcast coordination tool
tools = 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.

First, create the shared memory block and archive:

# Shared memory block for guidelines
guidelines_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 findings
findings_archive = client.archives.create(
name="research_findings",
description="Collaborative archive for all research findings"
)

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

Create specialized workers, each with their own expertise:

# Technical research worker
tech_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 worker
market_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_guidelines memory block.
  • All share the research_findings archive.
  • 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 worker
response = 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 worker
response = 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 workers
response = 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)

The supervisor autonomously:

  1. Analyzes the task content to understand what expertise is needed
  2. Decides routing strategy without explicit instructions:
    • Technical questions → Routes to technical worker
    • Market questions → Routes to market worker
    • Comprehensive tasks → Broadcasts to all workers
  3. Uses the broadcast tool with appropriate match_all and match_some parameters
  4. Workers receive and process their assigned tasks
  5. Supervisor receives worker responses
  6. Supervisor synthesizes results from worker contributions

Here’s a minimal end-to-end example:

from letta_client import Letta
import os
client = Letta(api_key=os.getenv("LETTA_API_KEY"))
# Get broadcast tool
tools = client.tools.list(name="send_message_to_agents_matching_tags")
broadcast_tool = tools.items[0]
# Create shared resources
guidelines = client.blocks.create(
label="guidelines",
value="Focus on quality sources."
)
archive = client.archives.create(name="findings")
# Create supervisor with broadcast tool
supervisor = 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 worker
tech_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 worker
response = 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
# Cleanup
client.agents.delete(tech_worker.id)
client.agents.delete(supervisor.id)
client.archives.delete(archive.id)
client.blocks.delete(guidelines.id)
  • 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.