hermes-token-logger 2.1.0: The Database Repairs Itself
- hermes
- token-logger
- sqlite
- observability
- cost-tracking

I built hermes-token-logger to answer one question: what did today cost? The plugin writes every API call to a daily CSV file and a SQLite database, and /token-summary reads the database back.
Two stores means two chances to disagree. Version 2.1.0 makes that disagreement impossible to miss, and makes the database fix itself when it happens.
What changed
Four changes, all serving the same property: the numbers you read should be the numbers that were logged.
The database backfills itself. The CSV archives are now the recovery source. On every plugin start the plugin reads them and inserts whatever the database is missing, then fills in cost for any row that was written without one. Each call is identified by a hash of its contents, so the import is safe to repeat - a second run adds nothing.
/token-summary reconciles before it reports. Before printing totals, the tool compares the database against the archives. When they disagree it prints a warning naming the calls and dollars missing, plus any archive it could not read. A stale database can no longer return a plausible-looking total without saying something about it.
Cache-miss counts are real. The column existed and was written as a hardcoded zero, so it carried no information. It is now derived as input_tokens - cache_hit_tokens, which is what a miss is on any provider.
A stopped logger says so. Failures during logging are still swallowed so they never affect the agent. Five in a row now raise a warning, so a logger that has quietly stopped recording is visible.
What the archive looks like now
The database holds 66,620 calls across 1,307 sessions, from 2026-05-16 to today. Over the last 30 days that is 17,256 calls and $4.7434.
| What | Value |
|---|---|
| Rows in SQLite | 66,620 |
| Distinct sessions | 1,307 |
| Calls, last 30 days | 17,256 |
| Cost, last 30 days | $4.7434 |
| Rows carrying a cost | 28,256 |
| Input tokens, all time | 562,876,508 |
| Tokens served from cache | 7,295,623,202 |
| Duplicate row keys | 0 |
That cache figure is the reason this plugin earns its keep. 7.3 billion tokens came out of cache against 563 million that were not. Prompt caching is doing most of the work, and without a per-call log you are guessing at the ratio.
The row key detail
Worth writing down, because it is the kind of thing that quietly costs you data.
The obvious way to make an import idempotent is a unique index on (timestamp, session_id, api_call_n). That triple is not unique. Timestamps have one-second resolution, so two different calls in the same second with the same call number collide. The archives contain 21 such pairs, each with its own cost and latency, and a unique index drops one row from every pair.
Hashing the full row instead gives a key that is stable when the row repeats and distinct when two rows differ. Both rows of every colliding pair are now retained, and re-running the import still adds nothing.
Upgrading
cd ~/.hermes/plugins/token-logger && git pull
hermes plugins disable token-logger && hermes plugins enable token-logger
There is no migration step to run. The backfill happens when the plugin loads.
To see what a run did:
cd ~/.hermes/plugins/token-logger
python3 -c "from token_logger import import_existing_logs; print(import_existing_logs())"
# {'imported': 0, 'refreshed': 0, 'files_ok': 88, 'files_corrupt': 7, ...}
Seven May archives from the gzip era are corrupt and stay unreadable. They are listed by name now rather than skipped quietly.
One note on dual writes
Keeping a CSV and a database in sync is more work than keeping one, and this release is what that work looks like when it is not maintained. The CSV earns its place here for a specific reason: it is the independent record that lets the plugin check the database. Drop it and there is nothing left to reconcile against.
If you want a single store instead, the database handles the whole job on its own. That is a reasonable choice for a new install.
MIT licensed. github.com/underdown/hermes-token-logger