Elapsed is null when a window has no reset timestamp (MiniMax v1 fallback) so pacing consumers fail closed; negative reset_in_seconds clamps to 0. Claude-Session: https://claude.ai/code/session_01YQDoWNM7XPPii28khFWoMc
12 KiB
agent-subscriptions
Purpose
Show live subscription usage percentages and weekly-reset timing for each AI provider used by the agent runtimes system (Anthropic OAuth, MiniMax). Output is human-readable by default; a --output json mode produces a machine-consumable structure for downstream cron jobs.
Usage
agent-subscriptions [OPTIONS]
Options:
-n, --dryrun Show what would be probed without making API calls
-j, --output json Emit structured JSON to stdout (plain text, no ANSI)
-h, --help Show this help message and exit
The default mode (no flag) prints a coloured table suitable for terminals.
Behaviour
- Read the Anthropic OAuth token from
~/dev/claude/secrets/anthropic/api_key(whole-file Bearer token). - Probe Anthropic subscription usage and reset times:
- First attempt:
GET https://api.anthropic.com/v1/modelswithAuthorization: Bearer <token>— zero token cost. - Read
anthropic-ratelimit-unified-5h-utilizationandanthropic-ratelimit-unified-7d-utilization(fractions 0.0–1.0; multiply by 100 for percentage). - Read
anthropic-ratelimit-unified-5h-resetandanthropic-ratelimit-unified-7d-reset. Values are Unix epoch seconds (integer string).- Source: https://platform.claude.com/docs/en/api/rate-limits and https://github.com/anthropics/claude-code/issues/12829 (example values
1764554400,1764615600).
- Source: https://platform.claude.com/docs/en/api/rate-limits and https://github.com/anthropics/claude-code/issues/12829 (example values
- If headers absent, fall back:
POST https://api.anthropic.com/v1/messageswith modelclaude-haiku-4-5-20251001,max_tokens=1, message"hi"— same headers on response (or on the HTTPError if 429).
- First attempt:
- Read the MiniMax API key from
~/dev/claude/projects/agent-runtime-secrets/providers/minimax/v1/provider.sops.envviasops --decrypt --output-type dotenv(key:ANTHROPIC_AUTH_TOKEN). UsesSOPS_AGE_KEY_FILE=~/dev/claude/secrets/sops/provider-age-key.txt. - Probe MiniMax subscription usage and reset times:
GET https://www.minimax.io/v1/token_plan/remainswithAuthorization: Bearer <key>andUser-Agent: curl/7.88.1(minimax.io blocks Python-urllib default UA).- For the
model_remains[].model_name == "general"entry:five_hour = 100 - current_interval_remaining_percentseven_day = 100 - current_weekly_remaining_percent- 5-hour reset:
end_time(Unix epoch milliseconds) — divide by 1000 for seconds. - Weekly reset:
weekly_end_time(Unix epoch milliseconds).
- Source for response shape: https://github.com/Hukilow/Minimax-usage/blob/main/PLAN.md
- v1 fallback (
category_remains[]wherecategory == "text_generation") carries no reset timestamp fields — showUNKNOWNreset and continue.
- Display the formatted table (default) or JSON (
--output json). - Colour-code the percentage column (default output only):
- < 60%: green
- 60–80%: yellow
- ≥ 80%: red
- JSON output is never coloured (safe to pipe).
Reset time fields
| Provider | Field | Format |
|---|---|---|
| Anthropic | anthropic-ratelimit-unified-5h-reset |
Unix epoch seconds (int) |
| Anthropic | anthropic-ratelimit-unified-7d-reset |
Unix epoch seconds (int) |
| MiniMax | model_remains[general].end_time |
Unix epoch milliseconds |
| MiniMax | model_remains[general].weekly_end_time |
Unix epoch milliseconds |
Note the unit difference: Anthropic emits seconds; MiniMax emits milliseconds. The implementation normalises both to seconds.
If a reset field is absent (header missing on the Anthropic side, or the v1 fallback path on the MiniMax side), the reset cell in the table shows UNKNOWN and the JSON field reset_at is set to null with reset_in_seconds: null. reset_in_seconds is computed as reset_at - now at probe time.
Dryrun behaviour
Prints what it would probe without reading credential files or making HTTP calls. The dryrun mode honours --output json and emits a JSON sample with placeholder values that match the live JSON schema (same keys, sample numbers, no API calls performed).
Default (no --output):
[dryrun] Would probe:
Anthropic — ~/dev/claude/secrets/anthropic/api_key (Bearer OAuth token)
GET https://api.anthropic.com/v1/models
MiniMax — ~/dev/claude/projects/agent-runtime-secrets/providers/minimax/v1/provider.sops.env (SOPS)
GET https://www.minimax.io/v1/token_plan/remains
With --output json (or --dryrun --output json):
{
"probed_at": "2026-08-01T14:23:00+00:00",
"providers": [
{
"provider": "Anthropic",
"available": true,
"windows": {
"five_hour": {
"utilization_pct": 23.4,
"reset_at": "2026-08-01T19:00:00+00:00",
"reset_in_seconds": 16620,
"window_seconds": 18000,
"elapsed_pct": 0.0767
},
"seven_day": {
"utilization_pct": 41.2,
"reset_at": "2026-08-07T23:00:00+00:00",
"reset_in_seconds": 538200,
"window_seconds": 604800,
"elapsed_pct": 0.1101
}
}
},
{
"provider": "MiniMax",
"available": true,
"windows": {
"five_hour": {
"utilization_pct": 12.1,
"reset_at": "2026-08-01T19:00:00+00:00",
"reset_in_seconds": 16620,
"window_seconds": 18000,
"elapsed_pct": 0.0767
},
"seven_day": {
"utilization_pct": 8.3,
"reset_at": "2026-08-07T23:00:00+00:00",
"reset_in_seconds": 538200,
"window_seconds": 604800,
"elapsed_pct": 0.1101
}
}
}
]
}
Note: probed_at and the reset values are placeholders — the dryrun output does not depend on the actual wall clock, only on the structure. window_seconds is always the fixed constant for that window key (never a placeholder); elapsed_pct is derived from reset_in_seconds and window_seconds so the sample stays internally consistent (shown rounded to 4 decimal places above; the implementation does not round).
Output format
Default table
Agent Subscription Usage
========================
Provider Window Usage Resets
----------- ---------- -------- -------
Anthropic 5-hour 23.4% 4h 37m
Anthropic 7-day 41.2% 6d 8h
MiniMax 5-hour 12.1% 2h 11m
MiniMax 7-day 8.3% 4d 19h
Resetscolumn shows relative time until the window resets (1d 2h,12h 23m,45m,12s).- 7-day window: days+hours (
6d 8h). 5-hour window: hours+minutes (4h 37m). ResetsshowsUNKNOWN(dim) when the underlying field is absent.- Percentage column is ANSI-coloured (green/yellow/red) when stdout is a TTY;
Resetsis always plain. - JSON output is always plain (no ANSI), regardless of TTY state.
JSON (--output json / -j)
Top-level keys:
probed_at(string, ISO 8601 with timezone offset, UTC if unknown): when the probe was performed.providers(array): one entry per provider in fixed order —Anthropicfirst, thenMiniMax.
Each provider entry:
provider(string):"Anthropic"or"MiniMax".available(bool):trueif at least one window returned data;falseif the whole probe failed.- On failure, add
error(string) describing the reason and omitwindows. - On success, add
windows(object) with bothfive_hourandseven_daysub-objects.
Each window sub-object:
utilization_pct(float, may benull): percentage of the window already used (0.0–100.0).reset_at(string ISO 8601, may benull): absolute wall-clock time of the next reset.reset_in_seconds(int, may benull): seconds fromprobed_atuntilreset_at. Downstream consumers computing "days remaining" divide this by 86400. Clamped to a minimum of 0 — if the reset epoch is already in the past at probe time (clock skew, or probing in the same second the reset fired), the script clamps the value to0itself rather than emitting a negative number. This also pinselapsed_pct(below) to1.0in that case.window_seconds(int, may benull): the nominal length of this window in seconds — a fixed constant, not measured:18000forfive_hour,604800forseven_day. These are assumed nominal lengths (Anthropic documents 5h/7d unified rate-limit windows; MiniMax v2'send_time/weekly_end_timefields are consistent with the same cadence) — the script does not attempt runtime verification against either API.nullonly when the window key itself has no defined constant (should not occur forfive_hour/seven_day).elapsed_pct(float, may benull): fraction of the window already elapsed, computed as1 − (reset_in_seconds / window_seconds), clamped to[0.0, 1.0].nullwheneverreset_in_secondsisnull— i.e. whenever this window has no reset timestamp (the MiniMax v1 fallback path returns utilization with no reset fields). This is a deliberate fail-closed contract: downstream consumers (e.g. an idle-capacity scheduler pacing dispatch against elapsed window time) MUST treatnullas "cannot pace this window" and never substitute0.0or1.0.
Example live output:
{
"probed_at": "2026-08-01T14:23:00+00:00",
"providers": [
{
"provider": "Anthropic",
"available": true,
"windows": {
"five_hour": {
"utilization_pct": 23.4,
"reset_at": "2026-08-01T19:00:00+00:00",
"reset_in_seconds": 16620,
"window_seconds": 18000,
"elapsed_pct": 0.0767
},
"seven_day": {
"utilization_pct": 41.2,
"reset_at": "2026-08-07T23:00:00+00:00",
"reset_in_seconds": 538200,
"window_seconds": 604800,
"elapsed_pct": 0.1101
}
}
},
{
"provider": "MiniMax",
"available": false,
"error": "HTTP 401 Unauthorized"
}
]
}
The downstream consumer (cron job that drafts workload based on subscription usage thresholds) needs utilization_pct, reset_in_seconds, and elapsed_pct for the seven_day window. utilization_pct and reset_in_seconds are guaranteed present (non-null) on the success path; elapsed_pct is guaranteed present only when the provider's reset timestamp is available (true for both providers' v2/header paths; null for MiniMax's v1 fallback — see Edge cases).
Edge cases
- If the Anthropic token file does not exist, mark Anthropic
available: false, seterror, continue. - If SOPS decryption fails (missing key file, wrong key, sops not installed), mark MiniMax
available: false, seterror, continue. - If an API call fails for any reason, that provider is
available: falsewitherror. The other provider is still probed. - If a utilization header is present for only one window, the other window has
utilization_pct: null. The reset field is independent — a window can have a reset timestamp without a utilization value, or vice versa. - If the reset field is absent for a window:
reset_at: null,reset_in_seconds: null,elapsed_pct: null. The default table printsUNKNOWNin theResetscell. This is the normal case for MiniMax's v1 fallback path (category_remains[]), which carries utilization but no reset timestamps. - If
reset_in_secondswould be negative (reset epoch already passed at probe time), it is clamped to0before being emitted — never negative in JSON output.elapsed_pctfor that window is then1.0(fully elapsed), notnull. elapsed_pctis computed only fromreset_in_secondsand the fixedwindow_secondsconstant; it does not depend onutilization_pct. A window can haveelapsed_pctwithutilization_pct: null, or vice versa.window_secondsvalues (18000,604800) are the same regardless of provider or probe outcome — they are compile-time constants, not derived from any API response.- Exit 0 even if some providers are unavailable (the tool is informational). The only non-zero exit is
--helpis not requested and an unknown flag was passed. --output jsonand--dryruncompose:--dryrun --output jsonemits the dryrun JSON sample without making API calls.
Examples
agent-subscriptions # live probe, coloured table
agent-subscriptions --output json # live probe, machine-readable JSON
agent-subscriptions -j # short flag for JSON
agent-subscriptions --dryrun # preview only (table)
agent-subscriptions --dryrun -j # preview only (JSON sample)
agent-subscriptions --help # usage