tokenarchive
Enables agents to query your archived AI coding usage through read-only tools for usage summaries, project breakdowns, daily trends, and archive health.
README
tokenarchive
Daily snapshots of your AI coding usage, kept forever.

ccusage can tell you what Claude Code, Codex, Gemini and friends cost you — but only as far back as the logs on your machine go, and those logs rotate. tokenarchive snapshots the ccusage report once a day, keeps every snapshot as an append-only JSON archive, and renders a dashboard from it. Optionally, a Cloudflare Worker keeps a copy of the archive off your machine, behind a passkey.
Two principles shape everything here:
- Nothing is ever erased. Snapshots are the archive; every database is a derived copy that can be rebuilt from them.
- Absence is never reported as zero. A day with no snapshot says so. $0.00 would claim we looked and you spent nothing.
Quickstart (macOS)
npx tokenarchive
The installer prompts for a device name and an optional Worker URL, puts the
runtime under ~/.local/share/tokenarchive/app, schedules the daily job
(23:50 plus every login — the script is idempotent), lets security prompt
for the ingest token so it never crosses the installer's hands, and proves
the whole thing with one real run. Re-run it any time to reconfigure;
--uninstall removes everything except your archive.
Snapshots land in ~/.local/share/tokenarchive/{device}/{date}.json. To try
it once without installing anything:
git clone https://github.com/ddyy/tokenarchive && cd tokenarchive && ./snapshot.sh
Other platforms: everything except the scheduling glue is portable. sync.js,
the importer and the dashboard are plain Node; port snapshot.sh to a systemd
timer or cron job and the rest follows.
The dashboard
generate-dashboard.js builds a single self-contained HTML file — no
framework, no server, no external requests. It imports new snapshots into a
local SQLite read model first (import-snapshots.js), so regeneration is
incremental.
Every panel is a filter: click or drag across models, devices, agents, days, or billing windows and the rest of the page follows (⌘ adds to a selection, ⇧ extends it). Filters compose across dimensions with AND, and live in the URL fragment, so a view can be bookmarked.
<table> <tr> <td width="50%"><img src="docs/models.png" alt="Cost by model"></td> <td width="50%"><img src="docs/projects.png" alt="Cost by project"></td> </tr> <tr> <td><img src="docs/devices.png" alt="Cost by device"></td> <td><img src="docs/blocks.png" alt="Recent billing windows"></td> </tr> </table>
A Display as switch — above the totals, and again in the sticky bar once they scroll away — measures the whole page in dollars or in tokens: the chart and its axis, the coverage shading, the billing windows, and every list, which reorders to match. Hovering a row gives the full name it had to truncate, its cost, tokens, the implied rate per million, its share of what is on screen, and — for projects — the session count and the span they cover:

The coverage strip shows one cell per calendar day, so a gap is visible as a gap — days with no snapshot are never drawn as zero-usage days:

Multiple devices
The archive is partitioned by device from the filesystem up: snapshots live
in {data}/{device}/{date}.json, every database row carries the device, and
importing is upsert-only. Machines therefore never merge or clobber each
other, and anything that lands both machines' files under one data directory
gives you a combined archive — a Worker, a synced folder, or a copied
directory all work the same way.
Health is judged per device: each gets its own green/amber/red dot, its own last-snapshot date, and its own missing-days list, so one current machine cannot hide another that has gone quiet. A device that stops reporting keeps all of its history — the archive never erases; it just shows the gap.
The Worker below is the way to do this without moving files by hand.
The Worker (optional, recommended)
The worker/ directory is a Cloudflare Worker that accepts snapshot pushes
and serves the same dashboard from D1, behind WebAuthn passkeys. The raw
snapshots are kept verbatim in R2 — that is what makes it a backup rather
than a view: /admin/replay can rebuild D1 from the bucket without your
laptop. See worker/README.md for the five-command deploy.
Once deployed, register a passkey at /auth/ — the first passkey claims the
archive; adding another device's passkey requires being signed in. Then
generate a per-device ingest token at /admin (the token reveal includes
setup instructions) and the daily snapshot job pushes automatically. A
machine that never syncs has lost nothing: the files on disk are the
archive, and the next successful sync catches up. Stale pushes cannot
clobber newer data — ingest keeps whichever snapshot is newest.
/admin manages the rest: ingest tokens and read-only MCP tokens (shown
once, revocable per device), session-key rotation, a snapshot inventory,
and /admin/replay, which rebuilds D1 from the R2 originals.
To add a second machine, run the installer there with the same Worker URL and mint it its own ingest token — a token only ingests as the device it was minted for, so one machine cannot write as another and revoking one never touches the others.
MCP
Ask your agent about your own usage. Two servers, same four read-only tools
(usage_summary, usage_by_project, usage_by_day, archive_health),
one shared implementation:
-
Local, over the SQLite archive on this machine:
claude mcp add tokenarchive node /path/to/tokenarchive/mcp-server.js -
Remote, served by the Worker at
/mcpfor machines that do not hold the archive. Mint anmcptoken at/admin, then:claude mcp add --transport http tokenarchive https://YOUR-WORKER/mcp \ --header "Authorization: Bearer YOUR-TOKEN"
Read-only by construction: there is no tool that writes, deletes or rewrites anything.
Configuration
Everything is overridable by environment variable, nothing requires it:
| Variable | Default |
|---|---|
TOKENARCHIVE_DATA |
~/.local/share/tokenarchive |
TOKENARCHIVE_DB |
{data}/tokenarchive.db |
TOKENARCHIVE_DEVICE |
short hostname |
TOKENARCHIVE_URL |
unset — no sync |
TOKENARCHIVE_TOKEN |
unset — read from the login keychain (tokenarchive-ingest) |
Tests
bash test/run.sh
Most suites are hermetic. Three (static, interaction, tooltip) run
against the dashboard you last generated at
~/.local/share/tokenarchive/index.html, so they need a real archive on the
machine — run the snapshot once first.
License
MIT
Recommended Servers
playwright-mcp
A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.
Magic Component Platform (MCP)
An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.
Audiense Insights MCP Server
Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.
VeyraX MCP
Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.
graphlit-mcp-server
The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.
Kagi MCP Server
An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.
E2B
Using MCP to run code via e2b.
Neon Database
MCP server for interacting with Neon Management API and databases
Exa Search
A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.