How to Integrate Jido Agents with OTP Supervision Trees

Jido provides a built-in OTP supervisor that embeds directly into your application supervision tree, combining a Task.Supervisor, Registry, and DynamicSupervisor to manage agent lifecycles with standard OTP primitives.

The agentjido/jido library implements autonomous agents as pure Elixir functions while delegating all process management to battle-tested OTP supervisors. When you integrate Jido agents with OTP supervision trees, you gain automatic restarts, graceful shutdowns, and full supervision-tree introspection without sacrificing the isolation of your agent logic.

Understanding Jido's OTP Architecture

The core Jido module in lib/jido.ex implements the Supervisor behaviour and wires together three OTP components that handle every aspect of agent runtime management.

The Three Core Components

Each Jido instance creates its own isolated supervision infrastructure:

  • Task.Supervisor – Runs asynchronous work such as scheduled actions and background tasks without blocking the agent's main process.

  • Registry – Stores a mapping from an agent's id (a string) to its PID, enabling fast lookups via Jido.whereis/2. According to the source code in lib/jido.ex (lines 38-44), this uses Registry.lookup/2 under the hood.

  • DynamicSupervisor – The AgentSupervisor that hosts each running agent as a child process using the Jido.AgentServer child spec. This is the component that enables dynamic agent spawning with full OTP supervision semantics.

When you define a Jido instance (e.g., MyApp.Jido), the system automatically creates MyApp.Jido.Registry, MyApp.Jido.TaskSupervisor, and MyApp.Jido.AgentSupervisor under your application's supervisor.

Adding Jido to Your Application Supervision Tree

Integration requires two steps: defining a Jido instance module and adding it to your application's supervision tree.

First, define the Jido instance module using the use Jido macro with your OTP application name:


# lib/my_app/jido.ex

defmodule MyApp.Jido do
  use Jido, otp_app: :my_app
end

This single declaration creates the Registry, TaskSupervisor, and DynamicSupervisor under the instance's namespace.

Next, add this module to your Application.start/2 callback:


# lib/my_app/application.ex

defmodule MyApp.Application do
  use Application

  def start(_type, _args) do
    children = [
      MyApp.Repo,
      # Insert the Jido instance here

      MyApp.Jido
    ]

    opts = [strategy: :one_for_one, name: MyApp.Supervisor]
    Supervisor.start_link(children, opts)
  end
end

Because MyApp.Jido implements the Supervisor behaviour, you can nest it under any other supervisor (e.g., OneForOne or RestForOne) and combine it with your own workers.

Starting and Managing Agents

Once integrated, starting an agent requires a single call to your instance's start_agent/2 function, which delegates to the underlying OTP primitives.

Starting Agents via DynamicSupervisor

The Jido.start_agent/3 function (implemented in lib/jido.ex, lines 94-106) builds a child specification for Jido.AgentServer and hands it to the instance's DynamicSupervisor:


# Start a Counter agent with a custom identifier

{:ok, pid} = MyApp.Jido.start_agent(MyApp.CounterAgent, id: "counter-1")

Internally, this uses DynamicSupervisor.start_child/2 to spawn the agent process under MyApp.Jido.AgentSupervisor, ensuring it inherits the supervision tree's restart policies.

Agent Lifecycle Operations

All lifecycle operations delegate to standard OTP primitives, as implemented in lib/jido.ex:

  • Stop an agent: Uses DynamicSupervisor.terminate_child/2 (lines 16-25) via MyApp.Jido.stop_agent/1.

  • Find an agent: Uses Registry.lookup/2 (lines 38-44) via MyApp.Jido.whereis/2.

  • List agents: Uses Registry.select/2 (lines 55-60) via MyApp.Jido.list_agents/0, returning tuples of {"agent-id", #PID<...>}.

  • Count agents: Uses DynamicSupervisor.count_children/1 (lines 66-71) via MyApp.Jido.count_agents/0.


# Find the PID by its ID

pid = MyApp.Jido.whereis("counter-1")

# List all agents registered under this Jido instance

agents = MyApp.Jido.list_agents()

# Stop a specific agent

:ok = MyApp.Jido.stop_agent("counter-1")

Advanced Supervision Patterns

You can create dedicated supervisors that manage isolated agent pools, for example separating "payment" agents from general workers.

Creating Dedicated Agent Pools

Define a separate Jido instance with the agent_pools option:


# lib/my_app/payment_jido.ex

defmodule MyApp.PaymentJido do
  use Jido,
    otp_app: :my_app,
    agent_pools: [{:payment_pool, max_concurrency: 10}]
end

Add this to your application supervisor alongside the default instance:

children = [
  MyApp.Jido,
  MyApp.PaymentJido   # separate pool, separate registry

]

Now MyApp.PaymentJido.start_agent/2 places agents under MyApp.PaymentJido.AgentSupervisor, completely isolated from the default pool's registry and supervisor.

Summary

  • Jido implements the OTP Supervisor behaviour in lib/jido.ex, embedding Task.Supervisor, Registry, and DynamicSupervisor components for each instance.
  • Add a Jido instance to your supervision tree by defining a module with use Jido, otp_app: :my_app, then including it in your Application.start/2 children list.
  • Start agents via Jido.start_agent/3 (or your instance wrapper), which delegates to DynamicSupervisor to spawn Jido.AgentServer processes as supervised children.
  • Manage lifecycles through standard OTP primitives: Registry.lookup/2 for discovery, DynamicSupervisor.terminate_child/2 for shutdown, and Registry.select/2 for enumeration.
  • Create isolated pools by defining multiple Jido instances with custom agent_pools configuration, each with separate registries and supervisors.

Frequently Asked Questions

How do I start a Jido agent under a custom supervisor?

Define a dedicated Jido instance module using use Jido with the agent_pools option, then add this instance to your application supervisor's children list alongside or instead of the default instance. Each instance creates its own named Registry and DynamicSupervisor.

What OTP primitives does Jido use for agent discovery?

Jido uses Registry.lookup/2 (exposed via Jido.whereis/2) to map string agent IDs to PIDs, and Registry.select/2 (exposed via Jido.list_agents/0) for listing all registered agents. These operations run in constant time against the ETS tables managed by the instance's Registry.

Can I nest multiple Jido instances in the same supervision tree?

Yes. Because each Jido instance creates its own uniquely named Registry and DynamicSupervisor (e.g., MyApp.Jido.Registry vs. MyApp.PaymentJido.Registry), you can run multiple isolated pools under a single OTP supervisor without name collisions.

How does Jido handle agent crashes and restarts?

Agents run as Jido.AgentServer children under a DynamicSupervisor, which provides OTP-compliant process supervision. The DynamicSupervisor handles restart semantics according to the child specifications, while metadata about each child (including id, tag, and parent relationships) is tracked in lib/jido/agent_server/child_info.ex for supervision logic.

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 →