## 1. Project Overview & Quickstart (steipete/CodexBar)

## File: README.md

# CodexBar 🎚️ — May your tokens never run out.

> Every AI coding limit, in your menu bar.

[](https://github.com/steipete/CodexBar/releases/latest)
[](https://github.com/steipete/CodexBar/releases/latest)
[](https://github.com/steipete/homebrew-tap)
[](https://aur.archlinux.org/packages/codexbar-cli)
[](LICENSE)
[](https://codexbar.app)

[](https://codexbar.app)

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
```bash
brew install --cask codexbar
```

### CLI Tarballs (macOS/Linux)
Homebrew formula (Linux today):
```bash
brew install steipete/tap/codexbar
```
Arch Linux AUR package:
```bash
yay -S codexbar-cli
```
Or 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:

```bash
codexbar config providers
codexbar config enable --provider grok
codexbar config disable --provider cursor
```

For API-key providers, store a key without opening Settings:

```bash
printf '%s' "$ELEVENLABS_API_KEY" | codexbar config set-api-key --provider elevenlabs --stdin
```

`set-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](docs/cli-configuration.md) for the full flow.

## Providers

- [Codex](docs/codex.md) — OAuth API or local Codex CLI, plus optional OpenAI web dashboard extras.
- [OpenAI](docs/openai.md) — Admin API key usage/cost graphs with legacy credit-balance fallback.
- [Azure OpenAI](docs/azure-openai.md) — API key, endpoint, and deployment validation probe.
- [Claude](docs/claude.md) — OAuth API, browser cookies, or CLI PTY fallback; session and weekly usage where available.
- [Cursor](docs/cursor.md) — Browser session cookies for plan + usage + billing resets.
- [OpenCode](docs/opencode.md) — Browser cookies for workspace subscription usage.
- [OpenCode Go](docs/opencode.md) — Usage API, browser fallback, and local SQLite cost history.
- [Alibaba Coding Plan](docs/alibaba-coding-plan.md) — Web cookies or API key for coding-plan quotas.
- [Alibaba Token Plan](docs/alibaba-token-plan.md) — Bailian browser/manual cookies for token-plan credits.
- [Qwen Cloud](docs/qwen-cloud.md) — 5-hour and weekly individual Token Plan usage via browser/manual cookies.
- [Gemini](docs/gemini.md) — OAuth-backed quota API using Gemini CLI credentials (no browser cookies).
- [Antigravity](docs/antigravity.md) — Local language server probe, `agy` CLI HTTPS source, and Google OAuth fallback (experimental).
- [Droid](docs/factory.md) — Browser cookies + WorkOS token flows for Factory usage + billing.
- [Copilot](docs/copilot.md) — GitHub device flow + Copilot internal usage API.
- [Devin](docs/devin.md) — Chrome localStorage session or manual Bearer token for daily and weekly quotas.
- [z.ai](docs/zai.md) — API token for personal/team quota, MCP, 5-hour, and hourly usage windows.
- [Manus](docs/manus.md) — Browser `session_id` auth for credit balance, monthly credits, and daily refresh tracking.
- [MiniMax](docs/minimax.md) — API token, cookie header, or browser cookies for coding-plan usage.
- [T3 Chat](docs/t3chat.md) — Browser cookies capture for Base and Overage usage buckets.
- [ZoomMate](docs/zoommate.md) — Chrome cookie auto-import or manual cURL capture for credits usage.
- [Kimi](docs/kimi.md) — Auth token (JWT from `kimi-auth` cookie) for weekly quota + 5‑hour rate limit.
- [Kilo](docs/kilo.md) — API token with CLI-auth fallback for Kilo Pass usage.
- [Kiro](docs/kiro.md) — CLI-based usage; monthly credits + bonus credits.
- [Vertex AI](docs/vertexai.md) — Google Cloud gcloud OAuth with token cost tracking from local Claude logs.
- [Augment](docs/augment.md) — Augment CLI or browser cookies for credits tracking and usage monitoring.
- [Amp](docs/amp.md) — Browser cookie-based authentication with Amp Free usage tracking.
- [Ollama](docs/ollama.md) — API key access plus browser cookies for Ollama Cloud usage windows.
- [Synthetic](docs/synthetic.md) — API key quota endpoint for rolling five-hour, weekly token, and search-hourly usage.
- [JetBrains AI](docs/jetbrains.md) — Local XML-based quota from JetBrains IDE configuration; monthly credits tracking.
- [Warp](docs/warp.md) — API token for GraphQL request limits and monthly credits.
- [ElevenLabs](docs/elevenlabs.md) — API key for character credits and voice slot usage.
- [OpenRouter](docs/openrouter.md) — API token for credit-based usage tracking across multiple AI providers.
- [Windsurf](docs/windsurf.md) — Browser localStorage session import or local SQLite cache for plan usage.
- [Zed](docs/zed.md) — Zed editor Keychain session for plan, edit-prediction quota, billing cycle, and overdue invoices.
- [Perplexity](docs/perplexity.md) — Account usage credits from Perplexity usage data.
- [Xiaomi MiMo](docs/mimo.md) — Browser cookies for balance and token-plan usage.
- [Doubao](docs/doubao.md) — API key for Volcengine Ark request-limit probes.
- [Sakana AI](docs/sakana.md) — Manual Cookie header for 5-hour and weekly quota windows.
- [Abacus AI](docs/abacus.md) — Browser cookie auth for ChatLLM/RouteLLM compute credit tracking.
- [Mistral](docs/mistral.md) — Browser cookies for API spend, credit balance, and monthly-plan usage.
- [DeepSeek](docs/deepseek.md) — API key for credit balance tracking (paid vs. granted breakdown).
- [Fireworks](docs/fireworks.md) — API key + account slug for 30-day spend from the billing summary API.
- [DeepInfra](docs/deepinfra.md) — API key for prepaid balance, current-month spend, and spending-limit tracking.
- [Moonshot / Kimi API](docs/moonshot.md) — API key for Moonshot/Kimi API account balance tracking.
- [Venice](docs/venice.md) — API key for DIEM or USD balance tracking.
- [Codebuff](docs/codebuff.md) — API token (or `~/.config/manicode/credentials.json`) for credit balance + weekly rate limit.
- [Crof](docs/crof.md) — API key for dollar credit balance and optional request quota tracking.
- [Command Code](docs/command-code.md) — Browser or manual cookies for monthly USD credits from Command Code billing.
- [Qoder](docs/qoder.md) — Browser or manual cookies for Qoder big model credit usage.
- [StepFun](docs/stepfun.md) — Username + password login for Step Plan rate limits (5‑hour + weekly windows) and subscription plan name.
- [AWS Bedrock](docs/bedrock.md) — 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](docs/grok.md) — Grok CLI billing RPC plus grok.com browser-session fallback.
- [GroqCloud](docs/groqcloud.md) — API key for Enterprise Prometheus request/token/cache-hit metrics.
- [LLM Proxy](docs/llm-proxy.md) — API key + base URL for aggregate proxy quota stats and provider breakdowns.
- [ClawRouter](docs/clawrouter.md) — API key for monthly budget, spend, requests, tokens, and routed-provider usage.
- [sub2api](docs/sub2api.md) — Self-hosted gateway key quota, subscription limits, wallet balance, and per-key usage.
- [Wayfinder](docs/wayfinder.md) — Local router gateway polling for health, per-route breakdown, savings, and decision latency.
- [LiteLLM](docs/litellm.md) — Virtual key + proxy URL for personal and team budget/spend tracking.
- [Deepgram](docs/deepgram.md) — API key usage summaries across speech, agent, token, and TTS metrics.
- [Poe](docs/poe.md) — API key for current point balance and recent points history.
- [Chutes](docs/chutes.md) — API key for subscription usage, rolling and monthly quota windows, and pay-as-you-go quotas.
- [Neuralwatt](docs/neuralwatt.md) — API key for subscription kWh usage and prepaid credit balance.
- [ZenMux](docs/zenmux.md) — Management API key for rolling five-hour and seven-day quota windows plus PAYG balance.
- [xAI](docs/xai.md) — Management API key + team ID for prepaid credit balance and daily platform spend.
- [IBM Bob](docs/ibm-bob.md) — API key for monthly Bobcoin budget and usage across subscription teams.
- Open to new providers: [provider authoring guide](docs/provider.md).

## 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 (including `codexbar cost --provider codex`, `claude`, or `both` for 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](https://github.com/steipete/CodexBar/issues/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](docs/keychain-prompts.md) 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](docs/providers.md)
- Provider authoring: [docs/provider.md](docs/provider.md)
- Issue labeling guide: [docs/ISSUE_LABELING.md](docs/ISSUE_LABELING.md)
- UI & icon notes: [docs/ui.md](docs/ui.md)
- CLI reference: [docs/cli.md](docs/cli.md)
- Configuration: [docs/configuration.md](docs/configuration.md)
- Keychain prompts: [docs/keychain-prompts.md](docs/keychain-prompts.md)
- CLI configuration: [docs/cli-configuration.md](docs/cli-configuration.md)
- Widgets: [docs/widgets.md](docs/widgets.md)
- Architecture: [docs/architecture.md](docs/architecture.md)
- Refresh loop: [docs/refresh-loop.md](docs/refresh-loop.md)
- Status polling: [docs/status.md](docs/status.md)
- Sparkle updates: [docs/sparkle.md](docs/sparkle.md)
- Packaging: [docs/packaging.md](docs/packaging.md)
- Development: [docs/DEVELOPMENT.md](docs/DEVELOPMENT.md)
- Release checklist: [docs/RELEASING.md](docs/RELEASING.md)
- Changelog: [CHANGELOG.md](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+.

```bash
./Scripts/package_app.sh        # builds CodexBar.app in-place with ad-hoc signing
open CodexBar.app
```

Dev loop:
```bash
./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 summaries
```

CLI install:
```bash
# after installing CodexBar.app in /Applications
./bin/install-codexbar-cli.sh
```

## Related
- ✂️ [Trimmy](https://github.com/steipete/Trimmy) — “Paste once, run once.” Flatten multi-line shell snippets so they paste and run.
- 🧳 [MCPorter](https://mcporter.dev) — TypeScript toolkit + CLI for Model Context Protocol servers.
- 🧿 [oracle](https://askoracle.dev) — Ask the oracle when you're stuck. Invoke GPT-5 Pro with a custom context and files.

## Looking for a Windows version?
- [Win-CodexBar](https://github.com/Finesssee/Win-CodexBar)

## Linux desktop integration?
- [codexbar-waybar](https://github.com/Marouan-chak/codexbar-waybar) — Waybar custom module + GTK4 popover for Hyprland / Sway / other Wayland compositors, built on top of the bundled Linux CLI.
- [codexbar-cosmic-applet](https://github.com/andrew-verde/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](https://extensions.gnome.org/extension/9841/codexbar/) — GNOME Shell extension that brings CodexBar usage into the desktop panel.
- [codexbar-cinnamon-applet](https://github.com/jacobcalvert/codexbar-cinnamon-applet) — Linux Mint Cinnamon panel applet powered by CodexBar's JSON output.
- [noctalia-codex-usage](https://github.com/rayoplateado/noctalia-codex-usage) — Noctalia/Quickshell plugin that shows Codex 5-hour and weekly usage limits, built on top of the bundled Linux CLI.
- [KodexBar](https://github.com/tylxr59/KodexBar) — KDE Plasma widget that shows CodexBar usage in the Plasma panel, built on top of the bundled Linux CLI.
- [codexbar-plasmoid](https://github.com/psimaker/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](https://github.com/Lucenx9/codexbar-plasma) — KDE Plasma 6 widget with multi-provider views, account selection, cost history, notifications, configurable providers, and installable `.plasmoid` releases, powered by the bundled Linux CLI.
- [CodexBar Meter](https://github.com/noctalia-dev/community-plugins/tree/main/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](https://github.com/enieuwy/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](https://github.com/lenadweb/stream-deck-ai-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](https://github.com/ryoppippi/ccusage) (MIT), specifically the cost usage tracking.

## License
MIT • Peter Steinberger ([steipete](https://twitter.com/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 `usage` and `cost` commands.
- Errors appear as payload entries with `error` set.
- Global/CLI errors use `provider: "cli"` and `source: "cli"`.

```json
{
  "provider": "cli",
  "source": "cli",
  "error": { "code": 1, "message": "...", "kind": "config" }
}
```

## Config validation rules
- `source` must be in provider descriptor `fetchPlan.sourceModes`.
- `apiKey` only valid when provider supports `.api`.
- `cookieSource` only valid when provider supports `.web`/`.auto`.
- `region` only for `zai` or `minimax` with known values.
- `workspaceID` only for `opencode`.
- `tokenAccounts` only for providers in `TokenAccountSupportCatalog`.

## 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
1. **Add validation types**
   - `CodexBarConfigIssue` + `CodexBarConfigValidator` in `CodexBarCore/Config`.
   - Keep file <500 LOC.
2. **Hook validation into CLI**
   - New `config validate` command.
   - `--json-only` emits JSON array of issues.
3. **Unify CLI error reporting**
   - Parse `--json-only` early.
   - Route all exits through a JSON-aware reporter.
   - Use provider-scoped errors where possible.
4. **Split CLIEntry.swift**
   - Extract helpers + payload structs into dedicated files (<500 LOC each).
5. **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`.
6. **Provider toggles cleanup**
   - Remove unused `ProviderToggleStore` + tests; keep migrator path for legacy toggles.
7. **Tests**
   - CLI json-only error payloads (invalid source, invalid provider selection).
   - Config validation (bad region/source/apiKey field).
   - SettingsStore order/toggle invariants still pass.
8. **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 usage` when the Amp CLI is installed and signed in.
- **Access token support**: Uses `AMP_API_KEY` or 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

1. Open **Settings → Providers**
2. Enable **Amp**
3. 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)

1. Open `https://ampcode.com/settings`
2. Copy a `Cookie:` header from your browser’s Network tab
3. Paste it into **Amp → Cookie Source → Manual**

## How it works

- Runs `amp usage` first in automatic mode
- Calls `POST https://ampcode.com/api/internal?userDisplayBalanceInfo` with 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:

1. The Antigravity 2.0 app's local `language_server` (preferred when the app is open).
2. The `agy` CLI's embedded HTTPS localhost server (preferred over the IDE because it exposes richer quota data).
3. The Antigravity IDE extension `language_server` (used after `agy` CLI because current IDE local payloads only expose session/model quota data).
4. 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-in
`agy`, 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 to
`GetUserStatus`, 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.app` or overridden with `ANTIGRAVITY_OAUTH_CLIENT_ID` and `ANTIGRAVITY_OAUTH_CLIENT_SECRET`.
- A successful login writes the latest shared credentials to `~/.codexbar/antigravity/oauth_creds.json` and upserts a token-account entry for the Google account.
- Each token-account entry stores serialized `AntigravityOAuthCredentials` and is injected into remote fetches through `ANTIGRAVITY_OAUTH_CREDENTIALS_JSON`.
- When a token account is selected, the OAuth fetcher uses that account before falling back to the shared credentials file.
  In `auto` mode the ambient Antigravity app, `agy` CLI, 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 (see
  `AntigravitySelectedAccountGuard`). If no account is selected/injected, `auto` includes OAuth only when the legacy
  shared credentials file already exists. Explicit `cli`/`oauth` source modes stay authoritative and are not re-checked.
- Removing the last saved token account that matches `~/.codexbar/antigravity/oauth_creds.json` deletes 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:loadCodeAssist`
- `POST https://cloudcode-pa.googleapis.com/v1internal:onboardUser`
- `POST https://cloudcode-pa.googleapis.com/v1internal:fetchAvailableModels`
- `POST https://cloudcode-pa.googleapis.com/v1internal:retrieveUserQuota`
- `POST 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:

1. **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 or `agy` CLI process: a lower-information IDE payload should not mask
     `agy`'s richer quota summary, and a stale or still-initializing `agy` can accept the
     connection before it is ready. `agy` is 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 by `isRunning()` for status reporting):
     - the **Antigravity app** language server: process names such as `language_server`, `language_server_macos`,
       `language_server_macos_arm`, or `language-server` plus
       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_cli` path segment, or the
       `agy` binary (path-anchored so unrelated arguments/binaries do not match).
   - 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 legacy `GetUserStatus`
     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, otherwise `missingCSRFToken`
         is reported (unchanged behavior).
       - **CLI** matches accept an empty token, because the CLI's language server
         exposes no `--csrf_token` flag and requires none.
     - `--extension_server_port ` (HTTP fallback; app/IDE only).
     - `--extension_server_csrf_token <token>` (preferred HTTP fallback token when present).

2. **Port discovery**
   - Command: `lsof -nP -iTCP -sTCP:LISTEN -a -p `.
   - All listening ports are probed.

3. **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.

4. **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`.

### 2) `agy` CLI HTTPS source

When source mode is `auto` or `cli` and the desktop local probe fails, CodexBar resolves `agy` via:

- `ANTIGRAVITY_CLI_PATH`
- `PATH` / 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-user `agy` at 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: `agy` is 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-launched `agy`.

### 3) Antigravity IDE local probe

When the Antigravity 2.0 app and `agy` CLI are unavailable, CodexBar probes Antigravity IDE language servers with
`AntigravityStatusProbe(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 in
`auto` 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: antigravity`
  - `extensionName: antigravity`
  - `locale: en`
  - `ideVersion: unknown`

## Parsing and model mapping
- Preferred source fields:
  - `response.groups[].displayName`
  - `response.groups[].buckets[].bucketId`
  - `response.groups[].buckets[].displayName`
  - `response.groups[].buckets[].remaining.remainingFraction`
  - `response.groups[].buckets[].description`
- Legacy source fields:
  - `userStatus.cascadeModelConfigData.clientModelConfigs[].quotaInfo.remainingFraction`
  - `userStatus.cascadeModelConfigData.clientModelConfigs[].quotaInfo.resetTime`
- Preferred quota summary UI:
  - Render `Gemini Session`, `Gemini Weekly`, `Claude + GPT Session`, and `Claude + GPT Weekly` as named windows.
  - Keep Antigravity's bucket description as reset prose; infer `windowMinutes` from the bucket ID/display name.
  - Use the most constrained known bucket as the compact/menu-bar metric.
- Legacy user-facing quota groups:
  - `Gemini` groups Gemini Pro and Gemini Flash text models.
  - `Claude + GPT` groups 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.
- `resetTime` parsing:
  - ISO-8601 preferred; numeric epoch seconds as fallback.
- Identity:
  - `accountEmail` and `planName` only from `GetUserStatus`.

## UI mapping
- Provider metadata:
  - Display: `Antigravity`
  - Labels: `Gemini` (primary), `Claude + GPT` (secondary)
- 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
  in `extraRateWindows` for reset context and are marked with `usageKnown: false`; clients should not render their
  `usedPercent` as 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
  `idle` instead. The `codexbar serve` web UI skips those rows, so the web card matches the menu without repeating
  the family rule in JavaScript. See `docs/dashboard-api.md`.

## Constraints
- Internal protocol; fields may change.
- Requires `lsof` for 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.swift`
- `Sources/CodexBarCore/Providers/Antigravity/AntigravityProviderDescriptor.swift`
- `Sources/CodexBarCore/Providers/Antigravity/AntigravityStatusProbe.swift`
- `Sources/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 for `codexbar` usage/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` → `UsageStore` refresh 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 status` when 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

1. Open **Settings → Providers**
2. Enable **Augment**
3. 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

1. Check the menu bar for the Augment icon
2. Click the icon to see your current usage
3. If you see "Log in to Augment", visit [app.augmentcode.com](https://app.augmentcode.com) and sign in

## How It Works

### Cookie Import

The provider searches for Augment session cookies in this order:

1. **Chrome Beta** (if installed)
2. **Chrome** (if installed)
3. **Chrome Canary** (if installed)
4. **Arc** (if installed)
5. **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` (account `cookie.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**:
1. Open [app.augmentcode.com](https://app.augmentcode.com) in Chrome, Chrome Beta, or Arc
2. Sign in to your Augment account
3. Return to CodexBar and click "Refresh" in the menu

### "Session has expired"

**Cause**: Your browser session expired and automatic refresh failed.

**Solution**:
1. Visit [app.augmentcode.com](https://app.augmentcode.com)
2. Log out and log back in
3. Return to CodexBar - it will automatically import fresh cookies
4. 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:
1. Check that Chrome Beta is installed at `/Applications/Google Chrome Beta.app`
2. Verify you're logged into Augment in Chrome Beta
3. Try switching to regular Chrome temporarily

### Manual Cookie Import

If automatic import fails, you can manually paste cookies:

1. Open Chrome DevTools (⌘⌥I)
2. Go to **Application → Cookies → https://app.augmentcode.com**
3. Copy all cookie values
4. Format as: `cookie1=value1; cookie2=value2; ...`
5. In CodexBar: **Settings → Providers → Augment → Cookie Source → Manual**
6. Paste the cookie header

## Debug Mode

To see detailed cookie import logs:

1. Open **Settings → Debug**
2. Find **Augment** in the provider list
3. 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.com` domains 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

1. Keepalive checks cookie expiration every 1 minute
2. If expiration is within 5 minutes, triggers refresh
3. Pings `/api/auth/session` to trigger cookie update
4. Waits 1 second for browser to update cookies
5. Re-imports fresh cookies from browser
6. Logs success/failure for debugging

## Related Documentation

- [Provider Authoring Guide](provider.md) - How to create new providers
- [Development Guide](DEVELOPMENT.md) - 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](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 `.auto` order. That inconsistency is tracked in
  [docs/refactor/claude-current-baseline.md](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-credentials` may contain only MCP server OAuth state (`mcpOAuth`) with no `claudeAiOauth`. CodexBar treats that as an OAuth configuration error, does not run background delegated `claude /status` refresh, and surfaces re-auth guidance. Use Web or CLI usage source, or restore a valid Claude OAuth keychain entry. See #1844.
- Requires `user:profile` scope (CLI tokens with only `user:inference` cannot call usage).
- Endpoints:
  - `GET https://api.anthropic.com/api/oauth/usage`
  - `GET 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 when `five_hour` is absent or has no utilization.
  - `seven_day_sonnet` / `seven_day_opus` → model-specific weekly window.
  - `limits[].weekly_scoped` → model-specific weekly windows; generic `All models` scopes 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 a
  `claude-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-credentials` Keychain 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.json` visible as stale data and shows their capture age instead of blanking the quota bars.
- Plan inference: `subscriptionType` is preferred when present; `rate_limit_tier` falls back to
  Max/Pro/Team/Enterprise. When a Max `rate_limit_tier` carries 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 `sessionKey` cookies 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](refactor/claude-current-baseline.md).
- Cookie source order:
  1) Safari: `~/Library/Cookies/Cookies.binarycookies`
  2) Chrome/Chromium forks: `~/Library/Application Support/Google/Chrome/*/Cookies`
  3) Firefox: `~/Library/Application Support/Firefox/Profiles/*/cookies.sqlite`
- Domain: `claude.ai`.
- Cookie name required:
  - `sessionKey` (value prefix `sk-ant-...`).
- Cached cookies: Keychain cache `com.steipete.codexbar.cache` (account `cookie.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](claude-multi-account-and-status-items.md).

- Setup: Preferences → Providers → Claude → "Read accounts from claude-swap", then set the path to the
  [`cswap`](https://github.com/realiti4/claude-swap) executable (for example `~/.local/bin/cswap`).
- Behavior: on each Claude refresh, CodexBar runs `cswap --list --json` independently of the ambient Claude fetch (no
  shell, fixed arguments, bounded runtime and output), requires `schemaVersion == 1`, and parses only slot number,
  active state, usage status, email (display only), display-only `organizationName` (always present, may be empty),
  optional display-only `alias` when non-empty, the 5-hour/7-day windows, and optional display-only model-scoped
  weekly windows from `usage.scoped`. Identity stays `claude-swap:<slot>`; organization name and alias are never
  used as identity. When two or more slots share an email, cards append ` · organizationName` or ` · 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 cards` show 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 cards` keeps 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 set
  `claudeSwapShowSingleAccount: true` on 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 is `claude-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 auto` remains eligible, while `--account`, `--account-index`, `--all-accounts`, and
  explicit non-auto source flags bypass the adapter. `codexbar usage` and serve `/usage`/`/cost` remain unchanged,
  while `codexbar dashboard` and `GET /dashboard/v1/snapshot` additionally nest one entry per swap account in the
  Claude provider row, with full identity by default or redacted email local parts when `--identity redacted` is 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 distinct `Claude (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. When
  `unavailable` means 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 already `unavailable` with 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 `claude` in 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/ClaudeProbe` with local Claude settings that disable
  deep-link URL handler registration during headless probes.
- After transient probes exit, CodexBar removes Claude Code `.jsonl` session artifacts for that dedicated
  `ClaudeProbe` project directory so background `/usage` polling does not clutter the user's Claude project history.
- Command flow:
  1) Start CLI with `--allowed-tools ""` (no tools).
  2) Auto-respond to first-run prompts (trust files, workspace, telemetry).
  3) Send `/usage`, wait for rendered panel; send Enter retries if needed.
  4) Optionally send `/status` to extract identity fields.
- Parsing (`ClaudeStatusProbe`):
  - Strips ANSI, locates "Current session" + "Current week" headers.
  - Extracts percent left/used and reset text near those headers.
  - Parses `Account:` and `Org:` 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-sessions` points to shared CLI session JSONL by
      `cliSessionId`; metadata-only directories are not treated as usage sources.
  - Supported pi-compatible sessions:
    - `~/.pi/agent/sessions/**/*.jsonl`
    - `~/.omp/agent/sessions/**/*.jsonl`
- Files: `**/*.jsonl` under the native project roots, discovered Claude Desktop project roots,
  plus supported pi-compatible session files.
- Parsing:
  - Native Claude logs parse lines with `type: "assistant"` and `message.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 `anthropic` assistant 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.
- 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`

## 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`)

```mermaid
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`)

```mermaid
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)

```mermaid
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)

```mermaid
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)

```mermaid
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`)

```mermaid
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)

```mermaid
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)

```mermaid
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)

```mermaid
stateDiagram-v2
    [*] --> PromptAllowed
    PromptAllowed --> CooldownBlocked: recordDenied()
    CooldownBlocked --> CooldownBlocked: shouldAllowPrompt() before deniedUntil
    CooldownBlocked --> PromptAllowed: time >= deniedUntil (6h)
```

### OAuth Refresh Failure Gate (Now)

```mermaid
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: recordSuccess
```

## Key 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 `CodexBarCLI` to `/usr/local/bin/codexbar` and `/opt/homebrew/bin/codexbar`.
- From the repo, after installing `CodexBar.app` in `/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`
- Extract and run `./codexbar` (symlink) or `./CodexBarCLI`.

```
tar -xzf CodexBarCLI-v0.17.0-macos-x86_64.tar.gz
./codexbar --version
./codexbar usage --format json --pretty
```

## Build
- `./Scripts/package_app.sh` (or `./Scripts/compile_and_run.sh`) bundles `CodexBarCLI` into `CodexBar.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
- `codexbar` defaults to the `usage` command.
  - `--format text|json|toon` (default: text).
  - JSON uses the generic `usage.details` array for provider-specific information. Each section contains an optional
    `title`, `rows` (`label`, `value`, and optional `secondaryValue`), and an optional `bars` or `line` chart. The same
    shape is returned by `GET /usage` from `codexbar serve`.
  - Legacy provider-specific keys such as `openRouterUsage`, `clawRouterUsage`, and `sub2APIUsage` are not compatibility
    aliases; clients must read `usage.details`. Unknown legacy keys in cached or iCloud-synced snapshots are ignored
    when decoding.
  - `--format toon` emits the same payload as `--format json` (and implies `--json`'s credits/no-color behavior),
    rendered as [TOON](https://github.com/toon-format/spec) instead: uniform arrays of scalar-only objects (for
    example `usage.details[].rows`) collapse into a compact `rows[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
    toon` is the only command that supports it; every other command still advertises and accepts only
    `--format text|json`, and treats `toon` like any other unrecognized value.
- `codexbar cost` prints 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). `--json` includes 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's `totals` and emits `provenance`/`coverage` on that provider object; Export JSON nests `tokenMix`, `provenance`, and `coverage` under `groups[]`.
  - OpenCodex appears as a separate `opencodex` payload only when **Include OpenCodex usage logs** is on in Settings. That payload does not invent `projects` (OpenCodex logs have no workspace path).
  - `--refresh` ignores cached scans.
  - `--provider-native-only` is experimental and excludes pi and OMP session mirrors from Claude and Codex history.
- `codexbar cards` prints 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.
  - `--brief` renders a compact table (Provider / Usage / Reset) instead of the card grid.
  - Stdout is always rendered text; `--json-output` only 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
    `claudeSwapShowSingleAccount` enabled—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 auto` remains 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 unless `claudeSwapShowSingleAccount` is 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 distinct
    `Claude (claude-swap)` failure footer entry, and makes the command exit non-zero.
  - This precedence is cards-only: `codexbar usage` and `codexbar serve` keep their existing output cardinality.
  - Honors `$COLUMNS` for layout; falls back to 80 columns. Use `--no-color` for 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.
- `codexbar dashboard` prints 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 redacted` hides 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-output` logs go to stderr.
  - `--pretty` formats the document. `--timeout <seconds>` accepts `0...86400`, defaults to `30`, and uses `0` to disable the command deadline.
  - `--output ` atomically 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.md` for the shared payload contract.
- `codexbar serve` starts 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 `--identity` is 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 redacted` or `--identity full` to pin the mode and ignore the app setting, especially when responses cross a network.
  - `--host <host>` accepts `localhost` or an IPv4 address and defaults to `127.0.0.1`; `localhost` is normalized to `127.0.0.1`. Binding a non-loopback host requires a dashboard token **and** `--allow-plain-http` (see `docs/dashboard-api.md` for the threat model).
  - `--port ` defaults to `8080`.
  - `--refresh-interval <seconds>` defaults to `60` and controls the in-memory response cache TTL.
  - `--request-timeout <seconds>` defaults to `30` and bounds each request before returning `504 Gateway Timeout`; use `0` to 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 for `GET /dashboard/v1/snapshot`. Prefer the `CODEXBAR_DASHBOARD_TOKEN` environment variable (it wins over the flag; a flag value leaks via `ps`). Empty or whitespace-only tokens are startup errors. Without a token the snapshot route fails closed with `401`.
  - On a **non-loopback** host the token gates **all data routes** — `/usage`, `/cost`, and `/dashboard/v1/snapshot` all require `Authorization: Bearer YOUR_TOKEN`, so account data is never exposed to the network unauthenticated. The static web UI at `/` and `/health` are always open. On the default loopback bind, `/usage` and `/cost` stay unauthenticated.
  - `--allow-plain-http` is the explicit acknowledgment that the bearer token crosses the network **in cleartext on every request** when serving on a non-loopback host. `serve` refuses 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, `serve` returns the last-good response immediately while rebuilding it in the background; `--refresh-interval 0` keeps every request blocking.
  - The default loopback bind rejects non-loopback `Host` headers; a configured non-loopback `--host` additionally 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` (plus `provider=` and `detail=<full|shell>`).
  - `GET /dashboard/v1/snapshot` requires `Authorization: Bearer YOUR_TOKEN`; responses (and all `401`s) carry `Cache-Control: no-store`. The token is never accepted via query string. See `docs/dashboard-api.md` for the payload contract.
  - `GET /health` returns `{"status":"ok"}` plus a `version` field with the running build (e.g. `"0.37.2"`) when resolvable; clients can compare it against `codexbar --version` to detect a `serve` process still running an older binary after an update.
  - Codex usage responses include every visible Codex account, matching the menu bar switcher.
- `codexbar cache clear` clears local CodexBar caches.
  - `--cookies` removes cached browser-cookie headers from the CodexBar Keychain cache.
  - `--cookies --provider ` removes browser-cookie cache entries for that provider, including managed Codex account scopes.
  - `--cost` removes local cost-usage scan caches.
  - `--all` clears both cookies and cost caches. `--provider` is cookie-only and cannot be combined with `--cost` or `--all`.
- `codexbar cookie refresh` ignores 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 `--provider ` or `--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.
- `codexbar guard --provider ` gates automation on one provider's remaining quota.
  - `--min-remaining ` sets the inclusive threshold (default: `10`; valid range: `0...100`).
  - `--window session|weekly` selects the primary/session window or secondary/weekly window (default: `session`).
  - `--timeout <seconds>` bounds the complete fetch (range: `0...86400`; default: `60`; `0` disables this guard-level deadline while provider-specific timeouts still apply).
  - `--json` emits the provider, window, remaining quota, threshold, decision, unavailable reason, and exit code; add `--pretty` for formatted JSON.
  - Stable guard exit codes: `0` means safe, `1` means below threshold, `64` (`EX_USAGE`) means invalid arguments, and `69` (`EX_UNAVAILABLE`) means the quota could not be checked or the selected window is unavailable. `--fail-open` changes only unavailable results from `69` to `0`; JSON still reports `decision: "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 all` to 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).
- `--source <auto|web|cli|oauth|api>` (default: `auto`).
    - `auto`: provider-specific fallback order from `docs/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 `source` reflects 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 `/tmp` when 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_KEY` is 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`/`web` modes 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 validate` checks the resolved config file for invalid fields.
  - `--format text|json`, `--pretty`, and `--json-only` are supported.
  - Warnings keep exit code 0; errors exit non-zero.
- `codexbar config dump` prints the normalized config JSON.
- `codexbar hooks list` shows the local hook configuration; `--format json` and `--pretty` are supported.
- `codexbar hooks enable|disable` changes the explicit top-level opt-in switch in the local config file.
- `codexbar hooks test <event> --provider ` invokes matching enabled rules with a representative event. Hook
  commands run directly without a shell and receive `CODEXBAR_*` variables plus JSON on stdin. `--format json` and
  `--json-only` return structured per-rule results. See
  `docs/configuration.md#external-event-hooks` for the event, payload, timeout, and security contract.
- `codexbar hooks watch` polls 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. Default `300`, minimum `60`; 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 `watch` as 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 reports
    `refresh_failed` with 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 either `sessionKey` cookies or OAuth access tokens (`sk-ant-oat...`).
OAuth usage requires the `user:profile` scope; 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` (`local` for Claude/Codex log scans, `web` for Cursor dashboard data), `updatedAt`
- `sessionTokens`, `sessionCostUSD`
- `last30DaysTokens`, `last30DaysCostUSD`
- `historyCoverageIsEstablished`: `false` while a bounded Codex scan still has catch-up work pending; `true` once the requested history is covered.
- Cursor only: `meteredCostUSD` — what Cursor's plan actually deducts over the window, alongside the API-rate estimate in `last30DaysCostUSD`.
- `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`, `totalCost`
- `error`: 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: user@example.com
Plan: Pro

== Kilo (cli) ==
Credits: 60% left [=======-----]
40/100 credits
Plan: Kilo Pass Pro
Activity: Auto top-up: visa
Note: Using CLI fallback
```

### Sample output (JSON, pretty)
```json
{
  "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": "user@example.com",
      "accountOrganization": null,
      "loginMethod": "plus"
    },
    "accountEmail": "user@example.com",
    "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": "user@example.com",
    "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-color` or `NO_COLOR`/`TERM=dumb`.
- Copilot CLI queries require an API token via config `apiKey` or `COPILOT_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...` or `ANTHROPIC_ADMIN_KEY`).
- Codex CLI `auto` tries the OpenAI web dashboard, then Codex CLI RPC/PTy; the app’s Codex `auto` path prefers OAuth when credentials are present, then CLI.
- Claude CLI `auto` tries web, then CLI PTY; the app’s Claude `auto` path prefers OAuth, then CLI, then web.
- Kilo text output splits identity into `Plan:` and `Activity:` lines; in `--source auto`, resolved CLI fetches add
  `Note: 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.com` session 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 `openaiDashboard` JSON field is normally sourced from the app’s cached dashboard snapshot; `--source auto|web` refreshes it live via WebKit using a per-account cookie store.
- Future: optional `--from-cache` flag 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](https://starter.mintlify.com/quickstart)**

## Development

Install the [Mintlify CLI](https://www.npmjs.com/package/mint) to preview your documentation changes locally. To install, use the following command:

```
npm i mint
```

Run the following command at the root of your documentation, where your `docs.json` is located:

```
mint dev
```

View your local preview at `http://localhost:3000`.

## Publishing changes

Install our GitHub app from your [dashboard](https://dashboard.mintlify.com/settings/organization/github-app) 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 update` to 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`.

### Resources
- [Mintlify documentation](https://mintlify.com/docs)
- [Mintlify support](https://mintlify.com/support)