# How to Debug Jido Agents Using Debug Mode and the Event Buffer

> Debug Jido agents efficiently with per-instance debug mode and the event buffer. Inspect signal processing and state changes without altering agent logic. Learn how now!

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

---

**Jido provides a per-instance debug mode that automatically records agent execution events in a configurable ring buffer, allowing you to inspect signal processing and state changes without modifying agent logic.**

The `agentjido/jido` repository ships with built-in observability tools designed for production-safe debugging. By leveraging the debug subsystem implemented across [`lib/jido/debug.ex`](https://github.com/agentjido/jido/blob/main/lib/jido/debug.ex) and [`lib/jido/agent_server/state.ex`](https://github.com/agentjido/jido/blob/main/lib/jido/agent_server/state.ex), developers can capture a sliding window of recent events to diagnose agent behavior in real time.

## How Debug Mode Works

Jido's debugging architecture separates concerns into three distinct layers to maintain clean separation between agent logic and observability.

### Debug Configuration Layer

The `Jido.Debug` module in [`lib/jido/debug.ex`](https://github.com/agentjido/jido/blob/main/lib/jido/debug.ex) manages debug levels using Erlang persistent terms keyed by `{:jido_debug, instance}`. When enabled, it stores override maps that automatically adjust telemetry and observation settings:

- `:on` — Sets `telemetry_log_level: :debug` and `observe_debug_events: :minimal`
- `:verbose` — Sets `telemetry_log_level: :trace` and `observe_debug_events: :all`

### State and Buffering Layer

The `AgentServer.State` module in [`lib/jido/agent_server/state.ex`](https://github.com/agentjido/jido/blob/main/lib/jido/agent_server/state.ex) maintains the ring buffer. Each server instance holds a `debug_events` list with a configurable maximum size (default 500 events as defined in [`lib/jido/config/defaults.ex`](https://github.com/agentjido/jido/blob/main/lib/jido/config/defaults.ex)).

The `record_debug_event/3` function checks both the per-process `state.debug` flag and the global `Jido.Debug.enabled?/1` status before appending timestamped entries:

```elixir
def record_debug_event(%__MODULE__{} = state, type, data) do
  if state.debug || Jido.Debug.enabled?(state.jido) do
    event = %{at: System.monotonic_time(:millisecond), type: type, data: data}
    new_events = Enum.take([event | state.debug_events], state.debug_max_events)
    %{state | debug_events: new_events}
  else
    state
  end
end

```

### Public API Layer

The main `Jido` module and `AgentServer` in [`lib/jido.ex`](https://github.com/agentjido/jido/blob/main/lib/jido.ex) and [`lib/jido/agent_server.ex`](https://github.com/agentjido/jido/blob/main/lib/jido/agent_server.ex) expose functions to toggle debugging and retrieve events. These work for both the default Jido instance and custom named instances.

## Enabling Debug Mode

You can activate debugging globally for an instance or per-process without restarting your application.

### Default Instance

Toggle debug mode for the default Jido server using the main module API:

```elixir

# Standard debugging (minimal event detail)

Jido.debug(:on)

# Maximum detail (full arguments and state)

Jido.debug(:verbose)

# Disable debugging

Jido.debug(:off)

```

### Custom Instances

For applications using multiple Jido instances, enable debugging per module:

```elixir
defmodule MyApp.Jido do
  use Jido, name: __MODULE__
end

# Start the instance

MyApp.Jido.start_link(name: MyApp.Jido)

# Enable debug mode

MyApp.Jido.debug(:on)

```

### Per-Process Debugging

Enable debugging for a specific agent process without affecting the global instance setting:

```elixir

# Enable for specific PID

Jido.AgentServer.set_debug(pid, true)

# Disable for that process

Jido.AgentServer.set_debug(pid, false)

```

## Querying the Event Buffer

Once debugging is active, retrieve recorded events to inspect signal processing, directive execution, and state transitions.

### Basic Retrieval

Fetch recent events from the default instance:

```elixir

# Get the 10 most recent events

{:ok, events} = Jido.recent(self(), 10)

```

For custom instances, pass the specific server PID:

```elixir
{:ok, events} = MyApp.Jido.recent(pid_of_instance, 20)

```

### Event Structure

Each event in the buffer is a map containing:

```elixir
%{
  at: 1681234567890,           # Monotonic timestamp in milliseconds

  type: :signal_received,      # Event category (atom)

  data: %{                     # Contextual data

    type: "my.signal",
    id: "abc123"
  }
}

```

Common event types include `:signal_received`, `:directive_executed`, and `:state_changed`, though the specific atoms depend on the agent's activity.

## Configuration Options

Customize the debug buffer behavior through application configuration.

### Buffer Size

Adjust the maximum number of retained events in [`config/config.exs`](https://github.com/agentjido/jido/blob/main/config/config.exs):

```elixir
config :jido,
  debug_max_events: 200   # Default is 500

```

Smaller values reduce memory usage for high-throughput agents; larger values provide deeper historical context for intermittent issues.

### Redaction Settings

When calling `debug/2`, control whether sensitive data appears in logs:

```elixir

# Keep sensitive data visible (use with caution)

MyApp.Jido.debug(:on, redact: false)

```

## Summary

- **Debug mode** operates at the instance level via `Jido.Debug`, storing configuration in Erlang persistent terms and automatically adjusting telemetry verbosity.
- **Event buffering** happens inside each `AgentServer` process, maintaining a configurable ring buffer (default 500 events) of timestamped execution events.
- **Activation** works globally through `Jido.debug/1` or per-process via `AgentServer.set_debug/2`, requiring no code changes to agent logic.
- **Retrieval** uses `Jido.recent/2` to fetch historical events, returning structured maps containing timestamps, event types, and contextual data.

## Frequently Asked Questions

### How do I check if debug mode is currently enabled for my Jido instance?

Call `Jido.Debug.enabled?/1` with your instance name (or the default instance). This reads the persistent term set by `Jido.debug/1` and returns a boolean indicating whether the instance is in `:on` or `:verbose` mode. For per-process checks, inspect the `debug` field in the agent's state struct.

### What happens to events when the buffer reaches its maximum size?

The event buffer operates as a ring buffer using `Enum.take/2` in `State.record_debug_event/3`. When new events arrive and the buffer contains `debug_max_events` entries (default 500), the oldest events are automatically discarded to make room for new entries. This ensures constant memory usage regardless of runtime duration.

### Can I enable debug mode in production without impacting performance?

Yes, but with caveats. The debug system uses persistent terms and conditional checks (`state.debug || Jido.Debug.enabled?(state.jido)`) to minimize overhead when disabled. However, enabling `:verbose` mode captures full argument data and increases telemetry logging, which impacts throughput. Use `:on` mode for production debugging, or enable it selectively per-process using `AgentServer.set_debug/2` rather than globally.

### Where are the debug events actually stored?

Events are stored in the `debug_events` field of the `AgentServer.State` struct, which resides in the heap of each individual agent process. This is defined in [`lib/jido/agent_server/state.ex`](https://github.com/agentjido/jido/blob/main/lib/jido/agent_server/state.ex). There is no centralized storage; each agent maintains its own isolated buffer, ensuring that debugging one agent does not affect others and preventing cross-contamination of debug data.