Show HN: Tallyhook – price Claude Code and Codex logs per client you bill Tallyhook, a dependency-free Node.js tool, prices Claude Code and Codex CLI session logs per repository and per billable client using public API list prices, running entirely on the user's machine with no account or upload. The tool reports a sample 30-day total of $2,740.96 across 266 sessions, with the previous 30 days at $1,602.11 across 186 sessions, a 71% increase. Tallyhook deduplicates streamed JSONL rows by message.id and prices cache reads, 5-minute cache writes at 1.25x input, and 1-hour cache writes at 2x input. What your AI coding agents actually cost — per repo, and per client you bill. One dependency-free Node.js file. It reads the session logs Claude Code and Codex CLI already write on your machine and prices them. No account, no signup, nothing uploaded. npx tallyhook AI coding-agent usage on this machine, last 30 days public API list prices REPO SESSIONS OUTPUT LIST COST github.com/acme/storefront 118 10.8M $1,450.59 github.com/acme/patient-portal 100 7.2M $867.84 github.com/globex/intranet 44 3.1M $402.17 local:scratch 4 96.2k $20.36 TOTAL 266 21.2M $2,740.96 Previous 30 days: $1,602.11 across 186 sessions — up 71%. If you run agents on work you bill someone for, the number you need is not "what did this repo cost" — it's "what do I put on Acme's invoice this month." So group the repos and set a rate: npx tallyhook clients add "Acme Corp" acme/storefront acme/patient-portal --rate 20 npx tallyhook clients add "Globex" globex/ --rate 35 npx tallyhook --by client CLIENT SESSIONS OUTPUT LIST COST BILLABLE Acme Corp 218 18.0M $2,318.43 $2,782.12 Globex 44 3.1M $402.17 $542.93 TOTAL 262 21.1M $2,720.60 $3,325.05 Not counted: $20.36 in repos no client claims. tallyhook clients lists them. That mapping lives in ~/.tallyhook/clients.json , on your machine, and it is still free and still uploads nothing. tallyhook clients on its own prints the map plus every repo no client claims yet, most expensive first — which is the list of work standing between you and a complete invoice. Billable totals are summed from rows rounded to the cent, deliberately: a client who adds up the lines you showed them has to land on the total you billed. npx tallyhook spend per repo, last 30 days npx tallyhook --by client roll repos up into the clients you bill npx tallyhook --by model the same spend per model npx tallyhook clients the billing map, and which repos nobody claims npx tallyhook mcp MCP server, so an agent can ask what its own work cost | flag | what it does | |---|---| | --days 90 | a longer window. The trend line always compares against the equally long window immediately before it, so --days 7 compares this week against last week. | | --by client\|model\|repo | how to group. A session that spanned two models has its cost split between them rather than attributed whole. | | --markup 20 | try a rate without saving it. Beats any stored rate for that one run, so it never silently no-ops. | | --json | the same numbers with no prose, for a script. Nothing unpriceable is guessed: if the price table is unreachable every cost is null and priced is false . With --by client it also carries counted and not counted cost usd , which always add up to total cost usd , so a script can tell how much of the machine the client rows actually cover. | Everything above runs entirely on your machine. The only network call is a GET for the public price table https://tallyhook.dev/api/prices . Prefer to read it before you run it? It is one file, tallyhook.js , in this repo — download it, read it, then node tallyhook.js . Most of the work in this file is in not being wrong: - Streamed rows: Claude Code writes one JSONL row per content block, each carrying the same usage object. Rows are deduplicated by message.id , or the same tokens get counted many times. - Subagents: forked subagent transcripts copy the parent's assistant rows. Deduplication spans every file of a session, including subagents/ .jsonl . - Cache pricing: cache reads, 5-minute cache writes 1.25× input and 1-hour cache writes 2× input are each priced separately. Fast-mode messages are priced at the fast-mode rate. - Codex: reads ~/.codex/sessions/ / .jsonl , and the .jsonl.zst files Codex compresses after seven days needs Node 22.15+; older Node skips them rather than guessing . - Repos, not folders: sessions group by git remote host/org/repo , so the same repo in two checkouts is one line. No remote means local: