A local-first Windows tray monitor for the usage, quotas, accounts and session activity of Claude Code / Desktop, Codex CLI / Desktop, and Grok CLI.
English | 简体中文
Download the latest Windows build · Quick start · Development
Note
For Claude and Codex, the cost shown is an API-equivalent value computed from official standard API prices (the price table updates itself from this repository; its date is shown at the bottom of the panel) — a way to compare burn rates. Subscriptions are not billed by this amount. Grok's cost comes from the official billed value recorded by Grok CLI; within your subscription quota it does not cost extra either.
Regular Claude Desktop Home chats only leave session metadata and quota percentages on disk, with no token detail, so no cost can be computed for them. Cost only covers Claude Code / Cowork sessions that have a local transcript. Connecting a Claude account improves quota and reset accuracy but cannot fill in Home-chat tokens.
| Claude + Codex + Grok in one place | Claude Code, Claude Desktop, Codex CLI/Desktop and Grok CLI share one panel. |
| Independent date ranges | Each provider gets its own 1–90 day range. |
| Quota windows | 5h / 7d usage percentages, reset times and data freshness. With a Claude account connected, the Fable window appears when available. |
| Per-account usage | Once enabled on this machine, tokens accumulate under the current account; older records stay out. The ledger is encrypted locally by Windows. |
| Session states | Working, needs attention, and idle. Desktop sessions open straight from the panel. |
| Live activity ring | While a session is running, that provider lights up with a ring of travelling light on the floating bar. It watches session directories for writes instead of waiting for the 30s refresh. Switch it to rainbow or turn it off. |
| Edge-docked floating bar | Docks to the top or right edge, expands on hover; auto-hides over fullscreen apps (exclusive or borderless-fullscreen games, videos, presentations), and the tray menu can turn that off. |
| Local-first | It reads what the clients already wrote on this machine and uploads nothing about you. Unless you connect a Claude account, the one automatic request downloads the public price table from this repository. |
| Prices stay current | New models and price changes arrive within a day of being fixed here, without a new version. Turn it off in the tray menu. |
| Zero API keys | Local mode needs no API key. Claude OAuth is optional, for more accurate quotas. |
- The price table updates itself. It now lives in
lib/prices.jsonin this repository, and the app downloads it about 10 seconds after launch and then once a day, retrying hourly after a failure (at login the network is often not up yet). A price change or a new model reaches every installed copy within a day, with no new version to install. A download is used only if it validates and is at least as new as the table in use; offline, the last good download or the built-in copy keeps working. The request sends nothing about you, and the tray menu can turn it off (自动更新价格表). See How the cost is computed. - The weekly price check reads the vendors' own pages.
npm run check-pricesnow compares every price on Anthropic's and OpenAI's pricing pages and flags any model the Codex model page offers that has no row. GPT-6 Sol and Luna showed as $0 until 1.4.0 because the old check only verified rows the table already had.
- Live activity ring. While a session runs, that provider's segment of the floating bar is wrapped in a ring of travelling light: orange for Claude, mint for Codex, blue for Grok, and the warning colour when a session needs you. "Activity ring style" in the tray menu offers brand colours, rainbow or off; with "reduce motion" enabled system-wide it becomes a still glow.
- The ring does not wait for the 30s refresh. The main process watches all three session directories and the hook status directory, and lights up within 0.4s of a write. A turn often finishes in well under 30 seconds, so a ring driven by the snapshot would mostly appear after the work was done.
- File events are re-checked against mtime. A client renaming or migrating old session files fires the watch too, but the file itself is not new, so it does not count as running — Codex Desktop's session migration at startup used to spin the ring for 20 seconds on its own.
- The installer asks where to install. The one-click build went to the per-user location without asking. It is now an assisted install with a directory page, still defaulting to per-user and still needing no admin rights.
- Prices re-checked against all three vendors' official pages. Claude Opus 5.5 was being priced as Opus 5, cache reads at 2.5x the official rate, so if you use Opus 5.5 the cost shown drops noticeably — that is the correction, not lost data. GPT-6 Sol and GPT-6 Luna were not recognized and cost nothing; they now use official rates, as do GPT-5.4 and GPT-5.4 mini, which Codex still lists. Grok needs no table: its cost is the billed value Grok CLI records.
- Upgrading no longer turns launch-at-login off. v1.3.1 taught the uninstaller to clear the startup entry, but a one-click install runs the previous uninstaller first, so every update silently switched the setting off. The uninstall hook now skips that when it is part of an update; a real uninstall still clears it.
- Running the portable build no longer takes the startup entry from an installed copy. Installing is a deliberate act and still takes it over; being double-clicked once is not. A portable launch now claims the entry only when the exe it points at is gone.
- Leftover temporary files are cleared at startup. Writes go through a temp file, and a forced kill — which recovering a hung instance does — skipped the cleanup. Only this app's own
.tmpfiles are removed.
- Rate-limit waits are honored in full and survive restarts. v1.3.0 capped the wait Anthropic asked for at one hour, so when the server wanted longer the app knocked again every hour and stayed rate-limited — and every restart made a fresh request straight away. The cap is now 24 hours, and the wait is written to
%APPDATA%\ai-code-usage-tray\claude-oauth-throttle.json(status code and timestamps only, no tokens), so a restart respects it too. That file also tells you why the last request failed. - An expired login says so and stops retrying. When the refresh token has expired (Anthropic answers
400 Refresh token expired), the panel now says the login has expired instead of talking about an authorization code, and the app stops knocking on the API every 5 minutes until you reconnect the account. - Codex pricing covers the cyber models and the daybreak aliases.
gpt-5.5-cyberwas billed asgpt-5.5(2.5× under);gpt-5.6-cyber,gpt-daybreak-blue-latestandgpt-daybreak-red-latestwere not recognized at all and cost nothing. Confirmed against OpenAI's pricing page.
- Installer build. The one-click installer
AI-Code-Usage-Tray-Setup-*-win-x64.exeis now the recommended download. It installs for the current user under%LOCALAPPDATA%\Programswithout admin rights, starts without unpacking ~350 MB on every launch, and keeps the tray icon and launch-at-login entry on a stable path. The portable build is still published. - Opening the app again recovers a frozen instance. Before, once the app stopped responding, relaunching it did nothing: the frozen copy kept the single-instance lock and every new launch quit silently. A new launch now ends any copy Windows reports as not responding, then takes over.
- The portable build no longer damages a running copy. Every launch used to unpack into the same temporary folder and delete it on exit, including files that a copy still running from that folder needed. Each launch now gets its own folder.
- Hang log. If the main thread stops responding for more than 15 seconds,
%APPDATA%\ai-code-usage-tray\hang-log.jsonlrecords when it happened, which step was running and which processes had just started. Nothing is uploaded. See If the app stops responding. - The Claude account quota recovers from rate limiting. When Anthropic rate-limited the quota request, the app retried it on every 30-second refresh, which could keep the account rate-limited indefinitely and hide the Fable window. It now makes at most one attempt every 5 minutes, whether the last one succeeded or failed, and waits longer when Anthropic's response asks it to (up to an hour).
- Fixed the Grok weekly quota disappearing at the start of a billing period. xAI omits
creditUsagePercentwhen usage is 0, which was read as "no data" and hid the whole quota block until usage crossed 1%. An absent field now means 0%.
- The price table was re-verified end to end. Sonnet 5 and the whole GPT-5.6 family now use current official rates, and Claude Fable 5.1 / Mythos 5.1 read cache at 0.025x instead of a flat 0.1x. If you use Fable 5.1 heavily the cost shown drops noticeably — that is the correction, not lost data.
- Model resolution fixes. Longest-prefix matching, so
claude-opus-4no longer shadowsclaude-opus-4-5andgpt-5.5no longer shadowsgpt-5.5-pro(which had been billing 6x under). Bedrock and Vertex model ids are recognised; those sessions previously showed a cost of zero. - Missing multipliers added: Opus 5 fast mode (2x),
inference_geo: "us"(1.1x), and the Bedrock regional profile premium (10%). - New
npm run check-prices, run weekly by GitHub Actions so a stale table gets reported instead of quietly drifting. See Updating the price table.
Older versions are listed under Releases.
- Open GitHub Releases.
- Download the installer
AI-Code-Usage-Tray-Setup-*-win-x64.exeand run it. It asks where to install, defaulting to the current user under%LOCALAPPDATA%\Programs(no admin rights; choosing all users needs them). It adds desktop and Start menu shortcuts and starts the app. Uninstall it from Windows Settings → Apps; settings and the account ledger in%APPDATA%\ai-code-usage-trayare kept. - Click the floating bar or tray icon to open the full panel.
- Right-click the floating bar or tray icon to refresh, toggle launch-at-login, toggle price-table updates, change the activity ring style, switch top/right docking, hide the floating bar, toggle fullscreen auto-hide, or quit.
Prefer not to install? AI-Code-Usage-Tray-*-win-x64.exe (no Setup in the name) is the portable build: double-click to run. It unpacks itself to a new temporary folder on every launch, so it starts slower, and Windows may treat its tray icon as a new program each time.
Moving from the portable build to the installer: quit the portable app first (right-click → quit), because the installer may not notice a copy running from a temporary folder. If launch-at-login was on, the installed app takes the entry over the first time it starts, and running the portable build afterwards leaves that entry alone — it only claims it when the exe the entry points at is gone.
Warning
The builds are not code-signed yet, so SmartScreen may warn you. Download only from this repository's Releases and verify the SHA-256 published with each release. Signed builds will follow the Code signing policy below.
| Client | Local source | Data provided |
|---|---|---|
| Claude Code | ~/.claude/projects/**/*.jsonl |
tokens, models, projects, session activity |
| Claude Desktop | %APPDATA%/Claude/plan-usage-history.json |
5h / 7d percentages |
| Claude Desktop | %APPDATA%/Claude/claude-code-sessions/**/*.json |
Claude Code / Cowork titles, client type, recent activity |
| Claude Desktop Home | %APPDATA%/Claude/IndexedDB/ |
regular-chat titles, model, message counts, recent activity (no token detail) |
| Claude account (optional) | Anthropic OAuth usage endpoint | official percentages and exact reset times |
| Codex CLI / Desktop | ~/.codex/sessions/**/*.jsonl |
tokens, quota windows, models, session activity |
| Grok CLI | ~/.grok/sessions/**/updates.jsonl + ~/.grok/logs/unified.jsonl |
per-turn tokens, official billed cost, subscription weekly quota, session activity |
The Microsoft Store build of Claude Desktop is detected automatically under %LOCALAPPDATA%/Packages/Claude_*/LocalCache/Roaming/Claude/.
Claude and Codex costs come from a hand-maintained table of official standard API list prices, lib/prices.json, stamped with the date it was last verified — the "price snapshot" date at the bottom of the panel. Neither vendor publishes pricing in a machine-readable form, so the table is kept here and the app fetches it: about 10 seconds after launch and then once a day (hourly after a failed attempt), from raw.githubusercontent.com, falling back to cdn.jsdelivr.net where GitHub is unreachable. A downloaded table is used only if it passes validation (known schema, sane numbers, every model still present) and is at least as new as the table in use. Otherwise, or offline, the app keeps the last good download (%APPDATA%\ai-code-usage-tray\prices.json) or the copy built into the app. The tray menu item 自动更新价格表 turns the download off; the table already in use stays. What the table models:
- Prompt caching: cache write 1.25x (5-minute) / 2x (1-hour), cache read 0.1x — 0.05x on Claude Opus 5.5, 0.025x on Claude Fable 5.1 and Mythos 5.1.
- Fast mode (2x) on Opus 5.5 / 5 / 4.8, and
inference_geo: "us"(1.1x), read from each transcript row. - Codex long context (input over 272K: 2x input, 1.5x output).
- Bedrock and Vertex model ids (
us.anthropic.…,name@date), with the documented 10% regional premium;global.profiles at base price. - Retired models stay listed so older transcripts still price.
Models without a public list price (for example Codex's internal codex-auto-review label) show as "unavailable", are left out of the total, and the total is marked incomplete rather than guessed.
npm run check-prices checks the table against Anthropic's and OpenAI's own pricing pages — every price, plus a row for every model the Codex model page offers — and against LiteLLM's community-maintained cost map; CI runs it weekly. It only reports: a person edits the table.
Everything is in one file, lib/prices.json. Pushing it to main updates every installed copy (1.5.0 and later) within a day; no release is needed.
| What | Where |
|---|---|
| Claude prices | The claude section. One row per model, USD per million tokens: "claude-opus-5": { "input": 5, "output": 25 }. Optional fields: cacheRead (cache-hit multiplier, default 0.1), fast (fast-mode multiplier), legacy: true (retired model, exempt from the Bedrock regional premium). |
| Codex prices | The codex section: "gpt-5.6-sol": { "input": 4, "cachedInput": 0.4, "output": 20 }. Which models get a row is written at the top of lib/codex-usage.js. codexAliases points ids the pricing page documents as aliases at a row. |
| Snapshot date | snapshot. The panel footer shows it. |
Row keys are the model id without a date suffix (claude-opus-5, not claude-opus-5-20260514). priceFor matches by prefix and the longest key wins, so claude-opus-4 and claude-opus-4-5 coexist. A model that only exists as a longer sibling of an existing key (gpt-5.5-pro next to gpt-5.5) needs its own row, or it silently takes the shorter key's price — npm run check-prices reports that as an unlisted id line.
npm run check-prices— each difference prints asofficial model field ours → official, or withclaude/codexin front for LiteLLM. Both vendors refuse some regions and Node'sfetchignores the system proxy; behind a proxy, runNODE_USE_ENV_PROXY=1 npm run check-prices(Node 24+, readsHTTPS_PROXY).officiallines come straight from the vendors' pages. Confirm LiteLLM lines there too: Anthropic pricing, OpenAI pricing. LiteLLM is community data and occasionally contradicts itself.- Edit the row(s), set
snapshotto today's date, runnpm test, commit, and push tomain.
Installed copies depend on this file, so four rules:
- Keep the path.
lib/prices.jsononmainis the exact file they download. - Set
snapshotto the day of the change, a rollback included — a table older than the one in use is ignored. Never a future date: copies refuse one, because it would outrank every later fix. - Never delete a row. Retired models still price old transcripts, and a table missing a row is rejected as truncated.
- New optional fields are fine (older copies ignore them). If an existing field changes meaning, raise
schema: older copies then keep the table they have instead of misreading the new one.
How you find out. The prices job in .github/workflows/ci.yml runs every Monday 06:17 UTC and fails on drift. GitHub sends the failure notification to the account whose commit last changed the cron: line of that file — by email and/or on the web, per Settings → Notifications → Actions (make sure Actions notifications are on there; "failed workflows only" is enough). You can also run it any time from the Actions tab with Run workflow. GitHub pauses scheduled workflows after 60 days without repository activity; re-enable it from the Actions tab if that happens.
- The app re-reads local data every 30 seconds.
- Claude Desktop samples its quota roughly every 5 minutes, so the UI shows "sampled N minutes ago by Desktop".
- Claude Desktop's local history has no
resets_at. The app infers reset times from the last reset-to-zero and the next sample, marks them with≈, and they are typically within about 5 minutes. - With a Claude account connected, official exact reset times take over. Credentials are encrypted with Windows
safeStoragein the app's data directory and deleted when you disconnect.
| Color | State | Meaning |
|---|---|---|
| 🟢 | Working | recently producing output, or the session file is still being written |
| 🔴 | Needs attention | waiting for a permission prompt or your action in the client |
| ⚫ | Idle | no recent activity |
With the optional Claude CLI hooks installed, working / attention / idle become precise; without them the state falls back to transcript write times. A freshly written transcript overrides a stale hook so a running session never shows an old state. A hook silent for more than 30 minutes falls back to idle.
While a session runs, its segment of the floating bar is wrapped in a ring of travelling light: orange for Claude, mint for Codex, blue for Grok, and the warning colour when a session needs you. "Activity ring style" in the tray menu switches it to rainbow or turns it off; with "reduce motion" enabled system-wide it becomes a still glow.
The ring does not wait for the 30s snapshot. The main process watches ~/.claude/projects, ~/.codex/sessions, ~/.grok/sessions and the hook status directory, and lights up within 0.4s of a write (lib/activity.js):
- Claude sessions with hooks installed follow the hook's working / needs-attention state, which is exact.
- Sessions without hooks, plus Codex and Grok, fall back to "wrote to disk in the last 20 seconds" — so the ring can blink during a long think with no disk writes, and stays lit for up to 20s after a turn ends. Tune
WRITE_ACTIVE_MSinlib/activity.js. - Every file event is re-checked against the file's mtime: a client renaming or migrating old session files also fires the watch, but the file itself is not new, so it does not count as running.
Switching styles while nothing is running would show no difference, so a style change lights all three rings for two seconds as a preview.
Neither the installer nor the portable build includes the hook scripts — get the hooks/ directory from this repository (clone it, or download the two files). Then wire them into ~/.claude/settings.json:
{
"hooks": {
"SessionStart": [{ "hooks": [{ "type": "command", "command": "node C:/path/to/ai-code-usage-tray/hooks/report-status.js" }] }],
"UserPromptSubmit": [{ "hooks": [{ "type": "command", "command": "node C:/path/to/ai-code-usage-tray/hooks/report-status.js" }] }],
"Stop": [{ "hooks": [{ "type": "command", "command": "node C:/path/to/ai-code-usage-tray/hooks/report-status.js" }] }],
"Notification": [{ "hooks": [{ "type": "command", "command": "node C:/path/to/ai-code-usage-tray/hooks/report-status.js" }] }],
"SessionEnd": [{ "hooks": [{ "type": "command", "command": "node C:/path/to/ai-code-usage-tray/hooks/report-status.js" }] }]
},
"statusLine": { "type": "command", "command": "node C:/path/to/ai-code-usage-tray/hooks/report-rate-limits.js" }
}report-status.js writes per-session states to ~/.claude/usage-tray-status/ and always exits fast, so it never slows Claude Code down. report-rate-limits.js uses the statusLine slot to capture official rate limits and prints nothing. Claude Code has a single statusLine slot — if you already use one, keep yours and skip that part; session states work without it. New sessions pick the hooks up automatically.
Open it again. A new launch ends any copy that Windows reports as not responding and takes over. If that still does not help, end the process from Task Manager.
To see why it froze, open %APPDATA%\ai-code-usage-tray\hang-log.jsonl. A freeze longer than 15 seconds adds these lines:
hang—lastBeatAtis when the main thread stopped.stepnames the synchronous call into another process that was running (tasklist,registry,tray,window,safe-storage), or isidleif none was: the thread froze while handling window messages, which is where code injected from outside the app runs.processes— processes started in the 15 minutes before the freeze, plus input-method and text-services processes with their start times.recovered— written if the thread comes back, with how long it was stuck.ended-hung-instance— written by the launch that took over, naming the process it ended.watchdog-error/watchdog-exit— the watchdog itself could not start, or stopped early. Without these an empty log would be ambiguous.
Input methods that load a text-service DLL into every program (Tencent WeType, for example) are a known cause of this kind of cross-process freeze in other software, and the one freeze analysed so far had that DLL loaded. That is a lead, not a verdict: an idle step together with an input-method process that started just before the freeze would confirm it. Please attach the log when you report a hang.
- No transcripts, prompts, project paths or session titles are uploaded.
- Apart from the optional Claude account (which asks Anthropic for your quota), the only automatic network request downloads the public price table (
lib/prices.json) from this repository, at launch and once a day (hourly after a failed attempt). It sends nothing about you; the server sees an ordinary download. Turn it off with the tray menu item 自动更新价格表. - No browser cookies are read, and no Anthropic / OpenAI / xAI API key is needed.
- If a local file is corrupt, locked or unreadable, the last snapshot is kept and marked stale.
- OAuth login is optional. Local monitoring keeps working offline or when Anthropic rate-limits.
- The hang log (
hang-log.jsonl) stays on this machine. It holds timestamps, a step name, and process names with their start times — no usage data or session content. claude-oauth-throttle.jsonrecords the last account quota request's status code and timestamps, so a rate-limit wait survives a restart. No tokens.- Full details in the Privacy Policy.
- Free code signing provided by SignPath.io, certificate by SignPath Foundation.
- SignPath-signed releases will be built from this repository by GitHub Actions and manually approved before signing. All releases to date remain unsigned; signing starts once the SignPath Foundation approval completes.
- Committer, reviewer, and approver: @saime428.
- Privacy policy: PRIVACY.md.
Requires Windows 10/11, Node.js 22+ and npm:
git clone https://github.com/saime428/ai-code-usage-tray.git
cd ai-code-usage-tray
npm ci
npm test
npm start
npm run usage # print today's usage in the terminal, no Electron needed
npm run check-prices # check the price table against the vendors' pages and LiteLLMBuild the Windows x64 installer and portable executable:
npm run distBoth land in dist/: AI-Code-Usage-Tray-Setup-<version>-win-x64.exe (installer) and AI-Code-Usage-Tray-<version>-win-x64.exe (portable). To update your own install, quit the running app and run the new Setup file.
main.js Electron main process, tray, windows, refresh scheduling
preload.js restricted IPC bridge
lib/usage.js Claude local usage and session parsing
lib/codex-usage.js Codex local usage and quota parsing
lib/prices.json Claude / Codex price table (the app also downloads it from main)
lib/prices.js price table validation, and the URLs it is downloaded from
lib/grok-usage.js Grok local usage, official cost and weekly quota
lib/claude-oauth.js optional Claude OAuth / PKCE
lib/hang-guard.js hang log watchdog and not-responding instance lookup
renderer/index.html full panel
lib/activity.js activity watch behind the ring (session writes + hook state)
renderer/floating.html edge-docked floating bar
hooks/ optional Claude Code state hooks
npm test
npm run check-prices
npm run dist
git status --shortPrice fixes don't need a release — see Updating the price table. For a release, bump the version in package.json, refresh the "What's new" section at the top of both READMEs, install the Setup build on a clean Windows machine, then create a GitHub Release with both .exe files and their SHA-256.
- Windows x64 only.
- The app itself does not auto-update yet; only the price table does.
- The app UI is currently Chinese-only.
- The builds are not code-signed yet. The SignPath Foundation application and signing automation are in progress.
- Claude OAuth may be rate-limited by Anthropic or affected by your network egress. Local inference is unaffected.
- Regular Claude Desktop Home chats expose no token detail, so only session state and quota percentages can be shown — no cost.
- Grok sessions are CLI-only: no per-account tracking (no identity detection yet) and no click-to-open deep link.
- The Grok weekly quota comes from what Grok CLI writes to disk: after a billing period rolls over it only reappears the next time you run Grok CLI (2–57 hours in local measurements). It stays hidden during that window — the weekly quota is account-wide, so you may have spent part of it on the web, and a guess would be worse than nothing.
- Bedrock's own pricing for retired models is not modeled.
- Codex fast mode (
service_tier: "priority", 2x the standard price, 2.5x on gpt-5.5) is not modeled; those turns show the standard price. - Models without a public list price (such as
codex-auto-review) are excluded from the total and flagged, not estimated.
Issues and pull requests are welcome. Before submitting, run:
npm testIf you add parsing logic that is not obvious at a glance, include a small test covering the real format. Never commit transcripts, credentials or personal project paths.
MIT © 2026 saixin
Not affiliated with or endorsed by Anthropic, OpenAI, or xAI.
