Operational Telemetry
From spec-memo Wiki, the living architecture & domain knowledge base
Feature Overview [edit]
spec-memo optionally records a structured, append-only usage stream to help agents and operators analyze latency, error frequency, and unused endpoints. Telemetry is controlled by enableTelemetry (default true) in config.json, with rolling file limits under the external vault at $SPEC_MEMO_ROOT/telemetry/ — never inside a product git repository.
Each event is one JSON line:
{"timestamp":"2026-08-27T04:20:00.000Z","eventId":"tel-<uuid>","category":"mcp_tool","operation":"bootstrap","durationMs":18.3,"success":true,"projectId":"github.com-org-repo","metadata":{"itemCount":12}}
Capture surfaces: MCP tool executions (mcp_tool), HTTP requests in the SSE and status servers (http_endpoint), CLI subcommand runs (cli_command), sync cycles (sync_operation), curator GC (curator_gc), the importer (importer), and handoffs (handoff).
Business Rules & Logic [edit]
- Enable precedence:
SPEC_MEMO_ENABLE_TELEMETRYenv var wins overconfig.jsonenableTelemetry, which defaults totruewhen unset. Env falsy values are0,false,off,no; truthy values are1,true,on,yes. When disabled,recorddiscards immediately with zero disk I/O and zero queue growth. - Event schema:
timestamp(ISO-8601 UTC),eventId(tel-<uuid>),category(enum),operation,durationMs(rounded to 1 decimal, floored at 0),success(boolean), optionalerrorCode, optionalprojectId, optional sanitizedmetadataobject. - Rolling files:
telemetry-YYYY-MM-DD.part-N.jsonlunder$SPEC_MEMO_ROOT/telemetry/. The date is the event's UTC day;Nstarts at1. When appending would push the current part pastmaxFileSizeMb(default10MB), the engine advances topart-{N+1}; on a new UTC day it starts atpart-1without a process restart. - Batching is non-blocking: events queue in memory and flush on a timer (
flushIntervalMs, default500ms) or immediately when the queue reachesmaxQueueSize(default50). Flush writes are wrapped in the vault lock and usefs.appendFileSync. - Fail-safe: any write, permission, or filesystem error is caught internally, stored as
lastError, and never rejects or interrupts an MCP tool response, CLI command, or HTTP request.recordTelemetryitself swallows errors. - Metadata is scrubbed through
sanitizeToolOutput; credentials, tokens, and absolute host paths must not appear in telemetry metadata. - Drain on exit: a
process.on('beforeExit')handler callsflushTelemetrySync, and serverclose()paths callflushTelemetrySyncplusawait closeTelemetry.closeTelemetrymarks the recorder closed, flushes asynchronously and synchronously, and removes the cached recorder and enabled-cache entry. memo doctortreats in-repotelemetry.jsonlas pollution; the vaulttelemetry/directory is in the vault-git ignore list.
Technical Architecture [edit]
src/telemetry.ts:isTelemetryEnabled,getTelemetryDir,TelemetryRecorderclass (record,flush,flushSync,resolveCurrentPartFile,applyConfig,close), and module functionsgetTelemetryRecorder,recordTelemetry,flushTelemetry,flushTelemetrySync,closeTelemetry,resetTelemetryRecorderForTest,listTelemetryFiles,readTelemetryEvents.DEFAULT_TELEMETRY_CONFIG={ maxFileSizeMb: 10, flushIntervalMs: 500, maxQueueSize: 50 };VaultConfig.telemetryacceptsmaxFileSizeMb,flushIntervalMs,maxQueueSize.applyConfigclampsflushIntervalMsto a 100 ms floor and sizes to at least 1.- Config reads are cached per vault root keyed by
config.jsonmtime, so hot edits take effect without repeated synchronous reads on the tool hot path. - One recorder instance is kept per vault root in a module-level map;
getTelemetryRecordermerges file config with per-call options. listTelemetryFilesreturnstelemetry-*.jsonlsorted;readTelemetryEvents(vaultRoot, { date?, part? })parses lines and skips corrupted entries.- Type contract (
src/types.ts):TelemetryCategory,TelemetryEvent,TelemetryEventInput,TelemetryConfig. - Provenance:
0028-operational-telemetry.spec.md. The spec's CLI inspector surface isreadTelemetryEvents/listTelemetryFiles(no new MCP tool or CLI command); telemetry is machine-local and excluded from backups of durable records.