spotify wrapped, but for the thing you actually did all year.
one command reads the claude code transcripts already sitting on your disk and turns them into a card worth posting: tokens processed (yes, cache counts, and yes, it is probably billions), an honest api-equivalent cost, your daily activity, your top tool, your longest session, and a punchline generated from your own numbers, at your own expense.
no api key. no network. no dependencies. nothing leaves your machine.
(rendered from the bundled synthetic examples/sample-month, not anyone's real
history. square is the default; --format wide gives a 1600x900 version.)
claude code tells you what this session cost, then forgets. there is no month view, no "what did i actually do in june", and nothing to drop in the chat when someone claims they use claude a lot. wrapped is that card, and the numbers are the receipt.
git clone https://github.com/adamentwistle/claude-code-wrapped
cd claude-code-wrapped
python3 wrapped.py # interactive: pick a profile, window, format, donethat is the whole install. python 3 and nothing else (a chromium-family browser if you want the card as a png; otherwise you get self-contained html to screenshot).
more precise moods:
python3 wrapped.py wrap # the terminal wrapped, all time
python3 wrapped.py wrap --month 2026-07 # one month only
python3 wrapped.py card --out wrapped.png # the share card, straight to png
python3 wrapped.py card --format wide --share # wide card + ready-to-paste captions
python3 wrapped.py profiles # list the claude profiles it can read
python3 wrapped.py demo # try it on the bundled fixtures
python3 wrapped.py selftest # make it prove its own numbersthe terminal wrapped is its own experience: a block-font hero number, a colour-coded stat grid, a sparkline of your daily activity, amber on dark. piped or NO_COLOR, it degrades to clean plain text:
● ● ● claude code · wrapped [ all time ]
────────────────────────────────────────────────────────────
TOKENS PROCESSED
████ █ ██ █ █
█ ██ █ █ ██ ██
███ █ ███ █ █ █
█ █ █ █ █
███ ████ ██ ██ █ █
cache included [██████████████████████████████] 49.5M cache · 2.4M new
$42.18 8 43
cost (api-equiv) sessions tool calls
Bash · 17 4h 45m jul 5
top tool longest session busiest day
DAILY ACTIVITY peak · jul 5 · 22.5M
▃▃▂▂▁▁██▁▁▁▁▂▂▁▁▁▁▁▁▂▂▁▁▁▁▂▂▁▁▁▁▁▁▁▁▃▃▁▁▁▁▁▁▁▁▂▂
jul 2 to jul 25
› claude said "you're absolutely right" 21 times. it meant it maybe 10.
run your own github.com/adamentwistle/claude-code-wrapped
a wrapped nobody can trust is just a meme generator. every number here is computed the
defensible way, and selftest proves it on a bundled fixture corpus:
- tokens processed is total throughput: input + output + cache reads + cache
writes. on claude code the cache reads are ~90%+ of it (the model re-reading context
it already had), so the card shows the from-cache / new split instead of one number
that looks wrong next to
/usage. - cost is api-equivalent: what those tokens would bill at api rates. on a flat subscription it is not what you paid; it is a "what if", and the card says so.
- requestId dedup: assistant records that share a requestId are one api turn with cumulative usage, so they are collapsed and counted once. skip this and cost and tool counts inflate severalfold on tool-heavy sessions.
- the chart covers the whole window. days off are zero bars, not missing bars, and when the window outgrows the chart, days are bucketed and the card says so ("3d bars") instead of quietly showing you the last two weeks and calling it all time.
- the punchline is deterministic. ten ranked rules, no model, no network; your own stats pick your roast. the "you're absolutely right" counter is honest, and if it never happened, that becomes the joke.
three reasons, all boring: /usage is a rolling-window plan view while wrapped is a
ledger; /usage counts tokens differently than a cache-inclusive total; and claude
code stores transcripts per profile under $CLAUDE_CONFIG_DIR (default ~/.claude),
so if you run several profiles, /usage reports the active one. wrapped reads the
active profile by default for exactly that reason. profiles lists everything it can
see, and you can point wrap/card at any profile's projects directory.
the card and the terminal wrapped never show repo names or file paths, full stop.
nothing is ever sent anywhere. the only name-bearing stat (top_project) exists
solely in the local wrap --json output on your own machine.
$ python3 wrapped.py selftest
PASS: 3 fixture sessions, deterministic. total 16.5K tokens (incl cache) / $0.17075
(requestId-deduped, cache priced); ... top tool Bash x3; longest session s2 3h 12m;
busiest day jun 30; --month windows to s3; formatters check out; stylesheet sound;
chart covers the full window (zero-filled, bucketed, sparse end+peak labels); no
project name ever reaches the card; captions are stats + compare-CTA; png cropper
exact; card --out x.html writes html
the fixture corpus is synthetic and bundled, so the selftest runs anywhere and the numbers cannot drift quietly.
run it, mod it for yourself, post your cards anywhere. the tool itself stays here: no redistribution, no rehosting, no bundling it into other things. see LICENSE.
