152 lines
6.6 KiB
Markdown
152 lines
6.6 KiB
Markdown
---
|
|
summary: "Grok provider data sources: ACP JSON-RPC, grok.com billing fallback, OAuth credentials, and local session signals."
|
|
read_when:
|
|
- Debugging Grok billing/usage parsing
|
|
- Updating `grok agent stdio` JSON-RPC integration
|
|
- Adjusting `~/.grok/auth.json` credential reading
|
|
---
|
|
|
|
# Grok provider
|
|
|
|
Grok uses xAI's official Grok Build CLI (`grok`, released 2026-05-14). Usage data is
|
|
fetched via the ACP JSON-RPC `x.ai/billing` extension method over `grok agent stdio`
|
|
when available, then via grok.com's billing gRPC-web endpoint using the signed-in
|
|
browser session when the CLI surface does not expose billing.
|
|
|
|
## Data sources + fallback order
|
|
|
|
1) **`~/.grok/auth.json` (primary; always works for SuperGrok subscribers)**
|
|
- Reads `email`, `team_id`, `first_name`/`last_name`, plan-hint (`auth_mode`)
|
|
for the identity row in the menu.
|
|
2) **`grok agent stdio` ACP JSON-RPC** (best-effort, currently disabled in grok 0.1.210)
|
|
- We spawn `grok agent stdio` and call `initialize` + `x.ai/billing` (no params).
|
|
- **Known limitation:** in grok 0.1.210 the `x.ai/billing` extension method
|
|
is only wired in the interactive TUI; the agent-stdio surface returns
|
|
`-32601 Method not found`. The provider degrades silently to identity-only
|
|
when this happens. When xAI exposes billing on the agent protocol, no
|
|
code change is required.
|
|
- One non-obvious quirk: grok's ACP parser does not unescape `\/` in method
|
|
names. `Foundation.JSONSerialization.data` defaults to escaping forward
|
|
slashes, so payloads must be re-encoded with `\/` → `/` before being
|
|
written to stdin or grok will silently drop them (12s client-side
|
|
timeout instead of the expected error response).
|
|
3) **grok.com billing gRPC-web fallback** (best-effort)
|
|
- POSTs an empty gRPC-web protobuf request to
|
|
`https://grok.com/grok_api_v2.GrokBuildBilling/GetGrokCreditsConfig`.
|
|
- Uses grok.com browser session cookies. When a non-expired
|
|
`~/.grok/auth.json` token is available, CodexBar first sends it with each
|
|
browser session, then retries that session with cookies only.
|
|
- CodexBar imports Chrome only by default to avoid unrelated browser
|
|
Keychain prompts.
|
|
- CLI/test runtime does not import browser cookies unless
|
|
`CODEXBAR_ALLOW_BROWSER_COOKIE_IMPORT=1` is set.
|
|
- `~/.grok/auth.json` is still used for identity and as a last best-effort
|
|
bearer-only probe after browser sessions fail. Expired tokens are not sent.
|
|
- Parses the returned protobuf enough to recover used percent and
|
|
reset timestamp, accepting both gRPC-web frames and the raw protobuf form
|
|
returned by some successful requests. A current billing period with an
|
|
omitted proto3 `credit_usage_percent` is treated as zero usage. This keeps
|
|
billing visible when `grok agent stdio` returns `Method not found`.
|
|
4) **Local session signals** (informational fallback)
|
|
- Walks `~/.grok/sessions/<encoded-cwd>/<session-id>/signals.json` files (last 30 days).
|
|
- Aggregates `totalTokensBeforeCompaction`, `contextTokensUsed`, `modelsUsed`,
|
|
and the most recent session timestamp.
|
|
|
|
## OAuth credentials
|
|
|
|
- File: `~/.grok/auth.json` (path overridable via `GROK_HOME`).
|
|
- Top-level keys are OIDC scope URLs. CodexBar prefers entries under
|
|
`https://auth.x.ai::<client-id>` (SuperGrok), falling back to
|
|
`https://accounts.x.ai/sign-in` (legacy session).
|
|
- Required fields per entry: `key` (bearer token), `refresh_token`, `expires_at`,
|
|
`auth_mode`, `email`, `team_id`, `user_id`, `first_name`/`last_name`.
|
|
- Tokens are issued by `grok login` and expire after ~7 days; refresh is handled by
|
|
the CLI itself (CodexBar does not refresh; it just reads the cached credential).
|
|
|
|
## JSON-RPC contract
|
|
|
|
- Transport: stdin/stdout, newline-delimited JSON-RPC 2.0 (no Content-Length framing).
|
|
- `initialize` params:
|
|
```json
|
|
{
|
|
"protocolVersion": "1",
|
|
"clientCapabilities": {
|
|
"fs": { "readTextFile": false, "writeTextFile": false },
|
|
"terminal": false
|
|
}
|
|
}
|
|
```
|
|
- `x.ai/billing` result shape (all monetary values are `{ val: <cents> }`):
|
|
```json
|
|
{
|
|
"billingCycle": {
|
|
"billingPeriodStart": "2026-05-01T00:00:00Z",
|
|
"billingPeriodEnd": "2026-06-01T00:00:00Z"
|
|
},
|
|
"monthlyLimit": { "val": 99900 },
|
|
"onDemandCap": { "val": 0 },
|
|
"on_demand_enabled": false,
|
|
"disabledByConfig": false,
|
|
"usage": {
|
|
"includedUsed": { "val": 12345 },
|
|
"onDemandUsed": { "val": 0 },
|
|
"totalUsed": { "val": 12345 }
|
|
}
|
|
}
|
|
```
|
|
- Auth errors surface as JSON-RPC errors with the message
|
|
`"Authentication required to fetch billing data. Run 'grok login' to authenticate."`.
|
|
- Timeouts: 8s for `initialize`, 12s for `x.ai/billing`. CodexBar terminates the
|
|
child `grok` process on timeout to avoid leaking subprocesses.
|
|
|
|
## Mapping to `UsageSnapshot`
|
|
|
|
- **Primary window** = credit usage (against the subscription/included limit):
|
|
- CLI RPC: `usedPercent` = `usage.totalUsed.val / monthlyLimit.val * 100`;
|
|
`resetsAt` = `billingCycle.billingPeriodEnd`.
|
|
- grok.com fallback: `usedPercent` and `resetsAt` parsed from the gRPC-web
|
|
billing protobuf.
|
|
- The UI label for the live usage bar is dynamic: "Weekly" or "Monthly"
|
|
when `resetsAt` matches a common cycle, falling back to the registered
|
|
"Credits" label otherwise. Settings and history views continue to use
|
|
"Credits" as the stable metric name.
|
|
- **Identity**:
|
|
- `accountEmail` from credential `email`.
|
|
- `accountOrganization` from credential `team_id`.
|
|
- `loginMethod` = "SuperGrok" for OIDC, otherwise the raw `auth_mode`.
|
|
|
|
## Local fallback (`~/.grok/sessions/`)
|
|
|
|
Each session directory contains `signals.json` with fields like:
|
|
|
|
```json
|
|
{
|
|
"turnCount": 1,
|
|
"contextTokensUsed": 2968,
|
|
"contextWindowTokens": 512000,
|
|
"totalTokensBeforeCompaction": 0,
|
|
"modelsUsed": ["grok-build"],
|
|
"primaryModelId": "grok-build",
|
|
"sessionDurationSeconds": 47
|
|
}
|
|
```
|
|
|
|
CodexBar aggregates these into a `GrokLocalSessionSummary` (session count, total
|
|
tokens, last session time, primary model) and exposes it for diagnostics even when
|
|
the RPC path is unavailable.
|
|
|
|
## Status
|
|
|
|
xAI has not exposed a Statuspage-style status feed yet. The "View Status" link
|
|
points to `https://status.x.ai`.
|
|
|
|
## Key files
|
|
|
|
- `Sources/CodexBarCore/Providers/Grok/GrokProviderDescriptor.swift`
|
|
- `Sources/CodexBarCore/Providers/Grok/GrokAuth.swift`
|
|
- `Sources/CodexBarCore/Providers/Grok/GrokRPCClient.swift`
|
|
- `Sources/CodexBarCore/Providers/Grok/GrokWebBillingFetcher.swift`
|
|
- `Sources/CodexBarCore/Providers/Grok/GrokStatusProbe.swift`
|
|
- `Sources/CodexBarCore/Providers/Grok/GrokLocalSessionScanner.swift`
|
|
- `Sources/CodexBar/Providers/Grok/GrokProviderImplementation.swift`
|