How to Implement Multi-Agent Orchestration in Jido: A Complete Guide
Multi-agent orchestration in Jido is achieved by returning SpawnAgent directives from an agent's cmd/2 function, which creates child AgentServer processes tracked in the parent's state.children map and enables bidirectional parent-child communication via signals.
Jido (agentjido/jido) is an Elixir framework where agents are pure decision-making modules that communicate with the runtime exclusively through directives. To implement multi-agent orchestration, you compose agent hierarchies by returning SpawnAgent directives from a parent agent's cmd/2 function, creating supervised child processes that maintain parent references for upstream signaling.
How Multi-Agent Orchestration Works in Jido
Jido treats agents as stateless decision functions (cmd/2) that produce directives. The Jido.AgentServer GenServer executes these directives to mutate runtime state. When an agent returns a %Jido.Agent.Directive.SpawnAgent{} struct, the DirectiveExec implementation in lib/jido/agent_server/directive_executors.ex (lines 85-131) creates a new child process and registers it in the parent's state.children map via State.add_child/3 from lib/jido/agent_server/state.ex.
The orchestration flow follows four steps:
- Start the root agent with
Jido.AgentServer.start/1. - Return
SpawnAgentdirectives fromcmd/2to declare child agents. - The runtime stores
%ChildInfo{}structs (defined inlib/jido/agent_server/child_info.ex) containing the child's PID, monitor reference, and metadata. - Parents address children by tag using
StopChilddirectives or direct PID signals, while children emit upstream viaemit_to_parent/3.
Spawning Child Agents with SpawnAgent
The SpawnAgent directive, defined in lib/jido/agent/directive.ex (lines 31-57), is a Zoi-validated struct with four fields:
agent: The module to instantiate.tag: A unique atom identifier for later reference.opts: Initialization options passed to the child.meta: Contextual data stored in the parent'sChildInfo.
Orchestrator Agent Example
defmodule OrchestratorAgent do
use Jido.Agent
def start_workers(count) do
Jido.Signal.new!("orchestrator.start", %{count: count})
|> Jido.AgentServer.cast(__MODULE__)
end
@impl true
def cmd(%__MODULE__{} = state, %Jido.Signal{type: "orchestrator.start", payload: %{count: n}}) do
directives =
for i <- 1..n do
%Jido.Agent.Directive.SpawnAgent{
agent: WorkerAgent,
tag: :"worker_#{i}",
opts: %{initial_state: %{worker_id: i}},
meta: %{origin: :orchestrator}
}
end
{:ok, state, directives}
end
end
This returns multiple SpawnAgent directives from a single cmd/2 invocation. The runtime executes these via DirectiveExec and populates state.children with ChildInfo structs keyed by each tag.
Managing Agent Lifecycles
Handling Child Exits
When a child crashes or stops, the runtime emits a jido.agent.child.exit signal. The parent handles this in cmd/2:
@impl true
def cmd(state, %Jido.Signal{type: "jido.agent.child.exit", payload: payload}) do
IO.puts("Child exited: #{inspect(payload)}")
{:ok, state}
end
The DirectiveExec implementation monitors child processes and converts exit messages into these signals automatically.
Stopping Child Agents
Use the StopChild directive (defined in lib/jido/agent/directive.ex, lines 94-112) to gracefully terminate a child by tag:
@impl true
def cmd(state, %Jido.Signal{type: "orchestrator.stop", payload: %{tag: tag}}) do
{:ok, state, [%Jido.Agent.Directive.StopChild{tag: tag}]}
end
The executor implementation in lib/jido/agent_server/directive_executors.ex (lines 141-176) handles the graceful shutdown and cleanup of the ChildInfo entry in state.children.
Bidirectional Parent-Child Communication
Child agents reference their parent via state.parent, injected during spawning by State.from_options/3. Workers notify parents using emit_to_parent/3 from the Jido.Agent.Directive module:
defmodule WorkerAgent do
use Jido.Agent
@impl true
def cmd(%__MODULE__{} = state, %Jido.Signal{type: "work", payload: payload}) do
result = do_work(payload)
emit_to_parent(state, "worker.done", %{id: state.state.worker_id, result: result})
{:ok, state}
end
end
This sends a signal that the parent receives as a normal inbound signal, enabling reactive orchestration patterns where parent agents respond to child lifecycle events and results.
Summary
- SpawnAgent Directive: The primary mechanism for multi-agent orchestration in Jido, creating child
AgentServerprocesses tracked viaChildInfostructs instate.children. - Pure Agent Logic: Agents remain stateless decision modules; the runtime handles all process management through
DirectiveExecimplementations inlib/jido/agent_server/directive_executors.ex. - Lifecycle Management: Automatic monitoring converts child exits to
jido.agent.child.exitsignals, whileStopChilddirectives enable graceful termination. - Hierarchical Communication: Children use
emit_to_parent/3to send signals upstream, and parents address children by tag or PID.
Frequently Asked Questions
How do I start a child agent from within a parent agent?
Return a %Jido.Agent.Directive.SpawnAgent{} struct from your agent's cmd/2 function. The runtime automatically creates the child process, registers it in the parent's state.children map, and establishes a monitor reference. You can return multiple SpawnAgent directives in a single list to spawn entire fleets.
What information is stored about each child agent?
The runtime stores a %ChildInfo{} struct (defined in lib/jido/agent_server/child_info.ex) containing the child's PID, monitor reference, module type, ID, tag, and metadata. This struct lives in the parent's state.children map, keyed by the atom tag you specified in the SpawnAgent directive.
How can a child agent send data back to its parent?
Use the emit_to_parent/3 function from the Jido.Agent.Directive module. This helper looks up the parent reference injected during spawning and emits a signal that the parent receives as a normal inbound signal. The parent handles these signals in its cmd/2 clauses just like any other event.
What happens when a spawned agent crashes?
The Jido.AgentServer monitors all child processes. When a child exits (normally or via crash), the runtime emits a jido.agent.child.exit signal to the parent containing exit details. The parent can pattern match on this signal in cmd/2 to implement restart logic, cleanup, or error handling.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →