1. Project Overview & Quickstart (steipete/CodexBar)
File: README.md
CodexBar 🎚️ — May your tokens never run out.
Every AI coding limit, in your menu bar.
Tiny macOS 14+ menu bar app that keeps AI coding-provider limits visible and shows when each window resets. Codex, OpenAI, Claude, Cursor, Gemini, Copilot, Grok, GroqCloud, ElevenLabs, Deepgram, z.ai, MiniMax, Kiro, Zed, Vertex AI, Augment, OpenRouter, LiteLLM, LLM Proxy, Codebuff, Command Code, ClinePass, AWS Bedrock, and many newer coding providers. One status item per provider, or Merge Icons mode with a provider switcher. No Dock icon, minimal UI, dynamic bar icons.
Why
- Plan around resets. Per-provider session, weekly, and monthly windows with countdowns to the next reset — stop guessing whether to start that long task.
- Credits, spend, and cost scans. Credit balances, Admin API spend dashboards, provider billing summaries, and local cost scans where the source exposes enough detail.
- Live status. Provider status polling surfaces incident badges in the menu and an indicator overlay on the bar icon.
- Privacy-first. Reuses existing provider sessions — OAuth, device flow, API keys, browser cookies, local files — so no passwords are stored.
Install
Requirements
- macOS 14+ (Sonoma)
GitHub Releases
Download: https://github.com/steipete/CodexBar/releases
Homebrew
brew install --cask codexbarCLI Tarballs (macOS/Linux)
Homebrew formula (Linux today):
brew install steipete/tap/codexbarArch Linux AUR package:
yay -S codexbar-cliOr download release tarballs from GitHub Releases:
- macOS:
CodexBarCLI-v<tag>-macos-arm64.tar.gz,CodexBarCLI-v<tag>-macos-x86_64.tar.gz - Linux (glibc):
CodexBarCLI-v<tag>-linux-aarch64.tar.gz,CodexBarCLI-v<tag>-linux-x86_64.tar.gz - Linux (static musl):
CodexBarCLI-v<tag>-linux-musl-aarch64.tar.gz,CodexBarCLI-v<tag>-linux-musl-x86_64.tar.gz
First run
- Open Settings → Providers and enable what you use.
- Install/sign in to the provider sources you rely on: CLIs, browser sessions, OAuth/device flow, API keys, local app files, or provider apps depending on the provider.
- Optional: Settings → Providers → Codex → OpenAI cookies (Automatic or Manual) to add dashboard extras.
Set API keys from the CLI
Provider toggles and API keys live in the resolved CodexBar config file. New installs use~/.config/codexbar/config.json; existing ~/.codexbar/config.json installs still load from the legacy path. You can
script the same provider list that Settings → Providers uses:
codexbar config providers
codexbar config enable --provider grok
codexbar config disable --provider cursorFor API-key providers, store a key without opening Settings:
printf '%s' "$ELEVENLABS_API_KEY" | codexbar config set-api-key --provider elevenlabs --stdinset-api-key trims the piped value, stores it with restrictive config-file permissions, and enables the provider by default. Use --no-enable to only save the key, or --api-key <key> for one-off local scripts where shell history is not a concern.
See CLI configuration for the full flow.
Providers
- Codex — OAuth API or local Codex CLI, plus optional OpenAI web dashboard extras.
- OpenAI — Admin API key usage/cost graphs with legacy credit-balance fallback.
- Azure OpenAI — API key, endpoint, and deployment validation probe.
- Claude — OAuth API, browser cookies, or CLI PTY fallback; session and weekly usage where available.
- Cursor — Browser session cookies for plan + usage + billing resets.
- OpenCode — Browser cookies for workspace subscription usage.
- OpenCode Go — Usage API, browser fallback, and local SQLite cost history.
- Alibaba Coding Plan — Web cookies or API key for coding-plan quotas.
- Alibaba Token Plan — Bailian browser/manual cookies for token-plan credits.
- Qwen Cloud — 5-hour and weekly individual Token Plan usage via browser/manual cookies.
- Gemini — OAuth-backed quota API using Gemini CLI credentials (no browser cookies).
- Antigravity — Local language server probe,
agyCLI HTTPS source, and Google OAuth fallback (experimental). - Droid — Browser cookies + WorkOS token flows for Factory usage + billing.
- Copilot — GitHub device flow + Copilot internal usage API.
- Devin — Chrome localStorage session or manual Bearer token for daily and weekly quotas.
- z.ai — API token for personal/team quota, MCP, 5-hour, and hourly usage windows.
- Manus — Browser
session_idauth for credit balance, monthly credits, and daily refresh tracking. - MiniMax — API token, cookie header, or browser cookies for coding-plan usage.
- T3 Chat — Browser cookies capture for Base and Overage usage buckets.
- ZoomMate — Chrome cookie auto-import or manual cURL capture for credits usage.
- Kimi — Auth token (JWT from
kimi-authcookie) for weekly quota + 5‑hour rate limit. - Kilo — API token with CLI-auth fallback for Kilo Pass usage.
- Kiro — CLI-based usage; monthly credits + bonus credits.
- Vertex AI — Google Cloud gcloud OAuth with token cost tracking from local Claude logs.
- Augment — Augment CLI or browser cookies for credits tracking and usage monitoring.
- Amp — Browser cookie-based authentication with Amp Free usage tracking.
- Ollama — API key access plus browser cookies for Ollama Cloud usage windows.
- Synthetic — API key quota endpoint for rolling five-hour, weekly token, and search-hourly usage.
- JetBrains AI — Local XML-based quota from JetBrains IDE configuration; monthly credits tracking.
- Warp — API token for GraphQL request limits and monthly credits.
- ElevenLabs — API key for character credits and voice slot usage.
- OpenRouter — API token for credit-based usage tracking across multiple AI providers.
- Windsurf — Browser localStorage session import or local SQLite cache for plan usage.
- Zed — Zed editor Keychain session for plan, edit-prediction quota, billing cycle, and overdue invoices.
- Perplexity — Account usage credits from Perplexity usage data.
- Xiaomi MiMo — Browser cookies for balance and token-plan usage.
- Doubao — API key for Volcengine Ark request-limit probes.
- Sakana AI — Manual Cookie header for 5-hour and weekly quota windows.
- Abacus AI — Browser cookie auth for ChatLLM/RouteLLM compute credit tracking.
- Mistral — Browser cookies for API spend, credit balance, and monthly-plan usage.
- DeepSeek — API key for credit balance tracking (paid vs. granted breakdown).
- Fireworks — API key + account slug for 30-day spend from the billing summary API.
- DeepInfra — API key for prepaid balance, current-month spend, and spending-limit tracking.
- Moonshot / Kimi API — API key for Moonshot/Kimi API account balance tracking.
- Venice — API key for DIEM or USD balance tracking.
- Codebuff — API token (or
~/.config/manicode/credentials.json) for credit balance + weekly rate limit. - Crof — API key for dollar credit balance and optional request quota tracking.
- Command Code — Browser or manual cookies for monthly USD credits from Command Code billing.
- Qoder — Browser or manual cookies for Qoder big model credit usage.
- StepFun — Username + password login for Step Plan rate limits (5‑hour + weekly windows) and subscription plan name.
- AWS Bedrock — AWS access keys or a named AWS profile (SSO/assume-role via the AWS CLI) for Cost Explorer spend, monthly budgets, and optional CloudWatch Claude activity.
- Grok — Grok CLI billing RPC plus grok.com browser-session fallback.
- GroqCloud — API key for Enterprise Prometheus request/token/cache-hit metrics.
- LLM Proxy — API key + base URL for aggregate proxy quota stats and provider breakdowns.
- ClawRouter — API key for monthly budget, spend, requests, tokens, and routed-provider usage.
- sub2api — Self-hosted gateway key quota, subscription limits, wallet balance, and per-key usage.
- Wayfinder — Local router gateway polling for health, per-route breakdown, savings, and decision latency.
- LiteLLM — Virtual key + proxy URL for personal and team budget/spend tracking.
- Deepgram — API key usage summaries across speech, agent, token, and TTS metrics.
- Poe — API key for current point balance and recent points history.
- Chutes — API key for subscription usage, rolling and monthly quota windows, and pay-as-you-go quotas.
- Neuralwatt — API key for subscription kWh usage and prepaid credit balance.
- ZenMux — Management API key for rolling five-hour and seven-day quota windows plus PAYG balance.
- xAI — Management API key + team ID for prepaid credit balance and daily platform spend.
- IBM Bob — API key for monthly Bobcoin budget and usage across subscription teams.
- Open to new providers: provider authoring guide.
Icon & Screenshot
The menu bar icon is a tiny usage meter. Bar meaning is provider-specific, and errors/stale data can dim the icon or
show an incident indicator.
Features
- Multi-provider menu bar with per-provider toggles (Settings → Providers).
- Provider-specific usage meters with reset countdowns.
- Optional Codex web dashboard enrichments (code review remaining, usage breakdown, credits history).
- Inline spend and usage charts for API-backed providers such as OpenAI, Claude Admin API, OpenRouter, LiteLLM, z.ai, MiniMax, Mistral, and AWS Bedrock.
- Configurable cost-usage scans for Codex + Claude, plus reused chart UI for supported provider histories. Codex history uses a WAL-enabled SQLite store capped at 25,000 retained session entries and 256 MiB.
- A persistent Settings → Usage & Spend view for local 7/30-day estimates, grouped by native currency and limited to providers that expose cost history.
- Provider status polling with incident badges in the menu and icon overlay.
- Merge Icons mode to combine providers into one status item + switcher.
- Display controls for provider icons, labels, bars, reset-time style, and highest-usage auto-selection.
- Fresh installs default to Adaptive refresh. Existing users keep every valid stored choice, while legacy unset or
invalid preferences resolve to 5 minutes. Manual and fixed 1m, 2m, 5m, 15m, and 30m alternatives remain available. - Bundled CLI (
codexbar) for scripts and CI (includingcodexbar cost --provider codex,claude, orbothfor local cost usage); macOS and Linux CLI builds available. - WidgetKit widgets for supported providers.
- Localized app and website with a shared 21-language catalog, automatic website detection, persistent pickers, and RTL support.
- Optional session quota notifications and weekly-reset confetti.
- Privacy-first: on-device parsing by default; browser cookies are opt-in and reused (no passwords stored).
Privacy note
Wondering if CodexBar scans your disk? It doesn’t crawl your filesystem; it reads a small set of known locations (browser cookies/local storage, provider config files, local JSONL logs) when the related features are enabled. Plain Adaptive refresh never inspects local agent activity. The separate Adaptive (agent-aware) option asks before inspecting the running-process list (including command lines) to identify Codex/Claude and reading bounded known-session metadata. Declining returns to plain Adaptive. When allowed with Agent Sessions hidden, CodexBar retains only the latest activity time and discards session paths and identities. Provider tokens and token-account settings live in the CodexBar config file with restrictive file permissions. See the discussion and audit notes in issue #12.
macOS permissions (why they’re needed)
- Full Disk Access (optional): only required to read Safari cookies/local storage for web-based providers. If you don’t grant it, use another supported browser, manual cookies/API keys, OAuth, or CLI/local sources where that provider supports them.
- Keychain access (prompted by macOS):
Chromium cookie import needs the browser’s Safe Storage item, and an explicitly enabled Claude OAuth repair may
read Claude Code’s own Keychain item. Background CodexBar paths fail or skip instead of requesting authorization;
a user-initiated import or repair can still show the macOS prompt. Settings → Advanced → Disable Keychain
access blocks CodexBar-owned Keychain operations and browser decryption, but cannot constrain provider-owned CLIs
that CodexBar launches. Manual cookie headers, API keys, and file-backed sources remain alternatives where
supported. See Keychain prompts for Allow Once vs. Always Allow, recurring grants, and
safe troubleshooting. - Files & Folders prompts (folder/volume access): CodexBar launches provider CLIs and local probes for some providers. If those helpers read a project directory or external drive, macOS may ask CodexBar for that folder/volume (e.g., Desktop or an external volume). This is driven by the helper’s working directory, not background disk scanning.
- What we do not request in the background: no Screen Recording or Accessibility permissions; user-triggered helper actions may ask macOS for Automation permission to open Terminal. No passwords are stored (browser cookies are reused when you opt in).
Docs
- Providers overview: docs/providers.md
- Provider authoring: docs/provider.md
- Issue labeling guide: docs/ISSUE_LABELING.md
- UI & icon notes: docs/ui.md
- CLI reference: docs/cli.md
- Configuration: docs/configuration.md
- Keychain prompts: docs/keychain-prompts.md
- CLI configuration: docs/cli-configuration.md
- Widgets: docs/widgets.md
- Architecture: docs/architecture.md
- Refresh loop: docs/refresh-loop.md
- Status polling: docs/status.md
- Sparkle updates: docs/sparkle.md
- Packaging: docs/packaging.md
- Development: docs/DEVELOPMENT.md
- Release checklist: docs/RELEASING.md
- Changelog: CHANGELOG.md
Getting started (dev)
- Clone the repo and open it in Xcode or run the scripts directly.
- Launch once, then toggle providers in Settings → Providers.
- Install/sign in to provider sources you rely on (CLIs, browser cookies, OAuth/device flow, API keys, or local app/config files).
- Optional: set OpenAI cookies (Automatic or Manual) for Codex dashboard extras.
Build from source
Requires macOS 14+ and Swift 6.2+.
./Scripts/package_app.sh # builds CodexBar.app in-place with ad-hoc signing
open CodexBar.appDev loop:
./Scripts/compile_and_run.sh
./Scripts/compile_and_run.sh --test # also run the sharded test suite before packaging/relaunching
make check # SwiftFormat + SwiftLint
make docs-list # list docs with frontmatter summariesCLI install:
# after installing CodexBar.app in /Applications
./bin/install-codexbar-cli.shRelated
- ✂️ Trimmy — “Paste once, run once.” Flatten multi-line shell snippets so they paste and run.
- 🧳 MCPorter — TypeScript toolkit + CLI for Model Context Protocol servers.
- 🧿 oracle — Ask the oracle when you're stuck. Invoke GPT-5 Pro with a custom context and files.
Looking for a Windows version?
Linux desktop integration?
- codexbar-waybar — Waybar custom module + GTK4 popover for Hyprland / Sway / other Wayland compositors, built on top of the bundled Linux CLI.
- codexbar-cosmic-applet — Native COSMIC (System76) desktop panel applet with a tab per provider, pace projections, and cost/token stats, built on top of the bundled Linux CLI.
- Codexbar GNOME — GNOME Shell extension that brings CodexBar usage into the desktop panel.
- codexbar-cinnamon-applet — Linux Mint Cinnamon panel applet powered by CodexBar's JSON output.
- noctalia-codex-usage — Noctalia/Quickshell plugin that shows Codex 5-hour and weekly usage limits, built on top of the bundled Linux CLI.
- KodexBar — KDE Plasma widget that shows CodexBar usage in the Plasma panel, built on top of the bundled Linux CLI.
- codexbar-plasmoid — KDE Plasma 6 widget for CodexBar's meter icon, provider switcher, quota windows, pace, credits, local cost, and status, powered by the bundled Linux CLI.
- CodexBar Plasma — KDE Plasma 6 widget with multi-provider views, account selection, cost history, notifications, configurable providers, and installable
.plasmoidreleases, powered by the bundled Linux CLI. - CodexBar Meter — Noctalia v5 bar widget and panel showing every enabled provider's quota windows, credits, and pace, installable from Noctalia's plugin store, built on the bundled Linux CLI.
Status bar & terminal integration
- showy-quota — always-on AI plan quota strips for SketchyBar, tmux, and Zellij (standalone WASM plugin), built on
codexbar serve/ the bundled CLI. - AI Usage Limits — Elgato Stream Deck integration for macOS: shows a selected CodexBar provider, account, and configurable quota or payload metrics on keys and Stream Deck+ dials, using local
codexbar serve.
Credits
Inspired by ccusage (MIT), specifically the cost usage tracking.
License
MIT • Peter Steinberger (steipete)
File: docs/refactor/cli.md
summary: "CLI refactor plan: JSON-only errors, config validation, SettingsStore split."
read_when:
- "Refactoring CodexBar CLI error handling or config parsing."
- "Splitting SettingsStore into smaller files."
- "Adding config validation or CLI config commands."
CLI Refactor Plan
Goals
- JSON-only: every error is valid JSON on stdout (no mixed stderr).
- Per-provider errors: provider failures yield provider-scoped error payloads.
- Config validation: warn on invalid fields, unsupported source modes, bad regions.
- Config parity: add CLI command to validate (and optionally dump) config.
- SettingsStore split: files <500 LOC; clear separation (defaults vs config).
Constraints (keep)
- Provider ordering stays driven by config
providers[]order. - Provider enable/disable stays in config (
enabled). - No Keychain persistence for provider secrets.
- CLI still supports text output for non-JSON use.
Error JSON shape
- JSON output remains an array for
usageandcostcommands. - Errors appear as payload entries with
errorset. - Global/CLI errors use
provider: "cli"andsource: "cli".
{
"provider": "cli",
"source": "cli",
"error": { "code": 1, "message": "...", "kind": "config" }
}Config validation rules
sourcemust be in provider descriptorfetchPlan.sourceModes.apiKeyonly valid when provider supports.api.cookieSourceonly valid when provider supports.web/.auto.regiononly forzaiorminimaxwith known values.workspaceIDonly foropencode.tokenAccountsonly for providers inTokenAccountSupportCatalog.
CLI commands
codexbar config validate- Prints JSON issues (or text summary).
- Exit non-zero if any errors.
- (Optional)
codexbar config dump- Prints normalized config JSON.
Step-by-step implementation guide
- Add validation types
CodexBarConfigIssue+CodexBarConfigValidatorinCodexBarCore/Config.- Keep file <500 LOC.
- Hook validation into CLI
- New
config validatecommand. --json-onlyemits JSON array of issues.
- New
- Unify CLI error reporting
- Parse
--json-onlyearly. - Route all exits through a JSON-aware reporter.
- Use provider-scoped errors where possible.
- Parse
- Split CLIEntry.swift
- Extract helpers + payload structs into dedicated files (<500 LOC each).
- Split SettingsStore.swift
- Move config-backed computed properties to
SettingsStore+Config.swift. - Move defaults-backed computed properties to
SettingsStore+Defaults.swift. - Move provider detection to
SettingsStore+ProviderDetection.swift.
- Move config-backed computed properties to
- Provider toggles cleanup
- Remove unused
ProviderToggleStore+ tests; keep migrator path for legacy toggles.
- Remove unused
- Tests
- CLI json-only error payloads (invalid source, invalid provider selection).
- Config validation (bad region/source/apiKey field).
- SettingsStore order/toggle invariants still pass.
- Verification
make test,swiftformat Sources Tests,swiftlint --strict,make check../Scripts/compile_and_run.sh.- CLI e2e:
codexbar --json-only ...,codexbar config validate.
File: docs/amp.md
summary: "Amp provider notes: CLI usage, web fallback, cookie auth, and credits."
read_when:
- Adding or modifying the Amp provider
- Debugging Amp cookie import or settings parsing
- Adjusting Amp menu labels or usage math
Amp Provider
The Amp provider tracks Amp Free usage, monthly subscription pools, and individual and workspace credits. It prefers the
local Amp CLI, then an Amp access token, and finally browser cookies.
Features
- Amp Free meter: Shows how much daily free usage remains.
- Daily reset: Percentage-based Amp Free usage resets at 8:00 PM America/New_York time.
- Monthly subscriptions: Shows the independently metered “Other usage” and “Orb usage” pools for Megawatt and
Gigawatt plans. - Time-to-full reset: Legacy dollar-based Amp Free output estimates when hourly replenishment reaches full.
- Individual credits: Shows the remaining paid credit balance when Amp reports one.
- Workspace credits: Shows each workspace's remaining paid credit balance separately.
- CLI-first fetch: Uses
amp usagewhen the Amp CLI is installed and signed in. - Access token support: Uses
AMP_API_KEYor the access token saved in CodexBar settings. - Browser cookie fallback: Reads the legacy settings-page payload when the CLI and access token are unavailable.
Setup
- Open Settings → Providers
- Enable Amp
- Install and sign in to the Amp CLI, add an Amp access token, or leave Cookie source on Auto for web fallback
Access token (optional)
Create an access token in Amp settings, then paste it into Amp → Access token or set AMP_API_KEY.
Manual cookie import (optional)
- Open
https://ampcode.com/settings - Copy a
Cookie:header from your browser’s Network tab - Paste it into Amp → Cookie Source → Manual
How it works
- Runs
amp usagefirst in automatic mode - Calls
POST https://ampcode.com/api/internal?userDisplayBalanceInfowith an Amp access token - Falls back to the settings page with browser cookies
- Parses the same usage display format returned to the CLI
- Uses Amp's calendar-month renewal period for subscriptions and its 8:00 PM New York reset for daily free usage
- Computes time-to-full from the hourly replenishment rate for legacy dollar-based Amp Free output
“Amp access token is invalid or expired”
Create a new access token in Amp settings, update AMP_API_KEY or CodexBar settings, then refresh.
Troubleshooting
“No Amp session cookie found”
Log in to Amp in a supported browser (Safari or Chromium-based), then refresh in CodexBar.
“Amp session cookie expired”
Sign out and back in at https://ampcode.com/settings, then refresh.
File: docs/antigravity.md
summary: "Antigravity provider notes: OAuth usage, multi-account switching, local LSP probing, and quota parsing."
read_when:
- Adding or modifying the Antigravity provider
- Debugging Antigravity port detection or quota parsing
- Adjusting Antigravity menu labels or model mapping
- Working with Antigravity OAuth or account switching
Antigravity provider
For Google individual, AI Pro, and Ultra accounts blocked by the June 2026 Gemini CLI OAuth
shutdown, Antigravity is the replacement path for Gemini quota tracking in CodexBar. Launch
the Antigravity app or run agy, sign in, then refresh. See docs/gemini.md for the Gemini
provider migration notes. CodexBar offers the handoff only after an observed Google migration
signal and never enables or falls back to Antigravity automatically.
To use the agy CLI source without keeping the desktop app open, install the CLI first
(brew install --cask antigravity-cli; use ANTIGRAVITY_CLI_PATH when it is not on PATH), then
run agy once and sign in. CodexBar keeps the signed-in agy local HTTPS server alive briefly
after each refresh and stops it when idle.
Antigravity supports four usage data sources:
- The Antigravity 2.0 app's local
language_server(preferred when the app is open). - The
agyCLI's embedded HTTPS localhost server (preferred over the IDE because it exposes richer quota data). - The Antigravity IDE extension
language_server(used afteragyCLI because current IDE local payloads only expose session/model quota data). - Google OAuth-backed remote usage (explicit OAuth mode, and the account-scoped fallback used for multi-account switching). The OAuth path can store multiple Google accounts through the shared token-account switcher.
When the Antigravity app is closed
The app-local language_server exists only while Antigravity.app is running. With the app closed,
CodexBar relies on the agy CLI HTTPS source or the Google OAuth fallback. Without a signed-inagy, the OAuth fallback can only prove model availability, so the menu shows an all-100%
placeholder instead of real quota numbers. A freshly spawned agy needs a few seconds for macOS
keyring authentication before its quota endpoints answer, so the first refresh after a cold start
can take a few extra seconds while CodexBar waits for readiness; later refreshes reuse the warmed session.
The local and CLI paths both prefer Antigravity's internal RetrieveUserQuotaSummary quota payload and may fall back toGetUserStatus, then GetCommandModelConfigs; CodexBar never scrapes the desktop UI or the agy TUI.
As of Antigravity 2.x, the Antigravity app and agy CLI payloads can be richer than Google OAuth and IDE payloads.RetrieveUserQuotaSummary exposes the same two groups shown by Antigravity's Model Quota UI:
Gemini Models: weekly limit and five-hour limit.Claude and GPT models: weekly limit and five-hour limit.
Older local payloads may only include raw Claude, GPT-OSS, Gemini tiers, account plan, and session reset timestamps.
Current Antigravity IDE local endpoints return GetUserStatus, GetAvailableModels, and GetCascadeModelConfigData
with five-hour/session reset data, but not the app/CLI RetrieveUserQuotaSummary weekly/session grouping. OAuth
payloads can be less complete and may only prove model availability. Treat auto as the authoritative user-facing mode:
it accepts the first account-matching source in Antigravity app -> agy CLI -> Antigravity IDE order, and adds OAuth
when CodexBar has a selected/injected Google account or an existing shared credentials file. An all-100%fetchAvailableModels payload is only accepted after retrieveUserQuota echoes bucket fractions; this can be an
availability-style fallback rather than the full Antigravity quota summary.
When OAuth identifies the account but quota endpoints deny access, CodexBar shows Limits not available instead of an
empty quota card.
OAuth account switching
- Login still uses Antigravity's Google OAuth client, discovered from
Antigravity.appor overridden withANTIGRAVITY_OAUTH_CLIENT_IDandANTIGRAVITY_OAUTH_CLIENT_SECRET. - A successful login writes the latest shared credentials to
~/.codexbar/antigravity/oauth_creds.jsonand upserts a token-account entry for the Google account. - Each token-account entry stores serialized
AntigravityOAuthCredentialsand is injected into remote fetches throughANTIGRAVITY_OAUTH_CREDENTIALS_JSON. - When a token account is selected, the OAuth fetcher uses that account before falling back to the shared credentials file.
Inautomode the ambient Antigravity app,agyCLI, and IDE probes still run first, but a snapshot whose account
does not match the selected account is rejected so the pipeline falls through to the account-scoped OAuth fetch (seeAntigravitySelectedAccountGuard). If no account is selected/injected,autoincludes OAuth only when the legacy
shared credentials file already exists. Explicitcli/oauthsource modes stay authoritative and are not re-checked. - Removing the last saved token account that matches
~/.codexbar/antigravity/oauth_creds.jsondeletes that shared file,
so a removed CodexBar account does not silently continue refreshing through the legacy shared cache. - The menu action is labeled
Add Account...; switching between saved accounts scopes Google OAuth fetches.
Remote OAuth data sources
POST https://cloudcode-pa.googleapis.com/v1internal:loadCodeAssistPOST https://cloudcode-pa.googleapis.com/v1internal:onboardUserPOST https://cloudcode-pa.googleapis.com/v1internal:fetchAvailableModelsPOST https://cloudcode-pa.googleapis.com/v1internal:retrieveUserQuotaPOST https://cloudcode-pa.googleapis.com/v1internal:retrieveUserQuotaSummary(available, but current observed OAuth
responses are model-bucket shaped rather than Antigravity 2.0's two quota groups)
Data sources + fallback order
1) Antigravity app local probe
When the Antigravity 2.0 app is running:
Process detection
- Command:
ps -ax -o pid=,command=. - The app local strategy scopes detection to the Antigravity app language server only
(AntigravityStatusProbe(processScope: .appOnly)). It deliberately does not
attach to an IDE oragyCLI process: a lower-information IDE payload should not maskagy's richer quota summary, and a stale or still-initializingagycan accept the
connection before it is ready.agyis owned exclusively by the CLI HTTPS source below,
which waits for real API readiness. The probe still classifies all kinds
(processInfo(scope: .ideAndCLI)is used byisRunning()for status reporting):- the Antigravity app language server: process names such as
language_server,language_server_macos,language_server_macos_arm, orlanguage-serverplus
Antigravity markers (--app_data_dir antigravity, an Antigravity app bundle path,
or a path containing/antigravity/); or - the IDE language server: the Antigravity IDE extension language server, usually under
Antigravity IDE.app/.../extensions/antigravity/bin/with--app_data_dir antigravity-ide; or - the CLI: an
antigravity-cli/antigravity_clipath segment, or theagybinary (path-anchored so unrelated arguments/binaries do not match).
- the Antigravity app language server: process names such as
- CodexBar collects all valid local app language-server candidates and probes each reachable one. If multiple
app processes are open, it prefers the richer quota-summary snapshot over the legacyGetUserStatus
two-pool fallback. - Extract CLI flags:
--csrf_token <token>. Requirement depends on the match kind:- App/IDE matches still require it - a tokenless desktop language-server match is
skipped so a later valid server can be found, otherwisemissingCSRFToken
is reported (unchanged behavior). - CLI matches accept an empty token, because the CLI's language server
exposes no--csrf_tokenflag and requires none.
- App/IDE matches still require it - a tokenless desktop language-server match is
--extension_server_port(HTTP fallback; app/IDE only).--extension_server_csrf_token <token>(preferred HTTP fallback token when present).
- Command:
Port discovery
- Command:
lsof -nP -iTCP -sTCP:LISTEN -a -p. - All listening ports are probed.
- Command:
Connect port probe (HTTPS)
POST https://127.0.0.1:/exa.language_server_pb.LanguageServerService/GetUnleashData- Headers:
X-Codeium-Csrf-Token: <token>Connect-Protocol-Version: 1
- First 200 OK response selects the connect port.
Quota fetch
- Primary:
POST https://127.0.0.1:<connectPort>/exa.language_server_pb.LanguageServerService/RetrieveUserQuotaSummary
- Fallback 1:
POST https://127.0.0.1:<connectPort>/exa.language_server_pb.LanguageServerService/GetUserStatus
- Fallback 2:
POST https://127.0.0.1:<connectPort>/exa.language_server_pb.LanguageServerService/GetCommandModelConfigs
- If HTTPS fails, retry over HTTP on
extension_server_port.
- Primary:
2) `agy` CLI HTTPS source
When source mode is auto or cli and the desktop local probe fails, CodexBar resolves agy via:
ANTIGRAVITY_CLI_PATHPATH/ login-shell path lookup- Well-known paths:
~/.local/bin/agy/opt/homebrew/bin/agy/usr/local/bin/agy
CodexBar launches agy in a PTY because the CLI exposes its quota server only while the interactive process is alive.
The implementation still does not scrape terminal output; it only keeps the process alive, drains discarded PTY
rendering, discovers listening ports with lsof, and probes the local HTTPS server:
- First:
POST https://127.0.0.1:/exa.language_server_pb.LanguageServerService/RetrieveUserQuotaSummary - Fallback 1:
POST https://127.0.0.1:/exa.language_server_pb.LanguageServerService/GetUserStatus - Fallback 2:
POST https://127.0.0.1:/exa.language_server_pb.LanguageServerService/GetCommandModelConfigs
The fallback can return quota without the account email or plan fields from GetUserStatus.
Differences from the desktop local probe:
- The CLI HTTPS endpoint does not require
X-Codeium-Csrf-Token. - Before a one-shot CLI invocation launches
agy, CodexBar spends at most two seconds looking for an already-running,
same-useragyat the selected binary path and reuses its tokenless local HTTPS endpoint when it returns parseable
usage for the selected account. Long-lived app/server refreshes keep using CodexBar's managed session, and
CodexBar-owned pids are excluded from external reuse so probe/idle lifecycle accounting stays balanced. - Readiness is endpoint-based: CodexBar retries until one of the quota endpoints parses, because fresh
agy
processes can bind a port before the quota service is initialized. - App runtime uses a bounded warm session:
agyis kept alive briefly after a refresh, then stopped on idle. CLI runtime
tears it down immediately after the one-shot fetch. - Repeated endpoint failures force a relaunch instead of reusing a wedged process forever.
- CodexBar records the launched pid + executable identity and conservatively reaps only its own matching stale
agy
process on the next launch. It never blind-kills a user-launchedagy.
3) Antigravity IDE local probe
When the Antigravity 2.0 app and agy CLI are unavailable, CodexBar probes Antigravity IDE language servers withAntigravityStatusProbe(processScope: .ideOnly). Current observed IDE payloads return model-level/session quota data
through GetUserStatus, GetAvailableModels, and GetCascadeModelConfigData; RetrieveUserQuotaSummary returns 404
from the IDE local server. This means the IDE fallback can show session bars, but should not be expected to provide the
weekly limit shown by Antigravity 2.0.
4) OAuth remote fallback
When source mode is auto, OAuth is used after app, agy CLI, and IDE paths fail if CodexBar has a selected/injected
Google account or an existing shared credentials file. The app, agy CLI, and IDE probes still run first, but inauto mode their snapshots are accepted only when the reported account matches the selected account; otherwise the
pipeline falls through to this account-scoped OAuth fetch. When source mode is oauth, only OAuth is used and the
shared OAuth file can still be used as a fallback credential source.
Request body (summary)
- Minimal metadata payload:
ideName: antigravityextensionName: antigravitylocale: enideVersion: unknown
Parsing and model mapping
- Preferred source fields:
response.groups[].displayNameresponse.groups[].buckets[].bucketIdresponse.groups[].buckets[].displayNameresponse.groups[].buckets[].remaining.remainingFractionresponse.groups[].buckets[].description
- Legacy source fields:
userStatus.cascadeModelConfigData.clientModelConfigs[].quotaInfo.remainingFractionuserStatus.cascadeModelConfigData.clientModelConfigs[].quotaInfo.resetTime
- Preferred quota summary UI:
- Render
Gemini Session,Gemini Weekly,Claude + GPT Session, andClaude + GPT Weeklyas named windows. - Keep Antigravity's bucket description as reset prose; infer
windowMinutesfrom the bucket ID/display name. - Use the most constrained known bucket as the compact/menu-bar metric.
- Render
- Legacy user-facing quota groups:
Geminigroups Gemini Pro and Gemini Flash text models.Claude + GPTgroups Claude text models and GPT/GPT-OSS text models.
- Representative selection:
- Hidden model rows such as Lite, autocomplete, and image variants do not drive summary bars.
- For each group, CodexBar uses the lowest remaining known quota row and preserves that row's reset metadata.
- Rows with reset metadata but no remaining fraction stay visible as unavailable reset context only when their group
has no known usage row.
resetTimeparsing:- ISO-8601 preferred; numeric epoch seconds as fallback.
- Identity:
accountEmailandplanNameonly fromGetUserStatus.
UI mapping
- Provider metadata:
- Display:
Antigravity - Labels:
Gemini(primary),Claude + GPT(secondary)
- Display:
- Status badge: Google Workspace incidents for the Gemini product.
- Antigravity exposes many model rows, but current local payloads show them collapsing into two real usage pools:
Gemini and Claude/GPT. Detailed usage should not list every raw Gemini tier unless a future source exposes a genuinely
distinct unknown or consumed quota window. - Some Antigravity local/CLI model config entries include reset metadata but omit
remainingFraction. Those windows stay
inextraRateWindowsfor reset context and are marked withusageKnown: false; clients should not render theirusedPercentas a real exhausted quota. - Antigravity reports every model family the plan covers, so an account that only uses Gemini still receives a
Claude/GPT pair pinned at 0%. Menu cards and widgets hide a family once every lane in it reports known zero usage.
A family with unknown usage stays visible, and every family remains visible when all are untouched, for example
right after a weekly reset. Provider details is the diagnostic surface and always lists every family, the same
principle it already applies to cost data. The filter is display-only: the snapshot, CLI output, and menu-bar
ranking still see every window, and menu-bar selection ranks by highest used, so an untouched family never wins. - The dashboard-v1 payload keeps every family for its script clients and marks the lanes of an untouched family with
idleinstead. Thecodexbar serveweb UI skips those rows, so the web card matches the menu without repeating
the family rule in JavaScript. Seedocs/dashboard-api.md.
Constraints
- Internal protocol; fields may change.
- Requires
lsoffor local/CLI port detection. - Local HTTPS uses a self-signed cert; the probe allows insecure TLS only for loopback hosts.
Key files
Sources/CodexBarCore/Providers/Antigravity/AntigravityCLISession.swiftSources/CodexBarCore/Providers/Antigravity/AntigravityProviderDescriptor.swiftSources/CodexBarCore/Providers/Antigravity/AntigravityStatusProbe.swiftSources/CodexBar/Providers/Antigravity/AntigravityProviderImplementation.swift
File: docs/architecture.md
summary: "Architecture overview: modules, entry points, and data flow."
read_when:
- Reviewing architecture before feature work
- Refactoring app structure, app lifecycle, or module boundaries
Architecture overview
Modules
Sources/CodexBarCore: fetch + parse (Codex RPC, PTY runner, Claude probes, OpenAI web scraping, status polling).Sources/CodexBar: state + UI (UsageStore, SettingsStore, StatusItemController, menus, icon rendering).Sources/CodexBarWidget: WidgetKit extension wired to the shared snapshot.Sources/CodexBarCLI: bundled CLI forcodexbarusage/status output.Sources/CodexBarClaudeWatchdog: helper process for stable Claude CLI PTY sessions.Sources/CodexBarClaudeWebProbe: CLI helper to diagnose Claude web fetches.
Entry points
CodexBarApp: SwiftUI keepalive + Settings scene.AppDelegate: wires status controller, Sparkle updater, notifications.
Data flow
- Background refresh →
UsageFetcher/provider probes →UsageStore→ menu/icon/widgets. - Settings toggles feed
SettingsStore→UsageStorerefresh cadence + feature flags. - Runtime-only provider settings flow through typed, descriptor-registered sections in
ProviderSettingsSnapshot.
Concurrency & platform
- Swift 6 strict concurrency enabled; prefer Sendable state and explicit MainActor hops.
- macOS 14+ targeting; avoid deprecated APIs when refactoring.
See also: docs/providers.md, docs/refresh-loop.md, docs/ui.md.
File: docs/augment.md
summary: "Augment provider notes: cookie auth, keepalive, and credits parsing."
read_when:
- Debugging Augment cookie import or keepalive
- Updating Augment usage or credits parsing
- Adjusting Augment menu labels or settings
Augment Provider
The Augment provider tracks your Augment Code usage and credits through browser cookie-based authentication.
Features
- Credits Tracking: Monitor your remaining credits and monthly limits
- Usage Monitoring: Track credits consumed in the current billing cycle
- Plan Information: Display your current subscription plan
- CLI Integration: Uses
auggie account statuswhen the Auggie CLI is installed (falls back to web) - Automatic Session Keepalive: Prevents cookie expiration with proactive refresh
- Multi-Browser Support: Chrome, Chrome Beta, Chrome Canary, Arc, Safari
Setup
1. Enable the Provider
- Open Settings → Providers
- Enable Augment
- The app will automatically import cookies from your browser
2. Cookie Source Options
Automatic (Recommended)
- Automatically imports cookies from your browser
- Supports Chrome, Chrome Beta, Chrome Canary, Arc, and Safari
- Browser priority: Chrome Beta → Chrome → Chrome Canary → Arc → Safari
Manual
- Paste a cookie header from your browser's developer tools
- Useful for troubleshooting or custom browser configurations
Off
- Disables Augment provider entirely
3. Verify Connection
- Check the menu bar for the Augment icon
- Click the icon to see your current usage
- If you see "Log in to Augment", visit app.augmentcode.com and sign in
How It Works
Cookie Import
The provider searches for Augment session cookies in this order:
- Chrome Beta (if installed)
- Chrome (if installed)
- Chrome Canary (if installed)
- Arc (if installed)
- Safari (if installed)
Recognized cookie names:
_session(legacy)auth0,auth0.is.authenticated,a0.spajs.txs(Auth0)__Secure-next-auth.session-token,next-auth.session-token(NextAuth)__Host-authjs.csrf-token,authjs.session-token(AuthJS)session,web_rpc_proxy_session(Augment-specific)
Cached cookies:
- Keychain cache
com.steipete.codexbar.cache(accountcookie.augment, source + timestamp). Reused before re-importing
from browsers.
Auggie CLI Integration
If the auggie CLI is installed, CodexBar will prefer auggie account status for usage data and avoid browser prompts.
When the CLI is unavailable or not authenticated, CodexBar falls back to browser cookies.
Automatic Session Keepalive
The provider includes an automatic session keepalive system:
- Check Interval: Every 1 minute
- Refresh Buffer: Refreshes 5 minutes before cookie expiration
- Rate Limiting: Minimum 1 minute between refresh attempts
- Session Cookies: Refreshed every 30 minutes (no expiration date)
This ensures your session stays active without manual intervention.
API Endpoints
The provider fetches data from:
- Credits:
https://app.augmentcode.com/api/credits - Subscription:
https://app.augmentcode.com/api/subscription
Troubleshooting
"No session cookie found"
Cause: You're not logged into Augment in any supported browser.
Solution:
- Open app.augmentcode.com in Chrome, Chrome Beta, or Arc
- Sign in to your Augment account
- Return to CodexBar and click "Refresh" in the menu
"Session has expired"
Cause: Your browser session expired and automatic refresh failed.
Solution:
- Visit app.augmentcode.com
- Log out and log back in
- Return to CodexBar - it will automatically import fresh cookies
- If needed, use the menu action Refresh Session to force a re-import
Cookies not importing from Chrome Beta
Cause: Chrome Beta might not be in the browser search order.
Solution: This fork includes Chrome Beta support by default. If issues persist:
- Check that Chrome Beta is installed at
/Applications/Google Chrome Beta.app - Verify you're logged into Augment in Chrome Beta
- Try switching to regular Chrome temporarily
Manual Cookie Import
If automatic import fails, you can manually paste cookies:
- Open Chrome DevTools (⌘⌥I)
- Go to Application → Cookies → https://app.augmentcode.com
- Copy all cookie values
- Format as:
cookie1=value1; cookie2=value2; ... - In CodexBar: Settings → Providers → Augment → Cookie Source → Manual
- Paste the cookie header
Debug Mode
To see detailed cookie import logs:
- Open Settings → Debug
- Find Augment in the provider list
- Click Show Debug Info
This displays:
- Cookie import attempts and results
- API request/response details
- Session keepalive activity
- Error messages with timestamps
Privacy & Security
- Cookies are stored securely in macOS Keychain
- Only cookies for
*.augmentcode.comdomains are imported - Cookies are filtered by domain before sending to API endpoints
- No cookies are sent to third-party services
- Session keepalive only runs when Augment is enabled
Technical Details
Cookie Domain Filtering
The provider implements RFC 6265 cookie semantics:
- ✅ Exact match:
app.augmentcode.com→app.augmentcode.com - ✅ Parent domain:
augmentcode.com→app.augmentcode.com - ✅ Wildcard:
.augmentcode.com→app.augmentcode.com - ❌ Different subdomain:
auth.augmentcode.com❌→app.augmentcode.com
This prevents cookies from other subdomains being sent to the API.
Session Refresh Mechanism
- Keepalive checks cookie expiration every 1 minute
- If expiration is within 5 minutes, triggers refresh
- Pings
/api/auth/sessionto trigger cookie update - Waits 1 second for browser to update cookies
- Re-imports fresh cookies from browser
- Logs success/failure for debugging
Related Documentation
- Provider Authoring Guide - How to create new providers
- Development Guide - Build and test instructions
File: docs/claude.md
summary: "Claude provider data sources: OAuth API, web API (cookies), CLI PTY, and local cost usage."
read_when:
- Debugging Claude usage/status parsing
- Updating Claude OAuth/web endpoints or cookie import
- Adjusting Claude CLI PTY automation
- Reviewing local cost usage scanning
Claude provider
Claude supports three usage data paths plus local cost usage. The main provider pipeline uses runtime-specific
automatic selection, but the codebase still has multiple active Claude .auto decision sites while the refactor is
pending. For the exact current-state parity contract, see
docs/refactor/claude-current-baseline.md.
When an Anthropic Admin API key is configured, Claude can also show organization-level spend/messages/tokens in the
same inline dashboard pattern used by the OpenAI API provider.
Data sources + selection order
Default selection (debug menu disabled)
- If an Admin API key is configured, the Admin API strategy is used for Claude API spend/usage.
- App runtime main pipeline: OAuth API → CLI PTY → Web API.
- CLI runtime main pipeline: Web API → CLI PTY.
- Explicit picker modes (OAuth/Web/CLI) bypass automatic fallback.
- A lower-level direct Claude fetcher still contains a separate
.autoorder. That inconsistency is tracked in
docs/refactor/claude-current-baseline.md.
Usage source picker:
- Preferences → Providers → Claude → Usage source (Auto/OAuth/Web/CLI).
Admin API key setup:
- Preferences → Providers → Claude → Admin API key, stored in
~/.codexbar/config.json. - CLI/env:
printf '%s' "$ANTHROPIC_ADMIN_KEY" | codexbar config set-api-key --provider claude --stdin. - Token accounts can also hold
sk-ant-admin...keys; they route to the Admin API instead of cookie/OAuth usage. - Environment fallback:
ANTHROPIC_ADMIN_KEY.
Admin API
- Key prefix:
sk-ant-admin.... - Endpoints:
/v1/organizations/cost_report/v1/organizations/usage_report/messages
- Output:
- Today/7d/30d spend and message/token summaries.
- Inline 30-day dashboard chart when daily buckets are present.
- Identity login method:
Admin API.
Keychain prompt policy (Claude OAuth)
- Preferences → Providers → Claude → Keychain prompt policy.
- Options:
Never prompt: never attempts interactive Claude OAuth Keychain prompts.Only on user action(default): interactive prompts are reserved for user-initiated repair flows.Always allow prompts: allows interactive prompts in both user and background flows.
- This setting only affects Claude OAuth Keychain prompting behavior; it does not switch your Claude usage source.
- If Preferences → Advanced → Disable Keychain access is enabled, this policy remains visible but inactive until
Keychain access is re-enabled.
Debug selection (debug menu enabled)
- The Debug pane can force OAuth / Web / CLI.
- Web extras are internal-only (not exposed in the Providers pane).
OAuth API (preferred)
- Credentials:
- CodexBar OAuth cache when available.
- File fallback:
~/.claude/.credentials.json. - Claude CLI Keychain bootstrap/repair fallback:
Claude Code-credentials.
- On Claude Code 2.1.x,
Claude Code-credentialsmay contain only MCP server OAuth state (mcpOAuth) with noclaudeAiOauth. CodexBar treats that as an OAuth configuration error, does not run background delegatedclaude /statusrefresh, and surfaces re-auth guidance. Use Web or CLI usage source, or restore a valid Claude OAuth keychain entry. See #1844. - Requires
user:profilescope (CLI tokens with onlyuser:inferencecannot call usage). - Endpoints:
GET https://api.anthropic.com/api/oauth/usageGET https://api.anthropic.com/api/oauth/profile→ account identity used to verify that optional Web enrichment
belongs to the same Claude account.
- Headers:
Authorization: Bearer <access_token>anthropic-beta: oauth-2025-04-20
- Mapping:
five_hour→ session window.seven_day→ weekly window; also becomes the primary fallback whenfive_houris absent or has no utilization.seven_day_sonnet/seven_day_opus→ model-specific weekly window.limits[].weekly_scoped→ model-specific weekly windows; genericAll modelsscopes stay in the main weekly row.seven_day_routines/seven_day_cowork→ Daily Routines extra window.- Claude Design/Omelette keys are ignored because Claude Design shares the main Claude usage limit.
extra_usage→ Extra usage cost (monthly spend/limit).
- Preferences → Providers → Claude → Show Daily Routines usage hides only the Daily Routines row in menus and the
provider preview. The global optional credits and extra usage setting is its master switch. The Claude-specific
setting does not change fetching, history, notifications, widgets, model-scoped weekly limits, hooks, or CLI output. - Preferences → Providers → Claude → Show model-specific weekly usage in widgets controls model-scoped weekly quota
rows in desktop widgets. It is off by default; turning it on displays every known Claude window with aclaude-weekly-scoped-identifier (for example, Fable). Turning it back off also drops scoped rows that a previous
snapshot persisted. It does not change fetching, the menu, history, notifications, hooks, or CLI output. - Successful OAuth login enables Claude and preserves the selected usage source. With the default Auto source, OAuth
remains preferred when readable, while CLI/Web fallback stays available when OAuth credentials are not usable. - Claude Code periodically rotates its
Claude Code-credentialsKeychain item and can replace the ACL grant that
allowed CodexBar to read it. Auto treats that as a failed OAuth source, reuses a recent successful CLI result or
continues to CLI/Web, and does not misreport the existing credentials as missing. A manual Refresh can re-grant
Keychain access; selecting CLI or Web avoids the foreign-Keychain dependency. - When every live Auto source fails, CodexBar keeps the last captured session/weekly percentages from
history/claude.jsonvisible as stale data and shows their capture age instead of blanking the quota bars. - Plan inference:
subscriptionTypeis preferred when present;rate_limit_tierfalls back to
Max/Pro/Team/Enterprise. When a Maxrate_limit_tiercarries a usage multiplier
(default_claude_max_5x/default_claude_max_20x), it is surfaced in the label as "Max 5x" / "Max 20x".
Web API (cookies)
- Preferences → Providers → Claude → Cookie source (Automatic or Manual).
- Manual mode accepts a
Cookie:header from a claude.ai request. - Multi-account manual tokens: add entries to
~/.codexbar/config.json(tokenAccounts) and set Claude cookies to
Manual. The menu can show all accounts stacked or a switcher bar (Preferences → Advanced → Display). - Claude token accounts accept either
sessionKeycookies or OAuth access tokens (sk-ant-oat...). OAuth-token
accounts route to the OAuth path and disable cookie mode; session-key or cookie-header accounts stay in manual
cookie mode. The exact edge-routing rules are documented in
docs/refactor/claude-current-baseline.md. - Cookie source order:
- Safari:
~/Library/Cookies/Cookies.binarycookies - Chrome/Chromium forks:
~/Library/Application Support/Google/Chrome/*/Cookies - Firefox:
~/Library/Application Support/Firefox/Profiles/*/cookies.sqlite
- Safari:
- Domain:
claude.ai. - Cookie name required:
sessionKey(value prefixsk-ant-...).
- Cached cookies: Keychain cache
com.steipete.codexbar.cache(accountcookie.claude, source + timestamp).
Reused before re-importing from browsers. - API calls (all include
Cookie: sessionKey=<value>):GET https://claude.ai/api/organizations→ org UUID.GET https://claude.ai/api/organizations/{orgId}/usage→ session/weekly/opus.GET https://claude.ai/api/organizations/{orgId}/overage_spend_limit→ Extra usage spend/limit.GET https://claude.ai/api/organizations/{orgId}/prepaid/credits→ remaining Usage credits balance.GET https://claude.ai/api/account→ email + plan hints.
- Outputs:
- Session + weekly + model-specific percent used.
- Daily Routines extra window when returned by the usage API.
- Extra usage spend/limit (if enabled).
- Remaining Usage credits balance (if enabled).
- Account email + inferred plan.
claude-swap accounts (opt-in)
The accepted multi-account design in
claude-multi-account-and-status-items.md.
- Setup: Preferences → Providers → Claude → "Read accounts from claude-swap", then set the path to the
cswapexecutable (for example~/.local/bin/cswap). - Behavior: on each Claude refresh, CodexBar runs
cswap --list --jsonindependently of the ambient Claude fetch (no
shell, fixed arguments, bounded runtime and output), requiresschemaVersion == 1, and parses only slot number,
active state, usage status, email (display only), display-onlyorganizationName(always present, may be empty),
optional display-onlyaliaswhen non-empty, the 5-hour/7-day windows, and optional display-only model-scoped
weekly windows fromusage.scoped. Identity staysclaude-swap:<slot>; organization name and alias are never
used as identity. When two or more slots share an email, cards append· organizationNameor· Account N;
a user-chosen cswap alias replaces that label. Unique emails stay email-only. - Display: when claude-swap reports more than one account, the Claude menu and
codexbar cardsshow one card per
account (active account first, then numeric slot) instead of ambient/token-account Claude cards. With four or more
accounts the app menu switches to a compact layout (AccountMenuLayoutPlanner): the active account keeps its full
card, inactive accounts become one-line rows sorted by remaining headroom (most constrained first, red/amber below
50%/10% left, a star on the healthiest activatable account), and healthy rows fold behind a "N more accounts ready"
summary row. Clicking a compact row expands that account's full card for the current menu session; the summary row
reveals the hidden rows.codexbar cardskeeps the full per-account output. The same compact layout applies to
every stacked multi-account list (token accounts on any provider, and flat Codex account lists; workspace-grouped
Codex lists keep their sectioned stacked layout). To use this
presentation with one account, enable “Show account card when only one account is available” or setclaudeSwapShowSingleAccount: trueon the Claude provider in the resolved config file (normally~/.config/codexbar/config.json; legacy installs may use~/.codexbar/config.json). The option defaults off,
zero accounts still use the ambient presentation, and account identity isclaude-swap:<slot>, never the display
email. - Terminal scope: this automatic precedence is cards-only and works on every supported CLI platform. An explicit
Claude provider or--source autoremains eligible, while--account,--account-index,--all-accounts, and
explicit non-auto source flags bypass the adapter.codexbar usageand serve/usage//costremain unchanged,
whilecodexbar dashboardandGET /dashboard/v1/snapshotadditionally nest one entry per swap account in the
Claude provider row, with full identity by default or redacted email local parts when--identity redactedis set. - Isolation: CodexBar never reads claude-swap or Claude Code credential storage for this feature; the
subprocess handles its own credential access. In the app, adapter failures keep the last successful accounts as
stale data, surface the error in provider settings, and never affect the ambient Claude usage card. In terminal
cards, a list failure retains the current ambient output, adds a distinctClaude (claude-swap)footer entry, and
exits non-zero. - Sentinel statuses (
token_expired,api_key,keychain_unavailable,no_credentials,
and unknown future values) render as per-account notes instead of usage bars in both full and brief cards. Whenunavailablemeans claude-swap deferred polling because a window is at 100%, CodexBar keeps that slot's last
projected usage bars and names the exhausted window (5-hour session, 7-day weekly, and/or a scoped model such as
Fable) plus its reset time — not "Usage fetch failed." A first refresh that is alreadyunavailablewith no
retained windows still notes that polling is deferred. Active rows are marked[active]; no claude-swap row infers
a plan badge. - Switching: an inactive account with usable source credentials shows “Switch Account…”. Clicking it runs exactly
cswap --switch-to <slot> --json, validates the versioned result and requested slot, then refreshes both ambient
Claude usage and every claude-swap account card. Switches are serialized; no automatic switching occurs. While
claude-swap owns account presentation, the separate ambient OAuth action reads “Sign in with Claude Code…” and does
not add or switch a claude-swap account. - Expired, missing, unknown, or Keychain-inaccessible credentials stay non-actionable. A failed switch remains visible
on that account without discarding its last successful usage. A running Claude Code process can take up to the
claude-swap Keychain cache interval to observe the new account. - Multiple claude-swap accounts—and a single account when explicitly enabled—take precedence over Claude
token-account presentation (stacked cards and the segmented switcher).
Packaged synthetic proof (fake cswap executable, no real accounts or credentials):
Model-scoped weekly-window proof (synthetic data, no real accounts or credentials):
| Before | After |
|---|---|
CLI PTY (fallback)
- Runs
claudein a PTY session (ClaudeCLISession). - Default behavior: exit after each probe; Debug → "Keep CLI sessions alive" keeps it running between probes.
- Probe working directory:
~/Library/Application Support/CodexBar/ClaudeProbewith local Claude settings that disable
deep-link URL handler registration during headless probes. - After transient probes exit, CodexBar removes Claude Code
.jsonlsession artifacts for that dedicatedClaudeProbeproject directory so background/usagepolling does not clutter the user's Claude project history. - Command flow:
- Start CLI with
--allowed-tools ""(no tools). - Auto-respond to first-run prompts (trust files, workspace, telemetry).
- Send
/usage, wait for rendered panel; send Enter retries if needed. - Optionally send
/statusto extract identity fields.
- Start CLI with
- Parsing (
ClaudeStatusProbe):- Strips ANSI, locates "Current session" + "Current week" headers.
- Extracts percent left/used and reset text near those headers.
- Parses
Account:andOrg:lines when present. - Surfaces CLI errors (e.g. token expired) directly.
- Some Education and organization-managed subscriptions return only a subscription notice, with no numeric
session or weekly quota fields. CodexBar reports those limits as unavailable, keeps local cost/token history
visible, and never derives quota percentages from spend or token totals.
Cost usage (local log scan)
- Source roots:
- Native Claude logs:
$CLAUDE_CONFIG_DIR(comma-separated), each root uses<root>/projects.- Fallback roots:
~/.config/claude/projects~/.claude/projects(Claude Code and current Claude Desktop Code/Cowork CLI sessions)- Additional embedded Claude Desktop project stores, when present:
~/Library/Application Support/Claude/local-agent-mode-sessions/**/.claude/projects~/Library/Application Support/Claude/claude-code-sessions/**/.claude/projects
- Current Claude Desktop metadata under
claude-code-sessionspoints to shared CLI session JSONL bycliSessionId; metadata-only directories are not treated as usage sources.
- Supported pi-compatible sessions:
~/.pi/agent/sessions/**/*.jsonl~/.omp/agent/sessions/**/*.jsonl
- Native Claude logs:
- Files:
**/*.jsonlunder the native project roots, discovered Claude Desktop project roots,
plus supported pi-compatible session files. - Parsing:
- Native Claude logs parse lines with
type: "assistant"andmessage.usage. - Uses per-model token counts (input, cache read/create, output).
- Deduplicates streaming chunks by
message.id + requestId(usage is cumulative per chunk). - pi and OMP sessions attribute
anthropicassistant usage to Claude and bucket it by assistant-turn timestamp, so a
single pi-compatible session can contribute to multiple models/days. - Matching assistant entry IDs within the same session are counted once across roots; distinct turns are retained.
- Native Claude logs parse lines with
- Cache:
- Native + merged provider cache:
~/Library/Caches/CodexBar/cost-usage/claude-v2.json - pi-compatible session cache:
~/Library/Caches/CodexBar/cost-usage/pi-sessions-v7.json
- Native + merged provider cache:
Key files
- OAuth:
Sources/CodexBarCore/Providers/Claude/ClaudeOAuth/* - Web API:
Sources/CodexBarCore/Providers/Claude/ClaudeWeb/ClaudeWebAPIFetcher.swift - CLI PTY:
Sources/CodexBarCore/Providers/Claude/ClaudeStatusProbe.swift,Sources/CodexBarCore/Providers/Claude/ClaudeCLISession.swift - Cost usage:
Sources/CodexBarCore/CostUsageFetcher.swift,Sources/CodexBarCore/PiSessionCostScanner.swift,Sources/CodexBarCore/PiSessionCostCache.swift,Sources/CodexBarCore/Vendored/CostUsage/*
File: docs/claude-comparison-since-0.18.0beta2.md
summary: "Claude fetch behavior comparison covering OAuth, web, CLI, and Keychain prompt changes."
read_when:
- Reviewing Claude fetch regressions since 0.18.0 beta 2
- Changing Claude OAuth, web, CLI, or Keychain prompt behavior
- Comparing old and current Claude credential flows
Claude Fetch Comparison (`7b79b2d` vs `HEAD`)
This document compares Claude data fetching behavior between:
- Baseline commit:
7b79b2d080c6b00f6c8f52f89ac115f33a7ca8b0 - Current
HEAD:37841489f849567a598d2a8ba601eb6f1228644e
Focus areas:
- OAuth
- Web
- CLI
- Keychain permission prompts, cooldowns, and re-prompt behavior
- OAuth token fetch/use/refresh behavior
High-level Changes
- OAuth moved from "load token and fail if expired" to "auto-refresh when expired".
- Claude keychain reads now use stricter non-interactive probes (
LAContext.interactionNotAllowed) before any promptable path. - New Claude keychain prompt cooldown gate: 6-hour suppression after denial.
- New OAuth refresh failure gate:
invalid_grant=> terminal block until auth fingerprint changes.- repeated
400/401(non-invalid_grant) => transient exponential backoff (up to 6h).
- Auto-mode availability checks were hardened to avoid interactive prompts where possible.
OAuth Flow
OAuth (Before: `7b79b2d`)
flowchart TD
A["Claude OAuth fetch starts"] --> B["load(environment)"]
B --> C{"token found?"}
C -- "no" --> K["OAuth not available / fail"]
C -- "yes" --> D{"token expired?"}
D -- "yes" --> E["Fail: token expired (run claude)"]
D -- "no" --> F{"has user:profile scope?"}
F -- "no" --> G["Fail: missing scope"]
F -- "yes" --> H["GET /api/oauth/usage with Bearer access token"]
H --> I{"HTTP success?"}
I -- "yes" --> J["Map usage response -> snapshot"]
I -- "no" --> L["Invalidate cache, surface OAuth error"]OAuth (Now: `HEAD`)
flowchart TD
A["Claude OAuth fetch starts"] --> B["hasCachedCredentials?"]
B --> C{"cached/refreshable creds exist?"}
C -- "yes" --> D["loadWithAutoRefresh(allowKeychainPrompt=false unless bootstrap needed)"]
C -- "no" --> E["Gate: should allow keychain prompt now?"]
E --> F["loadWithAutoRefresh(allowKeychainPrompt=true if gate allows)"]
D --> G{"expired?"}
F --> G
G -- "no" --> H["Use access token directly"]
G -- "yes" --> I["POST /v1/oauth/token refresh_token grant"]
I --> J{"Refresh status"}
J -- "200" --> K["Save refreshed creds to CodexBar keychain cache + memory"]
J -- "400/401 + invalid_grant" --> L["Record terminal auth failure; block refresh until auth fingerprint changes"]
J -- "400/401 other" --> M["Record transient failure; exponential backoff"]
K --> H
H --> N{"has user:profile scope?"}
N -- "no" --> O["Fail: missing scope"]
N -- "yes" --> P["GET /api/oauth/usage with Bearer access token"]
P --> Q["Map usage response -> snapshot"]OAuth Token Source Resolution (Now)
flowchart TD
A["load(...)"] --> B["Environment token (CODEXBAR_CLAUDE_OAUTH_TOKEN)"]
B -->|miss| C["Memory cache (valid + unexpired)"]
C -->|miss| D["CodexBar keychain cache: com.steipete.codexbar.cache/oauth.claude"]
D -->|miss| E["~/.claude/.credentials.json"]
E -->|miss| F{"allowKeychainPrompt && prompt gate open?"}
F -- "yes" --> G["Claude keychain service: Claude Code-credentials (promptable fallback)"]
F -- "no" --> H["Stop without keychain prompt path"]Web Flow
Web (Before and Now: core fetch path largely unchanged)
flowchart TD
A["Claude Web fetch starts"] --> B{"manual cookie header configured?"}
B -- "yes" --> C["Extract sessionKey from manual header"]
B -- "no" --> D["Enumerate cookie import candidates"]
D --> E["Try browser cookie import (claude.ai domain)"]
E --> F{"sessionKey found?"}
C --> F
F -- "no" --> G["Fail: noSessionKeyFound"]
F -- "yes" --> H["GET organizations + usage endpoints"]
H --> I["Build web usage snapshot + identity + optional cost extras"]Web Candidate Filtering + Prompt Implications (Now)
flowchart TD
A["cookieImportCandidates(...)"] --> B{"browser uses keychain for decryption?"}
B -- "no (Safari/Firefox/Zen)" --> C["Keep candidate even if keychain disabled"]
B -- "yes (Chromium family)" --> D{"Keychain disabled?"}
D -- "yes" --> E["Drop candidate"]
D -- "no" --> F["Check BrowserCookieAccessGate cooldown"]
F --> G{"cooldown active?"}
G -- "yes" --> E
G -- "no" --> H["Attempt import; on access denied record 6h cooldown"]CLI Flow
CLI Fetch Path (Provider Runtime = `.cli`)
flowchart TD
A["CLI command (provider=claude)"] --> B{"source mode"}
B -- "auto" --> C["Strategy order: web -> cli"]
B -- "web" --> D["Web strategy only"]
B -- "cli" --> E["CLI PTY strategy only"]
B -- "oauth" --> F["OAuth strategy only"]
E --> G["ClaudeStatusProbe via PTY session"]
G --> H["Parse /usage output -> snapshot"]Notes:
- The PTY parsing path itself is functionally stable in this range.
- Claude CLI session environment still scrubs OAuth env overrides and
ANTHROPIC_*vars before launching the subprocess.
App Runtime Auto Pipeline (Provider Fetch Plan)
App Auto Strategy Order (Descriptor Pipeline)
flowchart TD
A["App runtime source=auto"] --> B["Try OAuth strategy first"]
B -->|"available + success"| Z["Done"]
B -->|"unavailable or fallback on error"| C["Try Web strategy"]
C -->|"success"| Z
C -->|"unavailable or fallback on error"| D["Try CLI strategy"]
D -->|"success"| Z
D -->|"fail"| E["Provider fetch failure"]Internal `ClaudeUsageFetcher(dataSource:.auto)` Heuristic (Now)
flowchart TD
A["ClaudeUsageFetcher.loadLatestUsage(dataSource=.auto)"] --> B["Probe OAuth creds non-interactively"]
B --> C{"usable OAuth creds?"}
C -- "yes" --> D["Use OAuth path"]
C -- "no" --> E{"has web session?"}
E -- "yes" --> F["Use Web path"]
E -- "no" --> G{"claude binary present?"}
G -- "yes" --> H["Try CLI PTY, if fails then OAuth"]
G -- "no" --> I["Fallback to OAuth"]Keychain Prompt / Re-prompt Behavior
Claude OAuth Keychain Prompt Gate (Now)
stateDiagram-v2
[*] --> PromptAllowed
PromptAllowed --> CooldownBlocked: recordDenied()
CooldownBlocked --> CooldownBlocked: shouldAllowPrompt() before deniedUntil
CooldownBlocked --> PromptAllowed: time >= deniedUntil (6h)OAuth Refresh Failure Gate (Now)
stateDiagram-v2
[*] --> Open
Open --> TransientBackoff: recordTransientFailure (400/401 non-invalid_grant)
TransientBackoff --> Open: cooldown expires
TransientBackoff --> Open: auth fingerprint changes
Open --> TerminalBlocked: recordTerminalAuthFailure (invalid_grant)
TerminalBlocked --> TerminalBlocked: unchanged auth fingerprint
TerminalBlocked --> Open: auth fingerprint changes
TransientBackoff --> TerminalBlocked: terminal auth failure observed
TerminalBlocked --> Open: recordSuccessKey Differences in Permission Prompt Surfaces
- Before:
- OAuth availability/load paths could reach Claude keychain access with less strict non-interactive protection.
- No dedicated Claude OAuth prompt cooldown gate.
- No terminal-vs-transient refresh failure gate.
- Now:
- Non-interactive probes are stricter and reused broadly.
- Promptable Claude keychain access is gated and usually only bootstrap-oriented.
- Denials cause cooldown suppression to avoid repeated prompts.
- Refresh failures can suppress repeated attempts until either timeout (transient) or credential change (terminal).
Related Files
/Users/ratulsarna/Developer/staipete/CodexBar/Sources/CodexBarCore/Providers/Claude/ClaudeUsageFetcher.swift/Users/ratulsarna/Developer/staipete/CodexBar/Sources/CodexBarCore/Providers/Claude/ClaudeProviderDescriptor.swift/Users/ratulsarna/Developer/staipete/CodexBar/Sources/CodexBarCore/Providers/Claude/ClaudeOAuth/ClaudeOAuthCredentials.swift/Users/ratulsarna/Developer/staipete/CodexBar/Sources/CodexBarCore/Providers/Claude/ClaudeOAuth/ClaudeOAuthKeychainAccessGate.swift/Users/ratulsarna/Developer/staipete/CodexBar/Sources/CodexBarCore/Providers/Claude/ClaudeOAuth/ClaudeOAuthRefreshFailureGate.swift/Users/ratulsarna/Developer/staipete/CodexBar/Sources/CodexBarCore/KeychainAccessPreflight.swift/Users/ratulsarna/Developer/staipete/CodexBar/Sources/CodexBarCore/KeychainNoUIQuery.swift/Users/ratulsarna/Developer/staipete/CodexBar/Sources/CodexBarCore/BrowserCookieImportOrder.swift/Users/ratulsarna/Developer/staipete/CodexBar/Sources/CodexBarCore/BrowserCookieAccessGate.swift
File: docs/cli.md
summary: "CodexBar CLI for fetching usage from the command line."
read_when:
- "You want to call CodexBar data from scripts or a terminal."
- "Adding or modifying Commander-based CLI commands."
- "Aligning menubar and CLI output/behavior."
CodexBar CLI
A lightweight Commander-based CLI that mirrors the menu bar app’s provider fetchers and config file.
Use it when you need usage numbers in scripts, CI, or dashboards without UI.
Install
- In the app: Preferences → Advanced → Install CLI. This symlinks
CodexBarCLIto/usr/local/bin/codexbarand/opt/homebrew/bin/codexbar. - From the repo, after installing
CodexBar.appin/Applications:./bin/install-codexbar-cli.sh(same symlink targets). - Manual:
ln -sf "/Applications/CodexBar.app/Contents/Helpers/CodexBarCLI" /usr/local/bin/codexbar.
Release tarball install (macOS/Linux)
- Homebrew formula (Linux today):
brew install steipete/tap/codexbar. - Download release tarballs from GitHub Releases:
- macOS:
CodexBarCLI-v<tag>-macos-arm64.tar.gz,CodexBarCLI-v<tag>-macos-x86_64.tar.gz - Linux (glibc):
CodexBarCLI-v<tag>-linux-aarch64.tar.gz,CodexBarCLI-v<tag>-linux-x86_64.tar.gz - Linux (static musl):
CodexBarCLI-v<tag>-linux-musl-aarch64.tar.gz,CodexBarCLI-v<tag>-linux-musl-x86_64.tar.gz
- macOS:
- Extract and run
./codexbar(symlink) or./CodexBarCLI.
tar -xzf CodexBarCLI-v0.17.0-macos-x86_64.tar.gz
./codexbar --version
./codexbar usage --format json --prettyBuild
./Scripts/package_app.sh(or./Scripts/compile_and_run.sh) bundlesCodexBarCLIintoCodexBar.app/Contents/Helpers/CodexBarCLI.- Standalone:
swift build -c release --product CodexBarCLI(binary at./.build/release/CodexBarCLI). - Dependencies: Swift 6.2+, Commander package (
https://github.com/steipete/Commander).
Configuration
CodexBar reads the resolved config file for provider settings, secrets, and ordering. New installs use~/.config/codexbar/config.json; absolute XDG_CONFIG_HOME paths and CODEXBAR_CONFIG are supported, and existing~/.codexbar/config.json installs keep using the legacy file when no XDG config exists.
See docs/configuration.md for the schema.
Command
codexbardefaults to theusagecommand.--format text|json|toon(default: text).- JSON uses the generic
usage.detailsarray for provider-specific information. Each section contains an optionaltitle,rows(label,value, and optionalsecondaryValue), and an optionalbarsorlinechart. The same
shape is returned byGET /usagefromcodexbar serve. - Legacy provider-specific keys such as
openRouterUsage,clawRouterUsage, andsub2APIUsageare not compatibility
aliases; clients must readusage.details. Unknown legacy keys in cached or iCloud-synced snapshots are ignored
when decoding. --format toonemits the same payload as--format json(and implies--json's credits/no-color behavior),
rendered as TOON instead: uniform arrays of scalar-only objects (for
exampleusage.details[].rows) collapse into a compactrows[N]{label,value}:table, everything else falls
back to an indented list form. This is a presentation-only mapping of the existing JSON schema — no new fields,
no denormalization — intended for agents that want a token-cheaper alternative to parsing JSON.usage --format toonis the only command that supports it; every other command still advertises and accepts only--format text|json, and treatstoonlike any other unrecognized value.
codexbar costprints token cost usage for Claude, Codex, and Cursor.- Claude and Codex are scanned from local session logs without web/CLI access.
- Cursor is fetched from the cookie-authenticated cursor.com dashboard API (macOS only; see
docs/cursor.md) and honors the configured cookie source: a non-empty Manual header is required and forwarded, while Off fails explicitly instead of silently omitting Cursor. --format text|json(default: text).--jsonincludes the same cost concepts as Settings → Usage & Spend (token mix,provenance, coverage), but it is not the dashboard Export JSON schema. CLI places mix fields under each provider'stotalsand emitsprovenance/coverageon that provider object; Export JSON neststokenMix,provenance, andcoverageundergroups[].- OpenCodex appears as a separate
opencodexpayload only when Include OpenCodex usage logs is on in Settings. That payload does not inventprojects(OpenCodex logs have no workspace path). --refreshignores cached scans.--provider-native-onlyis experimental and excludes pi and OMP session mirrors from Claude and Codex history.
codexbar cardsprints a one-shot usage snapshot as a responsive terminal card grid.- Reuses the same provider, source, account, credits, and status flags as
codexbar usage. - Account lines and plan badges are included in the card grid by default.
--briefrenders a compact table (Provider / Usage / Reset) instead of the card grid.- Stdout is always rendered text;
--json-outputonly affects stderr logs (no JSON card payload). - Failed providers are summarized in a footer (not rendered as error cards).
- When the opt-in Claude claude-swap integration returns two or more accounts—or one account with
claudeSwapShowSingleAccountenabled—cards renders every account in active-first/slot order instead of the
ambient or token-account Claude cards. This applies on macOS and Linux, including an explicit--provider claude;--source autoremains eligible. --account,--account-index,--all-accounts, and explicit non-auto source flags preserve their requested
ambient behavior and do not invoke claude-swap. Zero-account lists always retain ambient Claude output;
one-account lists do so unlessclaudeSwapShowSingleAccountis enabled.- claude-swap sentinel accounts remain successful cards with their problem text and no fabricated usage metrics.
A list adapter, parser, or timeout failure retains useful ambient Claude output, adds a distinctClaude (claude-swap)failure footer entry, and makes the command exit non-zero. - This precedence is cards-only:
codexbar usageandcodexbar servekeep their existing output cardinality. - Honors
$COLUMNSfor layout; falls back to 80 columns. Use--no-colorfor plain output. - Kitty, Ghostty, WezTerm, and other truecolor terminals auto-enable enhanced gradients/outlines.
- Force enhanced mode elsewhere with
CODEXBAR_CARDS_ENHANCED=1. - Exit code is non-zero when any provider fetch fails.
- Reuses the same provider, source, account, credits, and status flags as
codexbar dashboardprints one dashboard-v1 JSON snapshot and exits.- Honors enabled providers in stable order, carries configured display sort keys, and defaults to full account identity;
--identity redactedhides email local parts. - Provider failures remain row-level errors alongside healthy rows; a valid partial snapshot exits
0. - Stdout contains only the snapshot document. Diagnostics and optional
--json-outputlogs go to stderr. --prettyformats the document.--timeout <seconds>accepts0...86400, defaults to30, and uses0to disable the command deadline.--outputatomically writes the snapshot to a file (0644) instead of stdout — staged in the destination directory, fsync'd, then renamed over the target so readers never observe a partial document. The parent directory must already exist (it is not created), and stdout stays silent on success.- Starts no HTTP server and requires no dashboard bearer token. See
docs/dashboard-api.mdfor the shared payload contract.
- Honors enabled providers in stable order, carries configured display sort keys, and defaults to full account identity;
codexbar servestarts a foreground HTTP server for usage and cost JSON, a token-gated dashboard snapshot, and a built-in web UI at/.- Dashboard snapshot identity follows the app's "Hide personal information" setting when
--identityis absent: the toggle on redacts email local parts, off keeps full emails. The setting is read per request, so a change applies without a serve restart. Pass--identity redactedor--identity fullto pin the mode and ignore the app setting, especially when responses cross a network. --host <host>acceptslocalhostor an IPv4 address and defaults to127.0.0.1;localhostis normalized to127.0.0.1. Binding a non-loopback host requires a dashboard token and--allow-plain-http(seedocs/dashboard-api.mdfor the threat model).--portdefaults to8080.--refresh-interval <seconds>defaults to60and controls the in-memory response cache TTL.--request-timeout <seconds>defaults to30and bounds each request before returning504 Gateway Timeout; use0to keep waiting indefinitely. Slow builds continue past the deadline, commit their finished result to the cache, and feed any same-config request already waiting so a 504 self-heals on retry.--dashboard-token <token>sets the static bearer token forGET /dashboard/v1/snapshot. Prefer theCODEXBAR_DASHBOARD_TOKENenvironment variable (it wins over the flag; a flag value leaks viaps). Empty or whitespace-only tokens are startup errors. Without a token the snapshot route fails closed with401.- On a non-loopback host the token gates all data routes —
/usage,/cost, and/dashboard/v1/snapshotall requireAuthorization: Bearer YOUR_TOKEN, so account data is never exposed to the network unauthenticated. The static web UI at/and/healthare always open. On the default loopback bind,/usageand/coststay unauthenticated. --allow-plain-httpis the explicit acknowledgment that the bearer token crosses the network in cleartext on every request when serving on a non-loopback host.serverefuses to start on a non-loopback host without it.- Provider config is reloaded for each usage/cost request; cache entries are keyed by the loaded config so provider toggles and source changes do not require restarting
serve. - Transient refresh failures fall back to the last good response for up to ten refresh intervals (minimum five minutes) so polling clients do not flicker between data and errors; disabled when
--refresh-interval 0. - After a cached response expires,
servereturns the last-good response immediately while rebuilding it in the background;--refresh-interval 0keeps every request blocking. - The default loopback bind rejects non-loopback
Hostheaders; a configured non-loopback--hostadditionally accepts its own name. No CORS, TLS, or daemon mode. - Endpoints:
GET /(web UI),GET /health,GET /usage,GET /usage?provider=,GET /cost,GET /cost?provider=,GET /dashboard/v1/snapshot(plusprovider=anddetail=<full|shell>). GET /dashboard/v1/snapshotrequiresAuthorization: Bearer YOUR_TOKEN; responses (and all401s) carryCache-Control: no-store. The token is never accepted via query string. Seedocs/dashboard-api.mdfor the payload contract.GET /healthreturns{"status":"ok"}plus aversionfield with the running build (e.g."0.37.2") when resolvable; clients can compare it againstcodexbar --versionto detect aserveprocess still running an older binary after an update.- Codex usage responses include every visible Codex account, matching the menu bar switcher.
- Dashboard snapshot identity follows the app's "Hide personal information" setting when
codexbar cache clearclears local CodexBar caches.--cookiesremoves cached browser-cookie headers from the CodexBar Keychain cache.--cookies --providerremoves browser-cookie cache entries for that provider, including managed Codex account scopes.--costremoves local cost-usage scan caches.--allclears both cookies and cost caches.--provideris cookie-only and cannot be combined with--costor--all.
codexbar cookie refreshignores the provider's current cookie caches while importing a replacement through its web strategy. A failed or interrupted import leaves existing cookies intact.- Choose exactly one of
--provideror--all; provider support comes from shared browser-cookie metadata rather than a fixed CLI list. - Prompt-capable Chromium imports require
--allow-keychain-prompt. Without it, the command fails before cache mutation with an interactive-retry hint. - A six-hour Keychain-denial cooldown is bypassed only by that explicit acknowledgment flag. Output never includes cookie values.
- Providers configured for Manual or Off cookie sources are skipped.
- Choose exactly one of
codexbar guard --providergates automation on one provider's remaining quota.--min-remainingsets the inclusive threshold (default:10; valid range:0...100).--window session|weeklyselects the primary/session window or secondary/weekly window (default:session).--timeout <seconds>bounds the complete fetch (range:0...86400; default:60;0disables this guard-level deadline while provider-specific timeouts still apply).--jsonemits the provider, window, remaining quota, threshold, decision, unavailable reason, and exit code; add--prettyfor formatted JSON.- Stable guard exit codes:
0means safe,1means below threshold,64(EX_USAGE) means invalid arguments, and69(EX_UNAVAILABLE) means the quota could not be checked or the selected window is unavailable.--fail-openchanges only unavailable results from69to0; JSON still reportsdecision: "unknown"and the reason. - Guard fetches are read-only and use background interaction policy, matching
codexbar usage; they never request interactive Keychain access.
--provider(default: enabled providers in config; falls back to defaults when missing).- Provider IDs live in the config file (see
docs/configuration.md). - With three or more providers enabled, the default stays scoped to enabled providers; use
--provider allto query
every registered provider. --account <label>/--account-index <n>/--all-accounts(token accounts from config, or all visible Codex accounts for Codex; requires a single provider).--no-credits(hide Codex credits in text output).--pretty(pretty-print JSON).--status(fetch provider status pages and include them in output).--antigravity-plan-debug(debug: print Antigravity planInfo fields to stderr).
- Provider IDs live in the config file (see
--source <auto|web|cli|oauth|api>(default:auto).auto: provider-specific fallback order fromdocs/providers.md.web: web-only where that provider exposes an explicit web source; no CLI/API fallback. Browser import is macOS-only, while supported providers can use configured manual cookies on Linux.cli: CLI/local-helper source where the provider exposes one (for example Codex RPC/PTy, Claude PTY, Kilo CLI fallback, Kiro CLI, local probes).oauth: OAuth-backed source where supported (Codex, Claude, Vertex AI).api: API-key/token flow when the provider supports it (OpenAI, Claude Admin API, z.ai, Gemini, Alibaba, Copilot, OpenCode Go, Kilo, Kimi, MiniMax, Ollama, Warp, OpenRouter, ElevenLabs, Deepgram, Synthetic, DeepSeek, DeepInfra, Moonshot, Doubao, Codebuff, Crof, Venice, AWS Bedrock).- Output
sourcereflects the strategy actually used (openai-web,web,oauth,api,local,cli, or provider CLI label). - Codex web: OpenAI web dashboard (usage limits, credits remaining, code review remaining, usage breakdown).
--web-timeout <seconds>(default: 60)--web-debug-dump-html(writes HTML snapshots to/tmpwhen data is missing)
- Claude web: claude.ai API (session + weekly usage, account metadata, and prepaid Usage credits balance when
available).
CLI Auto falls back to the installed Claude executable when web credentials are unavailable. This foreground
command delegates authentication to Claude Code; the app keeps its stricter prompt-free background availability
gate for scheduled refreshes. - Command Code web: commandcode.ai browser session cookies on macOS, or a configured manual cookie on Linux, for monthly credit usage.
- OpenCode Go auto: local SQLite cost history on macOS and Linux with API usage-window enrichment when
OPENCODE_API_KEYis configured, plus legacy manual-cookie web fallback. - Kilo auto: app.kilo.ai API first, then CLI auth fallback (
~/.local/share/kilo/auth.json) on missing/unauthorized API credentials. - Linux: browser-backed
auto/webmodes are not supported; local sources and configured manual-cookie paths remain available where documented.
- Global flags:
-h/--help,-V/--version,-v/--verbose,--no-color,--log-level,--json-output,--json-only.--json-output: JSONL logs on stderr (machine-readable).--json-only: suppress non-JSON output; errors become JSON payloads.
codexbar config validatechecks the resolved config file for invalid fields.--format text|json,--pretty, and--json-onlyare supported.- Warnings keep exit code 0; errors exit non-zero.
codexbar config dumpprints the normalized config JSON.codexbar hooks listshows the local hook configuration;--format jsonand--prettyare supported.codexbar hooks enable|disablechanges the explicit top-level opt-in switch in the local config file.codexbar hooks test <event> --providerinvokes matching enabled rules with a representative event. Hook
commands run directly without a shell and receiveCODEXBAR_*variables plus JSON on stdin.--format jsonand--json-onlyreturn structured per-rule results. Seedocs/configuration.md#external-event-hooksfor the event, payload, timeout, and security contract.codexbar hooks watchpolls enabled providers and fires matching hooks on real quota and status transitions.
Without it, hook rules only ever fire from the macOS app, so a headless install can configure hooks that never run.--interval <seconds>: poll period. Default300, minimum60; a smaller value is rejected rather than
clamped, because each tick fetches every selected provider.--provider: restrict to one provider; repeatable. Defaults to every enabled provider.--format json/--json/--pretty: emit each fired event as JSON.- Events are edge-triggered against the previous poll, so a condition that merely persists (a saturated window,
an ongoing outage) does not re-fire every tick. State is in-memory only: a restart re-establishes baselines and
the first poll of any lane fires nothing. - Run
watchas one continuous process. Repeated one-shot invocations cannot preserve transition baselines or event
rate limits between polls. - Runs read-only, like
codexbar guard: it never prompts for credentials. A failed refresh reportsrefresh_failedwith a coarse category (timeout,offline,auth_required,network_error) and never
forwards the raw provider error. - Stops cleanly on
SIGINT/SIGTERM/SIGHUP.
Token accounts
The CLI reads multi-account tokens from the same resolved config file as the app.
- Select a specific account:
--account <label>(matches the label/email in the file). - Select by index (1-based):
--account-index <n>. - Fetch all accounts for the provider:
--all-accounts.
Account selection flags require a single provider (--provider claude, etc.).
For Claude, token accounts accept eithersessionKeycookies or OAuth access tokens (sk-ant-oat...).
OAuth usage requires theuser:profilescope; inference-only tokens will return an error.
Codex accounts
For Codex, --all-accounts and codexbar serve enumerate the same visible accounts as the app switcher:
managed Codex accounts from managed-codex-accounts.json plus the live system account when present.
Each fetch is scoped to that account's Codex home before the normal Codex web/OAuth/CLI strategy runs, and JSON
payloads include the visible account label in account.
Cost JSON payload
codexbar cost --format json emits an array of payloads (one per provider).
provider,source(localfor Claude/Codex log scans,webfor Cursor dashboard data),updatedAtsessionTokens,sessionCostUSDlast30DaysTokens,last30DaysCostUSDhistoryCoverageIsEstablished:falsewhile a bounded Codex scan still has catch-up work pending;trueonce the requested history is covered.- Cursor only:
meteredCostUSD— what Cursor's plan actually deducts over the window, alongside the API-rate estimate inlast30DaysCostUSD. daily[]:date,inputTokens,outputTokens,cacheReadTokens,cacheCreationTokens,totalTokens,totalCost,modelsUsed,modelBreakdowns[](modelName,cost)- Codex only:
projects[]:name,path,totalTokens,totalCost,daily[],modelBreakdowns[],sources[] totals:inputTokens,outputTokens,cacheReadTokens,cacheCreationTokens,totalTokens,totalCosterror: structured provider error when a fetch fails (for example Cursor requested while its cookie source is Off).
Example usage
/* Detailed source-code truncated for AI context efficiency. */Sample output (text)
== Codex 0.6.0 (codex-cli) ==
Session: 72% left [========----]
Pace: 12% in deficit | Expected 16% used | Projected empty in 2h 30m
Resets today at 2:15 PM
Weekly: 41% left [====--------]
Pace: 6% in reserve | Expected 47% used | Lasts until reset
Resets Fri at 9:00 AM
Credits: 112.4 left
== Claude Code 2.0.58 (web) ==
Session: 88% left [==========--]
Pace: On pace | Expected 13% used | Lasts until reset
Resets tomorrow at 1:00 AM
Weekly: 63% left [=======-----]
Pace: On pace | Expected 37% used | Runs out in 4d
Resets Sat at 6:00 AM
Sonnet: 95% left [===========-]
Account: [email protected]
Plan: Pro
== Kilo (cli) ==
Credits: 60% left [=======-----]
40/100 credits
Plan: Kilo Pass Pro
Activity: Auto top-up: visa
Note: Using CLI fallbackSample output (JSON, pretty)
{
"provider": "codex",
"version": "0.6.0",
"source": "openai-web",
"status": { "indicator": "none", "description": "Operational", "updatedAt": "2025-12-04T17:55:00Z", "url": "https://status.openai.com/" },
"usage": {
"primary": { "usedPercent": 28, "windowMinutes": 300, "resetsAt": "2025-12-04T19:15:00Z" },
"secondary": { "usedPercent": 59, "windowMinutes": 10080, "resetsAt": "2025-12-05T17:00:00Z" },
"tertiary": null,
"updatedAt": "2025-12-04T18:10:22Z",
"identity": {
"providerID": "codex",
"accountEmail": "[email protected]",
"accountOrganization": null,
"loginMethod": "plus"
},
"accountEmail": "[email protected]",
"accountOrganization": null,
"loginMethod": "plus"
},
"pace": {
"primary": { "stage": "ahead", "deltaPercent": 12, "expectedUsedPercent": 16, "willLastToReset": false, "etaSeconds": 9000, "summary": "12% in deficit | Expected 16% used | Projected empty in 2h 30m" },
"secondary": { "stage": "slightlyBehind", "deltaPercent": -6, "expectedUsedPercent": 47, "willLastToReset": true, "summary": "6% in reserve | Expected 47% used | Lasts until reset" }
},
"credits": { "remaining": 112.4, "updatedAt": "2025-12-04T18:10:21Z" },
"antigravityPlanInfo": null,
"openaiDashboard": {
"signedInEmail": "[email protected]",
"codeReviewRemainingPercent": 100,
"creditEvents": [
{ "id": "00000000-0000-0000-0000-000000000000", "date": "2025-12-04T00:00:00Z", "service": "CLI", "creditsUsed": 123.45 }
],
"dailyBreakdown": [
{
"day": "2025-12-04",
"services": [{ "service": "CLI", "creditsUsed": 123.45 }],
"totalCreditsUsed": 123.45
}
],
"updatedAt": "2025-12-04T18:10:21Z"
}
}Exit codes
- 0: success
- 2: provider missing (binary not on PATH)
- 3: parse/format error
- 4: CLI timeout
- 1: unexpected failure
For codexbar dashboard, 0 includes a valid partial snapshot whose provider rows contain errors. The command exits
non-zero only when it cannot produce a valid snapshot document.
Notes
- CLI uses the config file for enabled providers, ordering, and secrets.
- CLI binary discovery checks explicit overrides, captured login PATH, inherited PATH, and known install paths before falling back to an interactive shell probe.
- Reset lines follow the in-app reset time display setting when available (default: countdown).
- Text output uses ANSI colors when stdout is a rich TTY; disable with
--no-colororNO_COLOR/TERM=dumb. - Copilot CLI queries require an API token via config
apiKeyorCOPILOT_API_TOKEN. - OpenAI API charts require an Admin API key for organization costs/usage. Normal API keys can only use the legacy balance fallback.
- Claude Admin API charts require an Anthropic Admin API key (
sk-ant-admin...orANTHROPIC_ADMIN_KEY). - Codex CLI
autotries the OpenAI web dashboard, then Codex CLI RPC/PTy; the app’s Codexautopath prefers OAuth when credentials are present, then CLI. - Claude CLI
autotries web, then CLI PTY; the app’s Claudeautopath prefers OAuth, then CLI, then web. - Kilo text output splits identity into
Plan:andActivity:lines; in--source auto, resolved CLI fetches addNote: Using CLI fallback. - Kilo auto-mode failures include a fallback-attempt summary line in text mode (API attempt then CLI attempt).
- OpenAI web requires a signed-in
chatgpt.comsession in a supported browser or a manual cookie header. No passwords are stored; CodexBar reuses cookies. - Safari cookie import may require granting CodexBar Full Disk Access (System Settings → Privacy & Security → Full Disk Access).
- The
openaiDashboardJSON field is normally sourced from the app’s cached dashboard snapshot;--source auto|webrefreshes it live via WebKit using a per-account cookie store. - Future: optional
--from-cacheflag to read the menubar app’s persisted snapshot (if/when that file lands).
2. Official Technical Reference & Guides (steipete/docs)
Mintlify Starter Kit
Use the starter kit to get your docs deployed and ready to customize.
Click the green Use this template button at the top of this repo to copy the Mintlify starter kit. The starter kit contains examples with
- Guide pages
- Navigation
- Customizations
- API reference pages
- Use of popular components
Follow the full quickstart guide
Development
Install the Mintlify CLI to preview your documentation changes locally. To install, use the following command:
npm i mintRun the following command at the root of your documentation, where your docs.json is located:
mint devView your local preview at http://localhost:3000.
Publishing changes
Install our GitHub app from your dashboard to propagate changes from your repo to your deployment. Changes are deployed to production automatically after pushing to the default branch.
Need help?
Troubleshooting
- If your dev environment isn't running: Run
mint updateto ensure you have the most recent version of the CLI. - If a page loads as a 404: Make sure you are running in a folder with a valid
docs.json.