A utility for managing isolated Codex CLI profiles and monitoring quota usage across multiple Codex environments.
Includes JSON output for automation and a live terminal dashboard.
Note: This is an independent community tool. It is not affiliated with or endorsed by OpenAI.
- Python 3.11+
- Official Codex CLI available as
codex
Install Codex CLI:
npm install -g @openai/codexor
brew install codexTested with codex-cli 0.136.0.
Install from PyPI:
pip install codex-quotaInstall from source:
git clone https://github.com/ssh-den/codex-quota.git
cd codex-quota
python -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -e .# Initialize (creates config and profiles directory)
codex-quota init
# Add a profile and log in
codex-quota profile add personal --login
# Check quota status
codex-quota status
# Force an auth keepalive refresh for CI or cron
codex-quota wake
# Launch the live terminal dashboard
codex-quota tuiAuthentication is fully delegated to the official Codex CLI. codex-quota never reads, stores, or transmits credentials. It sets CODEX_HOME and calls codex on your behalf.
Profile and config directories are created with 0700 permissions on POSIX systems so auth.json and related state are not exposed by a weak umask on multi-user machines.
~/.codex-quota/profiles/
├── personal/
├── work/
└── testing/
~/.config/codex-quota/
└── config.json
The filesystem is the source of truth. Profiles are discovered dynamically. The configuration file stores application settings only and does not maintain a profile registry.
Default configuration:
{
"profiles_dir": "~/.codex-quota/profiles",
"codex_bin": "codex",
"default_model": "gpt-5.4-mini",
"reasoning_effort": "low",
"refresh_seconds": 30.0
}Edit ~/.config/codex-quota/config.json to change model defaults or reasoning effort.
On successful status-time auth keepalive, codex-quota also stores a per-profile auth_refresh map in this same config file using UTC ISO-8601 timestamps ending in Z. This state is created lazily, preserves unknown config keys, and never inspects or modifies auth.json.
codex-quota initBehavior:
- Create config directory if missing
- Create profiles directory if missing
- Create
config.jsonif missing - Preserve existing configuration
- Verify Codex CLI installation
- Print detected Codex version
- Discover existing profiles by scanning
~/.codex-quota/profiles/*
Overwrite configuration:
codex-quota init --overwrite-configRun bootstrap plus quota verification (--check is an alias):
codex-quota init --verifyList profiles:
codex-quota profile listAdd profile:
codex-quota profile add personalCreate and login immediately:
codex-quota profile add personal --loginCreate and force device-code auth on headless or remote machines:
codex-quota profile add personal --login --device-authPrint profile path:
codex-quota profile path personalRemove profile:
codex-quota profile remove personalForce remove (non-interactive):
codex-quota profile remove personal --yesProfile names are validated. Path traversal, path separators, absolute paths, whitespace, and suspicious characters are rejected.
codex-quota login personalEquivalent to:
CODEX_HOME="$HOME/.codex-quota/profiles/personal" codex loginUse device authorization instead of the local browser callback flow:
codex-quota login personal --device-authCreate the profile automatically if missing:
codex-quota login personal --createCombine both when bootstrapping a remote profile in one step:
codex-quota login personal --create --device-authAll profiles:
codex-quota statusSingle profile:
codex-quota status personalJSON output:
codex-quota status --jsonStatus collection opportunistically performs an auth keepalive through the official Codex App Server before reading rate limits. When the last successful refresh for a profile is 4 hours old or older, codex-quota calls account/read with refreshToken=true. This refresh is best-effort:
- Auth-related failures are classified as
AUTH_REQUIRED - Transient refresh failures do not block a later successful rate-limit read
- No separate maintenance command is required for normal operation
Example human-readable output:
Profile Status 5h Left Week Left
personal OK 99% 69%
work AUTH_REQUIRED
Default JSON is safe for CI logs and automation:
- No absolute profile paths
- No raw
rateLimitspayload - No plan or credits metadata unless explicitly requested
Machine-readable status output includes these stable top-level fields per profile:
statusfor explicit classifications such asAUTH_REQUIREDerrorfor the raw internal/backend error string when presentrate_limitsfor normalized quota data
Opt in to the extra fields only when you need them:
codex-quota status --json --json-paths --json-rawQuota lockout detection uses rateLimitReachedType != null. The tool does not infer lockout solely from usedPercent == 100.
Automation-oriented health check:
codex-quota checkSingle profile:
codex-quota check personalExit codes:
| Code | Meaning |
|---|---|
| 0 | Selected profiles are authenticated, readable, and not quota-blocked |
| 2 | Codex missing, auth missing/expired, app-server failure, quota block, or no selected profiles found |
Force the official auth keepalive even when the last successful refresh is still recent:
codex-quota wakeSingle profile:
codex-quota wake personalThis is mainly useful for scheduled CI or cron jobs that want to keep managed auth warm proactively. wake follows the same login_status() -> account/read(refreshToken=true) -> account/rateLimits/read pipeline as check, prints the same human-readable table, and exits with the same codes.
Run Codex under a selected profile:
codex-quota exec personal "Reply with exactly: ok"Disable forced JSON output:
codex-quota exec personal "Say hello" --rawexec now respects the user's existing Codex config and rules by default instead of disabling them.
Launch:
codex-quota tuiCustom refresh interval:
codex-quota tui --refresh 15The TUI uses Textual and dynamically discovers profiles from the filesystem.
Available commands:
refresh
login <profile> [--device-auth]
exec <profile> <prompt>
quit
Status collection launches:
CODEX_HOME=<profile-home> codex app-server --stdioThen performs the following JSON-RPC sequence:
1. initialize
2. initialized
3. account/read {"refreshToken": true} when auth refresh is due
4. account/rateLimits/read
Responses are normalized for display and safe JSON output. Human-readable tables show AUTH_REQUIRED for auth failures instead of large backend payloads. Raw rateLimits values are available only through explicit --json-raw, while raw backend error strings remain available in JSON output.
MIT License