Tiny macOS 15+ menu bar app that keeps your Codex and Claude Code limits visible (5‑hour/session + weekly windows) and when each window resets. One status item per provider; enable either or both from Settings. No Dock icon, minimal UI, dynamic bar icons in the menu bar.
Login story
- Codex — Prefers the local codex app-server RPC for 5h/weekly limits + credits. Falls back to a PTY scrape of
codex /status(auth/email/plan from the RPC or~/.codex/auth.json). All parsing stays on-device; no browser required. - Claude Code — Reads session + weekly + Sonnet-only weekly usage from the Claude CLI by running
/usage+/statusin a local PTY (no tmux). Shows email/org/login method directly from the CLI output. No browser or network calls beyond the CLI itself. - Provider detection — On first launch we detect installed CLIs and enable Codex by default (Claude turns on when the
claudebinary is present). You can toggle either provider in Settings → General or rerun detection after installing a CLI.
Icon bar mapping (grayscale)
- Top bar: 5‑hour window when available; if weekly is exhausted, the top becomes a thick credits bar (scaled to a 1k cap) to show paid credits left.
- Bottom bar: weekly window (a thin line). If weekly is zero you’ll see it empty under the credits bar; when weekly has budget it stays filled proportionally.
- Errors/unknowns dim the icon; no text is drawn in the icon to stay legible. Codex icons keep the eyelid blink; when Claude is enabled the template switches to the Claude notch/leg variant while keeping the same bar mapping.
- Dual providers: Codex status item (5h/weekly + credits) and Claude Code status item (session/weekly + Sonnet-only weekly limit) can be shown together; Codex defaults on, Claude turns on when the CLI is present. Both sections show last-updated time and surface errors inline.
- Codex path: prefers the codex app-server RPC (run with
-s read-only -a untrusted) for rate limits and credits; falls back to a PTY scrape ofcodex /status, keeping cached credits when RPC is unavailable. - Claude path: runs
claude /usageand/statusin a local PTY (no tmux) to parse session/week/Sonnet percentages, reset strings, and account email/org/login method; debug view can copy the latest raw scrape. - Account line keeps data siloed: Codex plan/email come from RPC/auth.json, Claude plan/email come only from the Claude CLI output; we never mix provider identity fields.
- Auto-update via Sparkle (Check for Updates… menu item, auto-check enabled). Feed defaults to the GitHub Releases appcast (replace SUPublicEDKey with your Ed25519 public key).
- Ready-to-run zips are published in GitHub Releases: https://github.com/steipete/CodexBar/releases
swift build -c release # or debug for development
./Scripts/package_app.sh # builds CodexBar.app in-place
open CodexBar.appRequirements:
- macOS 15+.
- Codex: Codex CLI ≥ 0.55.0 installed and logged in (
codex --version) to show the Codex row + credits. If your account hasn’t reported usage yet, the menu will show “No usage yet.” - Claude: Claude Code CLI installed (
claude --version) and logged in viaclaude loginto show the Claude row. Run at least one/usageso session/week numbers exist.
Menu → “Refresh every …” presets: Manual, 1 min, 2 min, 5 min (default), 15 min. Manual still allows “Refresh now.”
export APP_STORE_CONNECT_API_KEY_P8="-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----"
export APP_STORE_CONNECT_KEY_ID="ABC123XYZ"
export APP_STORE_CONNECT_ISSUER_ID="00000000-0000-0000-0000-000000000000"
./Scripts/sign-and-notarize.shOutputs CodexBar-<version>.zip ready to ship. Adjust APP_IDENTITY in the script if needed.
Account details stay local and per-provider:
- Codex: email/plan come from the codex RPC response; falls back to decoding
~/.codex/auth.json(JWT only) if the RPC is unavailable. - Claude: email/org/login method are pulled from the Claude CLI
/statusoutput. - We never mix provider data (no showing Claude org in Codex mode, etc.). Nothing is sent anywhere.
- Codex: if Codex hasn’t returned rate limits yet, you’ll see “No usage yet.” Run one Codex prompt and refresh.
- Codex: if the event schema changes, percentages may fail to parse; the menu will show the error string while keeping cached credits.
- Claude: if the CLI is missing or not logged in you’ll see the CLI error (e.g., “Claude CLI is not installed” or “claude login”).
- Claude: reset strings sometimes omit time zones; we surface the raw text when parsing fails.
- Only arm64 build is scripted; add
--arch x86_64if you want a universal binary.
- Update version in Scripts/package_app.sh, Scripts/sign-and-notarize.sh, About panel (CodexBarApp) and CHANGELOG.md
- Run swiftlint & swiftformat
- swift test / swift build -c release
- ./Scripts/package_app.sh release
- ./Scripts/sign-and-notarize.sh (arm64)
- Verify .app:
spctl -a -t exec -vv CodexBar.app;stapler validate CodexBar.app - Generate Sparkle appcast with notarized zip using your Ed25519 key; upload appcast + zip to Releases; set SUPublicEDKey in Info.plist
- Upload
CodexBar-<version>.zipto GitHub Releases and tag - README download link points to the new release
See CHANGELOG.md.
- ✂️ Trimmy — “Paste once, run once.” Flatten multi-line shell snippets so they paste and run.
- 🧳 MCPorter — TypeScript toolkit + CLI for Model Context Protocol servers.
- Cross-promote: Download CodexBar at codexbar.app and Trimmy at trimmy.app.
License: MIT • Peter Steinberger (steipete)
