# 01 — jackin-usage current provider coverage (https://jackin.tailrocks.com/research/product/desktop/usage-provider-apis/01-current-coverage/)



## Summary [#summary]

Current probes cover seven providers through one normalized limits pipeline, with provider-specific credential and quota gaps documented below.

## Question and scope [#question-and-scope]

For each provider probe in `crates/jackin-usage/src/usage/` (codex.rs, claude.rs, amp.rs, grok.rs, zai.rs, minimax.rs, kimi.rs): (1) which HTTP endpoints/URLs it calls for usage/quota; (2) which credential source it uses (location/type only); (3) which fields and UI labels it produces; (4) confirm/refute two suspected gaps — (a) no run-out/projection phrases in jackin-usage, (b) no Amp workspace credit balance; (5) how data flows to display surfaces (HostUsageRuntime, usage\_snapshot\_store, jackin-usage-ffi DTOs).

This chapter informs jackin-desktop.

## Method [#method]

**Method:** codebase read
&#x2A;*Verification cutoff:** 2026-07-24

All paths below are relative to the repository root unless absolute. `usage/` means `crates/jackin-usage/src/usage/`.

## Findings [#findings]

### Q1 — Endpoints/URLs per probe [#q1--endpointsurls-per-probe]

* **Codex (usage/codex.rs)** — dual source, RPC preferred over OAuth HTTP (`codex_snapshot`, usage/codex.rs:122-136):
  * CLI RPC: spawns `codex -s read-only -a untrusted app-server` (usage/codex.rs:719-720); JSON-RPC methods `account/rateLimits/read` (usage/codex.rs:771) and `account/read` (usage/codex.rs:781). (confidence: HIGH)
  * OAuth HTTP: base URL from `$CODEX_HOME/config.toml` `chatgpt_base_url`, default `https://chatgpt.com/backend-api` (usage/codex.rs:1040-1062); usage path `/wham/usage` (or `/api/codex/usage` for non-backend-api bases) via `resolve_codex_usage_url` (usage/codex.rs:1023-1031); reset-credits at `{base}/wham/rate-limit-reset-credits` via `resolve_codex_reset_credits_url` (usage/codex.rs:1033-1038). (confidence: HIGH)
  * Token refresh (401/403 retry only, never persisted back): POST `https://auth.openai.com/oauth/token` with public client id — `CODEX_OAUTH_TOKEN_URL` / `CODEX_OAUTH_CLIENT_ID` (crates/jackin-usage/src/usage.rs:1294-1295; refresh flow usage/codex.rs:930-986). (confidence: HIGH)
* **Claude (usage/claude.rs)** — GET `https://api.anthropic.com/api/oauth/usage` with `anthropic-beta: oauth-2025-04-20` and a `claude-code/<version>` User-Agent (endpoint gated to that UA) (usage/claude.rs:825-846; UA resolution 848-873, fallback `claude-code/2.1.0` at crates/jackin-usage/src/usage.rs:179). Fallback when OAuth fetch fails but a token exists: CLI `claude -p /usage` (usage/claude.rs:901-911; command args crates/jackin-usage/src/usage.rs:1522). (confidence: HIGH)
* **Amp (usage/amp.rs)** — POST `https://ampcode.com/api/internal?userDisplayBalanceInfo` with JSON body `{"method":"userDisplayBalanceInfo","params":{}}` (usage/amp.rs:214-243). Fallback: CLI `amp --no-color usage` (usage/amp.rs:339-343). (confidence: HIGH)
* **Grok (usage/grok.rs)** — dual source (usage/grok.rs:336-353):
  * CLI ACP RPC preferred: spawns `~/.grok/bin/grok agent stdio` (or `grok` on PATH) (usage/grok.rs:355-366, 440-447); JSON-RPC method `x.ai/billing` (usage/grok.rs:416-423). (confidence: HIGH)
  * Web fallback: POST `https://grok.com/grok_api_v2.GrokBuildBilling/GetGrokCreditsConfig` as gRPC-web+proto with bearer token; response parsed by a hand-rolled protobuf scanner (usage/grok.rs:461-506, 553-600). (confidence: HIGH)
* **Z.AI (usage/zai.rs)** — GET `{host}/api/monitor/usage/quota/limit`, default host `https://api.z.ai`; overridable via `ZAI_QUOTA_URL`/`Z_AI_QUOTA_URL` (full URL) or `ZAI_API_HOST`/`Z_AI_API_HOST` (usage/zai.rs:257-290). (confidence: HIGH)
* **MiniMax (usage/minimax.rs)** — GET with four-URL fallback: `https://api.minimax.io/v1/token_plan/remains`, `https://api.minimax.io/v1/api/openplatform/coding_plan/remains`, then same two paths on `https://api.minimaxi.com` (usage/minimax.rs:391-394); overrides `MINIMAX_REMAINS_URL` / `MINIMAX_API_HOST` / `MINIMAX_HOST` (usage/minimax.rs:371-374). Sends header `MM-API-Source: jackin-capsule` (usage/minimax.rs:349). (confidence: HIGH)
* **Kimi (usage/kimi.rs)** — GET `https://api.kimi.com/coding/v1/usages` (usage/kimi.rs:258-267). (confidence: HIGH)

All bearer GETs route through the shared `get_json_bearer` helper (crates/jackin-usage/src/usage.rs:1451-1479). (confidence: HIGH)

### Q2 — Credential sources (locations/types only; no values) [#q2--credential-sources-locationstypes-only-no-values]

* **Codex**: OAuth token file `$CODEX_HOME/auth.json` (env `CODEX_HOME`, default `~/.codex/`), then container handoff `/jackin/codex/auth.json` (`container_paths::CODEX_AUTH`, crates/jackin-core/src/container\_paths.rs:77) (usage/codex.rs:14-19, 96-100). `auth.json` may alternatively carry an `OPENAI_API_KEY` string (usage/codex.rs:262-274). Env `OPENAI_API_KEY` is presence-checked for status/origin only (usage/codex.rs:113-121). Account label decoded from the id\_token JWT payload (email/preferred\_username/name/sub) (usage/codex.rs:321-332). No keychain reader. (confidence: HIGH)
* **Claude**: OAuth credential candidates, home-first: `$CLAUDE_CONFIG_DIR/.credentials.json`, `~/.claude/.credentials.json`, `~/.claude.json` (metadata only, never token), handoff `/jackin/claude/credentials.json` (`container_paths::CLAUDE_CREDENTIALS`, crates/jackin-core/src/container\_paths.rs:73) (usage/claude.rs:19-26). Token key `claudeAiOauth.accessToken` (usage/claude.rs:235-257). Env `ANTHROPIC_API_KEY`/`ANTHROPIC_AUTH_TOKEN` are presence/origin only — never used for the fetch (usage/claude.rs:63-89, comment 73-75). No keychain reader in the capsule (comment usage/claude.rs:48-49). (confidence: HIGH)
* **Amp**: env `AMP_API_KEY` wins; else API key from `~/.local/share/amp/secrets.json` (`apiKey@*` keys), then handoff `/jackin/amp/secrets.json` (`container_paths::AMP_SECRETS`, crates/jackin-core/src/container\_paths.rs:79) (usage/amp.rs:15-34, 245-266). (confidence: HIGH)
* **Grok**: OAuth bearer from `~/.grok/auth.json`, else handoff `/jackin/grok/auth.json` (`container_paths::GROK_AUTH`, crates/jackin-core/src/container\_paths.rs:83) (usage/grok.rs:21-28); token entries keyed by `https://auth.x.ai::` (OIDC) or legacy sign-in scopes, with expiry check (usage/grok.rs:508-551). Env `XAI_API_KEY` / `GROK_DEPLOYMENT_KEY` are presence/origin only (usage/grok.rs:29-30, 59-71). (confidence: HIGH)
* **Z.AI**: API key only — injected `provider_keys` map (Desktop `set_provider_key`), else env `Z_AI_API_KEY` / `ZAI_API_KEY` (crates/jackin-usage/src/usage.rs:901-907). No file/keychain source. (confidence: HIGH)
* **MiniMax**: env `MINIMAX_CODING_API_KEY`, else injected `provider_keys`, else env `MINIMAX_API_KEY` (crates/jackin-usage/src/usage.rs:918-926). No file source. (confidence: HIGH)
* **Kimi**: env `KIMI_AUTH_TOKEN`/`kimi_auth_token`, else local OAuth token file `~/.kimi-code/credentials/kimi-code.json` or `~/.kimi/credentials/kimi-code.json` (expiry-checked `access_token`), else same file under handoff home `/jackin/kimi-code` (`container_paths::KIMI_CODE_DIR`, crates/jackin-core/src/container\_paths.rs:38), else injected `provider_keys`, else env `KIMI_CODE_API_KEY` (crates/jackin-usage/src/usage.rs:909-916; usage/kimi.rs:269-297). (confidence: HIGH)
* The host credential matrix (docs/debug, no secret reads) mirrors this at crates/jackin-usage/src/host.rs:1035-1087. (confidence: HIGH)

### Q3 — Extracted fields and UI labels [#q3--extracted-fields-and-ui-labels]

* **Codex**: primary/secondary rate-limit windows (`used_percent`, `resets_at`, window duration) → buckets "Session" (StatusSlot::Session) and "Weekly" (StatusSlot::Weekly) (usage/codex.rs:567-584); per-limit-id extra limits (everything except limit id `codex`) → "`<label>` 5-hour" / "`<label>` Weekly" detail rows — the Codex-Spark entry yields "Codex Spark 5-hour"/"Codex Spark Weekly" (usage/codex.rs:446-448, 521-542, 586-609; fallback placeholders 163-204); "Limit Reset Credits" bucket with "N manual resets available · Next expires …" detail (usage/codex.rs:610-622, 649-675); "Credits" bucket with balance/unlimited (usage/codex.rs:624-637); plan label mapped following CodexBar — `pro` → "Pro 20x", pro-lite variants → "Pro 5x" (usage/codex.rs:36-76); account label from RPC email or JWT email (usage/codex.rs:501-511). (confidence: HIGH)
* **Claude**: authoritative `limits[]` entries (`kind` session/weekly\_all/weekly\_scoped, `percent`, `severity`, `resets_at`, `scope.model.display_name`) → "Session", "All models" (Weekly slot), and per-model weekly windows labeled by model display name (Fable etc., no per-model code) (usage/claude.rs:264-307, 361-380, 548-594); legacy named windows backfill → "Session", "Weekly", "Sonnet", "Opus", "Daily Routines" (usage/claude.rs:596-689); fallback placeholder buckets "Session"/"Weekly"/"Daily Routines" (usage/claude.rs:110-138); money-cap surfaces: "Extra usage" spend bucket (StatusSlot::Spend, Money-typed used/limit, disabled-reason honesty) from `spend{}` or legacy `extra_usage` (usage/claude.rs:309-336, 382-399, 740-823) and rotating-codename dollar-budget windows (e.g. `amber_ladder`) → title-cased dollar buckets with used/limit money (usage/claude.rs:691-736); plan label from `oauthAccount.organizationType` else `subscriptionType`/`rateLimitTier` (usage/claude.rs:140-147, 210-257); CLI fallback parses "Current session:", "Current week (all models):", "Current week (Sonnet only):", and generic `"Current week (<model>):"` lines (crates/jackin-usage/src/usage.rs:1535-1566), marked `UsageConfidence::Estimated` (usage/claude.rs:160-171). (confidence: HIGH)
* **Amp**: `free_remaining`/`free_limit`/`hourly_replenishment`/`individual_credits` (+account email) (usage/amp.rs:129-165) → buckets "Amp Free" (currency used/limit, remaining %, replenishment-derived "Resets in …" label) and "Individual credits" (usage/amp.rs:177-211, 278-337); plan label fixed "Amp Free" when data present (usage/amp.rs:99); CLI fallback parses "Signed in as", "Amp Free:", "Individual credits:" lines (usage/amp.rs:345-372). (confidence: HIGH)
* **Grok**: RPC billing — `monthlyLimit`, `onDemandCap`, `on_demand_enabled`, usage `includedUsed`/`onDemandUsed`/`totalUsed` (cents), billing cycle start/end (usage/grok.rs:129-163) → headline bucket labeled "Weekly"/"Monthly"/"Credits" by cycle length (Weekly slot; Grok has no session window), plus "Included usage" and "On-demand usage" detail rows (usage/grok.rs:223-334); web fallback extracts only `used_percent` + reset epoch from protobuf (usage/grok.rs:171-221); plan label `auth_mode` oidc → "SuperGrok" (usage/grok.rs:793-802); account from email/user\_id/team\_id keys (usage/grok.rs:786-791). (confidence: HIGH)
* **Z.AI**: `limits[]` with `type` TOKENS\_LIMIT/TIME\_LIMIT, unit/number windows, usage/currentValue/remaining/percentage, `nextResetTime` (ms) (usage/zai.rs:83-117) → buckets "5-hour" (Session slot, shortest token window), "Tokens" (Weekly slot, longest), "MCP" (time limit, count detail line) (usage/zai.rs:119-161); plan label from `planName`/aliases (usage/zai.rs:92-102, 163-170). (confidence: HIGH)
* **MiniMax**: per-model `model_remains[]` interval + weekly counts/percents/status/end-times (usage/minimax.rs:116-144) → buckets "General · 5h" (Session slot) and "General · Weekly" (Weekly slot) for the `general` model; other models render as `"<Model>"` / `"<Model> · Weekly"` detail rows (usage/minimax.rs:166-199, 283-316); "Usage: X / Y" count detail (usage/minimax.rs:318-333); plan label from subscribe/plan/combo titles (usage/minimax.rs:201-217). (confidence: HIGH)
* **Kimi**: `usage`/`usages[]` (scope FEATURE\_CODING preferred) detail limit/used/remaining/resetTime + `limits[]` rate windows (usage/kimi.rs:88-125) → buckets "Rate Limit" (Session slot, window-paced) and "Weekly" (Weekly slot) (usage/kimi.rs:127-160); fallback placeholders "Weekly" and "5-hour rate limit" (usage/kimi.rs:29-52); no plan label (usage/kimi.rs:60). (confidence: HIGH)
* Pace vocabulary (where emitted): "On pace" / "N% in reserve" / "N% in deficit" (`quota_pace_label`, usage/format.rs:164-191) — reserve/deficit against elapsed window, not a run-out projection. Grok buckets pass `None` for pace on both web and RPC branches (usage/grok.rs:215, 259 — verified 2026-07-24), even though the RPC path has period bounds. (confidence: HIGH)

### Q4 — Confirmed gaps [#q4--confirmed-gaps]

* **(a) No run-out/projection phrases — CONFIRMED.** Method: `grep -rniE "runs out|projected empty|lasts until|run-out|projection"` over `crates/jackin-usage` and `crates/jackin-usage-ffi` returned zero matches. The only forward-time strings produced are reset countdowns ("Resets in …", usage/amp.rs:332-336; `compact_duration_label` usage/format.rs:193-208), expiry labels (usage/format.rs:146-155), and the pace reserve/deficit tokens (usage/format.rs:184-190). (confidence: HIGH)
  * Adjacent signal outside the crate: the Swift Desktop shell *can split* a pace label of the form "On pace · Runs out in 4d 21h" (native/Sources/JackinDesktop/UsageWindow/ProviderCardView\.swift:209 comment cites CodexBar's dual-column pace; tests native/Tests/JackinUsageBridgeTests/ArchitectureTests.swift:368-369 and native/Tools/StatusItemChipHarness/main.swift:396-397 use that exact fixture), but no Rust producer emits such a phrase — the display splitter is fed only the vocabulary above. (confidence: HIGH)
* **(b) No Amp workspace credit balance — CONFIRMED.** `AmpApiUsage.individual_credits` (usage/amp.rs:135) is the only credit-balance field; the JSON parse looks for `individualCredits`/`individualBalance` only (usage/amp.rs:158-159), the CLI parse only for the "Individual credits:" line (usage/amp.rs:367-369). Method: `grep -n "workspace"` in usage/amp.rs → zero matches; no team/workspace key is requested or parsed, and the request asks only `userDisplayBalanceInfo` (usage/amp.rs:222-229). (confidence: HIGH)

### Q5 — Data flow to display surfaces [#q5--data-flow-to-display-surfaces]

* **Probe dispatch**: `build_snapshot` selects the per-surface probe and resolves keys (crates/jackin-usage/src/usage.rs:887-931); each probe returns a `FocusedUsageView` via the shared `usage_view` builder.
* **Cache + persistence (capsule and host share one path)**: `UsageCache::refresh_active_account_snapshots` (crates/jackin-usage/src/usage.rs:434) runs due probes, then persists all refreshed views with `usage_snapshot_store::store_usage_snapshots` (crates/jackin-usage/src/usage.rs:536-538) and materializes accounts JSON (crates/jackin-usage/src/usage.rs:543-545, 630-634). Readers call `UsageCache::focused_snapshot` (crates/jackin-usage/src/usage.rs:394).
* **Durable store**: `store_usage_snapshots` flattens each view into per-bucket `StoredAccountUsageSnapshot` rows (crates/jackin-usage/src/usage\_snapshot\_store.rs:80-90, row shape 47-73, SCHEMA\_VERSION "4" at line 24). Capsule store lives under `/jackin/state/` (module header, crates/jackin-usage/src/usage\_snapshot\_store.rs:4-9); host store at `<data_dir>/usage-menu-bar/snapshots.db` (crates/jackin-usage/src/host.rs:31, 233-235).
* **HostUsageRuntime** (crates/jackin-usage/src/host.rs:274-290): `open` wires the store/accounts paths into the cache (host.rs:312-320); `refresh` drives `cache.refresh_active_account_snapshots` under a ≥60s floor (host.rs:425-465); `snapshot` returns the live focused view or a selected durable account view (host.rs:493-515); `overview_rows` builds Desktop popover/Usage-window rows (percent headline, reset countdown + exact clock, status word, worst severity) (host.rs:783-831); compact menu-bar labels pick the min-remaining bucket (host.rs:682-761, 988-1003). Provider keys for Z.AI/MiniMax/Kimi are injected credential-free via `set_provider_key` (host.rs:393-399).
* **FFI layer** (crates/jackin-usage-ffi): `bridge.rs` wraps `HostUsageRuntime` with a coarse sync API — `snapshot` maps through `view_dto` (crates/jackin-usage-ffi/src/bridge.rs:95-100), `overview_rows` through `overview_row_dto` (bridge.rs:190-194). DTOs mirror the protocol views 1:1: `UsageViewDto` (crates/jackin-usage-ffi/src/dto.rs:62-80), `QuotaBucketDto` incl. `used_money`/`limit_money` Money mirrors and `status_slot` session/weekly/spend strings (dto.rs:44-58, 234-261), `OverviewRowDto` (dto.rs:93-101), `AccountDescriptorDto` (dto.rs:105-113). (all confidence: HIGH)
* **Settled-ground note (location only, not evaluated)**: monetary data in the pipeline is exclusively provider-supplied caps/balances (Claude "Extra usage" + dollar-budget windows, Grok billing cents, Amp dollars, Codex credits). A static USD-per-1M-token pricing table and per-session cost estimation exist in `crates/jackin-usage/src/token_monitor/pricing.rs:1-34` and `crates/jackin-usage/src/token_monitor.rs:180-187` (token-monitor internals, not part of the seven probes above). (confidence: HIGH)

### Current provider gaps and confirmations [#current-provider-gaps-and-confirmations]

* **Grok current config fields dropped**: official `x.ai/billing` carries
  `config.prepaidBalance`, `onDemandCap`, and `onDemandUsed`; jackin❯
  obsolete top-level decoder misses them. Extra Usage Credits and on-demand
  cap/used are quota bounds; `history`/`productUsage` remain excluded.
  (confidence: HIGH)
* **MiniMax documented host absent**: jackin❯ URL fan-out covers only `api.minimax.io` / `api.minimaxi.com` (usage/minimax.rs:391-394); the officially documented host `www.minimax.io` (chapter 06) is not probed. (confidence: HIGH)
* **Codex OAuth client-id parity OK**: jackin❯ `CODEX_OAUTH_CLIENT_ID = app_EMoamEEZ73f0CkXaXp7hrann` (crates/jackin-usage/src/usage.rs:1295) matches the official CLI's client id (chapter 02). No stale-constant risk. (confidence: HIGH)

### Dead ends and contradictions [#dead-ends-and-contradictions]

* No probe has a macOS Keychain credential reader; comments state the origin always names a file (usage/claude.rs:48-49). Ruled out.
* Claude env keys (`ANTHROPIC_API_KEY`/`ANTHROPIC_AUTH_TOKEN`) are not used to fetch usage; presence/origin only (usage/claude.rs:73-89). Same for Codex `OPENAI_API_KEY` env and Grok `XAI_API_KEY`/`GROK_DEPLOYMENT_KEY` env (usage/codex.rs:113-121; usage/grok.rs:29-30, 59-71).
* Telemetry route-template vs actual URL mismatch for Codex reset credits: the telemetry label says `/backend-api/wham/usage/reset_credits` (usage/codex.rs:1011) while the real request path is `{base}/wham/rate-limit-reset-credits` (usage/codex.rs:1033-1038). Label-only discrepancy; the HTTP call uses the latter.
* Credential-origin label vs actual source for MiniMax/Z.AI: MiniMax always reports "API token · env MINIMAX\_API\_KEY" (usage/minimax.rs:49-56) and Z.AI "API token · env ZAI\_API\_KEY" (usage/zai.rs:58-62) even when the key came from `MINIMAX_CODING_API_KEY`, `Z_AI_API_KEY`, or the injected `provider_keys` map (crates/jackin-usage/src/usage.rs:901-926). Cosmetic origin inaccuracy, not a data-flow issue.
* Codex RPC reset credits carry only `availableCount` (usage/codex.rs:464-467, 543-548); expiry detail ("Next expires …") is available only on the OAuth HTTP path (usage/codex.rs:988-1021, 649-675) — the two sources are not equivalent for that bucket.
* No embedded instructions were encountered in any file read; comments referencing CodexBar/OpenUsage are provenance notes, not directives.

## Implications for jackin❯ [#implications-for-jackin]

Keep one normalized limits pipeline, but correct provider-specific credential, freshness, reset-credit, and account-balance gaps before Desktop treats every probe as equivalent.

## Limitations and unknowns [#limitations-and-unknowns]

* Whether the Amp `userDisplayBalanceInfo` endpoint *could* return a workspace/team balance field that the parser silently drops (the parser whitelists keys, so any such field would be ignored) — determining this requires observing a live response from a workspace-attached Amp account, not the codebase. (LOW lead)
* Whether `seven_day_oauth_apps` (explicitly ignored, usage/claude.rs:268-271) carries limit data that would matter for Desktop; code states it is not a CodexBar quota window, but its live payload shape was not verified here. (LOW lead)
* The Grok web-billing protobuf field mapping (path `[.., 1]` fixed32 = used percent, epoch varints = reset) is heuristic by construction (usage/grok.rs:553-600); which proto schema it actually corresponds to is unverified against any xAI IDL. (MED — code read is primary, wire schema is not)
* OpenCode has a probe surface (`opencode_snapshot`, crates/jackin-usage/src/usage.rs:928) outside this chapter's seven-file scope; its endpoint/credential story is not covered here.

## Sources [#sources]

* <RepoFile path="crates/jackin-usage/src/usage/codex.rs" /> — representative provider probe and normalization path.
* <RepoFile path="crates/jackin-usage-ffi/src/dto.rs" /> — desktop-facing quota DTOs.

## Related work [#related-work]

* [Provider API coverage](/research/product/desktop/usage-provider-apis/)
* [Codex API evidence](/research/product/desktop/usage-provider-apis/02-codex-api/)
