Storage Architecture
Storage Interface
All storage operations go through the IEventStore interface defined in @agentlensai/core. This makes the storage backend pluggable — SQLite and PostgreSQL share the same contract.
typescript
interface IEventStore {
// Write
insertEvents(events: AgentLensEvent[]): Promise<void>;
upsertSession(session: Partial<Session>): Promise<void>;
upsertAgent(agent: Agent): Promise<void>;
// Read — Events
queryEvents(query: EventQuery): Promise<EventQueryResult>;
getEvent(id: string): Promise<AgentLensEvent | null>;
getSessionTimeline(sessionId: string): Promise<AgentLensEvent[]>;
countEvents(query: EventQuery): Promise<number>;
// Read — Sessions
querySessions(query: SessionQuery): Promise<SessionQueryResult>;
getSession(id: string): Promise<Session | null>;
// Read — Agents
listAgents(): Promise<Agent[]>;
getAgent(id: string): Promise<Agent | null>;
// Analytics
getAnalytics(params: AnalyticsParams): Promise<AnalyticsResult>;
// Alert Rules
createAlertRule(rule: AlertRule): Promise<void>;
updateAlertRule(id: string, updates: Partial<AlertRule>): Promise<void>;
deleteAlertRule(id: string): Promise<void>;
listAlertRules(): Promise<AlertRule[]>;
getAlertRule(id: string): Promise<AlertRule | null>;
// Maintenance
applyRetention(maxAgeDays: number): Promise<{ deletedCount: number }>;
getStats(): Promise<StorageStats>;
}SQLite (Default)
Why SQLite?
- Zero external dependencies — just a file on disk
- WAL mode enables concurrent reads with writes
- Excellent performance for single-instance deployments
- Perfect for self-hosted and edge deployments
Configuration
| Pragma | Value | Purpose |
|---|---|---|
journal_mode | WAL | Concurrent read/write |
synchronous | NORMAL | Balance durability + speed |
cache_size | -64000 | 64 MB page cache |
busy_timeout | 5000 | 5s retry on contention |
Schema
Managed by Drizzle ORM with automatic migrations on startup.
Tables: events, sessions, agents, alert_rules, alert_history, api_keys, config_kv
Key Indexes:
idx_events_timestamp— Time-range queriesidx_events_session_id— Session timelineidx_events_agent_id— Agent filteringidx_events_type— Event type filteringidx_events_session_ts— Composite: session + timestampidx_events_agent_type_ts— Composite: agent + type + timestamp (dashboard pattern)idx_sessions_agent_id,idx_sessions_started_at,idx_sessions_status
PostgreSQL (Team)
For teams needing shared access, configure with:
bash
DATABASE_URL=postgresql://user:pass@host:5432/agentlens
DB_DIALECT=postgresqlSame IEventStore interface, same API behavior.
Retention Policy
A configurable retention engine deletes old events to prevent unbounded growth:
- Default: 90 days
- Configurable:
RETENTION_DAYSenvironment variable or Settings page 0= keep forever- Sessions with no remaining events are also cleaned up
- Runs daily on a scheduled interval
This is the only exception to the "no DELETE" rule — retention cleanup is an audited operation.
Performance Targets
| Metric | Target |
|---|---|
| Event ingestion throughput | ≥ 1,000 events/sec |
| Ingestion latency (P95) | < 5ms per event (batch of 100) |
| Query latency (P95) | < 100ms for filtered queries (< 1M events) |
| Timeline render | < 1s for sessions with 1,000 events |