01 — jackin-usage current provider coverage
Inventories current provider probes, credential sources, normalized fields, coverage gaps, and display flow.
Summary
Current probes cover seven providers through one normalized limits pipeline, with provider-specific credential and quota gaps documented below.
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: codebase read Verification cutoff: 2026-07-24
All paths below are relative to the repository root unless absolute. usage/ means crates/jackin-usage/src/usage/.
Findings
Q1 — Endpoints/URLs 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 methodsaccount/rateLimits/read(usage/codex.rs:771) andaccount/read(usage/codex.rs:781). (confidence: HIGH) - OAuth HTTP: base URL from
$CODEX_HOME/config.tomlchatgpt_base_url, defaulthttps://chatgpt.com/backend-api(usage/codex.rs:1040-1062); usage path/wham/usage(or/api/codex/usagefor non-backend-api bases) viaresolve_codex_usage_url(usage/codex.rs:1023-1031); reset-credits at{base}/wham/rate-limit-reset-creditsviaresolve_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/tokenwith 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)
- CLI RPC: spawns
- Claude (usage/claude.rs) — GET
https://api.anthropic.com/api/oauth/usagewithanthropic-beta: oauth-2025-04-20and aclaude-code/<version>User-Agent (endpoint gated to that UA) (usage/claude.rs:825-846; UA resolution 848-873, fallbackclaude-code/2.1.0at crates/jackin-usage/src/usage.rs:179). Fallback when OAuth fetch fails but a token exists: CLIclaude -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?userDisplayBalanceInfowith JSON body{"method":"userDisplayBalanceInfo","params":{}}(usage/amp.rs:214-243). Fallback: CLIamp --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(orgrokon PATH) (usage/grok.rs:355-366, 440-447); JSON-RPC methodx.ai/billing(usage/grok.rs:416-423). (confidence: HIGH) - Web fallback: POST
https://grok.com/grok_api_v2.GrokBuildBilling/GetGrokCreditsConfigas gRPC-web+proto with bearer token; response parsed by a hand-rolled protobuf scanner (usage/grok.rs:461-506, 553-600). (confidence: HIGH)
- CLI ACP RPC preferred: spawns
- Z.AI (usage/zai.rs) — GET
{host}/api/monitor/usage/quota/limit, default hosthttps://api.z.ai; overridable viaZAI_QUOTA_URL/Z_AI_QUOTA_URL(full URL) orZAI_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 onhttps://api.minimaxi.com(usage/minimax.rs:391-394); overridesMINIMAX_REMAINS_URL/MINIMAX_API_HOST/MINIMAX_HOST(usage/minimax.rs:371-374). Sends headerMM-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)
- Codex: OAuth token file
$CODEX_HOME/auth.json(envCODEX_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.jsonmay alternatively carry anOPENAI_API_KEYstring (usage/codex.rs:262-274). EnvOPENAI_API_KEYis 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 keyclaudeAiOauth.accessToken(usage/claude.rs:235-257). EnvANTHROPIC_API_KEY/ANTHROPIC_AUTH_TOKENare 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_KEYwins; 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 byhttps://auth.x.ai::(OIDC) or legacy sign-in scopes, with expiry check (usage/grok.rs:508-551). EnvXAI_API_KEY/GROK_DEPLOYMENT_KEYare presence/origin only (usage/grok.rs:29-30, 59-71). (confidence: HIGH) - Z.AI: API key only — injected
provider_keysmap (Desktopset_provider_key), else envZ_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 injectedprovider_keys, else envMINIMAX_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.jsonor~/.kimi/credentials/kimi-code.json(expiry-checkedaccess_token), else same file under handoff home/jackin/kimi-code(container_paths::KIMI_CODE_DIR, crates/jackin-core/src/container_paths.rs:38), else injectedprovider_keys, else envKIMI_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
- 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 idcodex) → "<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 (kindsession/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) fromspend{}or legacyextra_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 fromoauthAccount.organizationTypeelsesubscriptionType/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), markedUsageConfidence::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, usageincludedUsed/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 onlyused_percent+ reset epoch from protobuf (usage/grok.rs:171-221); plan labelauth_modeoidc → "SuperGrok" (usage/grok.rs:793-802); account from email/user_id/team_id keys (usage/grok.rs:786-791). (confidence: HIGH) - Z.AI:
limits[]withtypeTOKENS_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 fromplanName/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 thegeneralmodel; 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 passNonefor 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
- (a) No run-out/projection phrases — CONFIRMED. Method:
grep -rniE "runs out|projected empty|lasts until|run-out|projection"overcrates/jackin-usageandcrates/jackin-usage-ffireturned zero matches. The only forward-time strings produced are reset countdowns ("Resets in …", usage/amp.rs:332-336;compact_duration_labelusage/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 forindividualCredits/individualBalanceonly (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 onlyuserDisplayBalanceInfo(usage/amp.rs:222-229). (confidence: HIGH)
Q5 — Data flow to display surfaces
- Probe dispatch:
build_snapshotselects the per-surface probe and resolves keys (crates/jackin-usage/src/usage.rs:887-931); each probe returns aFocusedUsageViewvia the sharedusage_viewbuilder. - 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 withusage_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 callUsageCache::focused_snapshot(crates/jackin-usage/src/usage.rs:394). - Durable store:
store_usage_snapshotsflattens each view into per-bucketStoredAccountUsageSnapshotrows (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):
openwires the store/accounts paths into the cache (host.rs:312-320);refreshdrivescache.refresh_active_account_snapshotsunder a ≥60s floor (host.rs:425-465);snapshotreturns the live focused view or a selected durable account view (host.rs:493-515);overview_rowsbuilds 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 viaset_provider_key(host.rs:393-399). - FFI layer (crates/jackin-usage-ffi):
bridge.rswrapsHostUsageRuntimewith a coarse sync API —snapshotmaps throughview_dto(crates/jackin-usage-ffi/src/bridge.rs:95-100),overview_rowsthroughoverview_row_dto(bridge.rs:190-194). DTOs mirror the protocol views 1:1:UsageViewDto(crates/jackin-usage-ffi/src/dto.rs:62-80),QuotaBucketDtoincl.used_money/limit_moneyMoney mirrors andstatus_slotsession/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-34andcrates/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
- Grok current config fields dropped: official
x.ai/billingcarriesconfig.prepaidBalance,onDemandCap, andonDemandUsed; jackin❯ obsolete top-level decoder misses them. Extra Usage Credits and on-demand cap/used are quota bounds;history/productUsageremain 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 hostwww.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
- 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 CodexOPENAI_API_KEYenv and GrokXAI_API_KEY/GROK_DEPLOYMENT_KEYenv (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 injectedprovider_keysmap (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❯
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
- Whether the Amp
userDisplayBalanceInfoendpoint 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
crates/jackin-usage/src/usage/codex.rs— representative provider probe and normalization path.crates/jackin-usage-ffi/src/dto.rs— desktop-facing quota DTOs.