How to Use the Jido Registry for Agent Naming and Lookup

Jido uses Elixir's built-in Registry to provide every agent with a stable, unique name that can be resolved across the entire supervision tree, exposing helper functions like Jido.whereis/2 and Jido.AgentServer.via_tuple/2 to abstract the low-level Registry API.

The Jido Registry is a core component of the agentjido/jido framework that separates agent identity from process state. By leveraging Elixir’s Registry with keys: :unique, Jido ensures that every agent ID maps to exactly one PID, enabling reliable distributed lookups without tight coupling to process lifecycle.

How the Jido Registry Works

Registry Naming Convention

Each Jido instance automatically derives its registry name from the module name. If your Jido module is MyApp.Jido, the registry is named MyApp.Jido.Registry. This convention is enforced by Jido.registry_name/1 in lib/jido.ex, which uses Module.concat/2 to build the atom:


# lib/jido.ex (line 371)

def registry_name(name) do
  Module.concat(name, Registry)
end

Automatic Startup in the Supervision Tree

The registry starts automatically when the Jido supervisor initializes. In lib/jido.ex (lines 443-452), the child_spec/1 function includes the Registry process in the supervision tree with keys: :unique, ensuring no duplicate agent IDs can exist:


# lib/jido.ex (lines 443-452)

def child_spec(opts) do
  %{
    id: __MODULE__,
    start: {__MODULE__, :start_link, [opts]},
    type: :supervisor
  }
end

# Within start_link, the registry is started as:

Registry.start_link(keys: :unique, name: registry_name(module))

Naming Agents with Via Tuples

Creating Via Tuples for Agent Servers

To register an agent process under the Jido Registry, use the via_tuple/2 helper in Jido.AgentServer. Located in lib/jido/agent_server.ex (lines 49-52), this function constructs the standard {:via, Registry, {registry, id}} tuple required by GenServer.start_link/3:


# lib/jido/agent_server.ex (lines 49-52)

def via_tuple(registry, id) do
  {:via, Registry, {registry, id}}
end

When starting an agent, pass this tuple as the name option:

opts = [
  agent: MyAgent,
  id: "agent-123",
  registry: MyApp.Jido.Registry
]

{:ok, pid} = Jido.AgentServer.start_link(opts)

Using the Utility Helpers for Generic Processes

For non-agent processes that still need Jido-compatible naming, lib/jido/util.ex provides generic via_tuple/2 and whereis/2 functions. These work with any Registry instance:

defmodule MyWorker do
  use GenServer

  def start_link(id) do
    name = Jido.Util.via_tuple(id, registry: MyApp.Jido.Registry)
    GenServer.start_link(__MODULE__, %{}, name: name)
  end
end

Looking Up Agents by Name

Instance-Level Lookup with Jido.whereis/2

The high-level Jido.whereis/2 function (defined in lib/jido.ex, lines 37-44) resolves an agent ID to its PID without requiring knowledge of the underlying registry name. It automatically derives the registry from the Jido module:


# lib/jido.ex (lines 37-44)

def whereis(jido, id) do
  registry = registry_name(jido)
  AgentServer.whereis(registry, id)
end

Usage:

pid = MyApp.Jido.whereis("agent-123")

# => #PID<0.123.0> | nil

Registry-Specific Lookup with AgentServer.whereis/2

For scenarios where you have direct access to the registry module, Jido.AgentServer.whereis/2 in lib/jido/agent_server.ex (lines 33-38) performs the lookup using Registry.lookup/2:


# lib/jido/agent_server.ex (lines 33-38)

def whereis(registry, id) do
  case Registry.lookup(registry, id) do
    [{pid, _}] -> pid
    [] -> nil
  end
end

This is useful when working with multiple Jido instances or custom registries:

pid = Jido.AgentServer.whereis(MyApp.Jido.Registry, "agent-123")

Listing All Registered Agents

To enumerate every registered agent in a Jido instance, use Jido.list_agents/1. This function uses Registry.select/2 to return a list of {id, pid} tuples:

agents = MyApp.Jido.list_agents()

# => [{"agent-123", #PID<0.123.0>}, {"other-agent", #PID<0.124.0>}]

Practical Code Examples

Starting an Agent with the Default Registry

When you start a Jido instance, the registry starts automatically. Agents started via start_agent/2 are automatically registered:

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

# Start the supervisor (usually in application.ex)

{:ok, _pid} = MyApp.Jido.start_link([])

# Start an agent - automatically registered under MyApp.Jido.Registry

{:ok, _agent_pid} = MyApp.Jido.start_agent(MyAgent, id: "agent-123")

Using a Custom Registry for Testing

Isolate tests by creating a temporary registry:

defmodule MyApp.AgentTest do
  use ExUnit.Case

  setup do
    # Create a temporary registry for this test

    {:ok, _registry} = Registry.start_link(keys: :unique, name: __MODULE__.Registry)
    
    # Start agent with custom registry

    opts = [
      agent: MyAgent,
      id: "test-agent",
      registry: __MODULE__.Registry
    ]
    
    {:ok, pid} = Jido.AgentServer.start_link(opts)
    %{agent_pid: pid, registry: __MODULE__.Registry}
  end

  test "can lookup agent in custom registry", %{registry: registry} do
    pid = Jido.AgentServer.whereis(registry, "test-agent")
    assert is_pid(pid)
  end
end

Registering Generic GenServer Processes

Any GenServer can use the Jido registry for naming:

defmodule MyWorker do
  use GenServer

  def start_link(id) do
    # Create via tuple using Jido utility

    name = Jido.Util.via_tuple(id, registry: MyApp.Jido.Registry)
    GenServer.start_link(__MODULE__, %{}, name: name)
  end

  def get_state(pid_or_id) do
    GenServer.call(pid_or_id, :get_state)
  end
end

# Usage

{:ok, _pid} = MyWorker.start_link("worker-1")
state = MyWorker.get_state("worker-1")  # Lookup by name works automatically

Summary

  • Automatic Registry Creation: Every Jido instance creates a dedicated Registry (e.g., MyApp.Jido.Registry) via Jido.registry_name/1 and starts it in the supervision tree via Jido.child_spec/1.
  • Via Tuple Naming: Agents are named using {:via, Registry, {registry, id}} tuples generated by Jido.AgentServer.via_tuple/2 or Jido.Util.via_tuple/2.
  • Safe Lookup: Resolve agent IDs to PIDs using Jido.whereis/2 (instance-level) or Jido.AgentServer.whereis/2 (registry-specific), both returning nil for missing agents rather than raising.
  • Process Isolation: The registry stores only identity mappings, not agent state, ensuring state mutations remain contained within the AgentServer process.

Frequently Asked Questions

How is the Jido Registry name generated?

The registry name is automatically derived from your Jido module name using Jido.registry_name/1 in lib/jido.ex. If your module is MyApp.Jido, the registry becomes MyApp.Jido.Registry via Module.concat(name, Registry). This convention ensures each Jido instance has an isolated namespace for its agents.

Can I use a custom Registry for testing?

Yes. While production code typically relies on the auto-generated registry, you can pass a custom :registry option to Jido.AgentServer.start_link/1, Jido.AgentServer.via_tuple/2, and Jido.AgentServer.whereis/2. This allows you to start a temporary Registry process in your test setup (e.g., Registry.start_link(keys: :unique, name: MyTest.Registry)) for complete test isolation.

What is the difference between Jido.whereis/2 and AgentServer.whereis/2?

Jido.whereis/2 is the high-level instance method that automatically resolves the registry name from your Jido module (e.g., MyApp.Jido.whereis("agent-123")), making it ideal for application code. Jido.AgentServer.whereis/2 requires you to explicitly pass the registry module as the first argument (e.g., Jido.AgentServer.whereis(MyApp.Jido.Registry, "agent-123")), which is useful when working with multiple registries or in library code where the Jido instance isn't available.

Is the Jido Registry suitable for high-frequency lookups?

Yes. The Jido Registry is a thin wrapper around Elixir's built-in Registry, which is implemented in ETS (Erlang Term Storage) and provides O(1) lookup times. Since Jido.whereis/2 and Jido.AgentServer.whereis/2 delegate to Registry.lookup/2, you can safely use them in hot paths, such as routing messages in Phoenix channels or dispatching work to specific agents in high-throughput pipelines.

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 →