codex-usage
Check OpenAI Codex / ChatGPT subscription usage — queries rate-limit windows, plan type and credits using a local OAuth token from fir or the Codex CLI.
- License 许可
- MIT
- 所属仓库
- kfet/fir
- 最近更新
- 2026-11-12
- Stars
- ★ 1
- Forks
- 0
01 前言 Front Matter
- name
- codex-usage
- builtin
- true
- override
- true
- description
- Check OpenAI Codex / ChatGPT subscription usage — queries rate-limit windows, plan type and credits using a local OAuth token from fir or the Codex CLI.
02 资源文件 1
- 脚本scripts/usage.sh8.8 KB
03 SKILL.md 正文
Codex Usage Skill
Query the ChatGPT backend usage endpoint to see Codex rate-limit utilization (the 5-hour / weekly / monthly windows a plan happens to have), plan type, and credit balance, using a ChatGPT OAuth Bearer token.
Background
The endpoint is GET https://chatgpt.com/backend-api/wham/usage. It needs an OAuth token issued by a ChatGPT login (what fir auth login openai-codex stores) — a platform sk-... API key will not work.
It is also fussy about headers: Authorization, chatgpt-account-id, originator: codex_cli_rs and a codex_cli_rs/<version> User-Agent. Omitting the User-Agent gets you a Cloudflare 403 HTML page rather than JSON.
The same numbers also ride back as x-codex-* response headers (x-codex-plan-type, x-codex-primary-used-percent, x-codex-secondary-used-percent, x-codex-primary-window-minutes, x-codex-primary-reset-at, x-codex-credits-*) on any real POST /backend-api/codex/responses call — but reading usage that way costs a model call, so this skill uses the GET endpoint.
Dead ends — do not retry these
/backend-api/codex/usage, /backend-api/codex/rate_limits, /backend-api/my/rate_limits and /backend-api/accounts/check/... all return Cloudflare 403. api.openai.com/v1/usage rejects the OAuth JWT outright. wham/usage is the one that works.
Multiple accounts
fir can store more than one Codex OAuth login at a time. In auth.json the bare openai-codex key is the default account, and additional accounts live under composite slot keys openai-codex#<accountId>.
With no explicit token, the script reports usage for every stored Codex account, one labelled section each:
▸ you@example.com
Plan plus
Weekly 34% — resets Sep 10, 4:49 PM EEST
5-Hour 7% — resets Sep 3, 6:00 PM EEST
Credits $12.40 balance
▸ work@acme.com
Plan free
Monthly 2% — resets Sep 30, 11:39 AM EEST
A failure on one account (e.g. an expired token) is reported under its header and does not abort the others; the script exits non-zero if any account failed. When only one account is stored, the section header is omitted.
Step 1 — Run the Script
The script auto-detects your OAuth token(s) from known credential files:
bash "$SKILL_DIR/scripts/usage.sh"
You can also pass a token explicitly:
bash "$SKILL_DIR/scripts/usage.sh" "$TOKEN"
# or
TOKEN="$TOKEN" bash "$SKILL_DIR/scripts/usage.sh"
--raw prints the full JSON response; --verbose prints the whole response body when a request fails.
There is no cached mode — unlike Anthropic usage, no fir extension maintains a Codex usage cache, so every run is a live call.
Where auto-detection looks
| Tool | File | Key(s) |
|---|---|---|
| fir | ~/.config/fir/auth.json |
.["openai-codex"].access + .extra.accountId (default) plus every openai-codex#<account> slot |
| Codex CLI | ~/.codex/auth.json |
.tokens.access_token / .tokens.account_id |
fir accounts take precedence; the Codex CLI credential is only used as a fallback when no fir Codex account is stored. Override the paths with FIR_AUTH_FILE=... / CODEX_AUTH_FILE=....
When a stored account has no accountId recorded (and for an explicitly supplied token), the script recovers it from the access token itself — it is a JWT carrying chatgpt_account_id under the https://api.openai.com/auth claim.
Manual fallback
# default fir account
TOKEN=$(jq -r '.["openai-codex"].access' ~/.config/fir/auth.json 2>/dev/null)
ACCOUNT=$(jq -r '.["openai-codex"].extra.accountId' ~/.config/fir/auth.json 2>/dev/null)
# list all stored Codex accounts (default + #account slots)
jq -r 'to_entries[] | select(.key=="openai-codex" or (.key|startswith("openai-codex#"))) | "\(.key)\t\(.value.label // "")"' ~/.config/fir/auth.json
# or Codex CLI
TOKEN=$(jq -r '.tokens.access_token' ~/.codex/auth.json 2>/dev/null)
curl -s https://chatgpt.com/backend-api/wham/usage \
-H "Authorization: Bearer $TOKEN" \
-H "chatgpt-account-id: $ACCOUNT" \
-H "originator: codex_cli_rs" \
-H "User-Agent: codex_cli_rs/0.56.0"
Step 2 — Interpret the Response
Windows are named from their declared length (limit_window_seconds), not from which slot they arrive in: 18000s → 5-Hour, 604800s → Weekly, 2592000s → Monthly. Which windows exist depends on the plan — a free plan typically reports only primary_window (monthly), while paid plans populate both primary_window (weekly) and secondary_window (5-hour) and carry a non-null credit balance. Any additional_rate_limits (prefixed Extra) and code_review_rate_limit (prefixed Review) are printed the same way.
Example output:
Plan plus
Weekly 34% — resets Sep 10, 4:49 PM EEST
5-Hour 7% — resets Sep 3, 6:00 PM EEST
Credits $12.40 balance
Status rate limit reached (secondary)
| Field | Meaning |
|---|---|
plan_type |
free, plus, pro, team, … |
rate_limit.*_window.used_percent |
% of that window's limit used |
rate_limit.*_window.limit_window_seconds |
Window length — the source of its label |
rate_limit.*_window.reset_at |
Unix seconds when the window resets (shown in local time; falls back to reset_after_seconds) |
rate_limit.limit_reached / rate_limit_reached_type |
Whether a limit is currently hit, and which window |
credits.balance |
Credit balance in dollars (null when the plan has none; unlimited is a separate flag) |
credits.overage_limit_reached, spend_control.reached |
Surfaced on the Status line |
Most fields are nullable — a plan simply omits what it doesn't have, and the script skips anything absent.
04 同仓库更多 Skills
wt
Spawn a fresh fir agent in its own tmux session on its own git worktree. Use whenever the user wants the work — or the conversation about the work — to happen over there, not here. If the user points at this skill, or has directly loaded it in the context, that alone is the cue — spawn, don't inline.
wrap-up
Wrap up work on a project branch — review, fix, and simplify in a loop until clean, then ff-merge to main.
tmux-observer
Attach a tmux window to an already-running fir session — observe its transcript and drive its input via tmux send-keys. Use when you need to watch or steer another fir agent.
tmux-driver
Drive interactive CLIs (python, gdb, etc.) via named tmux sessions with multi-window support. Falls back to fir's built-in PTY driver when tmux is unavailable.
telegram-bot-setup
Set up a new Telegram bot channel for a fir project — install the telegram MCP, create a per-project state dir, drop in the bot token, wire .fir/mcp.json with TELEGRAM_STATE_DIR, pair the user, and verify. Use when the user asks to add, configure, or onboard a Telegram bot for a fir worktree/project.
sync
Sync with an upstream source repo — detect changed files, apply equivalent downstream edits, update the baseline, and report any new features or non-trivial changes picked up.