AI subscription limits in the MacBook notch.
Shows how much of your Claude and Codex allowances you have burned, with a countdown to each reset.
◉ 5h 72% ◈ 7d 81%
Hover to expand for every window, plan tier, credit balance, and the model you've spent the most on. Click a provider to pin it to the collapsed strip.
| Provider | Source | Refresh |
|---|---|---|
| Claude | api.anthropic.com/api/oauth/usage, using the OAuth token Claude Code stores in your Keychain |
Polled every 60s |
| Codex | rate_limits embedded in Codex CLI session logs under ~/.codex |
Whenever Codex writes a turn |
Providers appear only when their data exists, so an uninstalled tool shows nothing rather than an empty row. Cursor and Grok are recognised but neither exposes usage data yet.
No telemetry. The only network request goes to Anthropic, and your token travels solely as a bearer header.
Claude Code caches usage figures in ~/.claude.json, and reading that file needs
no permissions at all. That was the original design. It doesn't work, because
only the stock interactive Claude Code TUI refreshes that cache.
Drive Claude Code any other way (an IDE agent, a wrapper, a non-TUI client) and the file keeps getting rewritten while its usage block stays frozen. On the machine this was built for, a config rewritten one minute ago still carried usage figures from 2.5 days earlier, describing a 5-hour window that had expired two days before.
The cache survives as a fallback, so the notch shows something at startup and whenever the live call fails. When that happens the app dims the figures and says how old they are. It will never show a confident red 93% for a window that reset on Monday.
The usage endpoint is undocumented. It isn't part of Anthropic's public API, may breach their terms, and can change without notice. Every failure path degrades to cached data rather than breaking. Use at your own risk.
Requires macOS 14+.
git clone https://github.com/<you>/notch-usage.git
cd notch-usage
./scripts/bundle.sh
open "dist/Notch Usage.app"bundle.sh signs the app with the first code-signing identity it finds,
preferring Developer ID over Apple Development. Override with
SIGN_IDENTITY="..." ./scripts/bundle.sh.
Signing is not cosmetic. Keychain grants bind to a code identity, and an ad-hoc signature has none, so macOS falls back to the binary's hash and forgets your "Always Allow" on every rebuild. With a certificate the grant survives.
On first launch macOS asks whether the app may read the
Claude Code-credentials Keychain item. Choose Always Allow.
To quit, expand the panel and click the power icon twice. It's an accessory app with no Dock icon or menu bar item, so the second click guards against losing it by accident.
Mac minis, Studios, external displays and pre-2021 laptops get an
identically-shaped floating pill at the top of the screen, via
DynamicNotchKit's .auto style.
swift run usage-probe --providers # what the notch would show
swift run usage-probe --models # per-model token burn from transcripts
swift run usage-probe --cache-only # no network, no KeychainClaude [live] plan=pro just now
5h 58% resets in 4h4m
7d 23% resets in 4d15h
OpenAI [logged] plan=prolite just now
7d 79% resets in 6d1h
credits 0
Account identifiers are omitted unless you pass --raw-account.
Sources/
├─ ClaudeUsageCore/ pure Swift, no AppKit, unit-tested
├─ NotchUsageApp/ window, polling, views
└─ UsageProbe/ CLI diagnostics
ClaudeUsageCore takes Data and a Date and returns a snapshot. It never
opens a window, resolves a path, or reads the clock, which is why staleness,
expiry and countdown rollover are all testable against fixtures.
Decisions worth knowing before you change anything:
- Limits decode generically from the payload's
limits[]array rather than as fixed fields. Both vendors carry plan-gated buckets that are null on most accounts (seven_day_opus, plus several codenamed ones), so a plan upgrade or a new server-side limit type appears without an app update. - Anthropic's
severityis used as sent. OpenAI reports a percentage and no classification, soSeverityHeuristicfills the gap using thresholds matched to Anthropic's own behaviour. Otherwise 75% would read amber for one vendor and green for the other. ProviderUsagewraps the sameLimitWindowtype for every vendor. Adding Cursor or Grok means writing a reader, not touching the UI.- Expiry overrides severity. A cached 93%
criticalwhose window reset yesterday displays as 0% andnormal. There's a regression test for it. - Two independent clocks. Polling changes values; a 60-second timer changes only countdown labels and is suspended while collapsed.
- A torn read is expected.
~/.claude.jsonis ~171KB and rewritten constantly, so a mid-write read keeps the last good snapshot instead of blanking the display. - The config watcher re-arms on
rename/delete. Atomic replacement orphans the file descriptor, and without re-arming the watch dies silently while appearing healthy. - Transcripts are read incrementally.
~/.claude/projectsruns to ~127MB; the reader tracks a byte offset per file, skips files untouched since the window, and stops each offset at the last complete newline.
swift testNever commit a real ~/.claude.json. It contains accountUuid,
emailAddress, organizationUuid and a userID hash. It's gitignored, and
every fixture under Tests/ClaudeUsageCoreTests/Fixtures/ is scrubbed.
Providers are identified by name in their brand colour — no logo artwork is bundled, so the repo redistributes no vendor images.
Notch geometry by DynamicNotchKit.
Unofficial. Not affiliated with Anthropic or OpenAI. It reads undocumented local files and an undocumented endpoint, both of which may change at any time.
MIT