/ai-usage — unified AI usage report
Run the platform launcher from this skill's directory: ./run.sh on macOS or Linux;
py -3 run.py on Windows, falling back to python run.py if py is unavailable.
Reformat its output into the table below. Nothing else. No browser, no stored
credentials, and no direct HTTP calls of your own.
/ai-usage fresh — same thing; the script always reads live. The flag only means "do not
reuse an answer from earlier in this conversation".
The first output line is ### ai-usage <version>. Put that version at the end of the
report's title line (USAGE — <time> · ai-usage <version>), so every report shows
which release produced it. This remains useful
for manually copied installations even though npx skills records source information
for installations it manages. Adding --version to the platform command prints the
version alone.
What must already be in place
Do not install anything and do not ask the user to log in. Just run the script and
report what comes back.
- Python 3.9+. The POSIX shim selects
python3 before python; Windows uses the
py -3 launcher when available. run.py then re-launches every probe with that exact
interpreter.
- At least one of
claude, codex, grok, already signed in. Zero of them is
still a valid run: every row prints not installed.
- Subprocess and network access. The host must allow local process launches, and
each installed provider CLI must be able to reach its own service. The Python code
does not make direct HTTP requests.
If a provider prints not installed, that is the whole answer for that row — say so
and move on. Do not suggest installing it unless the user asks. If a provider is
installed but its call fails, report the failure for that row and still print the
others; never substitute a number from memory or from an earlier run.
Where each number comes from
All three are live. No browser, no stored credentials, no cookie access.
Verified 2026-09-12 on macOS, and 2026-09-14 on a zh-TW Windows 11 machine (PowerShell,
Python 3.12) — that run surfaced and fixed a UnicodeDecodeError in the Claude probe
(see Limitations in README).
| Provider |
Method |
| Claude |
claude -p "/usage" < /dev/null — print mode routes the built-in slash command |
| ChatGPT |
codex app-server → JSON-RPC account/rateLimits/read — see codex_usage.py |
| Grok |
grok agent stdio → JSON-RPC _x.ai/billing — see grok_usage.py |
Two of the three are the CLI's own local agent server answering over stdio, so the
numbers are the same ones the TUI shows. Nothing is cached and nothing is scraped.
After each usage block, session_info.py <cli> prints four lines read from that CLI's
newest local session file (no network, nothing launched): session (last write time),
model, effort, then one option line per model that CLI offers (from its own
model cache: id, effort levels, default, vendor description), then one value line: the
shared model + effort pick from value.json, or value stale when a model was added
or dropped since that pick was made. A profile line follows a valid pick: what the shared set is
tuned for. These are what the CLI recorded for its
last turn, not config defaults. See the docstring in session_info.py for the files
and fields. A ? means the file did not carry that field — print ?, never a guess.
no local session means that CLI has never run here; print it as one row.
Reading the output
Claude — current session (5h) and current week. Claude omits the reset clock
when a window is 0% used; still print that row, without inventing a reset time.
ChatGPT — short (5h) and outer (7d), plus plan. Do not print a
"Usage limit resets" / "resets available" row. That count is not readable locally
(the app-server can spend one via account/rateLimitResetCredit/consume but has
no read counterpart). Do not print unknown (web only) either. credits.balance
is a different pool (paid top-ups) and is never that reset count.
Grok — weekly creditUsagePercent and the billing period end when the
percent is present. _x.ai/billing sometimes omits creditUsagePercent; the
probe then prints percent omitted. Print that week row without a bar or
percent, still print the reset clock, and do not invent 0%. Print prepaid /
on-demand only when any of those values is non-zero. Do not print
prepaid 0 / on-demand 0. Grok has only one window, not two — do not invent a
5h row for it. Do not pick Grok as the tool to use just because the percent is
missing.
Do not label any of these "redeem" unless the provider itself uses that concept.
Claude's current CLI response does not expose a reliable extra-usage field.
fast_mode_disabled_reason describes fast mode and must never be presented as extra
usage.
Output
USAGE — 09-12 01:08 · ai-usage 1.2.1
Claude pro
5h ███░░░░░░░ 29% resets 03:40 (2h32m)
week ████░░░░░░ 41% resets Mon 17:00 (2d16h)
now claude-opus-5 · effort high (0m ago)
ChatGPT plus
5h ░░░░░░░░░░ 0% resets 05:55 (4h47m)
week ░░░░░░░░░░ 0% resets 09-18 17:07 (6d15h)
now gpt-5.6-sol · effort high (3m ago)
Grok SuperGrok
week ███░░░░░░░ 27% resets 09-15 09:38 (3d8h)
now grok-4.7 · effort high (6m ago)
Value (evaluated 2026-09-22) — quality-leaning: Plan, Coding, Review, Bug Fix, Testing
Claude Opus 5 High
ChatGPT GPT-5.6 Sol High
Grok Grok 4.7 High
→ Use ChatGPT right now. Both windows are fresh.
Rules:
- Bars 10 chars,
█ used / ░ free. Percentages are whole numbers.
- Relative time next to every reset clock. If the probe omitted the reset (Claude
5h at 0% used), omit the reset clause — do not invent a time. If the probe
omitted the percent (Grok
percent omitted), omit the bar and percent — do
not invent 0%. Still print the reset clock.
- Never print ChatGPT "resets available" / "Usage limit resets", including
unknown (web only).
- Never invent a 5h row for Grok.
- Never print Grok prepaid / on-demand when every value is 0.
- One
now row per provider from the session lines: model · effort, then the
session age in parentheses. Never print the project folder. Omit the now row only when the probe printed
no local session; then print now no local session.
Value block: one line per provider — its value pick as <Model> <Effort>, nothing
else. This pick is shared and fixed: do not re-rank it by today's usage, and do not
print why unless asked. The header carries the evaluated date and the profile
text (once, not per provider).
- A
value stale line means a model shipped or was withdrawn. Only then re-evaluate,
and always delegate it to Codex; do not judge it yourself:
- Save the full probe output to a scratch file, then run from this skill's directory
codex exec --ephemeral --skip-git-repo-check -s read-only -o <scratch>/value.new.json -
with stdin = this prompt, the current value.json, and the probe output:
"Update this value.json for every provider marked value stale. For each: set
models to every current option id, and pick the best cost-effectiveness
default (pick, effort) that stays quality-leaning (fit for Plan,
Coding, Review, Bug Fix, Testing), choosing only from the
option lines and their effort levels. Keep providers that are not stale
unchanged. Set evaluated to today. Reply with the JSON only."
- Check the reply parses as JSON and every
pick is one of that provider's
option ids. If not, keep the old value.json and say Codex's answer was
rejected and why.
- Otherwise write it over
value.json in this skill's directory, show the user the
old → new pick in one line per provider, and say value.json changed and should
be committed to the skill's source repo so every user gets it.
If codex is not installed, print the stored pick with (stale) and do not guess.
Never cite prices or per-token costs; they are not in the probe output.
- Last line names which tool to use right now, and why in a few words.
- If any week row is over 80%, put a
⚠ line above the arrow saying how long until it
resets.
- A provider whose CLI is not installed prints
not installed and is shown as one
greyed row. Never drop it silently.
- No preamble, no recap, no closing offer.
- Write the whole report in the language the user wrote their request in: labels,
the
Value header and profile text, the ⚠ and → lines, and any stale or
rejection note. The sample above is English only as a template. Translate the
English text that comes from the probes and value.json; never translate model
ids, numbers, dates or times. With no user text to go by (a bare /ai-usage), use
the language of the conversation so far, else English.
1---2name: ai-usage3description: Check AI subscription usage limits across Claude, ChatGPT and Grok in one unified report — percent used, how much is left, when each window resets, the model / effort of each CLI's newest session, and a cost-effectiveness recommendation. Use when the user runs /ai-usage or /uu, or asks 額度, 用量, usage, limit, 還剩多少, 什麼時候 reset, 被限流了嗎, rate limit, quota, "am I out of Claude", "how much ChatGPT left".4---56# /ai-usage — unified AI usage report78Run the platform launcher from this skill's directory: `./run.sh` on macOS or Linux;9`py -3 run.py` on Windows, falling back to `python run.py` if `py` is unavailable.10Reformat its output into the table below. Nothing else. No browser, no stored11credentials, and no direct HTTP calls of your own.1213`/ai-usage fresh` — same thing; the script always reads live. The flag only means "do not14reuse an answer from earlier in this conversation".1516The first output line is `### ai-usage <version>`. Put that version at the end of the17report's title line (`USAGE — <time> · ai-usage <version>`), so every report shows18which release produced it. This remains useful19for manually copied installations even though `npx skills` records source information20for installations it manages. Adding `--version` to the platform command prints the21version alone.2223## What must already be in place2425Do not install anything and do not ask the user to log in. Just run the script and26report what comes back.2728- **Python 3.9+**. The POSIX shim selects `python3` before `python`; Windows uses the29 `py -3` launcher when available. `run.py` then re-launches every probe with that exact30 interpreter.31- **At least one** of `claude`, `codex`, `grok`, already signed in. Zero of them is32 still a valid run: every row prints `not installed`.33- **Subprocess and network access.** The host must allow local process launches, and34 each installed provider CLI must be able to reach its own service. The Python code35 does not make direct HTTP requests.3637If a provider prints `not installed`, that is the whole answer for that row — say so38and move on. Do not suggest installing it unless the user asks. If a provider is39installed but its call fails, report the failure for that row and still print the40others; never substitute a number from memory or from an earlier run.4142## Where each number comes from4344All three are live. No browser, no stored credentials, no cookie access.45Verified 2026-09-12 on macOS, and 2026-09-14 on a zh-TW Windows 11 machine (PowerShell,46Python 3.12) — that run surfaced and fixed a UnicodeDecodeError in the Claude probe47(see Limitations in README).4849| Provider | Method |50|---|---|51| Claude | `claude -p "/usage" < /dev/null` — print mode routes the built-in slash command |52| ChatGPT | `codex app-server` → JSON-RPC `account/rateLimits/read` — see `codex_usage.py` |53| Grok | `grok agent stdio` → JSON-RPC `_x.ai/billing` — see `grok_usage.py` |5455Two of the three are the CLI's own local agent server answering over stdio, so the56numbers are the same ones the TUI shows. Nothing is cached and nothing is scraped.5758After each usage block, `session_info.py <cli>` prints four lines read from that CLI's59newest local session file (no network, nothing launched): `session` (last write time),60`model`, `effort`, then one `option` line per model that CLI offers (from its own61model cache: id, effort levels, default, vendor description), then one `value` line: the62shared model + effort pick from `value.json`, or `value stale` when a model was added63or dropped since that pick was made. A `profile` line follows a valid pick: what the shared set is64tuned for. These are what the CLI recorded for its65last turn, not config defaults. See the docstring in `session_info.py` for the files66and fields. A `?` means the file did not carry that field — print `?`, never a guess.67`no local session` means that CLI has never run here; print it as one row.6869## Reading the output7071**Claude** — current session (5h) and current week. Claude omits the reset clock72when a window is 0% used; still print that row, without inventing a reset time.7374**ChatGPT** — `short` (5h) and `outer` (7d), plus `plan`. Do **not** print a75"Usage limit resets" / "resets available" row. That count is not readable locally76(the app-server can spend one via `account/rateLimitResetCredit/consume` but has77no read counterpart). Do not print `unknown (web only)` either. `credits.balance`78is a different pool (paid top-ups) and is never that reset count.7980**Grok** — weekly `creditUsagePercent` and the billing period end when the81percent is present. `_x.ai/billing` sometimes omits `creditUsagePercent`; the82probe then prints `percent omitted`. Print that week row without a bar or83percent, still print the reset clock, and do not invent 0%. Print prepaid /84on-demand only when any of those values is non-zero. Do not print85`prepaid 0 / on-demand 0`. Grok has only one window, not two — do not invent a865h row for it. Do not pick Grok as the tool to use just because the percent is87missing.8889Do not label any of these "redeem" unless the provider itself uses that concept.90Claude's current CLI response does not expose a reliable extra-usage field.91`fast_mode_disabled_reason` describes fast mode and must never be presented as extra92usage.9394## Output9596```97USAGE — 09-12 01:08 · ai-usage 1.2.19899 Claude pro100 5h ███░░░░░░░ 29% resets 03:40 (2h32m)101 week ████░░░░░░ 41% resets Mon 17:00 (2d16h)102 now claude-opus-5 · effort high (0m ago)103104 ChatGPT plus105 5h ░░░░░░░░░░ 0% resets 05:55 (4h47m)106 week ░░░░░░░░░░ 0% resets 09-18 17:07 (6d15h)107 now gpt-5.6-sol · effort high (3m ago)108109 Grok SuperGrok110 week ███░░░░░░░ 27% resets 09-15 09:38 (3d8h)111 now grok-4.7 · effort high (6m ago)112113 Value (evaluated 2026-09-22) — quality-leaning: Plan, Coding, Review, Bug Fix, Testing114 Claude Opus 5 High115 ChatGPT GPT-5.6 Sol High116 Grok Grok 4.7 High117118 → Use ChatGPT right now. Both windows are fresh.119```120121Rules:122- Bars 10 chars, `█` used / `░` free. Percentages are whole numbers.123- Relative time next to every reset clock. If the probe omitted the reset (Claude124 5h at 0% used), omit the reset clause — do not invent a time. If the probe125 omitted the percent (Grok `percent omitted`), omit the bar and percent — do126 not invent 0%. Still print the reset clock.127- Never print ChatGPT "resets available" / "Usage limit resets", including128 `unknown (web only)`.129- Never invent a 5h row for Grok.130- Never print Grok prepaid / on-demand when every value is 0.131- One `now` row per provider from the session lines: model · effort, then the132 session age in parentheses. Never print the project folder. Omit the `now` row only when the probe printed133 `no local session`; then print `now no local session`.134- `Value` block: one line per provider — its `value` pick as `<Model> <Effort>`, nothing135 else. This pick is shared and fixed: do not re-rank it by today's usage, and do not136 print `why` unless asked. The header carries the `evaluated` date and the `profile`137 text (once, not per provider).138- A `value stale` line means a model shipped or was withdrawn. Only then re-evaluate,139 and always delegate it to Codex; do not judge it yourself:140 1. Save the full probe output to a scratch file, then run from this skill's directory141 `codex exec --ephemeral --skip-git-repo-check -s read-only -o <scratch>/value.new.json -`142 with stdin = this prompt, the current `value.json`, and the probe output:143 "Update this value.json for every provider marked `value stale`. For each: set144 `models` to every current `option` id, and pick the best cost-effectiveness145 default (`pick`, `effort`) that stays quality-leaning (fit for Plan,146 Coding, Review, Bug Fix, Testing), choosing only from the147 `option` lines and their effort levels. Keep providers that are not stale148 unchanged. Set `evaluated` to today. Reply with the JSON only."149 2. Check the reply parses as JSON and every `pick` is one of that provider's150 `option` ids. If not, keep the old `value.json` and say Codex's answer was151 rejected and why.152 3. Otherwise write it over `value.json` in this skill's directory, show the user the153 old → new pick in one line per provider, and say `value.json` changed and should154 be committed to the skill's source repo so every user gets it.155 If `codex` is not installed, print the stored pick with `(stale)` and do not guess.156 Never cite prices or per-token costs; they are not in the probe output.157- Last line names which tool to use right now, and why in a few words.158- If any week row is over 80%, put a `⚠` line above the arrow saying how long until it159 resets.160- A provider whose CLI is not installed prints `not installed` and is shown as one161 greyed row. Never drop it silently.162- No preamble, no recap, no closing offer.163- Write the whole report in the language the user wrote their request in: labels,164 the `Value` header and `profile` text, the `⚠` and `→` lines, and any stale or165 rejection note. The sample above is English only as a template. Translate the166 English text that comes from the probes and `value.json`; never translate model167 ids, numbers, dates or times. With no user text to go by (a bare `/ai-usage`), use168 the language of the conversation so far, else English.