Architecture
How the pieces fit together.
System Overview
Data Flow
- Instrumentation: Your agent code uses decorators (
@track_agent,@track_tool_call) or manualagentlens.track()calls to create events. - Buffering: The
Transportlayer buffers events in memory and flushes them in batches (default: every 10 events or 5 seconds). - Ingestion: Batched events are sent via HTTP POST to
/events. Session lifecycle events (session_start,session_end) manage session records. - Storage: Events and sessions are persisted to SQLite with WAL mode for concurrent read/write performance.
- Visualization: The dashboard queries the API to display timelines, token charts, and explanations.
Component Details
Python SDK (sdk/)
| Module | Responsibility |
|---|---|
__init__.py | Module-level API (init, track, explain). Global tracker instance. |
models.py | Pydantic data models (AgentEvent, ToolCall, DecisionTrace, Session) |
tracker.py | AgentTracker — manages sessions, creates events, generates explanations |
transport.py | Batched HTTP transport with background flush thread and retry logic |
decorators.py | @track_agent and @track_tool_call for zero-config instrumentation |
Backend (backend/)
| File | Responsibility |
|---|---|
server.js | Express app setup, middleware, static file serving, routes |
db.js | SQLite connection (better-sqlite3), schema initialization |
routes/events.js | POST /events — batch event ingestion with transaction support |
routes/sessions.js | GET/POST sessions, session detail, explain endpoint |
seed.js | Demo data seeder |
Dashboard (dashboard/)
A lightweight single-page application built with vanilla HTML, CSS, and JavaScript. No build step, no framework dependencies. Served directly by the Express backend.
Design Decisions
Zero configuration. No external database to install or manage. SQLite with WAL mode handles concurrent reads and writes well for single-server deployments. The database file lives in the backend directory and can be backed up by copying a single file.
Sending individual HTTP requests per event would add unacceptable latency to agent execution. The Transport layer buffers events and sends them in batches, using a background thread so tracking never blocks your agent's main execution path.
No build step means zero friction to get started. The dashboard loads instantly without webpack, Vite, or any toolchain. For an observability tool, simplicity of deployment trumps framework features.