Architecture
How AgentDbg works: event schema, storage, viewer API, UI, and loop detection. For the full public contract (envelope, event types, payload schemas, run.json), see the Trace format reference.
Event schema
Every event is a JSON object with a common set of top-level fields:
| Field | Type | Description |
|---|---|---|
spec_version |
"0.1" |
Schema version |
event_id |
UUID string | Unique event identifier |
run_id |
UUID string | Run this event belongs to |
parent_id |
UUID string or null |
Parent event (for nesting) |
event_type |
string | One of the types below |
ts |
ISO8601 UTC (2026-02-15T20:31:05.123Z) |
Timestamp with milliseconds |
duration_ms |
integer or null |
Duration if applicable |
name |
string | Label (tool name, model name, etc.) |
payload |
object | Event-type-specific data |
meta |
object | Freeform user-defined metadata |
Event types
| Type | Emitted by | Payload highlights |
|---|---|---|
RUN_START |
@trace / traced_run |
run_name, python_version, platform, cwd, argv |
RUN_END |
@trace / traced_run |
status (ok / error), summary (counts + duration) |
LLM_CALL |
record_llm_call() |
model, prompt, response, usage, provider, status, error |
TOOL_CALL |
record_tool_call() |
tool_name, args, result, status, error |
STATE_UPDATE |
record_state() |
state, diff |
ERROR |
@trace (on exception) |
error_type, message, stack |
LOOP_WARNING |
Automatic detection | pattern, repetitions, window_size, evidence_event_ids |
Events are written as one JSON object per line (JSONL) and flushed after each write.
Storage layout
- Base directory:
~/.agentdbg/(orAGENTDBG_DATA_DIR). - Per run:
runs/<run_id>/ - run.json - Run metadata:
run_id,run_name,started_at,ended_at,duration_ms,status,counts(llm_calls, tool_calls, errors, loop_warnings),last_event_ts. - events.jsonl - Append-only; one event per line.
run.json is created at run start (status running) and updated at run end (status ok or error, counts, ended_at, duration_ms).
Viewer API
The local server (FastAPI) exposes:
| Endpoint | Description |
|---|---|
GET /api/runs |
List recent runs (metadata only). |
GET /api/runs/{run_id} |
Run metadata (run.json). |
GET /api/runs/{run_id}/events |
Events array for the run. |
GET /api/runs/{run_id}/paths |
Local filesystem paths for the run (run_dir, run_json, events_jsonl). |
POST /api/runs/{run_id}/rename |
Rename a run (body: {"run_name": "..."}, updates run.json). |
DELETE /api/runs/{run_id} |
Delete a run directory and its contents (returns 204). |
GET / |
Static UI (agentdbg/ui_static/index.html). |
Default bind: 127.0.0.1:8712. The UI fetches runs and events from these endpoints and renders a timeline.
UI overview
- Multi-file static UI (HTML, JS, CSS); no build step. Served from
agentdbg/ui_static/. - Loads run list from
/api/runs; when a run is selected (orrun_idin query), loads/api/runs/{run_id}/events. - Flat timeline: events are shown in chronological order (write order /
ts). Each event is expandable with payload shown as formatted JSON. Nesting byparent_idis not required. LOOP_WARNINGevents are displayed prominently.
Guardrails
Guardrails are opt-in limits that stop a run before it burns more time, tokens, or tool calls than you intended. They are designed for local debugging, not policy enforcement.
Available guardrails: stop_on_loop, stop_on_loop_min_repetitions, max_llm_calls, max_tool_calls, max_events, max_duration_s. All default to disabled.
Behavior when a guardrail triggers:
- The triggering event is recorded using existing event types (no new types)
AgentDbgLoopAbortorAgentDbgGuardrailExceededis raisedERRORevent is recorded (payload includesguardrail,threshold,actual)RUN_END(status="error")finalizes the run- The exception propagates to the caller
Configuration precedence (highest wins): function args (@trace(...), traced_run(...)) > env vars > project YAML > user YAML > defaults.
See Guardrails for usage examples, Configuration reference for all settings.
Live-refresh viewer
The UI supports automatic polling so you can start agentdbg view once and re-run your agent without manually refreshing.
- Run list sidebar: polls
GET /api/runsevery 3 seconds (configurable viapoll_runsURL param, 1–60s). New runs appear automatically; removed runs are cleared from the sidebar. - Event timeline: when the current run has
status: "running", events poll every 2 seconds (configurable viapoll_eventsURL param, 1–60s). Polling stops when the run finishes. - Visibility gating: polling pauses when the browser tab is not visible (Page Visibility API) and resumes when you switch back.
- Visual indicator: runs with
status: "running"show a pulsing dot in the sidebar.
Integration architecture
AgentDbg adapters are thin translation layers that hook into a framework's callbacks and emit record_llm_call / record_tool_call events. They do not introduce new event types.
| Integration | Module | Hook mechanism |
|---|---|---|
| LangChain / LangGraph | agentdbg.integrations.langchain |
Callback handler (on_llm_start/on_tool_start) |
| OpenAI Agents SDK | agentdbg.integrations.openai_agents |
Tracing processor (GenerationSpanData, FunctionSpanData, HandoffSpanData) |
| CrewAI | agentdbg.integrations.crewai |
Execution hooks (before/after_llm_call, before/after_tool_call) |
Integration lifecycle: agentdbg._integration_utils provides _invoke_run_enter / _invoke_run_exit callbacks that adapters register with. This ensures adapters activate only when an explicit AgentDbg run is active.
Guardrails with integrations: when a guardrail fires inside a framework callback, adapters raise _AgentDbgAbortSignal (a BaseException subclass) to bypass the framework's except Exception error handling and stop execution immediately.
All integrations are optional dependencies; the core package does not depend on any framework. See Integrations for usage details.
Loop detection
- Input: A sliding window of the last N events (default N=12;
AGENTDBG_LOOP_WINDOW). - Signature: Each event is reduced to a string: for
LLM_CALL->"LLM_CALL:"+model, forTOOL_CALL->"TOOL_CALL:"+tool_name, elseevent_type. - Rule: Look for a contiguous block of signatures that repeats K times (default K=3;
AGENTDBG_LOOP_REPETITIONS) at the end of the window. If found, emit oneLOOP_WARNINGper distinct pattern per run (deduplicated by pattern + repetitions). - Payload:
pattern(e.g. "LLM_CALL:gpt-4 -> TOOL_CALL:search"),repetitions,window_size,evidence_event_ids.
No ML; purely pattern-based on event type and name to give quick feedback on repetitive agent behavior.