Published:

Tagged: Swift macOS Open-Source Claude-Code Codex

Tokenz - Claude Code and Codex usage in the menu bar

TLDR; Tokenz is a macOS menu bar app that shows Claude Code and Codex plan usage side by side, a 5-hour percentage and a weekly underline for each, and counts the tokens both tools’ local logs record for today, the last 7 days and the last 30. It reads only files already on your Mac and makes no network requests. Swift, MIT, brew install pardel/tap/tokenz.

I use Claude Code and Codex side by side, and I wanted both tools’ limits in one view. I also wanted real token numbers for today, the week and the month, and the logs both tools already write on my Mac hold them.

Every screenshot here uses demo data, fake logs and a fake feed rather than my own usage. The menu bar items are drawn by the app’s own drawing code onto a stand-in menu bar strip, so the item is exact and the bar around it is approximate.

The menu bar

I’d have liked each tool’s own logo in the menu bar, but those logos belong to Anthropic and OpenAI and aren’t mine to use, so Tokenz uses two of Apple’s SF Symbols instead. Each tool gets a symbol, a sparkle for Claude on the left and a hexagon grid for Codex on the right. Beside each symbol is the 5-hour percentage, and under it a thin line fills with the week’s usage. Each reading is coloured on its own: green below 70%, orange from 70% to under 90% and red at 90% or above, with the symbol taking the colour of the weekly line. Hover for the exact percentages, when each window resets and when the reading was reported.

These are all thirteen states the item can draw, each in a dark menu bar and then a light one:

Thirteen rows, one for each state the Tokenz menu bar item can draw, each showing the item in a dark menu bar, then in a light one, then a caption. In a dark menu bar the item is a pale rounded rectangle with deeper greens, oranges and reds; in a light one it is a dark rounded rectangle. In most rows it holds the Claude sparkle and the Codex hexagon grid, a 5-hour percentage beside each and a weekly underline below. Below 70%, green: 23% and 12%. From 70% to under 90%, orange: Claude at 76%. 90% and above, red: Claude at 94%. Each reading coloured on its own: Claude's 95% in red over a green underline, Codex's 72% in orange over a red one. 5-hour reading missing, expired or 0%: both symbols with their underlines and no numbers. Weekly reported as 0%: a green sparkle with no number over an empty solid underline, beside Codex at 12%. Weekly missing or expired: neutral symbols beside 31% and 12%, each over a dotted underline. Nothing reported yet: neutral symbols over short dotted underlines. Only Claude found, by its app, logs or feed: the sparkle and 23% alone. Only Codex found, by its app, logs or feed: the hexagon grid and 12% alone. Neither found: the Tokenz app icon. Plan usage switched off in Settings: a small bar-chart symbol. Panel open: the item at 23% and 12%.

The colours really are independent: here Claude’s 5-hour window is nearly spent while its week is fine, and Codex is the other way round:

The Tokenz item with a green Claude sparkle beside 95% in red, over a green weekly underline about half full, and a red Codex hexagon grid beside 72% in orange, over a red underline that is almost full.

One rule runs through all of it: a missing reading is shown as missing, never as zero. When the 5-hour reading is absent or its reset time has passed, the number disappears and the item shrinks to fit rather than printing a 0% nobody reported. A missing weekly reading draws a dotted underline and turns the symbol neutral, a reported weekly zero draws an empty solid one, and neither period ever stands in for the other.

The Tokenz item with a white Claude sparkle beside 31% in green and a white Codex hexagon grid beside 12% in green, each over a dotted underline instead of a filled one.

A tool appears in the menu bar when its desktop app is installed, Claude for Claude Code and ChatGPT or Codex for Codex, or when Tokenz finds its session logs or plan feed, so the command-line tool alone is enough. With neither found you get the Tokenz icon alone, and the panel and Settings stay available. If you’d rather not see plan usage at all, one setting turns the item into a plain chart symbol, and there’s no Dock icon either way.

The panel

Click the item and the panel opens on today’s total, with Today, 7 days and Last 30 days above it. Today is the Mac’s calendar day, and the rolling views are today plus the previous 6 or 29 days. A bar chart follows the period you pick, hourly for today and daily otherwise, with each bar’s exact totals per tool on hover.

The Tokenz panel in light mode on Today. The header reads Tokenz, Your tokens, at a glance, with refresh, settings and quit buttons. Below the Today, 7 days and Last 30 days control is 1.6M tokens, labelled Local usage, and an hourly chart with orange Claude bars from about 08:00 to 14:00 and thin blue Codex bars at the base of some of them. The Claude Code card shows 1.5M: input 1.5M, output 40.1K, cache read 1.3M, cache write 153.0K, 2 sessions, the 5-hour limit at 23% used and the weekly limit at 41%, each with a reset time, last reported 10 Oct 2026 at 14:57. The Codex card shows 106.7K over 1 session, with the 5-hour limit at 34% and the weekly at 52%. The footer reads Updated 14:57, every 5 min, beside an Export button. The same Today panel in dark mode, with the same figures: 1.6M tokens in all, Claude Code at 1.5M and Codex at 106.7K, and the same limits and reset times.

Below the chart, each tool’s card splits its total into input, output and cache, with the session count and the plan limits beside it. Export writes the daily totals for the last 30 days as CSV, and nothing else.

The panel on 7 days: 36.0M tokens, a daily chart from Sunday to Saturday with tall orange Claude bars from Monday to Friday and a thin blue Codex band under each, Claude Code at 32.1M over 20 sessions and Codex at 3.9M over 1 session, with the same plan limits as before. The panel on Last 30 days: 138.0M tokens, a chart of thirty daily bars labelled 11, 18, 25, 2 and 10, mostly orange with blue at the base, Claude Code at 124.8M over 89 sessions and Codex at 13.2M.

The panel keeps the missing-not-zero rule too. Once a window’s reset time has passed, its row says so instead of guessing a fresh number:

The Today panel with Claude Code's 5-hour limit reading Awaiting update and, below it, Reset time passed; use Claude Code to update. Its weekly limit still shows 41% used, and the Codex card is unchanged.

Where the numbers come from

Token totals come from ~/.claude/projects/**/*.jsonl and ~/.codex/sessions/**/*.jsonl, including agent sessions. Input counts cache reads and writes, Codex reasoning tokens are already part of output, and the total is input plus output. If you keep either tool’s configuration somewhere else, choose the folder in Settings.

Counting a log honestly is mostly about not counting it twice. Claude Code writes the same message once for each content block, and copied transcripts repeat it, so Tokenz keys every message by its message and request ids. Codex logs running totals, so Tokenz takes the difference between one and the next, and a resumed or forked log, which starts out carrying its parent’s history, has its first record counted as its latest turn rather than the whole inherited total.

These are locally observed totals, not a bill. Chats on claude.ai, sessions on other machines, cloud-only Codex sessions and logs either tool has already deleted are all outside them. Both log formats are the tools’ own implementation details and can change, and a record Tokenz doesn’t recognise is ignored rather than guessed at.

Plan percentages, and the Claude catch

The percentages are the providers’ own figures, separate from anything Tokenz counts. Codex reports its plan limits in its own session logs, so they need no setup.

Claude Code reports them only to a status line command, as a rate_limits object, so Claude needs a one-time step: a status line that saves that object to a file Tokenz reads. Until that file exists, the Claude card says so and offers to do it:

The Today panel before setup. The Claude Code card shows 1.5M tokens, its input, output and cache figures and 2 sessions, then Claude percentages need a one-time status-line step, beside a Set up… button. The Codex card shows a dash instead of a total, a warning that reads Session folder not found. Choose your Codex folder in Settings, and Plan limit appears after Codex reports usage. The Tokenz panel switched to Preferences: Show plan usage in menu bar ticked and Open at login unticked; Session folders with the Claude Code and Codex paths under a demo home folder, /Users/you, each with a Choose button, and Restore default folders; Claude percentage feed set to tokenz-rate-limits.json in the .claude folder; a Claude status line section saying Claude Code reports plan percentages only to a status line and Tokenz can add one that saves just the percentages and reset times, with a Set up… button; About the counters; links to Claude plan usage and Codex plan usage; and a closing note that, apart from a CSV you export, Tokenz writes nothing unless you ask it to set up the status line, and then only its script and Claude's settings.json, which it backs up first.

Choose Set up… there or under Claude status line in Settings. If you have no status line yet, Tokenz asks before making two changes: it adds tokenz-statusline.sh to ~/.claude/, and adds a statusLine entry to ~/.claude/settings.json after saving a copy as settings.json.tokenz-backup. The entry goes in without reformatting the rest of the file, and Remove… undoes both while keeping the backup and the saved percentages. Tokenz never replaces a status line you already have, and never changes a settings.json it can’t read.

If you already have a status line of your own, Settings shows the one line to add to your script, after it has read its input with input=$(cat), and Install script only… adds the script without touching settings.json. The line passes your status line’s input on:

printf '%s\n' "$input" | ~/.claude/tokenz-statusline.sh > /dev/null

You can also do the whole thing by hand: copy scripts/tokenz-statusline.sh to ~/.claude/, make it executable with chmod +x ~/.claude/tokenz-statusline.sh, and use it as your status line in ~/.claude/settings.json:

"statusLine": { "type": "command", "command": "~/.claude/tokenz-statusline.sh" }

However it gets there, the script saves only the percentages and reset times to ~/.claude/tokenz-rate-limits.json, readable by you alone, and writes it beside the target then renames it, so Tokenz never reads a half-written file. Nothing else from the status-line input is kept, no folders, transcript paths or costs, and when an update arrives without rate_limits the last good file stays as it was. That path is the default under Settings → Claude percentage feed; to use another file, set TOKENZ_FEED for the script and choose the same file there.

Even then, Claude Code sends rate_limits only on Pro and Max plans and only after a session’s first response, so a new feed can sit empty for a while. The card tells that case apart from the missing step rather than showing a zero:

The Today panel after setup but before a reading. The Claude Code card shows 1.5M tokens over 2 sessions, then Waiting for Claude Code's next response. Plan percentages come on Pro and Max plans. The Codex card shows 106.7K tokens, its 5-hour limit at 34% used and its weekly limit at 52%.

What it doesn’t do

It sends no network requests, reads no authentication files and stores no conversation content. Besides the session logs and the feed it reads Claude’s settings.json, and apart from a CSV you export, it writes nothing unless you ask it to set up the status line, and then only its script and that settings.json, backed up first. Log lines without usage in them are skipped before they’re even decoded, only the numbers are kept from the rest, and those stay in memory. The two links at the bottom of Settings open the Claude and Codex plan usage pages in your browser, if you click them.

Under the hood

It’s a Swift package, SwiftUI and AppKit, with no third-party dependencies and no API keys, and the parsing and accounting live in a library of their own so they’re tested without any UI. The test script also fails if networking code ever appears in the source, which keeps the promise above from being one careless import away from broken.

Scanning is incremental: the first pass reads the files touched in the last 30 days, and after that each file is read from where the previous pass stopped, every five minutes and on wake, when the panel opens or when you press refresh. The whole app is under 1,500 lines of Swift with twenty-six tests.

The panel during the first scan: the header and the period control at the top, and in the middle a spinner over Reading local sessions… and The first scan can take a moment.

Try it

brew install pardel/tap/tokenz

macOS 14 or later, on Apple silicon or Intel. Settings has Open at login, and macOS may ask you to approve it under System Settings → General → Login Items. Codex needs no setup, and Claude needs a one-time status-line step that the app offers to do for you.

This is 0.1.0, so it’s early. MIT licensed, at github.com/pardel/tokenz.

Tokenz is an independent project, not affiliated with or endorsed by Anthropic or OpenAI. Claude, Claude Code, ChatGPT and Codex are trademarks of their owners.

Every number Tokenz shows is either something a provider reported or something a log on your Mac recorded, and where it has neither, it leaves the space empty.