Skip to main content
Anvil’s tracing system captures every agent run as a tree of spans — one span per model call, tool call, retrieval, cache hit, or judge evaluation — and rolls up token usage and cost into the parent trace. Pass a Tracer instance to defineAgent and every request handled by that route is automatically instrumented, with no changes required inside individual handlers or tools.

Stores: where traces live

Anvil ships two TraceStore implementations. Choose one based on your environment.

MemoryTraceStore

Zero-dependency in-memory store. Traces survive only for the lifetime of the process — ideal for unit tests and local experimentation where you don’t need a database.

SqliteTraceStore

SQLite-backed store powered by better-sqlite3 (optional peer dependency). Persists traces across restarts. The recommended default for production. Default path: .anvil/traces.db.

MemoryTraceStore

Call store.clear() between test cases to reset state.

SqliteTraceStore

SqliteTraceStore.open creates the file and schema on first call. Pass ':memory:' for a process-scoped SQLite database that behaves like MemoryTraceStore but uses the same SQL interface.
better-sqlite3 is an optional peer dependency. Install it before using SqliteTraceStore:

Creating a Tracer

Tracer wraps a TraceStore and optionally accepts an onExport hook that fires when each trace ends — this is the seam used by the OpenTelemetry exporter.
TracerOptions accepts one field:
(trace: Trace) => void
Callback invoked with the completed Trace after traceHandle.end() is called. Use this to pipe traces to an external system without coupling your store to the export logic.

Wiring the Tracer into defineAgent

Pass the tracer as an option to defineAgent. Anvil opens one TraceHandle per incoming request and closes it when the response stream ends.

Naming traces

By default, Anvil names each trace agent <route-path>. Override this with traceName:

The Trace and Span types

Every finished trace is a Trace object containing a flat list of Span records that form a tree via parentId references.

Trace

Span

SpanKind identifies what produced the span:
Retrieval spans from ctx.retrieve() are recorded in the same trace tree as the agent run. They appear as kind: 'retrieval' children of the enclosing agent span, so you can see the full RAG context alongside model calls in one view.

TraceStore interface

If you need a custom backend (Redis, Postgres, etc.) implement TraceStore directly:
ListTracesOptions accepts limit and offset for pagination.

Full example

Every request to this route produces a trace persisted to SQLite. Open /_anvil in the browser to inspect the span tree, token usage, and cost in real time.