AI subscription quotas in one command. subtrk reports remaining usage for
the plans its contributors use – today Claude Pro, Z.ai GLM Coding Plan, Alibaba
Cloud Model Studio, Google AI Pro, OpenCode Zen, OpenRouter, the ChatGPT plans
(via the OpenAI Codex CLI), the Kimi coding plans (via the Kimi Desktop app or
the Kimi Code CLI) and the z.ai Start Plan bundles (via the ZCode desktop app) –
in one compact view, designed first for the AI agents that work for you and
second for you.
Coverage expands as needs or requests come in: adding a provider is a contained
change (see the implementation guide), and PRs
adding providers are welcome.
Agents stop hitting brick walls at rate limits: subtrk status --json gives every
window's usage and reset time plus a computed nextEvent, so an agent can schedule a
wake-up at the reset instead of dying. Humans stop keeping a browser tab open per
provider. And because no API reports what a single task cost, subtrk track
measures it from the harnesses' own local stores – start, pause, resume, stop
with a reassessed complexity, recode later – and turns that history into
"does this task fit my remaining window?" estimates
(Task tracking).
$ subtrk
claude 5h 31% (reset 12:00) · behind · 7d 32% (reset 03:00) · behind · runway: through reset 12:00
glm 5h 17% (reset 14:47) · ahead – projected empty in 2h 25m · 7d 3% (reset 09:05) · ahead – projected empty in 1d 14h · MCP 1% (reset 09:05)
alibaba 30d 99% (reset 18:00) · ahead – projected empty in 3h 16m · runway: projected empty in 3h 16m (30d window) · credits 269/45,000 · cycle ends 2026-10-22 !
openai 30d 0% (reset 17:53) · behind · runway: through reset 17:53
openrouter $8.07 left · key today $0.00
next: claude 5h at 12:00 (1h 43m)
help: subtrk status --json | subtrk status --provider <id> | subtrk init

Web console
subtrk serve
Starts the dashboard on a random 127.0.0.1 port and prints the URL to open –
one page for every tracked provider: usage bars per window (with ≥80%/≥95% warning
levels), credit pools, a 7-day reset timeline, upcoming resets, and the same
agent view the CLI prints, auto-refreshing on the cache heartbeat. The top row
carries month-to-date token and value cards (local calendar month) – both open
the all-providers usage page. A provider that reports several model classes
(Google's Gemini and Claude/GPT, for example) renders one card per class. When
a provider's error says it is refreshable, its card shows a Refresh now
button that re-runs that provider's own refresh action on the host. A gear-icon
menu in the header toggles providers on/off, an eye-icon menu shows or hides
individual cards, every card has an × to hide itself, and cards drag
individually into any order – all persist across restarts (saved to
~/.subtrk/config.json, like subtrk init).

Every card is clickable into that provider's usage page – the headline addition of M3: a day/hour token chart with the provider's window-% history on the same time grid, a per-model table with API-equivalent costs labeled actual / est / blended, and the live windows, all served from the local usage store with no vendor calls while you browse (details in Usage history).

Both month-to-date cards open the all-providers usage page – the same day/hour charts with every token-reporting provider stacked on one grid: an API-equivalent spend chart (actual where the vendor reports cost, est from list rates, blended for totals-only – each segment names its kind on hover), a tokens chart, a facts row (top provider by tokens and by value, best and weakest cache hit, quietest reporter, requests), and a per-provider table with the live windows. Providers without a token surface keep their honest dash row instead of fake zeros.

The server is loopback-only, requires a per-run token (delivered in the printed
URL), never emits CORS headers, and status stays read-only – toggles and card
order persist through the authenticated POST /api/config – see
docs/spec.md §subtrk serve for the security design.
Why
Modern AI workstations juggle several subscriptions with different windows (5-hour,
weekly, monthly credit pools) and different dashboards. Without a combined view you
over-plan, under-use, and your agents discover limits by crashing into them. subtrk
reads each vendor's usage the same way their own CLIs do, normalizes it, caches it
politely, and speaks both human and agent.
Design principles
- Agents first – follows the AXI principles: token-efficient
output, pre-computed aggregates (
nextEvent,recheckAfter), structured errors you branch on by kind (never by message text), exit codes with meaning, no interactive traps in agent paths, content before help. - Zero runtime dependencies – TypeScript in the repository, executed
directly by Node ≥22.18 (type stripping, no build step in development); the
npm package ships compiled JavaScript (Node never type-strips under
node_modules). The dev toolchain (typecheck, linter, compiler) is dev-only and never ships. - Polite by construction – one shared TTL cache (
~/.subtrk/cache.json) with stale-while-revalidate and a hard 300s floor on the one endpoint known to punish polling. Six agents checking simultaneously produce one upstream request. - Fail soft, per provider – one broken endpoint never breaks the others; errors
carry a
kindand ahint, and stale cached numbers beat a wall of text. - Secrets stay put – reads the credential files your CLIs already maintain
(read-only), stores its own keys in
~/.subtrk/env(never global env vars), and mechanically redacts every secret from every output. The cache contains no secrets. - Ported ideas credit their source – a borrowed check or structure names its origin in-file (MIT attribution, e.g. quota-axi); the link between the idea and its upstream lives next to the code that carries it.
- Output is add-only – flags like
--fields/--jsonmay filter, and richer modes add detail, but a field's meaning never changes between modes: demotion happens in the renderer, never in the data. - Absent data stays absent – a missing window, reset time, or percentage is
never invented; if the wire carries
percentUsed,percentRemainingis left out rather than derived. - Expiry is advisory – a stored
expiresAtonly orders candidates; a credential is retired by the vendor endpoint's rejection, never by a clock. - Accounts don't mix – identity is the vendor's
accountId; windows from different accounts are never summed.
Install
Requires Node ≥22.18.
No install needed – every command runs through npx:
npx subtrk init # one-time interactive setup
npx subtrk serve # web console
npx subtrk auth refresh --provider <id> # re-authorise one provider (e.g. alibaba or google)
npx subtrk # same as: npx subtrk status
Or install globally:
npm install -g subtrk
subtrk init # one-time interactive setup
From source (development):
git clone https://github.com/ChaosChild/subtrk.git
cd subtrk
npm install # dev-only toolchain
npm link # puts `subtrk` on PATH (subtrk.cmd on Windows)
subtrk init first asks which providers you track – a numbered listing answered
with numbers and/or ids (e.g. 1 3 5 or claude, google) – and stores the
selection in ~/.subtrk/config.json; the checks below then only cover those.
Edit the file or re-run subtrk init to change the selection, delete it to
track all of them again. It runs the Alibaba login flow (bl auth login --api-key +
--console browser login), prompts for OpenRouter keys (hidden input, saved to
~/.subtrk/env), and verifies each provider honestly – [ok] only when a
credential actually works.
Agent instructions
subtrk init --agent <harness> appends a short marked section to a harness's
GLOBAL agent instructions file, so the agent knows how to call subtrk:
| harness | file |
|---|---|
claude |
~/.claude/CLAUDE.md (Claude Code global memory) |
zcode |
~/.zcode/AGENTS.md |
codex |
~/.codex/AGENTS.md |
opencode |
~/.config/opencode/AGENTS.md (this exact path on Windows too) |
agy |
~/.gemini/AGENTS.md (Antigravity; the path is ~/.gemini by convention) |
The write is idempotent – re-running replaces only subtrk's block between the
<!-- subtrk:begin --> / <!-- subtrk:end --> markers and never touches
anything else; to remove it, delete the block between the markers.
The section comes in two tiers. The default is quota guidance only – some
users never want task tracking in their agents' instructions. Interactive
subtrk init asks once whether to teach it (default No, stored as
agents.track in ~/.subtrk/config.json); subtrk init --agent <harness> --track opts in explicitly, --no-track opts back out. Both tiers keep the
AGENTS.md/CLAUDE.md section SLIM – the detailed contracts live on demand in
skills, installed into each harness's skills dir:
| harness | skills dir |
|---|---|
| claude | ~/.claude/skills |
| zcode | ~/.zcode/skills |
| codex | ~/.codex/skills |
| opencode | ~/.config/opencode/skills |
| agy | ~/.gemini/config/skills (IDE) and ~/.gemini/antigravity-cli/skills (CLI) |
The subtrk skill (both tiers) carries the full quota/status contract; the
subtrk-track skill (track tier) carries the lifecycle playbook – ladder,
pause/resume, stop-time reassessment, subagent session pins. init --agent
writes/refreshes them idempotently and --no-track removes subtrk-track.
The track tier also registers lifecycle hooks in the harnesses that support
them – claude (~/.claude/settings.json), zcode (~/.zcode/cli/config.json)
and codex (~/.codex/config.toml) – so the harness itself reminds the agent
to run track start/track stop at session start and turn end (subtrk track hook under the hood: read-only, throttled to once per session plus
open/paused-set changes, never blocks). Every hook entry subtrk writes carries the
literal subtrk track hook in its command; re-running with --no-track
removes exactly those and nothing else, and a JSON target gets a one-time
.subtrk-bak copy before its first modification. opencode and agy get
instructions only (agy hooks are documented but not yet wired). On any other
harness, paste the status body below into its instructions file manually
(without the markers – subtrk init --agent wraps it in them) and place the
skill bodies (subtrk, plus subtrk-track on the track tier) into its
skills dir – or inline them if it has none:
## subtrk
`subtrk` reports remaining quota for the AI plans configured on this machine.
Run `subtrk status --json` before committing to large or long-running provider
work, when a provider fails with quota or rate-limit errors, and on wake-ups -
`nextEvent.at` (or `recheckAfter` when absent) says when new information can
exist, so schedule around it instead of polling. The full contract (windows,
error kinds and remedies, exit codes, cache etiquette) is in the `subtrk`
skill. Run `subtrk auth refresh` only after the operator says go - it opens a
browser tab; surface any other remedy verbatim. A missing provider is not
configured, not an error.
The --track tier appends this section to the body above:
### track
Track every task that produces or changes a deliverable. First actions of any
task: `subtrk track status` (it lists every folder and session - touch only
markers you opened in this folder), then
`subtrk track start --task "<short description>" --complexity <xs|s|m|l|xl>`
(one-line ladder guess, no research; remember the printed id). When the task
ends: `subtrk track stop --status done|aborted|failed|paused --complexity
<reassessed>` (omit --id to close the newest open marker for this folder). The
full lifecycle playbook (pause/resume, reassessment, subagent session pins) is
the `subtrk-track` skill; hooks will remind you at the right moments.
Providers
| Provider | Plan | Reads | Windows | Status |
|---|---|---|---|---|
| Anthropic | Claude Pro (personal) | api.anthropic.com/api/oauth/usage via the OAuth token Claude Code already stores |
5h + 7d | reverse-engineered, de-facto standard |
| Z.ai | GLM Coding Plan | the same monitor endpoint ZCode itself uses; zhipu/ZHIPUAI_API_KEY credentials route to open.bigmodel.cn |
5h + weekly | unofficial, officially plugin-endorsed |
| Alibaba Cloud | Model Studio Token Plan (intl) | official bl CLI raw gateway passthrough (bl console call) |
30-day credits pool (monthly-only since 2026-09-22) | official (via bl) |
| AI Pro (personal) | Antigravity desktop app's local language server (the dashboard's own view); remote Code Assist summary fallback with read-only self-refresh | per-family 5h/7d (gemini + claude-and-gpt families) | best-effort – without the app it briefly runs the app's own language server standalone; labeled remote fallback as last resort | |
| OpenCode | Zen pay-as-you-go | no usage/balance API exists for PAYG | – | signals only (honest note) |
| OpenRouter | pay-as-you-go | /api/v1/key (+ /api/v1/credits and usage history via a management key) |
– | official |
| OpenAI | ChatGPT plan via Codex | the Codex CLI's own ChatGPT usage endpoint, read from its stored login; model-scoped code-review windows and the spend_control credit cap parsed when present; on definitive failure a read-only codex app-server fallback (Windows: set SUBTRK_CODEX_BINARY to codex.exe) |
free: one 30-day window; paid: 5h + weekly (+ code-review windows, spend cap) | official client endpoint, not a documented public API |
| Kimi | Kimi Desktop / Kimi Code CLI coding plans | the Kimi Desktop app's key or the Kimi Code CLI's OAuth login against the coding usage endpoints | free: one quota window; CLI login: 5h + 7d + monthly | official client endpoints, not a documented public API |
| ZCode | z.ai Start Plan bundles | the z.ai balance API via the local credential store (the ZCode desktop app's stored login) | one window per per-model token bucket, bucket expiry as reset | official client endpoint, undocumented |
| MiniMax | MiniMax coding plan (bearer key) or pay-as-you-go (sk-api- account key) |
the key's shape picks the endpoint: /v1/token_plan/remains for bearer keys, /account/query_balance for sk-api- keys (MINIMAX_API_KEY or the MiniMax CLI config, pinned to api.minimax.io / api.minimaxi.com) |
per-model 5h + weekly (bearer) or account balance (sk-api-) |
official client endpoints, not a documented public API |
| DeepSeek | pay-as-you-go | DEEPSEEK_API_KEY against the documented /user/balance account endpoint |
– | official, documented; experimental – not verified against a live account |
None of these vendors officially supports third-party quota readers except Alibaba
and OpenRouter; the others are the same calls their own CLIs make, and can change.
subtrk isolates that churn in small per-provider modules and degrades cleanly.
These are the providers the contributors use today – the set grows as needs or
requests come in, and additions are welcome as PRs (the
implementation guide walks through it).
Usage history
Beyond the quota snapshot, subtrk keeps a local usage ledger in
~/.subtrk/usage.json (hourly and daily token buckets per provider and model,
window-% samples, a weekly pricing cache). It fills from the calls you already
make – every subtrk status, dashboard refresh and subtrk usage harvests
the due sources, best-effort, and history is only ever written idempotently so
concurrent agents cannot double count.
subtrk usage # month-to-date tokens + API-equivalent cost
subtrk usage --json # machine-readable (per-provider, per-model)
subtrk usage --provider glm # one provider (includes its local harvest)
subtrk usage --days 7 --hour # last 7 days, hourly buckets
subtrk usage --rebuild # re-derive range-API history from the sources
GLM history survives a degraded z.ai. z.ai's usage-detail API has failed
in ways that look healthy – empty envelopes, all-zero buckets, a single stray
bucket. The local ZCode store acts as referee: the API is account-wide, so it
can never honestly report less than this machine burned in the same hours.
When it does (or reports nothing at all), the hourly glm history is rebuilt
from ~/.zcode/cli/db/db.sqlite, the span is recorded as local provenance,
and the next healthy fetch replaces it with the vendor's authoritative rows.
Task tracking – what did this task cost?
Wrap a task in markers and subtrk attributes the real token usage between
them from the harnesses' own local stores (ZCode's per-request telemetry in
~/.zcode/cli/db/db.sqlite, Claude Code transcripts, Codex rollouts) – no API
anywhere reports per-task usage:
subtrk track start --task "fix the boundary-day bug" --complexity m
# …the agent works, subagents included…
subtrk track stop --status done --complexity l # harvests in/cr/cw/out for the
# window; --complexity is the final reassessment
subtrk track stop --status paused # waiting on feedback – same identity…
subtrk track resume --id <id> # …picked up again: t0 kept, the gap is a pause segment
subtrk track recode --id <id> --complexity s # fix a drifted label, open or closed
subtrk track status # open + paused markers, records pending harvest
subtrk track list --days 30 # recent records
subtrk track prune # close markers orphaned by crashes (≥3d,
# --before 24h / --all)
The start complexity is a one-line guess; the stop is where it gets
reassessed against what the task actually turned out to be (the original
declaration survives in the record as recodeFrom). A paused record keeps its
identity – track status lists it with its resume command – and the final stop
re-harvests the whole span. For orchestrated work the stop output adds the
delegation split, and every stop ends with the recode hint:

Subagents. An orchestrator puts a track start --session <pin> into each
subagent's brief. The pin is per harness: ZCode sess_subagent_agent_<agentId>
and Claude Code agent-<agentId> (both from the spawn result, relayed to the
child), while Codex and Antigravity children pin themselves ($CODEX_THREAD_ID,
the SessionStart payload's conversationId). When the parent stops, its harvest
excludes the pinned children's sessions (named in excludedPins), so every
token is counted once – by the worker that burned it – and the parent's
calibration sample is its whole tree: its own burn plus its cleanly pinned
children. An unpinned child still tracks, as a window snapshot.
After a few tasks, the history answers the question that motivated all of this — "is my remaining window enough for an m task?" — with your own data:
subtrk track