Skip to Content

Supervisor

from loomflow.architecture import Supervisor

The 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

Typedict[str, Agent]
Defaultrequired

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

TypeArchitecture | None
DefaultNone (resolves to ReAct())

The architecture the supervisor itself runs. Default ReAct. Wrap inside Reflexion to learn delegation patterns across runs.

instructions_template

Typestr | None
DefaultNone (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

Typestr
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

Typestr
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.

ParameterTypeDescription
namestrMust be a valid Python identifier. Raises ValueError otherwise.
agentAgentThe 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

  1. 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.
  2. Build the delegate and forward_message tools. Both share a last_outputs dict (delegate writes, forward_message reads).
  3. Augment the supervisor’s tool host with these two extras.
  4. Run base.run(session, deps_with_extras, prompt). Forward all events.
  5. If the supervisor called forward_message(worker), override session.output with 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.

Last updated on