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:

  1. Start the root agent with Jido.AgentServer.start/1.
  2. Return SpawnAgent directives from cmd/2 to declare child agents.
  3. The runtime stores %ChildInfo{} structs (defined in lib/jido/agent_server/child_info.ex) containing the child's PID, monitor reference, and metadata.
  4. Parents address children by tag using StopChild directives or direct PID signals, while children emit upstream via emit_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's ChildInfo.

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 AgentServer processes tracked via ChildInfo structs in state.children.
  • Pure Agent Logic: Agents remain stateless decision modules; the runtime handles all process management through DirectiveExec implementations in lib/jido/agent_server/directive_executors.ex.
  • Lifecycle Management: Automatic monitoring converts child exits to jido.agent.child.exit signals, while StopChild directives enable graceful termination.
  • Hierarchical Communication: Children use emit_to_parent/3 to 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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →