A cross-platform port of the CodexBar CLI from Swift to TypeScript. It ships as a plain Node package — installed and run with npm/node — and is bundled at build time with Bun. It mirrors the original CLI's command/flag surface, its text and JSON output shapes, and the core usage / pace / cost logic. macOS-only mechanisms are replaced by cross-platform equivalents: secrets live in the OS keychain (via keytar — Windows Credential Manager, macOS Keychain, Linux libsecret) and WebKit browser scraping becomes a clean file-based stub, so it runs on Windows, Linux, and macOS.
The Swift original lives in CodexBar/ (reference only). The port
lives under src/.
- Node ≥ 20.11 (developed against 22.x) — to run the CLI
- Bun ≥ 1.1 (developed against 1.3.x) — only to build the bundle and run the tests
- A system keychain for secret storage. macOS Keychain and Windows Credential Manager work out of
the box; on Linux install libsecret and a Secret Service provider (e.g.
libsecret-1-0+gnome-keyring). To bypass the keychain and use a file instead, setCODEXBAR_SECRETS_FILE=<path>.
npm install -g codexbar # exposes the `codexbar` command globallyThe only runtime dependency is keytar, a native Node-API
addon for system-keychain access. It ships prebuilt binaries, but npm must be allowed to run its
install script — on npm ≥ 11 approve it with npm approve-scripts keytar if prompted, otherwise
keychain access fails with a clear error and you can fall back to CODEXBAR_SECRETS_FILE.
To install from a checkout instead:
npm install # dependencies
bun run build # bundle src/ -> dist/index.js
npm install -g . # or: node dist/index.js <command>codexbar <command> [flags] # after a global install
node dist/index.js <command> [flags] # from a checkoutCommands (mirrors CodexBar/docs/cli.md):
| Command | Description |
|---|---|
usage (default) |
Provider usage windows, pace, credits, reset times (text or JSON) |
cost |
Local token cost usage from Claude/Codex session logs |
cards |
Terminal card grid (--brief for a compact table) |
sessions list / sessions focus |
List local agent sessions (focus is a platform stub) |
serve |
Localhost-only HTTP JSON server (/health, /usage, /cost) |
config validate|dump|providers|enable|disable|set-api-key |
Config management |
cache clear |
Clear cookie / cost caches |
diagnose |
Safe, redacted JSON diagnostic export |
Key flags: --provider <id\|both\|all>, --source auto\|web\|cli\|oauth\|api,
--format text\|json, --pretty, --status, --no-credits,
--account/--account-index/--all-accounts. Globals: -h/--help, -V/--version,
-v/--verbose, --no-color, --log-level, --json-output, --json-only.
Exit codes: 0 success · 1 unexpected · 2 provider missing · 3 parse/format · 4 timeout.
codexbar --version
codexbar usage --provider claude --source oauth --format json --pretty
codexbar cost --days 30 --format json --pretty
codexbar cards --brief
codexbar serve --port 8080 # GET http://127.0.0.1:8080/health
codexbar diagnoseThree providers are implemented as the reference set:
- Claude (reference) — reads
~/.claude/.credentials.jsonOAuth token and callsGET https://api.anthropic.com/api/oauth/usage. Exercises the full session/weekly/pace/identity model with no macOS dependency. - Codex —
~/.codex/auth.jsonOAuth file. - OpenRouter — API-key credits.
The provider registry accepts descriptors, so the remaining ~55 CodexBar providers can be added by
implementing the ProviderDescriptor contract in src/core/contracts.ts.
In: full CLI command/flag surface, text + JSON output parity, UsagePace and UsageFormatter
logic, config load/normalize/validate, local cost scanning + pricing, serve, and the 3 providers
above.
Out (by design): the SwiftUI macOS app, the WidgetKit extension, and WebKit browser-cookie
scraping. Secrets are stored in the OS keychain via keytar
(Windows Credential Manager / macOS Keychain / Linux libsecret), with a file-backed fallback
selected by CODEXBAR_SECRETS_FILE; browser-cookie import is a stub that still honors a manual
cookieHeader from config. --source cli (PTY probes) returns a clean "unsupported" error.
Bun is the dev toolchain (bundler + test runner); the shipped artifact targets Node only.
bun run typecheck # tsc --noEmit (strict)
bun test # bun's built-in test runner
bun run build # bundle to dist/index.js (--target=node, keytar left external)
bun run src/cli.ts <command> # run from source without buildingservebinds to127.0.0.1only, rejects non-loopbackHostheaders, and intentionally has no auth / TLS / CORS (loopback-only v1). Do not expose it to a network.diagnoseand logs never emit secret values — only booleans indicating presence.- Secrets are only ever sent in provider
Authorizationheaders. They are stored in the OS keychain by default; the file-backed fallback (CODEXBAR_SECRETS_FILE) is written with restrictive0600permissions.