# How to Configure Signal Routes for Jido Agents: Complete Routing Guide

> Configure signal routes for Jido agents using signal_routes option or signal_routes/1 callback. Learn Jido agent routing for effective communication.

- Repository: [agentjido/jido](https://github.com/agentjido/jido)
- Tags: how-to-guide
- Published: 2026-03-09

---

**You configure signal routes for Jido agents by declaring static `{type, ActionModule}` tuples via the `signal_routes:` option or implementing the `signal_routes/1` callback in your agent module, with the framework's router resolving signals at runtime through a priority-based system that evaluates strategy, agent, and plugin definitions in descending order of precedence.**

Jido is an Elixir framework for building autonomous agents that process CloudEvents-style **signals** and route them to specific **actions**. Understanding how to configure these **signal routes** is essential for controlling agent behavior, as the routing table determines which action module executes when an agent receives a signal of a particular `type`.

## Understanding the Signal Router Priority System

The **Signal Router** (implemented in `Jido.AgentServer`) constructs a routing table by merging definitions from three sources. When a signal arrives, the router matches its `type` field against this table and executes the corresponding action. The framework resolves conflicts through a strict priority hierarchy:

- **Strategy routes (Priority 50+)**: Custom strategy modules can override all other routes.
- **Agent routes (Priority 0)**: Static declarations or dynamic callbacks defined directly in the agent.
- **Plugin routes (Priority -10)**: Pattern-based routes exposed by plugins.

Higher priority routes take precedence. If no match exists at any priority level, the signal is ignored.

### Strategy Routes

Custom strategies implement the `signal_routes/1` callback to inject their own routing logic. According to the source in [`lib/jido/agent/strategy.ex`](https://github.com/agentjido/jido/blob/main/lib/jido/agent/strategy.ex) (lines 296-301), these routes automatically receive priority 50 or higher, allowing strategies to intercept signals before they reach the agent's own handlers.

### Agent Routes

Every agent module receives default `signal_routes/0` and `signal_routes/1` callbacks injected automatically by `use Jido.Agent`. The source in [`lib/jido/agent.ex`](https://github.com/agentjido/jido/blob/main/lib/jido/agent.ex) (lines 36-42) provides these defaults, but you can override them through two mechanisms:

1. **Static declaration**: Pass a list of tuples to the `signal_routes:` option in `use Jido.Agent`
2. **Dynamic routing**: Override `def signal_routes(ctx)` to compute routes at runtime based on state or configuration

### Plugin Routes

Plugins contribute routes through the `signal_patterns` attribute and an optional `signal_routes/1` callback defined in [`lib/jido/plugin.ex`](https://github.com/agentjido/jido/blob/main/lib/jido/plugin.ex) (lines 10-13). These typically use wildcard matching and evaluate last in the priority chain.

## Configuring Static Signal Routes

The simplest approach defines routes at compile time using the `signal_routes:` option. This method is ideal for agents with fixed behavior patterns that do not change based on runtime conditions.

```elixir
defmodule MyApp.CounterAgent do
  use Jido.Agent,
    name: "counter",
    schema: [counter: [type: :integer, default: 0]],
    signal_routes: [
      {"increment", MyApp.Actions.Increment},
      {"decrement", MyApp.Actions.Decrement},
      {"reset",     MyApp.Actions.Reset}
    ]
end

```

This example mirrors the *Agent Signal Routes* section of the official guide (lines 99-107 in [`guides/signals.md`](https://github.com/agentjido/jido/blob/main/guides/signals.md)). Each tuple maps a signal `type` string to a module that `use Jido.Action` and implements the `run/2` function.

## Implementing Dynamic Signal Routes

For agents that must adapt their behavior based on configuration, environment variables, or internal state, override the `signal_routes/1` callback. This function receives the agent's context (`ctx`) and returns a list of route tuples computed at runtime.

```elixir
defmodule MyApp.ConfigurableAgent do
  use Jido.Agent,
    name: "configurable",
    schema: [mode: [type: :atom, default: :default]]

  @impl true
  def signal_routes(_ctx) do
    case Application.get_env(:my_app, :feature_flag) do
      true  -> [{"feature", MyApp.Actions.FeatureEnabled}]
      false -> [{"feature", MyApp.Actions.FeatureDisabled}]
    end
  end
end

```

Dynamic routing enables feature flags, A/B testing, and environment-specific behavior without recompiling the agent module.

## Strategy-Based Signal Routing

When an agent runs with a custom strategy, that strategy's routes take precedence over all others. Strategies implement `signal_routes/1` to handle protocol-specific signals or translate external events into internal action dispatches.

```elixir
defmodule MyApp.ReactiveStrategy do
  use Jido.Agent.Strategy

  @impl true
  def signal_routes(_ctx) do
    [
      {"react.user_query", {:strategy_cmd, :react_start}},
      {"ai.llm_result",   {:strategy_cmd, :react_llm_result}}
    ]
  end
end

```

With priority 50+, these routes intercept signals before they reach the agent's static or dynamic route definitions, making strategies ideal for implementing reusable interaction patterns across multiple agent types.

## Complete End-to-End Example

The following example demonstrates the full workflow: defining an action, configuring an agent with static routes, starting the server, and dispatching a signal. This pattern is validated in the test suite at [`test/examples/signals/signal_routing_test.exs`](https://github.com/agentjido/jido/blob/main/test/examples/signals/signal_routing_test.exs) (lines 88-94).

```elixir

# Define an action

defmodule MyApp.Actions.Increment do
  use Jido.Action,
    name: "increment",
    schema: [amount: [type: :integer, default: 1]]

  def run(%{amount: amt}, ctx) do
    current = Map.get(ctx.state, :counter, 0)
    {:ok, %{counter: current + amt}}
  end
end

# Agent with static routes

defmodule MyApp.CounterAgent do
  use Jido.Agent,
    name: "counter",
    schema: [counter: [type: :integer, default: 0]],
    signal_routes: [{"increment", MyApp.Actions.Increment}]
end

# Start the agent

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

# Send a signal

signal = Jido.Signal.new!("increment", %{amount: 10}, source: "/ui")
{:ok, agent} = Jido.AgentServer.call(pid, signal)

IO.inspect(agent.state.counter)   # => 10

```

The `Jido.AgentServer.call/2` function processes the signal synchronously, executing the matched action and returning the updated agent state. For asynchronous processing, use `cast/2` instead.

## Summary

- **Signal routes** map incoming CloudEvents-style messages to specific action modules based on the signal's `type` field.
- The router evaluates three sources in priority order: **Strategy (50+)** > **Agent (0)** > **Plugin (-10)**.
- Configure routes statically via the `signal_routes:` option in `use Jido.Agent` or dynamically by implementing the `signal_routes/1` callback.
- Routes are merged at runtime by `Jido.AgentServer`, which resolves the routing table before executing the matched action.
- Source definitions reside in [`lib/jido/agent.ex`](https://github.com/agentjido/jido/blob/main/lib/jido/agent.ex) (default callbacks), [`lib/jido/agent/strategy.ex`](https://github.com/agentjido/jido/blob/main/lib/jido/agent/strategy.ex) (strategy behavior), and [`lib/jido/plugin.ex`](https://github.com/agentjido/jido/blob/main/lib/jido/plugin.ex) (plugin contributions).

## Frequently Asked Questions

### How does the Jido router resolve conflicting signal routes?

The router assigns a numeric priority to each route source. Strategy routes receive priority 50 or higher, agent routes receive priority 0, and plugin routes receive priority -10. When multiple routes match a signal's `type`, the highest priority route wins. This ensures that strategies can override agent defaults, and agents can override plugin patterns.

### Can I change signal routes at runtime?

Yes. While static routes defined via the `signal_routes:` option are fixed at compile time, implementing the `signal_routes/1` callback allows dynamic route computation on every signal evaluation. The callback receives the current agent context, enabling routes to change based on state, configuration, or external conditions without restarting the agent.

### What is the difference between signal_routes/0 and signal_routes/1?

`signal_routes/0` is a simple callback that takes no arguments and returns the route list, suitable for static configurations. `signal_routes/1` receives the agent context (`ctx`) and allows runtime computation of routes. The `use Jido.Agent` macro injects default implementations of both callbacks (lines 36-42 in [`lib/jido/agent.ex`](https://github.com/agentjido/jido/blob/main/lib/jido/agent.ex)), which you can override as needed.

### How do plugins contribute to signal routing?

Plugins define routes through the `signal_patterns` module attribute and optionally implement `signal_routes/1` as shown in [`lib/jido/plugin.ex`](https://github.com/agentjido/jido/blob/main/lib/jido/plugin.ex) (lines 10-13). These routes evaluate at priority -10, making them a fallback when no strategy or agent route matches. Plugins typically use this mechanism to provide wildcard pattern matching for cross-cutting concerns like logging or telemetry.