I Built a Cost Dashboard for Claude Code. Then I Put It on a Raspberry Pi.
Claude Code writes all session data to local JSONL files. I wrote a tool that reads them, computes exact costs per session, and exposes a REST API. Then I deployed it on my always-on Pi and wired it into Telegram.
I run Claude Code 24/7 on a Raspberry Pi 5.
It handles Telegram messages, runs scripts, manages services. It is genuinely useful. It is also spending money continuously, and for a while I had no real-time visibility into how much.
I could check the Anthropic usage dashboard in a browser. But that is not the developer experience I wanted. What I wanted was to type /cost in Telegram and see today's spend in under a second, from anywhere.
So I built Ledger.
The Insight: The Data Is Already There
Claude Code stores every conversation as a JSONL file in ~/.claude/projects/. Each line is a structured event: user messages, assistant responses, tool calls. The assistant entries include full token usage data — input tokens, output tokens, cache writes, cache reads, even web search counts.
That is everything you need to compute an exact cost per conversation. No API key required. No external service. The data is sitting on your filesystem.
The pricing model is more detailed than it first appears:
- Input tokens — the base cost for what you send to the model
- Output tokens — typically 5x the input rate
- Cache writes (1-hour TTL) — 3.75x input rate
- Cache writes (5-minute TTL) — 1.25x input rate
- Cache reads — 0.10x input rate
Get the cache math wrong and your cost estimates can be off by 20-40%. Ledger handles the detailed breakdown when available, with a fallback to the rolled-up cache_creation_input_tokens field for older conversation files.
What Ledger Does
Ledger reads all the JSONL files in your Claude projects directory, parses every assistant entry, and aggregates cost, token counts, cache hit rates, and timing data. Entirely local. No network calls.
It exposes three interfaces:
- CLI —
ledgerprints a cost summary and exits.ledger todaygives you just today. - TUI —
ledger tuilaunches an interactive terminal dashboard built with Ink - Web dashboard —
ledger openstarts an Express server and opens a React + Recharts dashboard atlocalhost:4200
The REST API behind the web dashboard is what makes the Pi integration possible. Endpoints like /api/summary, /api/conversations, and /api/status return structured JSON that any client can consume.
Slash Commands for Session Tracking
Beyond cost tracking, Ledger includes slash commands that you drop into your project's commands/ directory. They let Claude Code track 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 becomes a Markdown file with YAML frontmatter — start time, end time, cost, commits, lines changed, model used. Ledger reads these alongside the JSONL data and computes efficiency metrics across sessions.
The Efficiency Metrics
Beyond raw costs, two metrics turned out to be the most useful.
Cache Hit Rate
Cache hit rate is cache reads divided by total cache activity (reads + writes). A high rate means Claude Code is reusing cached context instead of re-sending it every turn.
For an always-on daemon with stable system prompts, you want this above 70%. When a session starts cold after a restart, the rate drops. When the system has been running steadily, it climbs back. Watching this number over time tells you whether your setup is actually benefiting from prompt caching or just paying the write cost.
Dead-End Detection
A dead-end session is one with meaningful cost (more than $0.10) but zero commits. It spent money and produced nothing mergeable.
Sometimes that is fine — exploration, research, debugging. But when a session that was supposed to produce code produces nothing, you want to know.
Ledger flags these automatically. Over time, tracking dead-end rate by session type — feature, bug, refactor, explore — gives you real signal about where AI-assisted development is efficient and where it is not.
Deploying on the Raspberry Pi
My Pi 5 already runs Claude Code as a daemon via a tmux session managed by systemd. Adding Ledger as a second service was straightforward.
Install Node.js 22 LTS, then:
npm install -g @rezaiyan/ledger
The only difference between Mac and Pi is the JSONL directory path. On Mac: /Users/ali/.claude/projects. On Pi: /home/ali/.claude/projects. Ledger accepts a --dir flag, so no code changes are needed — just pass the right path in the service unit:
[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
At idle, the server uses about 30 MB of RAM. The JSONL parse on startup takes a couple of seconds for a large conversation history, then caches results with a 30-second TTL. Subsequent API calls return instantly.
Updating is a one-liner:
ssh ali@pi5.local "npm install -g @rezaiyan/ledger && sudo systemctl restart ledger"
Wiring Into Telegram
The Pi already runs a Python admin bot for controlling Claude Code — handling restarts, monitoring health, managing a command queue. Adding Ledger integration meant adding 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, active session, this month's total/cost— today, this month, all-time spend in three lines/sessions [N]— last N conversations with cost, cache rate, duration, and model/lastsession— full detail on the most recent conversation/efficiency— cache hit rate, average cost per conversation, dead-end count
All respond in under a second. No cloud. Everything stays local on the Pi.
What This Actually Changed
Having real-time cost visibility changed how I think about the Pi setup in three concrete ways.
Model selection. I run haiku on the Pi daemon because it is 5-10x cheaper than sonnet for the conversational and automation tasks the bot handles. Before Ledger, that was a guess. After Ledger, I could see per-conversation costs and confirm the model choice was right — sonnet on the Mac for interactive development, haiku on the Pi for always-on work.
Session discipline. I started tracking which tasks produce dead-end sessions. Exploratory research turned out to be the biggest source of sunk cost — not because it fails, but because I was not framing those sessions with clear deliverable expectations. Knowing that changed how I structure them.
Restart decisions. The cache hit rate makes the cost of restarts visible. When the Pi has been running steadily, the rate sits above 80%. After a restart, it drops to near zero and climbs back slowly. Each unnecessary restart has a concrete dollar cost now, not just an abstract "warm cache" argument.
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 are running Claude Code seriously — on a Pi, a VPS, or just your laptop — you should know what each session costs. The data is already on your filesystem. You just have to read it.