Codenotch
A macOS agent app that turns a small black notch on a screen edge into a live tally of the coding assistants you have running: a ring per provider for how much of its limit is already spent, a hover card listing every limit window and its reset time, and a pulse inside the ring that says whether an agent is working or has stopped to ask you something.

What it is
A macOS app with no window and no Dock icon: its whole surface is a small black notch welded to one screen edge, answering one question at a glance — how much of each coding assistant’s usage limit has already been spent. Claude Code, Cursor, Codex, Antigravity and about a dozen further providers each get a ring; hovering one lists its limit windows, when each resets, and every live session by name, with a thin arc inside the ring while an agent is working and an amber pulse when one is waiting on you. The five-hour limits can also be drawn into the menu bar as text, the last good reading survives a relaunch, and the same percentages go to a phone app over the local network. Underneath, one admission holds the design up: no vendor publishes a clean session-limit API, so every adapter declares its own fidelity, borrows what the owning tool already keeps, and turns each failure into a visible status rather than an invented percentage.
Who built itThe repository’s owner, under the account vinzdg: 387 of its 791 commits, all written in the 25 days between 2026-09-05 and 2026-09-30. The other 404 are spread over the forty-nine further accounts the contributor list names, led by RawJat on 58 and mulhamna on 57. 103 commits carry a co-author trailer, 88 of them naming a Claude model, with Codex on 4 and Cursor on 2.
How it is put together
The parts · 6A menu-bar-less agent app whose entire surface is one panel welded to a screen edge. The panel is a non-activating NSPanel at status-bar level, click-through everywhere outside its own shape, and the shape is a single SideNotchShape written for the right edge and transformed onto the other three rather than four hand-written variants. Everything inside works in one-dimensional stack space — along runs the length of the provider stack, across measures inward from the bezel — and NotchPlacement is the only place that maps that back onto real screen coordinates, which is what let a top or bottom placement become a second layout instead of a rotation. Every measurement in NotchLayout is quoted from docs/design/frame-124-hover-tooltip.png in design-frame pixels, so the layout can be checked against the frame directly. Underneath sits a provider protocol with a declared fidelity and a store that polls it, keeps the last good reading across launches, persists a rate-limit deadline, and turns every failure into a status the interface can draw.
- Sources/Providers/
- Eighty-nine files and 881 KB: one adapter per provider with its credential reader beside it, including the Claude OAuth provider at 46 KB, Codex’s local provider at 28 KB and Cursor’s credentials at 13 KB, plus the shared
SQLiteStore, a credential cache, and a 95 KBGlyphOutlineholding the vector marks — some traced from the design frame, some flattened from a vendor’s own SVG. - Sources/Notch/
- Fifteen files and 371 KB: the surface itself.
NotchWindowControlleris 100 KB,NotchViewModel73 KB,NotchRootView51 KB,SideNotchShape37 KB,NotchLayout30 KB andNotchGeometry25 KB — which is where the four edges, the folds, the corner passages and the merge with a hardware notch are decided. - Sources/Model/, Sources/Sessions/ and Sources/Costs/
- The store and everything that feeds it.
UsageStoreis 47 KB of polling, refresh scheduling, staleness and back-off;UsageArchivecarries the last good reading and the persisted rate-limit deadline across launches, andUsageResetWatcherwatches for a window rolling over. Twenty-eight session monitors sit beside them, one per tool, because each announces itself differently: Claude Code writes a session file per process, Cursor publishes no registry at all, and Codex only appends to a rollout. - Sources/Settings/, Sources/Features/ and Sources/App/
- The visible half.
SettingsViewalone is 123 KB andPreferences58 KB;ReleaseNotesis another 55 KB of the history the app ships with, written in Swift rather than fetched from the appcast so that it exists on a first launch with no network.TooltipCardis 53 KB of hover card,AppDelegate66 KB of application wiring, andSources/Localizable.xcstringsis 1.5 MB. - Tests/
- A hundred and thirteen files and 1.6 MB, mirroring
Sources/by concern rather than by file, and pinned to recorded responses instead of live endpoints:AntigravityTestsis 80 KB,CodexUsageTests70 KB,UsageResponseTests66 KB,NotchLayoutTests66 KB andMergesWithTheCutoutTests65 KB, with the layout tests checking a drawn profile by sampling it rather than probing one point. - windows/ and docs/
- The port and the paper trail.
windows/codenotchis sixty-three files of Rust and Tauri 2 with a 98 KBmain.rsand two HTML surfaces at 114 KB and 142 KB.docs/specs/2026-08-28-usage-notch-design.mdis the design the project was built to,docs/plans/holds three plans including a 35 KB one for local model providers,docs/providers/keeps per-provider notes, andTASKS.mdis 110 KB of implementation history with the corrections and the reasoning left in it.
Choices, and what they beat
Read the OAuth usage endpoint instead of the local transcripts over the planned first adapter, which parsed
~/.claude/projects/**/*.jsonlinto a rolling 5-hour windowThe corpus was there — 15,838 assistant messages with per-message token counts, enough to reconstruct 70 windows — but it carries no limit and no window metadata, so a percentage from it needs an invented denominator. The endpoint returns Anthropic’s own number instead. The trade is written down beside it: it is not a published API and can change without notice, so
UsageResponseTestsis what fails first if it does, and the local parser is still named as the fallback if the endpoint goes away.Borrow whatever credential the owning tool already holds over running an OAuth flow of its own, or offering a sign-in button
The author’s own line is that there is no account for the app to connect, so a Connect button would be theatre. It reaches into packaging: the App Sandbox stays off because it would block reading Cursor’s
state.vscdband Codex’s rollout logs. Borrowing also turned out to be a correctness question — an early version signed into cursor.com in a WebView, quietly created a second Cursor account, and reported zero usage belonging to somebody who was not the user.Name the headline window instead of taking the first one over
windows.first, and before that the most-constrained windowClaude drops
five_hourfrom its limit array the moment the window rolls over, so a positional rule let the weekly figure slide into the session’s place at exactly the moment someone was most likely to be looking at it. The most-constrained rule had a milder version of the same fault: session 22% against weekly 24% showed 24, then session 27% against weekly 24% showed 27. The headline is now a declared id, and when that window is genuinely absent the cell shows a dash rather than promoting another one.Ask Antigravity’s own language server over calling Google’s quota endpoint directly
retrieveUserQuotaSummaryoncloudcode-paanswers 403 for a personal account, because the API judges which client is asking and the app cannot honestly claim to be Antigravity. Antigravity’s own window has the same problem and solves it the same way, so the app does too: the server on the machine already holds both the credential and the client identity. The stated cost is that it works only while Antigravity is running — and a contributor later showed that constraint was narrower than it looked, because the server starts with--standaloneand reads the same keychain credential with no editor attached.Show a count where there is no limit to divide by over a percentage with a denominator the app made up
Antigravity answers with tiers and no numbers at all, and Google publishes no usage resource for a bare Gemini API key, so that ring is assembled from what the tools themselves wrote down — Gemini CLI’s session files, OpenCode’s database, Hermes’s usage table — deduped by call id because the CLI writes the same call twice. Perplexity, which reports only what is left and therefore has no denominator at all, is why a limit window’s fraction and reset time became optional fields; its adapter stays in the tree but is unregistered.
Read fromdocs/specs/2026-08-28-usage-notch-design.md, TASKS.md (109,699 characters), README.md (26,771 characters), CONTRIBUTING.md, docs/plans/2026-08-28-usage-notch-plan.md, Sources/Providers/AntigravityBridge.swift, Sources/Providers/CodexLocalProvider.swift, Sources/Providers/CursorCredentials.swift, Sources/Model/UsageStore.swift, .github/workflows/package.yml, and the complete 516-file tree with sizes.
Build log
6 stages- 01
Twenty-five days, nineteen releases, and one renamed app
The repository was created on 2026-09-05 and by 2026-09-30 had 791 commits, 2,639 stars, 420 forks and 19 releases —
v1.4.0on 2026-09-06 throughv1.20.0on 2026-09-30, plus a rollingpreviewtag that is rebuilt and re-uploaded on every push tomain. The app ships its own release-note catalogue going back to1.0.0, so the version line predates its first GitHub release, and the design spec still opens by calling the name a working one rather than a decision. The rename fromUsageNotchleft traces the author wrote down: the old app is still installed at/Applications/UsageNotch.appand nothing removes it, the keychain asks again because its access list is keyed on a designated requirement containing the bundle identifier, and the Sparkle feed still points atvinzdg.github.io/usage-notch/while the disk image is served fromhivinz.com. - 02
Claude Code and Cursor: the keychain, the cache, and the editor’s own database
The design document opens with the admission the project is built on: no vendor publishes a clean "your session limit is N% used" API. So each adapter borrows what the owning tool already holds, declares its own fidelity — official, derived or manual — and the tooltip prefixes anything computed here with a tilde. Claude Code has three sources in order. Claude Desktop is a Chromium app, so the usage response its own panel draws sits in an HTTP cache under
~/Library/Application Support/Claude; only entries whose cached URL is this account’s/api/organizations/<id>/usageare opened, matched on the organisation Claude Code records for the profile, and because the bodies are zstd a decode-only build of Zstandard is vendored underSources/Vendor/zstd. Thenclaude "/usage"is run. Then the OAuth token in the login keychain is sent toGET https://api.anthropic.com/api/oauth/usage, the same endpoint that command uses, which returns Anthropic’s own session and weekly figures. Cursor’s documented Admin and Analytics APIs are team-scoped and need an admin key, so the ring asksGET https://cursor.com/api/usage-summarywith the editor’s own session read out ofstate.vscdb—cursorAuth/accessTokenandcursorAuth/stripeMembershipAuthId— sent as the cookieWorkosCursorSessionToken=<account>::<token>, because a bearer header on the same token answers 401. - 03
Codex and Antigravity: a token off disk, and a language server on loopback
Codex is read live from
GET https://chatgpt.com/backend-api/wham/usage, authenticated with the access token and account id the Codex CLI keeps in~/.codex/auth.json, which this app reads and never refreshes or writes. When that fails it falls back to the rate-limit snapshots Codex writes into the rollout log of each thread, the newest found through thethreadstable ofstate_5.sqliterather than by walking a sessions tree of thousands of files. Antigravity is the interesting one, because Google refuses: the quota RPC oncloudcode-paanswers 403, "You do not have a valid license of this product", for a personal account, because the API judges which client is asking. Antigravity’s own window has the same problem and solves it the same way, so this app does too — it finds the language server’s pid in the process table, reads the--csrf_tokenoff its command line, finds the ports it listens on withlsof, and POSTs{"forceRefresh":true}to/exa.language_server_pb.LanguageServerService/RetrieveUserQuotaSummaryon loopback, with the header the binary turned out to want,x-codeium-csrf-token. - 04
How often it asks, and what happens when it is told to stop
UsageStoreticks every 15 seconds and refreshes a busy provider every 30, dropping to five minutes when nothing is running, because usage cannot move while nothing is using it. Three events ask outside that schedule — a session stopping, the menu bar item being opened, and the pointer landing on a ring — and the last is spaced so that four rings hovered in four seconds cost one fetch. Anthropic’s endpoint answers 429 withRetry-After: 0, which obeyed literally meant waiting zero seconds and firing straight back into the limit; the hint may now only raise a floor that starts at 60 seconds, doubles per consecutive 429 and caps at 15 minutes, and the deadline is persisted so that relaunching during a penalty waits instead of spending an attempt. The author’s note on that is blunt: a development loop ofmake runwas the thing sustaining its own punishment. A 429 renders as staleness rather than as an error, and a remembered reading is never presented as a live one — it comes back dimmed and dated. - 05
The bugs the author wrote down, including one he got wrong
The code comments and the task history keep the failures that cost a day each. Opening Cursor’s or Codex’s SQLite store with
immutable=1ignores the write-ahead log, so a live agent looks idle and a rotated token looks current — and after a restart, with the-shmsidecar gone, a read-only open fails outright, which is how the app came to report no Codex threads on a machine that had 2,752 of them. Claude’s session file writesprocStartas a ctime string in UTC, so parsing it as local time put the pid-reuse guard seven hours out and the activity indicator silently never appeared. The ring’s headline used to be the first window in the array, and Claude dropsfive_hourthe moment that window rolls over, so at exactly the moment someone was watching, the weekly figure slid into the session’s place; the headline is now named rather than positional and shows a dash when the named window is gone. On the disk image issue, the same commenter who had blamed a stale download published a correction — "I was wrong about the cause" — followed by a third state his own rebuild produced, three times out of three. - 06
A macOS app, a Rust port, and fifty accounts
The contributor list names fifty accounts, with the author on 387 commits and the next two on 58 and 57. The Windows port is not a port of the code:
windows/is a separate Rust and Tauri 2 application that reimplements every provider against the same wire formats, with its own i18n file, its own installer and its own packaging workflow — and the three pull requests that carry the notch round a Windows screen border all land there. The queue around it is a mix of ports and arguments. One contributor spent three pull requests on whether the menu bar item should reserve width, and settled it with counts rather than taste — five reflows per five-hour window for one provider, about one an hour — by reversing his own earlier position in the last of them. Another filled in the Chinese strings that release still showed in English, with Traditional Chinese keeping Taiwan wording. A third found that a Custom Endpoint reached over a Tailscale address failed on App Transport Security and added an exception scoped to100.64.0.0/10. Fifty-four issues were open at the end of the month. An agent app has no window to print into either, so failures go to the unified log, and the author records that the first attempts at a diagnosis were guesses made from screenshots.
Adjacent records
All records →No. 109
Whiteboard
A desktop app that puts an agent and a person on the same canvas: the agent draws the review — sequence diagrams, entity relationships, code peeks pinned to specific commits — and every shape on that canvas links back to the code it was drawn from.
No. 099
OpenMausBot
An open-source chat app where every bot in the sidebar is a real agent running through the CLI already installed on your machine, and each one can be handed a computer: a cloud Linux desktop, a Docker or Podman container on the same host, a container on a VPS you own, or the machine in front of you where the platform can show that it is safe.
No. 091
Lody
A workspace where a team shares the coding agents it already runs: connect a machine, bring Claude Code, Codex, Kimi or any other agent that speaks the protocol, and dispatch work from desktop, phone, web or terminal while sessions delegate to each other and the code stays on the machine its owner connected.