Supervisor
from loomflow.architecture import SupervisorThe hierarchical multi-agent pattern. Anthropic Multi-Agent Research
System (2026 internal report) + Anthropic Agent Teams (Feb 2026).
The supervisor’s base architecture sees delegate(worker, instructions)
and forward_message(worker) tools that route to named worker
Agents.
For the conceptual page see Supervisor.
Class signature
class Supervisor:
name: str = "supervisor"
def __init__(
self,
*,
workers: dict[str, Agent],
base: Architecture | None = None,
instructions_template: str | None = None,
delegate_tool_name: str = "delegate",
forward_tool_name: str = "forward_message",
) -> None: ...Constructor parameters
workers
| Type | dict[str, Agent] |
| Default | required |
Role-name → fully-built Agent mapping. Names must be valid Python
identifiers (the model emits them as the worker argument to
delegate / forward_message). Must be non-empty.
base
| Type | Architecture | None |
| Default | None (resolves to ReAct()) |
The architecture the supervisor itself runs. Default ReAct. Wrap
inside Reflexion to learn
delegation patterns across runs.
instructions_template
| Type | str | None |
| Default | None (uses built-in default) |
Format string with {worker_descriptions}. The default teaches the
supervisor to delegate effectively. The agent’s own instructions
are prepended to this template (so domain context survives).
delegate_tool_name
| Type | str |
| Default | "delegate" |
Customize to avoid clashes with user-defined tools that happen to
have the same name. The model calls this with
(worker, instructions) to dispatch a worker.
forward_tool_name
| Type | str |
| Default | "forward_message" |
The supervisor calls this with a worker name to return that worker’s last output verbatim as the supervisor’s final response. Skips a synthesis round-trip. Per the LangChain “benchmarking-multi-agent-architectures” benchmark, this earned +50% quality on tasks where the supervisor would otherwise paraphrase a worker’s output.
Methods
declared_workers
def declared_workers(self) -> dict[str, Agent]:
return dict(self._workers)Returns the worker mapping for AgentGraph / introspection.
add_worker
def add_worker(self, name: str, agent: Agent) -> None: ...Register a worker between runs. The new worker becomes available
for delegate(name, ...) on the next agent.run(). Calling mid-run
is undefined. The supervisor’s prompt is composed at run start.
| Parameter | Type | Description |
|---|---|---|
name | str | Must be a valid Python identifier. Raises ValueError otherwise. |
agent | Agent | The worker. |
remove_worker
def remove_worker(self, name: str) -> Agent | None: ...Unregister a worker. Returns the removed Agent if it was registered,
None otherwise. Same lifecycle rules as add_worker.
run
- Open a shared event channel so worker events stream through to the supervisor’s outer generator alongside the base architecture’s events. Without this, MODEL_CHUNK and TOOL_CALL events from workers would be dropped.
- Build the
delegateandforward_messagetools. Both share alast_outputsdict (delegate writes, forward_message reads). - Augment the supervisor’s tool host with these two extras.
- Run
base.run(session, deps_with_extras, prompt). Forward all events. - If the supervisor called
forward_message(worker), overridesession.outputwith that worker’s verbatim last output.
Multiple delegate calls in one supervisor turn run in parallel
because the base ReAct’s tool dispatch is already parallel
(anyio.create_task_group over all tool calls in a turn). Emit two
delegate calls in one turn and both workers run concurrently.
Replay correctness
Each delegated worker run is journaled by (session_id, "delegate_<turn>_<worker>")
in the runtime. With a SqliteRuntime or PostgresRuntime, a crash
mid-supervisor-turn replays cleanly: completed worker runs return
cached results; only the un-completed work re-executes.
Cost model
The supervisor itself runs an architecture (default ReAct, so N
turns of model+tools) PLUS each delegate call kicks off a full
worker agent.run(). For a typical 3-worker pipeline (research →
write → review): roughly 2 supervisor turns + 3 worker runs ≈ 2–4× a single-agent ReAct run.
Example
from loomflow import Agent
from loomflow.architecture import Supervisor
from loomflow.team import Team
researcher = Agent("Find sources, summarise key claims.",
model="claude-opus-4-7", tools=[search])
writer = Agent("Draft the article.",
model="claude-opus-4-7")
reviewer = Agent("Critique the draft for clarity and factual accuracy.",
model="gpt-4o")
# Via the Team facade
team = Team.supervisor(
workers={"researcher": researcher, "writer": writer, "reviewer": reviewer},
instructions=(
"Manage the article pipeline. Delegate research first, then "
"writing, then a review pass. Synthesize the final answer."
),
model="claude-opus-4-7",
)
# Or via the explicit Architecture form (for nesting)
agent = Agent(
"Manage the article pipeline.",
model="claude-opus-4-7",
architecture=Supervisor(workers={
"researcher": researcher,
"writer": writer,
"reviewer": reviewer,
}),
)The two forms are interchangeable. Use the Team facade for single-level teams; use the explicit form for recursive composition.
Source
loomflow/architecture/supervisor.py
Workers are real Agent instances. Each has its own model,
memory, tools, and architecture. Workers can themselves use Reflexion,
ActorCritic, or even another Supervisor. See
Recursive composition.