All work

Claude Usage Widget

Subscription limits parked in a corner of your desktop

Mac

Claude’s subscription limits run on three separate clocks: the current session, all models weekly, and one model weekly. Finding out where you stand means going and looking — and the moment you actually need to know is the moment you’re mid-task and least want to break off.

This is an always-on-top frosted-glass panel. At rest it’s one very compact row — three mini progress bars and their percentages, barely taking up space. Hover it and it expands into three full bars, each with its own reset countdown.

Details

  • Three colour bands: under 75% blue, 75–90% orange, above 90% red. The status dot on the left takes the worst of the three, so a glance at that one dot is enough.
  • Drag it anywhere; the position is remembered.
  • Right-click for refresh, paste a new token, or quit.
  • Refreshes every 60 seconds by default.

The login hurdle

Reading the usage endpoint needs an OAuth credential with the user:profile scope.

There’s an easy trap here: the token from claude setup-token only carries user:inference and cannot open the usage endpoint. So the project ships its own login flow that explicitly requests user:profile — browser authorisation, then paste the code from the callback URL back into the terminal. Access tokens expire after eight hours and the widget renews them with the refresh token.

Credentials live in a file, not the Keychain. That’s not laziness: the .app is ad-hoc signed, so its identity changes on every rebuild, and the Keychain responds by prompting for a password again and again. A 0600 file has no prompts and survives rebuilds.

How it’s built

Swift 6, buildable with Command Line Tools alone — no full Xcode needed. The code splits in two: UsageCore is a pure logic library (model, parsing, networking, OAuth, credential storage) and is fully testable; the GUI layer only handles the floating panel and the SwiftUI views. There’s no XCTest available, so the test suite is a standalone SelfTest executable whose assertions cover parsing, countdowns, thresholds and ISO dates.

Data comes from GET /api/oauth/usage, where the limits array carries the three windows and resets_at is an ISO-8601 string.

One networking detail deserves its own note: the widget’s URLSession forces a direct connection and bypasses the system proxy. With tools like Shadowrocket installed, URLSession can’t reach api.anthropic.com while a direct connection can — a symptom that costs real time to diagnose, because the browser and curl on the very same machine both work fine.

Claude Usage Widget — 1
Claude Usage Widget — 2
Launched
2026
My role
Solo developer
Built with
SwiftSwiftUIAppKitOAuth