# Cost visibility: data sources, recipes, and the live-counter design

Where "what did we spend?" gets answered from, in order of increasing effort. All verified 2026-08-09 against the VPS gateway (0.19.0 pip install).

## 1. `hermes insights` CLI — fastest overview

```bash
/root/.hermes/venv/bin/hermes insights --days 4
```

Gives sessions, messages, tool calls, input/output/total tokens, per-model / per-platform / per-tool / per-skill breakdowns, activity patterns, and "notable sessions" (most tokens, most tool calls). **It shows tokens, not dollars** — use it to find the fat sessions, then get costs from SQL or the API below.

## 2. Direct SQL on `/root/.hermes/state.db` — per-session dollars

Use the venv python heredoc (`sqlite3` CLI is not installed). Two tables matter:

- `sessions`: `estimated_cost_usd`, `actual_cost_usd`, `input_tokens`, `output_tokens`, `cache_read_tokens`, `api_call_count`, `message_count`, `tool_call_count`, `model`, `source`, `title`.
- `session_model_usage`: per-(session, model, task) rows — includes aux tasks (title_generation, vision) that never appear in `sessions`.

Per-day, per-model cost:

```sql
SELECT date(last_seen,'unixepoch'), model, SUM(api_call_count),
       SUM(input_tokens), SUM(output_tokens), SUM(cache_read_tokens),
       ROUND(SUM(estimated_cost_usd),4)
FROM session_model_usage
WHERE last_seen >= strftime('%s','2026-08-06')
GROUP BY 1, 2 ORDER BY 1;
```

Top sessions by cost:

```sql
SELECT id, source, model, message_count, tool_call_count, api_call_count,
       input_tokens, output_tokens, cache_read_tokens,
       ROUND(estimated_cost_usd,3), substr(coalesce(title,''),1,60)
FROM sessions WHERE started_at >= strftime('%s','2026-08-06')
ORDER BY estimated_cost_usd DESC LIMIT 12;
```

**Costs are gateway ESTIMATES** (`cost_status='estimated'`, `actual_cost_usd` = 0/NULL everywhere) — not reconciled against the Nous invoice. Expect a gap vs the user's perceived bill: image generation, Firecrawl web tools, and TTS are billed provider-side and don't land in these tables. When the user says "$70" and the DB says $52, that gap is the explanation — say so plainly.

## 3. Live REST API — the feed for any counter

`GET /api/analytics/usage?days=N` on the dashboard backend (127.0.0.1:9119). Returns JSON with `daily[]`, `by_model[]` (with `aux_tasks`), `by_task[]`, `totals{}` — all with `estimated_cost` per bucket. Auth: bearer token scraped from the dashboard HTML:

```bash
TOKEN=$(curl -s http://127.0.0.1:9119/ | grep -oP 'window.__HERMES_SESSION_TOKEN__="\K[^"]+')
curl -s "http://127.0.0.1:9119/api/analytics/usage?days=1" -H "Authorization: Bearer $TOKEN"
```

Token is pinned via `HERMES_DASHBOARD_SESSION_TOKEN` in `hermes-serve.service` — it survives restarts, so a poller can cache it. Also `/api/analytics/models`. Implementation: `web_server.py` `_get_usage_analytics` (~line 15976).

## Dead end (don't repeat)

`~/.hermes/sessions/request_dump_*.json` look like usage logs but are per-request **error dumps** (keys: timestamp, session_id, reason, request, error). No token or cost data. Sessions index `sessions.json` in the same dir is 444 bytes — not a ledger either.

## Worked anatomy: the Aug 8 session (why cache_read is the metric that matters)

"Bail Bonds Launch Session Handoff" (desktop, kimi-k3): 955 messages, 397 tool calls, **418 API calls**, 2.35M input tokens but **88.96M cache_read_tokens** → $29.18 estimated = 56% of the 4-day spend in one session. Every one of those 418 calls re-sent the entire growing conversation history; cache reads bill at a fraction of input price but 89M of them still cost real money. The model choice wasn't the problem (minimax-m3 ran $0.53 total across 7 sessions; deepseek-v4-flash subagents were $0.04/task). **The expensive behavior is long-lived sessions that never get compacted/reset.** Rule of thumb for the user: past a few hundred messages, `/new` + re-anchor with a handoff summary.

## Live counter design (options presented to user 2026-08-09, decision pending)

The data feed already exists (option 3 above) — the only decision is where to render it:

1. **VPS dashboard card** polling `/api/analytics/usage` — server-side, survives reboots, works from any client, lowest risk. RECOMMENDED.
2. **Windows tray widget** on Connie polling the VPS every 30s — best eyeline, but a new process to build/auto-start/maintain, and dies when the laptop sleeps (exactly when long sessions run).
3. **Desktop app header chip** — fragile: Connie runs an unpacked dev build (40.10.2) with no auto-update; the patch is throwaway once the proper Desktop install lands.
4. **Threshold alert cron** — not a counter, but the backstop that should ship regardless of which counter is chosen: `no_agent` cron, same wiring quirks as the gateway watchdog (pass script filename only — absolute paths rejected; set `deliver: 'origin'` explicitly or alerts save to the job log and go nowhere). Suggested thresholds from the Aug 8 anatomy: ping when any single session crosses ~$5 or the day crosses ~$20. SQL for the check: query `sessions` for `estimated_cost_usd` since midnight UTC / per-session over threshold, state-file to make it transition-only.
