I check my Claude usage way too much
A few times a day I want to know one number: how much of my Claude usage is left, on the 5-hour window and the weekly one. For a while my answer was to type /usage in Claude Code or open the settings page in a browser tab, and I did that way more than a number two keystrokes away should make you do. So I built a small Mac utility that keeps both numbers up in the menu bar, always there, nothing to click.

That’s the boring version of the story, and here’s the part that made it worth writing down.
The number was already there
It turns out I never had to ask Anthropic for the number, because Claude Code already knows it and already hands it to me. Every time it repaints its status line it pipes a blob of JSON to whatever command you’ve set as your statusline, and recent versions put your rate limits right in it:
{ "rate_limits": { "five_hour": { "used_percentage": 22, "resets_at": 1784311200 }, "seven_day": { "used_percentage": 24, "resets_at": 1784736000 } }}used_percentage is 0 to 100, resets_at is a unix timestamp, and that’s the whole thing. The number I kept walking across a browser tab to read was being handed to my own terminal a few times a second, so the tool never needed an API. It just needed to stop throwing that number away.
The version I almost shipped
My first instinct was worse, and I want to own it because it’s the interesting mistake. Claude Code keeps your login token in the macOS Keychain, and there’s an internal endpoint, /api/oauth/usage, that returns the same two numbers, so I wired it up and it worked on the first try, which is exactly the problem.
Sit with what that build actually is: a menu bar app that reads your credentials out of the Keychain and polls an undocumented endpoint on a loop, forever, for a number already sitting in your statusline. I ran it past Codex for a second opinion before committing, and it said the thing I was already starting to feel, which was to stop reading the token and stop hitting the private endpoint, because the honest source had been there the WHOLE time. I just liked my clever version too much to see it, so I threw it out.
Writer, file, reader
What’s left is deliberately dumb.
Claude Code statusline -> hook writes usage.json -> menu bar reads itA hook registered as my statusline reads the payload and writes a small file, and anything that wants to show the number just reads that file back. That’s the whole design, a writer and a reader with no network in either half. The file holds two percentages and two timestamps and nothing else, so there’s nothing in it I’d mind leaking, which is the bar I want a local file like this to clear.
SwiftBar couldn’t stack two lines
I wanted the numbers stacked, 5h on top and weekly under it, and my first reader was a SwiftBar plugin, which won’t do that. Give it two lines and it ROTATES them, showing one and then the other, which is worse than useless for something you’re meant to read at a glance. So the reader became a small native app instead, about two hundred lines of Swift wrapped around an NSStatusItem with a real two-line title, reading the same file, refreshing on a timer and when you open the menu, and coloring itself for a light or a dark menu bar.
The source I skipped made a good ruler
Here’s the turn I liked. I didn’t use the OAuth endpoint as my data source, but it makes a great referee, so to trust the whole chain I read my snapshot file and compared it against what that endpoint reported live. My file said 5h was 22 and weekly was 24, the endpoint said 23 and 25, off by one because I’d burned a little more usage in the seconds between the two reads. They agree, which means the boring path from statusline to file to menu bar is carrying the REAL number and not just a plausible one. The source I refused to build on turned out to be exactly good enough to check against.
The one catch
The file only updates while a Claude Code session is open and rendering, so when I’m not working the menu bar just shows the last value it saw. That’s fine, because my usage isn’t moving when I’m not using Claude. The one case it lags is usage I spend on my phone or another machine, and even that catches up the next time a session renders on my laptop.
The code
It’s on GitHub as agent-usage-bar. The native app is one Swift file, the writer is a small Node CLI with no dependencies, and there’s a SwiftBar version in there too if you already run SwiftBar. If you want the idea without my repo it’s really two moves: point your statusline at a script that saves the rate_limits block to a file, then read that file from wherever you want to see the number. The menu bar was just where I wanted mine.
Update: it does Codex too now
A couple hours after posting this I figured the same trick had to work for Codex, which I lean on just as much, and it does. Codex writes the exact same kind of rate_limits data to disk, into its newest session log, every time you run it. So I read that too and stacked both tools in one menu-bar item: CC for Claude Code, CX for Codex. I renamed the project to agent-usage-bar while I was at it, because it isn’t just a Claude thing anymore.

Digging into Codex taught me one more thing: OpenAI removed the Codex 5-hour cap in July 2026, so Codex reports a weekly number only right now. My own machine showed that before any doc did, which is the whole theme of this post repeating itself. The reader maps each window by its size, so if the 5-hour limit ever comes back, that empty column just fills in.