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— Setstelemetry_log_level: :debugandobserve_debug_events: :minimal:verbose— Setstelemetry_log_level: :traceandobserve_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
AgentServerprocess, maintaining a configurable ring buffer (default 500 events) of timestamped execution events. - Activation works globally through
Jido.debug/1or per-process viaAgentServer.set_debug/2, requiring no code changes to agent logic. - Retrieval uses
Jido.recent/2to 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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →