callmux has two complementary listener observability stores:
- The dashboard RRD JSON store (
callmux-metrics.json) keeps compact aggregate counters for history charts. - The optional SQLite event store (
eventStore) keeps bounded per-call rows for drill-down and audit queries.
The SQLite store is additive. Enabling it does not replace or disable the existing dashboard metrics.
eventStore requires Node 24's built-in node:sqlite module. It is off by default, so existing listener deployments keep the current no-database behavior until explicitly enabled:
{
"dashboard": {
"enabled": true
},
"eventStore": {
"enabled": true,
"path": "/var/lib/callmux/callmux-events.sqlite",
"maxRows": 100000,
"retentionDays": 14,
"pruneEvery": 100
}
}If path is omitted, listener mode stores callmux-events.sqlite beside the config file, or under ~/.config/callmux when no config file path is available.
Each completed top-level tool call records:
- timestamp
- requested tool, target tool, downstream server targets
- session id and authenticated principal when available
- transport:
clifor calls made through thecallmux call/tools/parallel/batch/pipelineCLI verbs,mcpfor any MCP client (including the stdio bridge) - duration, status, error class, cache hit
- approximate JSON bytes in and out
- call kind and downstream fan-out count
CLI and MCP traffic share the same authentication, authorization, and event-store recording path — a callmux call against an auth'd daemon carries the same principal an equivalent MCP tool call would. The transport tag is the only thing that tells them apart; use it to see whether a team is offloading long-tail tool usage to the CLI as intended.
Tool arguments and raw tool results are not stored in the event store.
For downstream servers configured with forwardHeaders, callmux records an audit row when a call used a session with a configured forwarded header present. The audit row stores:
- downstream server
- downstream tool
- session id
- principal
- forwarded header name
It does not store the header value. This preserves the credential passthrough invariant: callmux can show which credential scope was used without persisting the credential itself.
The event store uses SQLite WAL mode and prunes periodically:
retentionDaysdeletes old events by age.maxRowskeeps only the newest event rows by count.pruneEverycontrols how many completed calls occur between prune passes.
Both bounds can be active together. Deletes cascade to target and forwarded-header audit rows.
When both dashboard.enabled and eventStore.enabled are true, the dashboard exposes a Drill-down tab and JSON endpoint:
curl http://localhost:4860/dashboard/drilldown?range=1hSupported ranges match the existing dashboard charts: 1h, today, yesterday, 7d, and 30d.
The response includes a byTransport breakdown (alongside byServer/byTool/bySession) with one row per cli/mcp transport tag, so cli traffic showing up there is exactly how you confirm CLI calls are flowing through the same audit trail as MCP calls.