I Built a Cost Dashboard for Claude Code. Then I Put It on a Raspberry Pi.
Ali Rezaiyan6 min read
I run Claude Code all day on a Raspberry Pi 5. It answers Telegram messages, runs scripts, and manages services. It's really useful, and it's also spending money the whole time. For a while I had no quick way to see how much.
I could open Anthropic's usage dashboard in a browser, but I didn't want to. I wanted to type /cost in Telegram and see today's spend in under a second, wherever I was.
So I built Ledger.
The data is already on disk
Claude Code saves every conversation as a JSONL file in ~/.claude/projects/. Each line is an event: a user message, an assistant reply, a tool call. The assistant lines include token usage: input, output, cache writes, cache reads, and even the number of web searches.
That's all you need to work out exactly what a conversation cost. You don't need an API key or any outside service, because the data is already on your machine.
The pricing has more parts than you'd expect:
- Input tokens are the base rate, for what you send to the model.
- Output tokens usually cost 5x the input rate.
- Cache writes with a 1-hour TTL cost 3.75x the input rate.
- Cache writes with a 5-minute TTL cost 1.25x.
- Cache reads cost 0.10x.
If you get the cache part wrong, your estimate can be off by 20 to 40 percent. Ledger uses the detailed breakdown when it's there, and falls back to the combined cache_creation_input_tokens field for older files.
What Ledger does
Ledger reads every JSONL file in your Claude projects folder, goes through each assistant entry, and adds up cost, tokens, cache hit rate, and timing. It all happens locally, with no network calls.
You can use it three ways:
- As a CLI:
ledgerprints a cost summary and exits, andledger todayshows just today. - As a terminal dashboard:
ledger tuiopens an interactive view built with Ink. - As a web dashboard:
ledger openstarts an Express server and opens a React + Recharts page atlocalhost:4200.
The REST API behind the web dashboard is what makes the Pi setup work. Endpoints like /api/summary, /api/conversations, and /api/status return JSON that anything can read.
Slash commands for tracking sessions
Ledger also comes with slash commands you can drop into your project's commands/ folder. They let Claude Code keep track of its own work sessions:
/project:session-start feature "Add user auth"
# ... work happens ...
/project:session-update "OAuth flow working, writing tests"
# ... more work ...
/project:session-end
Each session turns into a Markdown file with YAML frontmatter: start and end time, cost, commits, lines changed, and the model used. Ledger reads these together with the JSONL data and works out how efficient each session was.
Two numbers worth watching
Apart from raw cost, two numbers turned out to be the most useful.
Cache hit rate
Cache hit rate is cache reads divided by all cache activity (reads plus writes). A high rate means Claude Code is reusing cached context instead of sending it again every turn.
For an always-on bot with a stable system prompt, you want this above 70%. It drops when a session starts cold after a restart, and climbs back once things have been running for a while. Watching it over time shows whether you're actually getting the benefit of prompt caching or just paying to write the cache.
Dead-end sessions
A dead-end session is one that cost something real (more than $0.10) but ended with no commits. Money spent, nothing to merge.
Sometimes that's fine: exploring, researching, debugging. But if a session was supposed to produce code and didn't, I want to know.
Ledger flags these on its own. If you track the dead-end rate by session type (feature, bug, refactor, explore), you start to see where AI-assisted work pays off and where it doesn't.
Running it on the Pi
My Pi 5 already runs Claude Code in a tmux session managed by systemd, so adding Ledger as a second service was easy.
Install Node.js 22 LTS, then:
npm install -g @rezaiyan/ledger
The only difference between the Mac and the Pi is where the JSONL files live: /Users/ali/.claude/projects on the Mac and /home/ali/.claude/projects on the Pi. Ledger takes a --dir flag, so I just pass the right path in the service file:
[Unit]
Description=Ledger — Claude Code cost and session API
After=network.target
[Service]
Type=simple
User=ali
ExecStart=/usr/local/bin/ledger serve \
--dir /home/ali/.claude/projects \
--sessions-dir /home/ali/sessions \
--port 4200
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
When idle, the server uses about 30 MB of RAM. Reading a big conversation history at startup takes a couple of seconds, and after that results are cached for 30 seconds, so API calls come back right away.
Updating takes one line:
ssh ali@pi5.local "npm install -g @rezaiyan/ledger && sudo systemctl restart ledger"
Hooking it up to Telegram
The Pi already runs a Python admin bot that controls Claude Code: it restarts it, checks its health, and manages a command queue. Adding Ledger meant a small HTTP helper and five new commands.
LEDGER_URL = "http://localhost:4200"
def ledger_api(path):
try:
req = urllib.request.Request(f"{LEDGER_URL}/api/{path}")
with urllib.request.urlopen(req, timeout=5) as r:
return json.loads(r.read()), None
except urllib.error.URLError:
return None, "Ledger service is not running."
The commands:
/overview: today's cost, the active session, and this month's total/cost: today, this month, and all-time spend in three lines/sessions [N]: the last N conversations with cost, cache rate, duration, and model/lastsession: everything about the most recent conversation/efficiency: cache hit rate, average cost per conversation, and dead-end count
They all answer in under a second, and nothing leaves the Pi.
What changed
Seeing costs as they happen changed how I run the Pi in three ways.
First, which model to use. I run Haiku on the Pi because it's 5 to 10 times cheaper than Sonnet for the chat and automation work the bot does. Before Ledger that was a guess. Now I can see the cost of each conversation, and it confirmed the split: Sonnet on the Mac for hands-on development, Haiku on the Pi for the always-on stuff.
Second, how I set up sessions. I started tracking which kinds of tasks end up as dead ends. Open-ended research was the worst, not because it failed, but because I wasn't starting those sessions with a clear idea of what I wanted out of them. Now I do.
Third, when to restart. The cache hit rate shows what a restart costs. When the Pi has been running for a while, the rate sits above 80%. After a restart it drops close to zero and takes a while to recover. So every unnecessary restart now has a price attached, instead of a vague "the cache will be cold" feeling.
Try it
npm install -g @rezaiyan/ledger
ledger # cost report
ledger today # today's summary
ledger tui # interactive dashboard
ledger open # web dashboard at localhost:4200
The source is at github.com/rezaiyan/ledger. MIT licensed.
If you use Claude Code a lot, on a Pi, a VPS, or just your laptop, it's worth knowing what each session costs. The data is already on your disk. You just have to read it.