A macOS menu bar widget that shows your remaining Claude Code and Codex usage limits as battery icons โ so you never have to open
/usageagain.
C = Claude ยท X = Codex. Each battery shows the remaining % of a limit window โ full & green means plenty left, red means almost out. Click for a detailed breakdown with reset times.
Ships two ways: a notarized native app (double-click install, zero prerequisites) and a single SwiftBar plugin โ one self-contained script, no third-party libraries. The battery icons are rendered as PNGs from scratch in pure JavaScript (node:zlib only), so there's no image library and no npm install. Network calls: two official usage endpoints โ Anthropic's and OpenAI's โ each fetched with your own local Claude Code / Codex login (the same data /usage and Codex's /status show โ see Privacy), plus an optional once-a-day update check (see Updating). (ccusage is an optional extra for the cost breakdown.)
| Group | Batteries | Source |
|---|---|---|
C Claude |
5-hour session ยท weekly ยท Fable (top-model weekly cap) | Anthropic's OAuth usage API โ queried live with your local Claude Code login; account-level, so usage from every device/surface is included |
X Codex |
5-hour ยท weekly (or credit balance on the premium plan) | Codex's account-level usage API (backend-api/wham/usage), queried live with your local Codex login โ same data Codex CLI's /status shows; falls back to ~/.codex/sessions/**/*.jsonl if offline |
Click the widget for a dropdown with, per limit:
Claude Code ยท % left
5h โโโโโโโโโโโโโโโโโโโโโโ 87% ยท resets 2h 36m
week โโโโโโโโโโโโโโโโโโโโโโ 67% ยท resets 4d 2h
Fable โโโโโโโโโโโโโโโโโโโโโโ 41% ยท resets 4d 2h
today by model ยท $55 total โธ
Codex ยท prolite ยท % left
week โโโโโโโโโโโโโโโโโโโโโโ 100% ยท resets 7d 0h
Colors follow a traffic-light scale: green โฅ 50 % left, amber < 50 %, red < 20 %.
Using the native app? Skip this table โ it has no prerequisites (Claude Code just needs to be logged in;
ccusageoptional). The table below is for the SwiftBar-plugin variant.
| Required? | Install | |
|---|---|---|
| macOS | โ | โ |
| SwiftBar | โ | brew install swiftbar |
| bun | โ | curl -fsSL https://bun.sh/install | bash |
| Claude Code | โ
for C batteries |
just needs to be logged in on this Mac (the widget reuses its login to query the usage API) |
| Codex CLI | optional | for the X batteries; without it, only Claude is shown |
| ccusage | optional | adds the cost / token / per-model breakdown in the dropdown โ the battery works fully without it |
Note: This widget shows your own account's limits โ via your local Claude Code login and your local Codex session logs. If you don't use Claude Code (or Codex), there simply won't be any data to display.
Download ClaudeCodexBattery-vX.Y.Z.dmg from Releases, open it, and drag ClaudeCodexBattery.app into Applications. That's it โ the app is signed & notarized, so it runs with a double-click, and on first launch it offers to start at login. (A .zip is also published; it's what the in-app self-updater downloads.)
It's a native Swift port of the same widget: identical battery rendering, identical dropdown, same privacy model (see Privacy โ your tokens go only to the two usage endpoints). ccusage remains optional for the cost breakdown. Source lives in app/ โ ./build.sh for a local ad-hoc build, ./release.sh for the notarized release.
UI languages: English ยท ํ๊ตญ์ด ยท ๆฅๆฌ่ช ยท ็ฎไฝไธญๆ ยท ็น้ซไธญๆ ยท Espaรฑol โ follows your system language, or pick one in Settings โ Language (the SwiftBar plugin follows the same choice).
git clone https://github.com/dennykim123/claude-codex-battery.git
cd claude-codex-battery
./install.shinstall.sh will:
- Verify bun and SwiftBar are present (and tell you how to install them if not)
- Copy the plugin into
~/.swiftbar-plugins/, rewriting the shebang to your machine'sbunpath (SwiftBar runs plugins with a minimalPATH, so an absolute shebang is required) - Point SwiftBar at the plugin folder and launch it
- Install a launchd KeepAlive agent so SwiftBar comes back on its own โ after a reboot, after sleep, and even if SwiftBar crashes (it occasionally does). The battery just stays there; you never have to relaunch it by hand. (To turn it off completely:
launchctl bootout gui/$(id -u)/com.dennykim.claude-codex-battery && osascript -e 'quit app "SwiftBar"'.)
No npm install, no bundled libraries โ the plugin is a single self-contained script.
The battery appears in your menu bar within a few seconds. It refreshes every 2 minutes (the .2m. in the filename).
If you prefer not to run the script:
mkdir -p ~/.swiftbar-plugins
# rewrite shebang to your bun path, then copy:
sed "1s|.*|#!$(command -v bun)|" claude-codex-usage.2m.js > ~/.swiftbar-plugins/claude-codex-usage.2m.js
chmod +x ~/.swiftbar-plugins/claude-codex-usage.2m.js
defaults write com.ameba.SwiftBar PluginDirectory -string ~/.swiftbar-plugins
open -a SwiftBarNative app โ checks GitHub for a newer version once a day (a tiny request for the VERSION file). When one is out, a green Install update row appears in the dropdown: one click downloads the signed zip from Releases, verifies its Developer ID code signature (team-pinned, so a tampered zip is refused), replaces itself in place, and relaunches. Headless equivalent: ClaudeCodexBattery.app/Contents/MacOS/ClaudeCodexBattery --self-update.
SwiftBar plugin โ the widget checks GitHub for a newer version at most once a day โ a tiny background request for the VERSION file. When a new version is out, a green ๐ update row appears in the dropdown; click it to replace the plugin in place and refresh (your previous copy is kept as .bak). There's also an always-visible โฌ๏ธ update now row that replaces the plugin with the latest main on demand โ no waiting for the daily check.
Prefer to do it yourself? From your clone: git pull && ./install.sh.
To turn the check off entirely, comment out the getUpdateInfo() call near the bottom of the script โ then the only network call left is the Anthropic usage query.
- Claude limits come straight from Anthropic. The widget reads your Claude Code OAuth token from the macOS Keychain (item
Claude Code-credentials) and callsapi.anthropic.com/api/oauth/usageโ the same endpoint/usageuses. The token is sent only to api.anthropic.com, passed via stdin (never visible inps), and never written to disk or logs. macOS may show a one-time Keychain permission prompt โ click Always Allow. (Clicking Deny makes macOS re-prompt on every refresh โ if you'd rather the widget never touch the Keychain, runtouch ~/.claude/swiftbar/.no-liveinstead; it then reads local cache files only, like v1.1.) - Codex limits come straight from OpenAI. Likewise, the widget reads your Codex OAuth token from
~/.codex/auth.jsonand callschatgpt.com/backend-api/wham/usageโ the same account-level endpoint Codex CLI polls itself. The token is sent only to chatgpt.com, via stdin (never visible inps), and never written to disk or logs. (touch ~/.claude/swiftbar/.no-livedisables both live queries; it then reads local files only.) - No API keys touched. Only the OAuth login tokens above are read โ never any
OPENAI_API_KEY/ANTHROPIC_API_KEY. - No usage data leaves your machine. Nothing is uploaded anywhere; the only outbound calls are the two usage queries above (to Anthropic and OpenAI) and the optional daily update check (Updating).
- No conversation content. From the Codex session-log fallback it parses only the
rate_limitsobject (numbers), never the messages. - Auditable in one sitting. The whole widget is a single dependency-free script โ grep for
curl/fetchand you've seen every network call it can make.
Claude โ live. Every refresh queries Anthropic's usage API directly with your local Claude Code login โ the same server-side data /usage shows, so the numbers match it by construction. Because the limits are account-level, usage from every surface and device (terminal, desktop app, web, another machine) is already included. If the query fails (offline, logged out), the widget falls back to its last successful response and labels the reading with its age in amber.
Codex โ live too. The widget queries the same account-level usage endpoint Codex CLI polls internally (backend-api/wham/usage), using your local Codex login token. It's a read-only call that costs no tokens, and because it's account-level, all your machines see the same numbers โ so two Macs stay in sync. If the query fails (offline, logged out), it falls back to the newest local session log (labeled "measured N ago", warns past 3h) and then to its last live response.
TL;DR โ Both Claude and Codex are live and account-level, so every device shows the same numbers. When a live query fails, each falls back to a clearly-labeled cached/snapshot reading.
The whole thing is one .js file run by bun on a timer.
- Battery icons are drawn pixel-by-pixel into an RGBA buffer and encoded to PNG using only
node:zlib(hand-rolled CRC32 + IHDR/IDAT/IEND chunks). A 5ร7 bitmap font renders the numbers and theC/Xgroup labels. SwiftBar displays the PNG at pixels รท 2 pt. - Claude limits are fetched from Anthropic's OAuth usage endpoint using the Claude Code login token in your Keychain, with the last good response cached at
~/.claude/swiftbar/.claude-usage.jsonas an offline fallback. The Fable cap is theweekly_scopedentry. - Codex limits are fetched live from
backend-api/wham/usagewith the token in~/.codex/auth.json, normalized to the same shape as the session-log format, and cached at~/.claude/swiftbar/.codex-usage.jsonas an offline fallback (with the newest session log as a second fallback). The premium plan reports acreditsobject instead of percentages when exhausted; the widget handles both shapes.
Both queries are read-only and cost no tokens โ you never have to use Claude or Codex to get a fresh reading, and every device sees the same account-level numbers. Older builds refreshed Codex by quietly running a real codex command in the background (spending tokens) when the session-log value went stale; that's gone โ the live endpoint makes it unnecessary.
| Want to change | Where |
|---|---|
| Refresh interval | filename .2m. โ .1m., .5m., .30s., โฆ |
| Battery size | โ row in the dropdown โ toggles between big (4ร6 font, default) and small (3ร5 font, ~25% narrower); stored in ~/.claude/swiftbar/.batt-size |
| Color thresholds | heatRemain / heatRemainHex (20 % / 50 %) |
| Disable live Claude + Codex APIs (Keychain / token access) | touch ~/.claude/swiftbar/.no-live (falls back to local cache files) |
| Which Claude limits to show | the battItems.push(...) block |
Both variants show exactly the same batteries and dropdown, from the same two usage endpoints.
- Native app โ one notarized
.app, zero prerequisites, double-click and done. For anyone who just wants the battery in the menu bar (this was the roadmap item; it shipped in v2.0.0). - SwiftBar plugin โ one self-contained script, easy to audit in a sitting and trivial to fork. Its audience (Claude Code / Codex developers) already lives in the terminal, so
brew install swiftbaris no barrier.
Issues and PRs welcome โ especially for other plans/tools (e.g. mapping additional rate_limit shapes, or adding providers). Keep it dependency-free.

