Daemon overview
The daemon is OpenUsage's runtime. It is a small background service that continuously collects usage data from AI providers and tool integrations, persists it to SQLite, and serves a unified read model to the TUI. The TUI is a thin client that reads from the daemon over a Unix domain socket.
Install once with:
openusage telemetry daemon install
What you get
- Long-lived history. Events persist across TUI restarts and machine reboots, so analytics and time-window views (
7d,30d,all) reflect real activity. - Hook-based ingestion. Tools like Claude Code, Codex, and OpenCode push every turn, message, and tool call directly to the daemon — no polling lag, no missed events.
- Single source of truth. All AI usage lives in one SQLite database with deduplication, retention, and provider linking.
- Always-on collection. Provider rate-limit headers are polled on the configured interval whether or not the TUI is open.
Dataflow
+----------------------+ +---------------------+
| Collectors | | Tool hooks |
| (poll providers) | | (claude-code, |
| | | codex, opencode) |
+----------+-----------+ +----------+----------+
| |
| HTTP over Unix socket | POST /v1/hook/{source}
v v
+------------------------------------+
| openusage daemon |
| +------------------------------+ |
| | Pipeline | |
| | - dedup (tool_call_id → | |
| | message_id → turn_id → | |
| | fingerprint hash) | |
| | - provider linking | |
| | - retention | |
| +--------------+---------------+ |
| v |
| +-----------------+ |
| | SQLite store | |
| | telemetry.db | |
| +--------+--------+ |
| v |
| +-----------------+ |
| | ReadModel | |
| +--------+--------+ |
+------------------|-----------------+
| POST /v1/read-model
v
+---------------+
| TUI client |
+---------------+
Three input sources feed the pipeline:
- Collectors — provider plugins driven by the daemon's polling loop. They ingest rate-limit headers, billing snapshots, and dashboard-scraped balances.
- Hooks — tool integrations POST events to the daemon over its Unix socket as they happen. See Integrations.
- Spool — when the daemon is unreachable (hook fired but socket missing), events are written to a disk queue and drained on next startup. See Storage.
Endpoints
The daemon listens on a Unix domain socket (no TCP):
| Method | Path | Purpose |
|---|---|---|
GET | /healthz | Liveness probe. Returns 200 OK when the pipeline is healthy. |
POST | /v1/hook/{source}?account_id=… | Hook ingestion. {source} matches a provider link. |
POST | /v1/read-model | TUI client fetches a UsageSnapshot map for the current time window. |
Default socket: ~/.local/state/openusage/telemetry.sock. Override with --socket-path or the OPENUSAGE_TELEMETRY_SOCKET environment variable.
Timeouts are tight and per-caller:
- TUI client (
/v1/read-model): 2-second dial, 12-second request. - Hook command (
POST /v1/hook/<source>): 15-second overall context. On failure the event is written to the spool and re-ingested when the daemon comes back.
The protocol is meant to be local and fast.
What the daemon is not
- Not a network service. It is bound to a Unix socket on your machine. There is no TCP listener, no auth, no remote ingest.
- Not multi-user. One daemon per user account. Run separate daemons for separate users.
- Not a replacement for provider dashboards. It mirrors and aggregates; it does not bill.
Next steps
- Install the daemon on macOS or Linux
- Configure tool integrations for Claude Code, Codex, and OpenCode
- Inspect the SQLite store and tune retention
- Troubleshoot socket, log, and corruption issues