cd /news/developer-tools/your-llm-usage-data-is-already-on-yo… · home topics developer-tools article
[ARTICLE · art-63544] src=blog.devgenius.io ↗ pub= topic=developer-tools verified=true sentiment=· neutral

Your LLM Usage Data Is Already on Your Disk. Your Limit Isn’t.

A developer created an open-source tool called tokenmeter to track LLM token usage locally from client logs, addressing the gap between exact per-session consumption data and the opaque plan limits enforced by API servers. The tool provides detailed session reports with token counts, cost estimates, and cache savings, but cannot read server-side plan ceilings, forcing any percentage-of-plan display to remain an estimate.

read10 min views1 publishedJul 17, 2026

How to Build an Honest Local Token Meter — and the One-Number Trick That Makes an Estimate Worth Trusting

If you run agentic coding tools — Claude Code, Cursor, Aider, or anything else that loops a model over your repository — you have probably hit the wall. Not a warning. A wall. You are deep in a refactor, the model finally has the shape of the problem loaded, and your plan limit lands mid-task.

The wall is not the interesting part. The interesting part is that you never saw it coming, and afterward you still don’t know what caused it.

Most tools expose some version of a usage command that reports a percentage and a reset time. That number is authoritative — it comes from the server that enforces the cap — and it answers exactly one question, once, when you remember to ask. It does not tell you what consumed the budget. Not which project, not which day, not which prompt.

That gap is worth closing, and closing it turns out to be a nice little exercise in measurement engineering: what you can know exactly, what you can only estimate, and what to do about the difference. I’ll use a small open-source tool I wrote, tokenmeter, as the worked example — it’s MIT-licensed and stdlib-only, so it’s easy to read along. But almost none of what follows is specific to it, or to Claude Code. The pattern applies anywhere you’re metering a metered resource you don’t control.

╭─ tokenmeter · detailed session report ─────────────────│ 6 prompts · 52 model turns · 28 tool calls · 09:14–11:05 (111m)││ TOTALS ────────────────────────────────────────│ tokens 3.4M│ est. cost $4.71│ input 33K · output 47K · cache-read 3.0M · cache-write 305K│ cache reuse 90% (higher = cheaper; reads are ~0.1x price)│ peak context 92K (9% of 1.0M window)│ cache savings $13.02 (73% off - reads saved $13.40, writes +$0.38)│ burn rate $2.55/hr this session││ TOP PROMPTS BY COST ─────────── (avg $0.79/prompt)│ 1. $2.60 2.4M tok · 28K out · 24t · 12 tools 09:41│ "refactor the auth middleware to use the new token store"│ 2. $1.05 712K tok · 9K out · 15t · 8 tools 09:15│ "why is the login flow throwing a 500 on expired sessions?"│ 3. $0.44 190K tok · 3K out · 6t · 4 tools 10:22│ "add a regression test for the expiry case"│ …and 3 more prompts totalling $0.62││ PLAN USAGE ─────────── (ESTIMATE - /usage is authoritative)│ last 5 hours $18.90│ vs 5h ceiling 38% of $50.00 █████·········╰─ prompts ranked by cost, not raw tokens: cache reads grow every turn, so late prompts look 'bigger' by token count even when cheap.

Start with the good news, because it’s better than most people expect.

Clients that talk to LLM APIs generally log what the API told them. Claude Code writes every session to a JSONL transcript under ~/.claude/projects/, and each assistant message carries the usage object the server returned [1]:

{  "input_tokens": 412,  "output_tokens": 1834,  "cache_read_input_tokens": 58201,  "cache_creation_input_tokens": 3092}

Plus a model identifier and a timestamp. That isn’t a reconstruction or a tokenizer estimate. It’s what the server said it charged, recorded by the client, sitting in a file you own.

So the per-session accounting is arithmetic. Parse the transcript, sum the fields, group by whatever you care about. This part is exact, and it’s exact for a reason worth internalizing: you are not measuring the model, you are reading a receipt.

I assumed that was the whole project. It was maybe a fifth of it.

Here’s the constraint that reshapes everything.

I could compute precisely how many tokens were consumed in the last five hours. But no local file says “and your ceiling is X.” The server enforces the cap and does not write it down anywhere you can read it.

That’s a hard wall, not an insufficiently-clever-search wall. And it forces a conclusion that any tool in this space has to confront: the moment you convert consumption into “percent of your plan,” you are estimating. Mine, ccusage, anything else. There’s no honest way around it.

You can hide that. Print a confident percentage and let the reader infer authority you don’t have. I’d argue you shouldn’t, and not for purely ethical reasons — it’s also just bad engineering. A tool that quietly disagrees with the authoritative source teaches users it’s broken. A tool that says “I’m an estimate, and here’s the number the server will actually enforce” stays useful precisely because it never competes with the oracle.

So the limitation goes in the README, in the tool’s own output, and in the docs:

The dollar figures are anestimate, not a bill. The authoritative source is the provider’s own usage command.

Naming that boundary cost me the ability to make a strong claim. It bought the thing that turned out to matter more, which I’ll get to in a moment — because the fix only becomes visible once you’ve admitted the problem.

An early wrong turn: I tried to build the whole thing in tokens.

It doesn’t work, and it’s worth being precise about why. A million Haiku tokens and a million Opus tokens are not the same quantity of anything you care about. Neither are a million cache reads and a million output tokens — cached input reads run roughly a tenth the price of fresh input. Any metric that adds these together is adding incommensurable units and will mislead you in proportion to how mixed your workload is.

So normalize. I priced each category with published per-token rates and used dollars as the common unit [2]. In my implementation that’s Opus at $5/$25 per million input/output, Sonnet at $3/$15, Haiku at $1/$5, with cache reads at roughly 0.1× input and cache writes at 1.25×.

Be careful what you claim that number is. On a subscription you don’t pay per token, so the dollar figure isn’t a bill. It’s an API-equivalent proxy — a synthetic common currency that makes Opus, Haiku, and cache reads comparable on a single axis. It answers “how much of my budget did this consume,” not “what do I owe.”

One deliberate asymmetry: unknown model identifiers get priced as the most expensive family. If I can’t identify a model, I’d rather overstate consumption than let a newly released model slip through undercounted and silently sail past a threshold.

This is the part that generalizes furthest beyond my little tool.

An estimate needs a ceiling before it can be a percentage. I shipped defaults, but they’re placeholders — subscription tiers differ by more than an order of magnitude, and nothing local tells me which one you’re on. A placeholder ceiling makes the percentage meaningless.

Then the reframe: I don’t need to know your ceiling. I need one reading of the ratio.

You run the authoritative usage command. It says 45% for the week. The tool already knows its own estimate for that same window — say $180 in proxy dollars. So:

ceiling = est / (pct / 100.0)    # 180 / 0.45 = 400

One number from the user, and the ceiling is back-computed in the tool’s own estimation units.

Sit with why that works, because it’s the whole trick. It does not matter that my pricing table is a proxy, or that the estimate carries systematic error. Both sides of that division are denominated in the same distorted currency, so the distortion cancels. The user isn’t telling the tool their plan. They’re telling it how wrong it is, once — and it corrects itself.

This is just single-point calibration of a proxy metric against a sparse oracle, and it shows up all over applied ML: you have a cheap signal you can compute continuously, an expensive ground truth you can sample rarely, and a monotonic relationship between them. You don’t need the expensive signal often. You need it once, to fix the constant.

The design consequence is that the irreducibly manual step — a human reading one number off an authoritative source — shrinks to a single sentence, said once. Everything downstream gets better for free. When you can’t eliminate a manual step, make it as small and as rare as possible, then build the rest of the system to exploit it.

A bug that taught me something general.

I ranked prompts by total token count. The output was wrong in a specific, suspicious way: the last prompt was always the most expensive. Every session. Even when the last prompt was “thanks, ship it.”

Cache reads. In a cached-context agent loop, every turn re-reads the accumulated context, so cumulative token counts grow monotonically through a session regardless of whether that turn did any work. Ranking by tokens doesn’t rank prompts by effort. It ranks them by how late they happened.

The fix is to rank by marginal cost — dominated by output and cache writes, the quantities that only rise when the model actually did something. Now “refactor the auth middleware” outranks “thanks, ship it,” which was the entire point of the feature.

The general lesson: in any system with cached or accumulated state, cumulative counters are a proxy for elapsed time, not for work. Attribute on the margin, not the total. And put the reasoning in the output where users can interrogate it — a ranking that can’t defend itself is a ranking nobody trusts.

Before publishing, I installed the tool clean, the way a stranger would.

First prompt of a fresh session, it announced: ⚡ 168% of your 5-hour window.

Of course it did. The default ceiling was a placeholder I’d told nobody about, and real usage sailed past it. Every new user’s first interaction would have been a loud, confident, entirely fabricated alarm.

That isn’t a threshold bug, it’s a category error. I was raising alarms against a number that was never a claim about anything. Take that seriously and the fix follows: if a value is a placeholder, it cannot raise an alarm. Uncalibrated means no threshold alerts at all — one gentle nudge explaining how to calibrate, and silence otherwise. Calibration is also tracked per-window, so calibrating the weekly ceiling doesn’t start firing alerts off a still-default hourly one.

The lesson isn’t “test before shipping.” I’d tested plenty — on the one machine where I’d long since configured everything correctly by hand. Your own machine is the environment least likely to reveal first-run bugs, because it’s the only one where you’ve already silently fixed them all.

The warning in tokenmeter runs on every prompt submission. That’s a nervous place for your code: slow means you made the tool slow, and throwing means you broke someone’s session.

Two rules, both non-negotiable for anything on a hot path.

Fail silent. Any exception exits zero. A broken meter is a minor annoyance; a meter that blocks work is uninstalled in anger.

if __name__ == "__main__":    try:        main()    except Exception:        sys.exit(0)    # never break the session

Never re-read what hasn’t changed. Naively, each invocation re-parses every transcript in every project — unbounded work that grows forever. A per-file cache keyed on (mtime, size), bucketing usage into hourly bins, means files untouched inside the window are skipped on a stat alone. In practice only the actively-written transcript is re-parsed.

Strip out the specifics and four things survive, and they apply to any metered resource you don’t control:

The tool still can’t beat the authoritative usage command on authority, and it was never going to — that number lives on a server I can’t see. What it does is answer the question the oracle can’t: what is consuming the budget. Which project, which day, which session, which prompt.

That’s usually the question you actually had.

[1] Anthropic, “Claude Code documentation.” [Online]. Available: https://code.claude.com/docs

[2] Anthropic, “Pricing.” [Online]. Available: https://www.anthropic.com/pricing

[3] ryoppippi, “ccusage: Usage analysis for Claude Code.” [Online]. Available: https://github.com/ryoppippi/ccusage

[4] “tokenmeter: Token and plan-usage reports for Claude Code.” [Online]. Available: https://github.com/plumbgoat/tokenmeter

Your LLM Usage Data Is Already on Your Disk. Your Limit Isn’t. was originally published in Dev Genius on Medium, where people are continuing the conversation by highlighting and responding to this story.

── more in #developer-tools 4 stories · sorted by recency
── more on @tokenmeter 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
Live at https://your-agent.zahid.host
Get free account → Pricing
from €0/mo · no card required
LIVE [news/your-llm-usage-data-…] indexed:0 read:10min 2026-07-17 ·