A Windows port of Codenotch — the usage notch that sits on the edge of your screen and answers two questions at a glance: how much of my AI allowance is left, and is Claude still working.
Same design language as the macOS original (inverse-rounded pill, colour-graded rings, hover card with per-window bars), rebuilt for Windows in Rust + Tauri 2 / WebView2. No code is copied from the Swift app; the providers are reimplemented from their documented behaviour and the wire formats.
| Cell | Source | How it reads it |
|---|---|---|
| Claude | GET https://api.anthropic.com/api/oauth/usage with the token Claude Code keeps in ~/.claude/.credentials.json |
Session / weekly windows, 429 back-off with a persisted deadline, stale readings dimmed with their age. Renews that token by running the standalone claude -p shortly before it expires (Claude Code inside the desktop app never writes this file), and never sends an expired one. A thin arc spins inside the ring while a Claude session is working, and pulses amber when one is waiting on you (Claude Code hooks + transcript watcher, desktop app included). |
| Codex | The local Codex sign-in in ~/.codex/auth.json (read only, never refreshed), falling back to the newest session snapshot |
Live primary/secondary windows (5h + weekly on paid plans, a monthly window on free) while Codex is signed in; Spark and Code review appear on the hover card when Codex reports them; otherwise the last snapshot, marked stale by its own timestamp. |
| Cursor | The editor's own session from state.vscdb → cursor.com/api/usage-summary |
Included usage / API usage / on-demand, reset at billing-cycle end. Nothing to sign into: it borrows the editor's session, so there is only ever one account. |
| Grok | The Grok CLI's own session in ~/.grok/auth.json (read only, never refreshed) → cli-chat-proxy.grok.com/v1/billing?format=credits, the endpoint that CLI's own /usage asks |
The weekly Grok Build allowance, with the account on the hover card. Only a session minted by auth.x.ai is used — the file can also hold a customer IdP token meant for that customer's private proxy. A fresh weekly period reads 0 %, not "unmetered". |
| Antigravity | Official agy CLI /usage print when installed; otherwise the existing local language_server bridge, Google Cloud Code API, or transcript model count |
Official four quota rows (Gemini & Claude/GPT 5h/weekly) without running the full IDE. When CLI is absent, falls back to legacy local bridge/API. |
Providers that are not installed simply do not get a cell.
The direct usage endpoint remains the first choice. If it fails, Codenotch can
ask an installed native codex.exe via the documented
account/rateLimits/read
app-server method before falling back to a rollout snapshot. The desktop's
%LOCALAPPDATA%\OpenAI\Codex\bin installation is checked as well as native CLI
candidates. No .cmd/Node wrapper is launched. The owned process is hidden,
limited to 20 seconds, and terminated/reaped after the read; no inference or
login command is sent. Existing HTTP 429 backoff and five-minute polling remain.
The main ring/tray selects only core primary, never a weekly, Spark or
code-review replacement. If primary is absent the headline stays blank;
secondary remains available to the separate weekly ring. App-server
multi-bucket replies prefer codex. Rollout fallback ignores explicitly different
bucket ids and, like macOS, reads the latest eight non-archived paths from
state_5.sqlite using a read-only, WAL-aware connection (50 ms busy timeout).
This finds resumed threads without scanning every session file. If the index
is unavailable, the original three-date-directory scan remains the fallback;
old resumed threads cannot be discovered through that scan alone. Missing data is
not a zero. Percentages retain the existing used semantics; this is quota
utilization, not an exact token count or a model-specific allowance.
Why launch a process at all? A borrowed stored-token HTTP read can fail while
the installed Codex client can still authenticate. The native client owns its
managed OAuth lifecycle and can recover live quotas without Codenotch copying
its refresh logic. This is not guaranteed for externally managed credentials
that require a host app: if it cannot read the quota, the usual stale/missing
rollout status remains. Unlike the old unconditional wrapper-based path, this
recovery runs only after HTTP failure, directly owns a native executable, and
does not use taskkill or launch a Node/cmd tree. Codenotch sends no login or
explicit token-refresh request; Codex may perform its own normal managed refresh.
Regression checks: cargo test --locked and node --test test-codex-headline.cjs
from windows/. Tests use synthetic quota fixtures, not account credentials.
The optional cargo test --release --locked codex::tests::live_native_quota -- --ignored
checks the actual native transport against an already signed-in local client;
it prints no account credentials or quota values and is not run by CI.
When Claude is signed out, its card offers Sign in, which opens the standalone
Claude Code CLI's browser login (claude auth login --claudeai). It is offered on
the default ~/.claude account only, since that is the one the CLI signs in.
Finish in the browser; if it
displays a code, paste it in the opened terminal, not in Codenotch. The card
refreshes after the CLI exits without restarting the widget. The native CLI must
already be installed; missing CLI, cancellation and launch errors are shown.
This explicit action shares a busy guard with automatic token renewal. Only the CLI handles OAuth and writes credentials; Codenotch does not receive login codes or expose tokens through UI IPC. The interactive child has a 15-minute timeout. To read Claude again, click its ring or choose Refresh now from the notch's right-click menu. HTTP 403 is reported as an access/network refusal rather than claiming that a still-valid login has expired. Existing automatic renewal is unchanged.
- Official CLI (Preferred): When the official Antigravity CLI (
agy.exe) is installed (%LOCALAPPDATA%\agy\bin\agy.exeor onPATH) and signed in, Codenotch reads official quotas directly without keeping the full IDE running. - Execution: Runs the official CLI in a hidden Windows pseudo-console, with a 70-second timeout and cleanup of its process tree. It does not need PowerShell scripts or a separate service.
- Refresh: Checks at startup and on hover/explicit request when readings are at least five minutes old; failed attempts are also limited to once per five minutes. It keeps previous readings on failure, without switching to legacy APIs. The CLI is not launched periodically while idle.
- Fallback: When the official CLI is not installed, Codenotch preserves the legacy local bridge (
language_server), Credential Manager, and transcript model turn counting to maintain compatibility with existing installations. - Official CLI Reference: Standalone
/usageprinting is described in the official Antigravity CLI documentation. Note: no categorical Terms of Service guarantee is made.
Restart Codenotch after installing or removing agy: the source is selected at startup.
The CLI's text report is parsed defensively; an unsupported format or failed sign-in
shows an error or the last reading marked stale. Codenotch does not automate sign-in.
Download Codenotch-Setup.exe
from the latest release. It installs for the current user without administrator rights, puts
codenotch-hook.exe beside the app where Install hooks looks for it, and fetches WebView2 if
Windows does not already have it. The installer is not code-signed, so SmartScreen stops it the
first time with Windows protected your PC: choose More info, then Run anyway.
Codenotch looks for a newer release about twenty seconds after it starts, and again whenever
Check for updates is pressed in Settings → General. The feed is latest.json on the newest
release, written by the Windows Package workflow beside the installer it describes, so publishing
a release is the whole of shipping an update.
Nothing about this nags. A check that fails — no network, an unreachable feed — leaves the app as it was and says so only next to the version. There is no dialogue and no badge.
The download is a minisign-signed archive, and the signature is checked against the public key in
tauri.conf.json before anything is run. This is what stands in for code signing here: the
installer itself is unsigned, so SmartScreen still warns on a first manual install, but an update
delivered to an already-installed copy is verified.
Before the first signed release, the key has to exist:
npx --yes @tauri-apps/cli@2.11.4 signer generate -w $env:USERPROFILE\.tauri\codenotch.keyPut the private key in the repository secret TAURI_SIGNING_PRIVATE_KEY and its password in
TAURI_SIGNING_PRIVATE_KEY_PASSWORD, and paste the public key into plugins.updater.pubkey
in codenotch/tauri.conf.json, replacing REPLACE_WITH_TAURI_PUBLIC_KEY. Until that is done the
app skips the check entirely rather than reporting a failure nobody can act on; the packaging job
builds an ordinary installer and warns that it made no feed, and a v* release fails loudly rather
than going out with an update path nobody can use.
Keep the private key. Losing it means no installed copy can be updated again, because every one of them checks against the public key it shipped with — they would all have to reinstall by hand.
To build from source instead — prerequisites: Rust (MSVC toolchain), WebView2 runtime (ships with Windows 11).
# from this directory (the repo root here; `windows/` inside the upstream repo)
cargo build --release
.\target\release\codenotch.exe # pill appears on the right edge of the primary monitor
.\target\release\codenotch.exe doctor # self-diagnosis: credentials, data sources, icons, hooksTo build the installer the way the Windows Package workflow does:
# the hook gets its own target dir, so the bundler never copies it onto itself
cargo build --release --locked -p codenotch-hook --target-dir target/hook
cd codenotch
npx @tauri-apps/cli@2 build --config tauri.bundle.conf.json
# → ..\target\release\bundle\nsis\Codenotch_<version>_x64-setup.exeTray menu: the readings themselves — a line per provider with its headline figure, and under it
one line per limit window — then Refresh all, Settings… and Quit Codenotch. Clicking a
provider's line re-reads that provider. Everything else is in the settings window: which rings the
notch shows, its size, the weekly ring, which screen edge it sits on and which screen,
start with Windows, the language, Claude Code hooks, reset
position, and the data folder (%APPDATA%\codenotch — logs, persisted readings, icon overrides).
Notch: clicking a ring re-reads that provider, as on the Mac. Right-clicking the notch or its card offers Refresh now, the provider's usage page (Open claude.ai, Open chatgpt.com, …) and Quit Codenotch. Neither click, nor the tray, asks Claude again while its rate-limit wait runs.
The notch pins to one edge of one screen. The arc above the pill carries it: hold it, and the four places it can go are outlined on the screen; release on one and the notch lands there, centred. Appearance → Show move handle hides that arc. Appearance → Edge picks left, right, top or bottom: it stands upright on the left and right edges with the hover card opening sideways, and lies flat on the top and bottom ones with the card opening below or above. Appearance → Screen appears once more than one monitor is attached.
Dragging does both at once: pick the pill up, drop it anywhere, and it snaps to the nearest edge
of the screen it was dropped on — across monitors, and across a change of DPI between them. The
choice is stored as notch_edge, notch_monitor (the device name, e.g. \\.\DISPLAY2) and
notch_y (the position along the edge, 0–1) in config.json. A monitor that is no longer
attached falls back to the primary one, so unplugging a screen cannot strand the notch off-screen;
Recentre centres it on the edge it is on, or on the primary screen's right-hand edge when the screen it was on is gone.
Provider marks are the SVGs from @lobehub/icons-static-svg
(MIT), embedded unmodified — see codenotch/glyphs/NOTICE.md. Drop your own
claude|codex|cursor|gemini.svg (or .png) into %APPDATA%\codenotch\glyphs\ to override.
The marks remain the trademarks of their owners.
Three surfaces draw their own text, so each keeps its own table:
| Surface | Table | Languages today |
|---|---|---|
| Tray menu | codenotch/src/i18n.rs (tr), codenotch/src/traymenu.rs (label) |
en · ru · zh · ja · ko · uk |
| Hover card | codenotch/ui/notch.html (TEXT, PATTERNS, UI) |
en · ru · zh |
| Settings window | codenotch/ui/settings.html (STATIC_TEXT, STATUS_TEXT) |
en · ru · zh · ja · ko |
Help is welcome on the gaps, which fall back to English rather than breaking anything:
- the hover card has no Japanese, Korean or Ukrainian;
- the settings window has no Ukrainian, although the tray menu and the language picker have had it since Ukrainian was added;
- Korean has none of the window names the Mac's catalog carries —
Current session,Weekly limit,Monthly limit,5-hour Limit,Included usage,API usage— because the catalog has no Korean to take them from.
Keys are the exact English string. A string the Mac also shows should be taken from
Sources/Localizable.xcstrings rather than translated afresh, so both platforms word it the same
way. One catalog feeding all three tables is the intended fix; until then a test in traymenu.rs
fails if the menu and the card stop naming the same window.
.
├── codenotch/ the Windows app (pill, hover card, settings, providers)
└── codenotch-hook/ tiny helper Claude Code calls to report session events
A pull request that touches this tree is built and tested; the check is skipped inside forks until the pull request is opened here.
This port follows the upstream design and provider semantics. It is developed at
Im-Midi/codenotch-windows and offered to the
upstream project as its windows/ tree; the two are kept in sync. Session detection
originated in Im-Midi/Pac-Man (MIT).
MIT — see LICENSE. The Codenotch design and name belong to the upstream author.