Skip to content

Debugging

An agent gives the wrong answer in production. The first 30 seconds of debugging matter most — was it the prompt? The tool result? A memory injection? A skill activation? agentfootprint exposes every one of those decisions as a typed event, recorded during the run, replayable later. You don’t reconstruct what happened from logs; you read the trace.

SurfaceWhen to use
Typed event listenersMid-run debugging in tests / dev — agent.on('*', ...) for every event, or agent.on('agentfootprint.stream.*', ...) per-domain
Narrative recorderPost-run human-readable trace (“what happened, in order”)
Time-travel checkpointReplay decisions cross-process, cross-day (Causal memory snapshot)

For interactive debugging in terminal:

agent.enable.thinking({
onStatus: (s) => console.log(`${s}`),
});

Prints one line per state transition — “calling LLM… tool weather(SF)… LLM… done”. The Claude-Code-style live status. Drop into your dev script.

For CI / staging environments:

import { LoggingDomains } from 'agentfootprint';
agent.enable.logging({
domains: [LoggingDomains.STREAM, LoggingDomains.AGENT, LoggingDomains.CONTEXT],
logger: pino(), // or console, winston, etc.
});

Filters the firehose to specific event domains; pipes to your structured logger.

For specific concerns:

agent.on('agentfootprint.context.injected', (e) => {
// Every Skill / Steering / Instruction / Fact / Memory / RAG that activates
console.log(`[ctx] ${e.payload.source}${e.payload.slot}`);
});
agent.on('agentfootprint.permission.denied', (e) => {
console.log(`[BLOCKED] ${e.payload.toolName}: ${e.payload.reason}`);
});
agent.on('agentfootprint.cost.tick', (e) => {
console.log(`[$] +${e.payload.estimatedUsd} (cum ${e.payload.cumulative.estimatedUsd})`);
});

47 typed events across 13 domains. Your IDE auto-completes payload shapes per event name. See Observability guide for the full taxonomy.

For “why did the agent make that decision two weeks ago?”:

import { defineMemory, MEMORY_TYPES, MEMORY_STRATEGIES, SNAPSHOT_PROJECTIONS } from 'agentfootprint';
const causal = defineMemory({
id: 'causal',
type: MEMORY_TYPES.CAUSAL,
strategy: { kind: MEMORY_STRATEGIES.TOP_K, topK: 1, threshold: 0.7, embedder },
store,
projection: SNAPSHOT_PROJECTIONS.DECISIONS,
});
agent.memory(causal);

Every run persists its decision evidence as a snapshot. Two weeks later, when the customer comes back asking why, the matching snapshot loads into the next prompt. The follow-up answer is grounded in the EXACT past facts — not reconstruction. See Memory guide § Causal.

Coming in v2.4 Phase 3 — a deep-link from any recorded trace into the agent playground for visual time-travel debugging. Until then, the typed events + Causal memory are the textual equivalents.

  • Don’t console.log inside tool execute. Subscribe to agentfootprint.stream.tool_* events instead — typed, filterable, sinkable.
  • Don’t try to reconstruct what happened from JSON.stringify(agent). Use the typed event stream — the agent’s internal state isn’t a stable inspection surface.
  • Don’t enable EVERY event domain in production. Filter. Logs add up.