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

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 and 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 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 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).

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:

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 and 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:


# 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:

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:


# 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:


# Get the 10 most recent events

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

For custom instances, pass the specific server PID:

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

Event Structure

Each event in the buffer is a map containing:

%{
  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:

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:


# 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. 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.

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 →