An LLM usage meter that clips onto the edge of your Mac's screen. It shows how much of your Claude Code and Codex rate-limit windows you have burned, expands into a full panel on hover, and shrinks to a sliver ("work mode") when you want it gone.

| state | top edge | side edge |
|---|---|---|
| resting | ![]() | ![]() |
| work mode | ![]() | ![]() |
Hovering either one opens the same panel: a 5-hour ring, a weekly meter, tokens, estimated spend and a reset countdown per provider.
Everything below is in the menu-bar gauge icon, or in the right-click menu on the pill itself.
The pill floats above the menu bar, but only over the pixels it actually draws: the
window is deliberately larger than the pill (so the panel can animate without the
window ever resizing) and stays mouse-transparent, opening up only while the cursor
is over the pill itself. A window swallows every click inside its frame no matter
what its views' hit tests return, so this is ignoresMouseEvents toggled from an
event monitor — nothing else can hand a click to another application.
Everything is read from files the two CLIs already write on this Mac. No API keys, no network calls, nothing leaves the machine (unless you opt into the Anthropic account check below).
Codex — reported, not guessed. Every token_count event in
~/.codex/sessions/**/rollout-*.jsonl carries the server's own answer:
payload.rate_limits.primary used_percent, window_minutes 300 -> 5-hour ring
payload.rate_limits.secondary used_percent, window_minutes 10080 -> weekly meter
The newest rollouts are tailed and the most recent event wins, so the ring matches what Codex itself would tell you as of your last Codex turn. Nothing writes to those files when you use the ChatGPT app, Codex on another machine, or the web, so the reading can trail your real usage until Codex next makes a request. Once a reading is more than five minutes old the panel says so ("as of 14:32 · 20m old"), and opening the panel forces a re-read.
Claude Code — estimated. ~/.claude/projects/**/*.jsonl records per-message
usage (input, output, cache creation, cache read) but no plan utilisation. The
provider replays those records, de-duplicates by message + request id, and buckets
them into rolling 5-hour blocks anchored to the top of the hour — the same shape as
Anthropic's session window. The ring compares the live block against a ceiling:
Rows measured this way carry an est badge. Spend is priced from the published
per-model list prices in Pricing.swift; treat it as an estimate, not a bill.
Optional: real Claude limits. Sources ▸ Use Claude account limits reads the Claude Code OAuth token from your login keychain and asks Anthropic for actual 5-hour and weekly utilisation. It is off by default. Enabling it explains itself first, then does one foreground read so the keychain prompt is visible; if access is denied it switches itself back off. After that the check runs on its own queue and never blocks the pill — the local estimate stays on screen if it fails.
The transcript folder can run to hundreds of megabytes. Lines are filtered on raw
bytes before any JSON is decoded, and the extracted usage plus per-file read offsets
are cached in ~/Library/Application Support/UsageNotch/claude-cache.json. First run
after install parses everything (~1s per 200MB); later launches restore from the
cache and refresh in single-digit milliseconds. Providers publish independently, so
a slow one never holds up the others, and one that stops answering is parked rather
than freezing the panel.
Xcode is not required — SwiftPM plus a hand-assembled bundle is enough.
./run.sh
That builds build/UsageNotch.app, replaces any running copy, and launches it.
./build.sh builds without launching. The app is an accessory (LSUIElement), so it
has no Dock icon; the menu-bar gauge icon carries the menu.
Requires macOS 14+ and a Swift 5.9+ toolchain (Command Line Tools are fine).
./build/UsageNotch.app/Contents/MacOS/UsageNotch --dump # what the providers see
./build/UsageNotch.app/Contents/MacOS/UsageNotch --placement # where the pill would land, per display
./build/UsageNotch.app/Contents/MacOS/UsageNotch --render ./docs # re-render the screenshots
USAGENOTCH_DEBUG=1 ./build/UsageNotch.app/Contents/MacOS/UsageNotch
--render snapshots the SwiftUI tree offscreen, which is also how the UI gets
checked when Screen Recording permission is unavailable. USAGENOTCH_DEBUG=1 traces
placement, hit regions, mode changes and provider timings on stderr.
main.swift entry point, --dump / --placement / --render modes
UI/NotchController panel + status item + refresh loop + menu + click routing
UI/NotchPanel borderless non-activating panel above the menu bar
UI/NotchGeometry notch metrics and per-display, per-edge placement
UI/Placement edge + anchor -> alignment, content rect, corner radii
UI/NotchState mini / pill / expanded, hover debounce, motion curves
UI/Interaction hover tracking and rect reporting for AppKit hit routing
UI/NotchRootView SwiftUI tree for the three states
Model/UsageStore provider fan-out, deadlines, published snapshot
Providers/* Claude Code, Codex, optional Anthropic account, cache, pricing
Two decisions are load-bearing:
UsageProvider plus a line in UsageStore.MIT — see LICENSE.
2 commits
Swift
99.1%
An LLM usage meter that clips onto the edge of your Mac's screen. It shows how much of your Claude Code and Codex rate-limit windows you have burned, expands into a full panel on hover, and shrinks to a sliver ("work mode") when you want it gone.

| state | top edge | side edge |
|---|---|---|
| resting | ![]() | ![]() |
| work mode | ![]() | ![]() |
Hovering either one opens the same panel: a 5-hour ring, a weekly meter, tokens, estimated spend and a reset countdown per provider.
Everything below is in the menu-bar gauge icon, or in the right-click menu on the pill itself.
The pill floats above the menu bar, but only over the pixels it actually draws: the
window is deliberately larger than the pill (so the panel can animate without the
window ever resizing) and stays mouse-transparent, opening up only while the cursor
is over the pill itself. A window swallows every click inside its frame no matter
what its views' hit tests return, so this is ignoresMouseEvents toggled from an
event monitor — nothing else can hand a click to another application.
Everything is read from files the two CLIs already write on this Mac. No API keys, no network calls, nothing leaves the machine (unless you opt into the Anthropic account check below).
Codex — reported, not guessed. Every token_count event in
~/.codex/sessions/**/rollout-*.jsonl carries the server's own answer:
payload.rate_limits.primary used_percent, window_minutes 300 -> 5-hour ring
payload.rate_limits.secondary used_percent, window_minutes 10080 -> weekly meter
The newest rollouts are tailed and the most recent event wins, so the ring matches what Codex itself would tell you as of your last Codex turn. Nothing writes to those files when you use the ChatGPT app, Codex on another machine, or the web, so the reading can trail your real usage until Codex next makes a request. Once a reading is more than five minutes old the panel says so ("as of 14:32 · 20m old"), and opening the panel forces a re-read.
Claude Code — estimated. ~/.claude/projects/**/*.jsonl records per-message
usage (input, output, cache creation, cache read) but no plan utilisation. The
provider replays those records, de-duplicates by message + request id, and buckets
them into rolling 5-hour blocks anchored to the top of the hour — the same shape as
Anthropic's session window. The ring compares the live block against a ceiling:
Rows measured this way carry an est badge. Spend is priced from the published
per-model list prices in Pricing.swift; treat it as an estimate, not a bill.
Optional: real Claude limits. Sources ▸ Use Claude account limits reads the Claude Code OAuth token from your login keychain and asks Anthropic for actual 5-hour and weekly utilisation. It is off by default. Enabling it explains itself first, then does one foreground read so the keychain prompt is visible; if access is denied it switches itself back off. After that the check runs on its own queue and never blocks the pill — the local estimate stays on screen if it fails.
The transcript folder can run to hundreds of megabytes. Lines are filtered on raw
bytes before any JSON is decoded, and the extracted usage plus per-file read offsets
are cached in ~/Library/Application Support/UsageNotch/claude-cache.json. First run
after install parses everything (~1s per 200MB); later launches restore from the
cache and refresh in single-digit milliseconds. Providers publish independently, so
a slow one never holds up the others, and one that stops answering is parked rather
than freezing the panel.
Xcode is not required — SwiftPM plus a hand-assembled bundle is enough.
./run.sh
That builds build/UsageNotch.app, replaces any running copy, and launches it.
./build.sh builds without launching. The app is an accessory (LSUIElement), so it
has no Dock icon; the menu-bar gauge icon carries the menu.
Requires macOS 14+ and a Swift 5.9+ toolchain (Command Line Tools are fine).
./build/UsageNotch.app/Contents/MacOS/UsageNotch --dump # what the providers see
./build/UsageNotch.app/Contents/MacOS/UsageNotch --placement # where the pill would land, per display
./build/UsageNotch.app/Contents/MacOS/UsageNotch --render ./docs # re-render the screenshots
USAGENOTCH_DEBUG=1 ./build/UsageNotch.app/Contents/MacOS/UsageNotch
--render snapshots the SwiftUI tree offscreen, which is also how the UI gets
checked when Screen Recording permission is unavailable. USAGENOTCH_DEBUG=1 traces
placement, hit regions, mode changes and provider timings on stderr.
main.swift entry point, --dump / --placement / --render modes
UI/NotchController panel + status item + refresh loop + menu + click routing
UI/NotchPanel borderless non-activating panel above the menu bar
UI/NotchGeometry notch metrics and per-display, per-edge placement
UI/Placement edge + anchor -> alignment, content rect, corner radii
UI/NotchState mini / pill / expanded, hover debounce, motion curves
UI/Interaction hover tracking and rect reporting for AppKit hit routing
UI/NotchRootView SwiftUI tree for the three states
Model/UsageStore provider fan-out, deadlines, published snapshot
Providers/* Claude Code, Codex, optional Anthropic account, cache, pricing
Two decisions are load-bearing:
UsageProvider plus a line in UsageStore.MIT — see LICENSE.
2 commits
Swift
99.1%