Real-time visualization interface for AI agent sessions. Monitor reasoning traces, explore knowledge graphs, and search session history.
Part of the Engram monorepo.
Session Browser
- Live sessions with real-time updates (WebSocket-powered)
- Historical sessions with timestamps and event counts
- Activity visualization bars showing event distribution
Session Detail View
- Lineage Graph: Interactive force-directed graph (React Flow) with Session, Turn, Reasoning, and ToolCall nodes
- Thought Stream: Scrollable timeline with user queries,
<thinking>blocks, tool calls, and assistant responses - Synchronized hover states between graph and timeline
Semantic Search
- UUID detection for direct navigation
- Hybrid search (vector + keyword) via Python search service
- Four-tier reranking system:
fast,accurate,code,llm - Configurable depth and latency budgets
System Health
- Real-time consumer group status footer
- Service monitoring: ingestion, memory, search, control
- Event-driven via Redis pub/sub (no polling)
# From monorepo root
bun install
bun run infra:up
# Start observatory
cd apps/observatory
bun run devAccess: http://localhost:6178
Custom WebSocket Server (server.ts)
- Next.js doesn't support WebSocket upgrades natively
- Custom HTTP server intercepts
/api/ws/*paths for WebSocket connections - Preserves HMR in development
Data Flow
Memory Service → Redis Pub/Sub → WebSocket Server → React Client
↓
FalkorDB (graph) → Observatory GraphQL/REST
↓
Qdrant (vectors) → Search Service → Observatory Search
WebSocket Endpoints
/api/ws/sessions- Global session list updates/api/ws/session/:sessionId- Individual session events/api/ws/consumers- Consumer health status
REST Endpoints
GET /api/sessions- List sessions (pagination)GET /api/lineage/:sessionId- Session graph (fallback)GET /api/replay/:sessionId- Session timeline (fallback)POST /api/search- Semantic search proxyPOST /api/graphql- GraphQL queries (GraphQL Yoga)
OAuth Endpoints (RFC 8628 Device Flow)
POST /api/auth/device/code- Generate device code for MCP authenticationPOST /api/auth/device/token- Poll for tokens or refresh existing tokensPOST /api/auth/introspect- RFC 7662 token introspectionGET /.well-known/oauth-authorization-server- RFC 8414 auth server metadata
Observatory issues OAuth tokens for MCP server authentication using a secure, identifiable format:
| Token Type | Format | Example |
|---|---|---|
| Access Token | egm_oauth_{random32}_{crc6} |
egm_oauth_a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4_X7kM2p |
| Refresh Token | egm_refresh_{random32}_{crc6} |
egm_refresh_a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4_Y8nL3q |
Format breakdown:
egm: Engram company identifier (unique to prevent prefix collisions)oauth/refresh: Token type identifierrandom32: 32 hex characters (128 bits of entropy fromcrypto.randomBytes)crc6: 6 Base62 characters (CRC32 checksum encoded as Base62)
Benefits:
- Secret scanning: Unique prefix allows GitHub/GitLab secret scanning to identify leaked tokens
- Offline validation: CRC32 checksum enables validation without database lookup (reduces false positives to ~0%)
- Type identification: Token type embedded in prefix for quick categorization
Implementation: See lib/device-auth.ts for generateAccessToken(), generateRefreshToken(), and validateTokenChecksum().
Design inspired by GitHub's token format.
- Framework: Next.js 16 (App Router, RSC), React 19
- TypeScript: 7 (tsgo - Go-based compiler)
- Visualization: React Flow (graph), Three.js (3D background)
- Real-time: WebSocket (
wslibrary) - Data: FalkorDB (graph), Qdrant (vectors via search service), NATS (streaming)
- Testing: bun:test, Playwright
- Linting: Biome
bun run dev # Dev server with WebSocket handler
bun run build # Production build
bun run typecheck # TypeScript validation
bun run lint # Biome linting
bun run test:e2e # Playwright E2E testsObservatory uses .env symlinked to configs/env/observatory.env:
REDIS_URL=redis://localhost:6379 # FalkorDB + Redis pub/sub
SEARCH_URL=http://localhost:6176 # Python search service
PORT=6178 # Observatory portWebSocket fails: Run bun run dev (not next dev), ensure Redis is running
No sessions: Check FalkorDB running, generate test data with bunx tsx scripts/traffic-gen.ts
Search fails: Verify Qdrant and search service running at http://localhost:6176
Services offline: Run bun run dev from monorepo root, allow 30s for heartbeats
- Engram Overview - Monorepo structure
- Search Service - Python/FastAPI search
- Memory Service - Graph persistence