Claude Observatory
Local-first session analytics for Claude Code, built because I had no idea where my tokens were going.
What this is
Observatory reads the JSONL transcripts Claude Code already writes to your machine and turns them into session economics. Cost per session, tokens by category, cache hit ratio, context escalation turn by turn, which workspace is eating your month, when you actually work. There's a terminal statusline that shows live token economics while you're in a session, and a static dashboard for the history.
No collector, no API key, no account. If you use Claude Code, the data already exists on disk.
The reason it exists: I was running dozens of agent sessions a week across three workspaces and could not answer the simplest question about them. Anthropic's dashboard shows billing. The /context command shows right now. Neither tells you that Thursday cost six times Tuesday and why. As of late July 2026 it has parsed 1,575 sessions of mine.
Why it's built this way
The transcript is truth
Every assistant message carries a usage block with exact input, output, cache-read, and cache-write counts, plus the model. That's everything needed. No sampling, no estimation, no instrumentation to add.
Local-first, deliberately
SQLite on your machine. Nothing leaves unless you export it. Transcripts contain your actual work, which for me means three businesses' worth of context. A hosted usage tool would be a lovely product and I would never install it.
Dollars, not tokens
"You used 1.8 million input tokens" means nothing to a person. "You spent $35 on that session, and 83% of your input was cache reads at a tenth the price" changes what you do next. The estimates are labeled as estimates... subscription users don't pay per token, and the number is still the best available signal about relative waste.
The build log, failures left in
2026-04-03
— Repo opened with the PRD written first, because I'd already built the wrong version once.
THE WRONG VERSION WAS OPENTELEMETRY
Claude Code sets OTEL env vars and connects to a local OTLP receiver, so I built one on port 4318 and ran it as a LaunchAgent. It logged 4,197 entries and zero non-empty payloads. The exporter was faithfully shipping empty batches because the application doesn't instrument its internals with OTEL metrics. I had built a collection pipeline for telemetry that does not exist. Ripped out, LaunchAgent unloaded, and the transcript parser became the only real data path.
2026-04-04 · THE COST BUG
The parser was rolling cache tokens into input_tokens, then the cost function charged those same tokens again at their cache rates. Cache reads were being billed at $16.50 per million instead of $1.50. Every number the dashboard had ever shown was wrong by a lot: total cost across 160-plus sessions dropped from roughly $25,000 to roughly $4,000 after re-backfill. The lesson I wrote down that day is the one I keep reusing... when you build a cost calculator over tiered pricing, prove the token categories are mutually exclusive before you sum them. Draw the flow. Raw tokens, then categorization, then pricing, then total.
SAME DAY · THE STALENESS FIX
Export had been a manual step, so the published dashboard was always behind. Now the SessionEnd hook chains into a background export and an hourly LaunchAgent runs as a safety net. Any pipeline with a manual transition goes stale. Automate every transition, including the boring one at the end.
Since then
— model pricing rows added as new models shipped, workspace and account mapping, and an ingest path that feeds the same parsed sessions into my larger personal system for search.
⚠ What would break
Unknown models silently price as Sonnet. The pricing table is a dict with a default fallback. Run a model that isn't in the table and its cost lands at Sonnet rates with no warning, no flag, no row in a report. If that model is Opus-class, the understatement is roughly 5x on input and output. My own table is already missing at least one model I actively use, which means some of my own numbers are low right now. It's the same shape of bug as the 2026-04-04 one: a cost system that fails quietly instead of loudly.
Estimates are not bills. Under a subscription, none of these dollars are charged. The tool is measuring what the work would cost at API rates, which is the right proxy for waste and the wrong number to put in a budget. Anyone reading the dashboard without that context will misread it.
Nothing separates real work from test runs. A verification script and a real session look identical to the parser. Every aggregate mixes them.
Account detection is macOS-only, since it reads the system keychain. Other platforms fall back to config or workspace inference.
What I learned
Presence of instrumentation is not presence of data. The OTEL env vars were there, the connection was there, the receiver worked perfectly, and it received nothing of value for weeks. I never checked payload contents until I went looking for why the numbers were empty.
Cost bugs are the worst class of bug, because the output is always plausible. A wrong function crashes. A wrong price just prints a number, and you believe it. I looked at an inflated $25,000 total for weeks and my reaction was "wow, this is expensive," never "this is wrong."
Where the AI was confidently wrong: it kept generating fixes for the OTEL collector. Parsing improvements, retry logic, buffering, all technically competent, all aimed at a pipeline that had no upstream. Nobody stopped to test whether the source produced anything. That's now a standing habit... before building collection, prove the source emits.
What this demonstrates
Observability of AI systems specifically: token accounting, cache economics, per-session attribution, and the discipline of naming the billing source rather than blending metered and subscription spend into one meaningless total. Also developer tooling as a shape, in that this runs on a laptop with no services and no keys.
Every team I talk to running agents is somewhere on the same curve I was: capable output, zero visibility into what it cost or whether it worked. Generation got cheap and accounting didn't get built. The systems that survive contact with a real budget will be the ones that can say what they did and what it cost, at the run level, without anyone SSHing anywhere.