An Evening Plugin: Local vs Cloud Token Analytics for Hermes Desktop

Created

August 21, 2026 · James Meadlock & Milo

Teknium asked for Hermes feature requests, and the one I actually wanted turned out to mostly exist already — just not on screen. Hermes records token usage per model, per endpoint, per task (chat vs compression vs approval checks vs title generation) in a local SQLite table, including cache reads/writes and reasoning tokens. The built-in /usage and hermes insights views aggregate most of that away. For someone running five LAN inference endpoints alongside cloud subscriptions, the question I care about — what did my own hardware serve vs what did I pay for? — was sitting unanswered in a table nobody was reading.

So instead of filing the feature request, Milo and I built it as a plugin in an evening: jmeadlock/hermes-usage-pane, public and MIT.

What it does

What the data actually showed

First real render, 30 days, milo profile:

BillingInput tokensCache hit
Subscription (OAuth flat-rate)153.3M93.3%
API (metered)8.2M97.9%
Unknown (aux routing)3.6M
Local0.4M

95% of my cloud tokens ride flat-rate OAuth subscriptions. Metered API spend is a rounding error. I suspected this; now it's a chart. The task view was the other surprise: background review, compression, and approval checks together burned ~12M input tokens in a month — overhead you never see in a chat window.

Why the honest floor is daily buckets

The source table stores running totals per (session, model, task) with only first-seen/last-seen timestamps. A three-day session that made 400 calls is one row; the individual call times were summed away at write time. Daily bucketing is the honest historical floor — drawing an hourly line from that data would be fake precision.

That's why sub-day charts are gated behind the sampler: it builds a true timeline going forward from deltas it observes itself, rather than back-filling guesswork. The tok/s metric it derives is labeled for what it is — output delta over wall-clock interval, an effective rate, not a decode benchmark.

Build notes: what bit us

Symlinked plugins don't hot-reload. The desktop app watches its plugin directory, but file watchers don't fire on symlink targets. Edits landed in the repo; the app kept running stale code. Dogfood loop is edit-in-repo, then cp into the watched directory.
Read the component source, not your assumptions. Hermes's SegmentedControl takes options:[{id,label}] + onChange — not the Radix-style value/onValueChange I wrote first. Wrong props fail silently: the toggle rendered fine and did nothing.
Tailwind classes only exist if the app compiled them. Plugin files load uncompiled, so utility classes the app itself never uses (grid-cols-3) are absent from the shipped CSS and silently no-op. Inline styles for any layout the host app doesn't already use.
Know which process serves your backend. The desktop app here rides the machine dashboard, not the profile gateway — so the plugin enable, the config edit, and the restart all target a different process (and a different profile's config) than the obvious one. My agent killed that process mid-turn once, taking its own session down with it. Once.
The backend was verified against the real database before ever touching the UI: locality classifier 11/11 test cases, live 30-day aggregates matching hermes insights totals, settings clamping. When the page first rendered, the numbers were already known-good.

Maintenance stance

This is a working prototype, v0.x. It runs on my machine against the current Hermes schema. The repo is public and MIT because that costs nothing and someone might want the idea, the queries, or the whole thing pulled into Hermes core — the session_model_usage table already has everything a native local/cloud analytics view needs. PRs welcome. Support promises: none.

Provenance: all figures measured live this session from ~/.hermes/profiles/milo/state.db via the plugin's own query path. Repo: github.com/jmeadlock/hermes-usage-pane. Built August 21, 2026 in one evening session with Milo (claude-fable-5).

← al-engr.com