Search
Search docs, blog posts, and ecosystem packages with citations.
Enter a query to see grounded citations.
We can't find the internet
Attempting to reconnect
Search docs, blog posts, and ecosystem packages with citations.
Diagnose agent issues with debug modes, event buffers, and structured diagnostics.
Mix.install([
{:jido, "~> 2.0"}
])
{:ok, _} = Jido.start()
Define a minimal agent for the examples in this guide.
defmodule MyApp.CounterAgent do
use Jido.Agent,
name: "counter_agent",
schema: [
count: [type: :integer, default: 0],
status: [type: :atom, default: :idle]
]
end
Jido has three instance-wide debug levels that control logging verbosity and event capture across all agents in that instance.
| Level | Logging | Argument display | Debug events |
|---|---|---|---|
:off | Configured defaults | N/A | None |
:on | :debug | Keys only | Minimal |
:verbose | :trace | Full values | All |
Toggle the level at runtime with Jido.debug/1.
Jido.debug(:on)
Check the current level by calling Jido.debug/0.
Jido.debug()
When you need to see full argument values including sensitive fields, disable redaction.
Jido.debug(:on, redact: false)
Turn debug mode off when you are done investigating.
Jido.debug(:off)
Warning: Never leave
redact: falseenabled in production. It exposes sensitive values in log output.
Instance-level debug controls verbosity globally. Per-agent debug enables a ring buffer on a specific AgentServer process that records internal events as they happen.
Pass debug: true when starting the agent server.
{:ok, pid} = Jido.AgentServer.start_link(
agent: MyApp.CounterAgent,
debug: true
)
Toggle debug mode on an already-running agent server.
:ok = Jido.AgentServer.set_debug(pid, true)
The ring buffer holds up to 500 events. When the buffer fills, the oldest events are dropped.
Retrieve events from the ring buffer with recent_events/2. Events arrive newest-first.
{:ok, events} = Jido.AgentServer.recent_events(pid, limit: 10)
Each event is a map with three keys.
%{
at: -576460734,
type: :signal_received,
data: %{signal_type: "counter.increment"}
}
The :at value is a monotonic timestamp in milliseconds. Use it for relative timing between events, not absolute wall-clock time.
| Type | Recorded when |
|---|---|
:signal_received | A signal arrives at the agent server |
:directive_started | A directive begins execution |
Pattern match on the event list to find specific issues.
{:ok, events} = Jido.AgentServer.recent_events(pid)
signals = Enum.filter(events, &(&1.type == :signal_received))
directives = Enum.filter(events, &(&1.type == :directive_started))
If debug mode is off, recent_events/2 returns {:error, :debug_not_enabled}.
Inspect the full debug configuration for an instance with Jido.Debug.status/1.
Jido.Debug.status(Jido.Default)
This returns a map with the current level and all active overrides.
%{
level: :on,
overrides: %{
telemetry_log_level: :debug,
telemetry_log_args: :keys_only,
observe_log_level: :debug,
observe_debug_events: :minimal
}
}
The override keys control specific subsystems.
| Key | :on value | :verbose value | Controls |
|---|---|---|---|
telemetry_log_level | :debug | :trace | Logger level for telemetry events |
telemetry_log_args | :keys_only | :full | How action arguments appear in logs |
observe_log_level | :debug | :debug | Logger level for the observer |
observe_debug_events | :minimal | :all | Which debug events are emitted |
Named instances expose this as MyApp.Jido.debug_status/0.
When Jido.AgentServer.await_completion/2 times out, it returns a structured diagnostic map instead of a bare :timeout error.
{:error, {:timeout, diagnostic}} =
Jido.AgentServer.await_completion(pid, timeout: 5_000)
The diagnostic map contains five keys.
%{
hint: "Agent is idle but await_completion is blocking",
server_status: :idle,
queue_length: 0,
iteration: nil,
waited_ms: 5000
}
| Status | Queue | Meaning |
|---|---|---|
:idle | Empty | Agent finished processing but its state does not match the await condition |
:waiting | Any | Strategy is waiting for an external response (LLM call, HTTP request) |
:running | Non-empty | Agent is still processing directives |
An :idle timeout with an empty queue usually means the agent completed its work but did not set the expected status field. Check state.agent.state.status to see where it ended up.
Inspect a running agent directly without waiting for completion.
{:ok, state} = Jido.AgentServer.state(pid)
The return value is the full AgentServer.State struct. Access the agent’s domain state through state.agent.state.
state.agent.state.count
state.agent.state.status
For a higher-level view, use status/1 which returns a snapshot of the agent’s strategy state along with process metadata.
{:ok, agent_status} = Jido.AgentServer.status(pid)
agent_status.snapshot.status
Enable debug mode through application config so it activates automatically when the instance starts. This is useful for development environments where you always want verbose output.
config :my_app, MyApp.Jido, debug: true
Set :verbose for maximum detail.
config :my_app, MyApp.Jido, debug: :verbose
Jido calls Jido.Debug.maybe_enable_from_config/2 during instance initialization. The config value maps directly: true enables :on level, :verbose enables :verbose level, and any other value (or absence) keeps debug off.
Now that you can inspect agent internals, explore related operational topics.