Symphony's token usage stats (input/output/total per Codex session, plus the codex_totals aggregate) currently live only in the running orchestrator's in-memory state. When Symphony restarts — which happens often during dogfooding — all token history resets to zero. There's no way to see cumulative cost over a day, week, or month, only "since boot."
What to build
Persist token stats across restarts and surface them in the dashboard with at least:
- Cumulative totals across all Symphony runs (lifetime input/output/total tokens, total Codex runtime seconds).
- Per-issue token history: each completed Codex session writes a record (issue id + identifier, started_at, completed_at, turns, input/output/total tokens, runtime_seconds, final state, model used).
- Per-restart aggregate: each Symphony boot writes a "run" record (started_at, stopped_at, restart reason if known, peak concurrent agents, sessions launched, tokens used during that run). Useful for spotting expensive restarts.
Storage
A small embedded SQLite database under ~/.local/share/symphony/stats.db (or whatever the workspace root sibling is) is enough. Schema sketch:
CREATE TABLE symphony_runs(id INTEGER PRIMARY KEY, started_at TEXT, stopped_at TEXT, …);
CREATE TABLE codex_sessions(id INTEGER PRIMARY KEY, run_id INTEGER, issue_id TEXT, identifier TEXT, started_at TEXT, completed_at TEXT, turns INTEGER, input_tokens INTEGER, output_tokens INTEGER, total_tokens INTEGER, runtime_seconds INTEGER, final_state TEXT, model TEXT);
Append-only writes; no migrations across schema changes — just version the DB file and write a new one.
Dashboard additions
- New "Lifetime totals" card on the hero metrics row (tokens + runtime + sessions across all runs).
- New "Recent sessions" section listing the last 20 completed Codex sessions with their token + runtime numbers.
- Existing "Runtime" metric shows the active run; add a tooltip or sub-line "this run / all time" so the cumulative number is visible.
Acceptance
- Tokens and runtime persist across
Ctrl-C + restart.
- Dashboard shows cumulative totals alongside current-run totals.
- The stats DB is portable: deleting it resets history without breaking Symphony.
- Existing
/api/v1/state endpoint stays backward-compatible; new lifetime data is exposed on a new endpoint or as an additive field.
- 100% coverage gate still passes; the SQLite layer goes through a small testable interface module (the raw connection stays in
ignore_modules like other HTTP/external shells).
Why now
Surfaced during dogfooding when the user restarted Symphony to pick up new workflow + favicon changes and noticed the token totals on the dashboard went back to zero. Hard to reason about spend without persistence.
Symphony's token usage stats (input/output/total per Codex session, plus the
codex_totalsaggregate) currently live only in the running orchestrator's in-memory state. When Symphony restarts — which happens often during dogfooding — all token history resets to zero. There's no way to see cumulative cost over a day, week, or month, only "since boot."What to build
Persist token stats across restarts and surface them in the dashboard with at least:
Storage
A small embedded SQLite database under
~/.local/share/symphony/stats.db(or whatever the workspace root sibling is) is enough. Schema sketch:Append-only writes; no migrations across schema changes — just version the DB file and write a new one.
Dashboard additions
Acceptance
Ctrl-C+ restart./api/v1/stateendpoint stays backward-compatible; new lifetime data is exposed on a new endpoint or as an additive field.ignore_moduleslike other HTTP/external shells).Why now
Surfaced during dogfooding when the user restarted Symphony to pick up new workflow + favicon changes and noticed the token totals on the dashboard went back to zero. Hard to reason about spend without persistence.