Repository navigation
Conversation
Add Grok Build as a managed app (--app grokbuild, aliases grok, grok-build, grok_build): provider add/edit/switch on ~/.grok/config.toml, proxy takeover with backup/restore, MCP, skills, prompts, env detection, TUI forms and deeplink imports. Add xAI OAuth managed accounts (cc-switch auth xai ...) and xai-oauth provider templates for Claude and Codex. Like Codex OAuth they bind a signed-in account instead of an API key, route through the local proxy with the managed token, and show the account's built-in weekly quota. Grok Official uses the same built-in quota without a usage template. Closes SaladDay#403
632671d to
f023224
Compare
|
@claude review |
|
@SaladDay could you take a look when you have a moment? |
Resolve the TUI provider-form conflicts between the managed-account rename (ManagedAccount / managed_account_id) and SaladDay#550's ChatGPT account binding for Codex official providers: the official-provider binding is ported onto the renamed field, so serialization, loading, the account picker, help text and tests keep both behaviors.
|
Merged What conflicted: the TUI provider-form files ( Resolution: unified on this branch's naming. #550's official-provider behavior is ported onto Validation (fresh Linux container, Rust 1.91.1):
|
Summary
Adds Grok Build (xAI) as a managed app and adds xAI OAuth sign-in providers for Claude Code and Codex. Closes #403.
Grok Build (
--app grokbuild, aliasesgrok,grok-build,grok_build)[model."..."]profile and[models].defaultin~/.grok/config.toml. Global settings, other custom models, MCP tables and~/.grok/auth.jsonare kept. Switches use the same crash-safe live engine as Codex./grokbuild/v1/responseswith backup/restore. While routed, Grok Official uses the managed xAI account.[mcp_servers]), Skills,AGENTS.mdprompts, env detection, TUI forms/templates, deeplink imports and a PackyCode sponsor preset.r). Like the managed OAuth providers in fix(tui): align managed Codex OAuth quota with upstream #534, its form has no Usage Query entry.grok.xAI OAuth providers (OAuth sign-in, not API key)
cc-switch auth xai login|status|list|default|remove|logoutmanages xAI device-flow accounts (stored in the CC-Switch config directory, mode 0600, refreshed per request).auth codex ...(aliasauth openai ...) mirrors it for ChatGPT accounts.xai-oauthtemplates:xAI (Grok)in Claude andxAI (Grok) OAuthin Codex, the same names as the desktop presets. They work like the Codex OAuth provider: the form binds a signed-in xAI account (or follows the default) and has no Base URL, API Key or Usage Query fields.provider currentand the add summary show the bound account.api.x.ai/v1with the account token injected. Claude traffic is converted from Anthropic Messages to the xAI Responses API. Codex uses native Responses with namespace-tool flattening and strict-field sanitization for xAI. Default modelgrok-4.7.Validation
What is being validated: xAI/Grok OAuth sign-in, not an API-key provider
xAI (Grok) support here is a managed OAuth sign-in provider, built the same way as the existing Codex OAuth (ChatGPT sign-in) provider. It is not a generic API-key provider pointed at
api.x.ai.cc-switch auth codex logincc-switch auth xai loginCodex(Claude)xAI (Grok)(Claude),xAI (Grok) OAuth(Codex), same names as the desktop presetsCustom/ built-in presetsprovider currentChatGPT Account: <id | follow default>xAI Account: <id | follow default>API Key: ...The weekly quota therefore reflects the signed-in Grok subscription, and every request is billed to that subscription. Nothing in this PR asks for or stores an xAI API key.
Environment
End-to-end run on 2026-10-29 in a clean Linux container (Debian, Rust 1.91.1 build of this branch), with no API keys in the environment. The only credential was one xAI account signed in through
cc-switch auth xai login(device flow). The email and account ID are redacted below.Results
xai-oauth(--template xai-oauth, no API key)127.0.0.1:15721"result":"GROK-OK",is_error:false, modelgrok-4.7weekly_limit, validxai-oauth(--template xai-oauth, no API key)127.0.0.1:15722agent_message "GROK-OK",turn.completed, no ChatGPT login requiredweekly_limit, validgrokbuild-official127.0.0.1:15724GROK-OKweekly_limit, valid1. Sign in to xAI
2. Claude Code routed to xAI (OAuth sign-in, no API key)
The provider has no API key. It is bound to the signed-in xAI account ("Follow default" means the account marked default in
cc-switch auth xai status). The template rejects--api-key,--base-url,--modeland--config.Claude Code also prints
[claude-code:unrecognized_model] {"model":"grok-4.7"}to stderr because it has no built-in metadata for non-Anthropic model names. The request still completes.3. Codex routed to xAI (OAuth sign-in, no ChatGPT login, no API key)
Codex holds only the
PROXY_MANAGEDplaceholder. The real xAI token never reaches~/.codex.For comparison, before the provider was added, the same
codex execwent toapi.openai.comand failed with401 Unauthorized: Missing bearer or basic authentication.4. Grok Build with Grok Official through the cc-switch route
Grok Build itself was never logged in (
~/.grok/auth.jsondoes not exist). The proxy adds the cc-switch managed xAI token to each request.TUI: the xAI OAuth form binds an account, like Codex OAuth
These captures come from the TUI (
cc-switch) in the container, using the build tested above. Adding a provider with the xAI template (xAI (Grok)in Claude,xAI (Grok) OAuthin Codex, as in the desktop app) gives the same form shape as the existing ClaudeCodex(ChatGPT OAuth) template: an account picker, and no Base URL, API Key or Usage Query fields.Claude, Add Provider, template
xAI (Grok):Enter on
xAI Accountlists the accounts signed in withcc-switch auth xai login:Codex, Add Provider, template
xAI (Grok) OAuth:For contrast, the
Customtemplate on the same screen showsBase URL,API Key,Upstream formatand aUsage Querytoggle. The xAI OAuth form shows none of them, because the endpoint and token come from the bound account and the quota comes from the account's built-in weekly query.TUI: Grok Official quota is built in
The Grok Build tab is shown as
grokin the TUI header, the same way Claude Code is shown asclaude. Grok Official shows the weekly quota of the signed-in account in the provider list, andrrefreshes it. Its edit form has noUsage Queryrow, the same as the managed OAuth providers (follows #534). Before this change the form showedUsage Query Disabledeven though the quota was being queried.Edit Provider: Grok Official
5. All three routes active
6. Restore
On restore, the managed
cc-switch-grok-officialprofile and thePROXY_MANAGEDplaceholder are removed. Settings that Grok Build wrote itself ([marketplace]) are kept.7. Proof the upstream is xAI
Requests below went straight to the local proxy routes with only the
PROXY_MANAGEDplaceholder as a credential. The response headers and body fields come from the upstream server unchanged. Long opaque values are elided.Claude route. The client asks for
claude-opus-5. The proxy maps it togrok-4.7and calls xAI.Codex route. This is a Responses API passthrough.
The evidence:
Domain=x.ai.x-metrics-ttft-ms,x-zero-data-retentionandx-data-retentionare xAI response headers.cost_in_usd_ticks,num_sources_usedandnum_server_side_tools_usedare xAI-only usage fields."model":"grok-4.7", and on the Claude route the proxy sentgrok-4.7upstream in place of the requestedclaude-opus-5.Negative controls. The container has no other model credentials:
Not logged in · Please run /login.api.openai.comand gets401 Unauthorized.Successful replies can therefore only have come through the xAI OAuth token. In an earlier run, while the weekly allowance was exhausted, all three clients received xAI's
personal-team-blocked:spending-limiterror through the same routes.Proxy request log. These are rows from
proxy_request_logsincc-switch.db, recorded during the first run, when the xAI OAuth providers had the IDxai-grok.request_modelis what the client sent andmodelis what went upstream.Why weekly usage still reads 0%. The quota comes from xAI's
GrokBuildBilling/GetGrokCreditsConfigresponse, which returned no usage-percent field. Protobuf leaves out a field whose value is 0, so the API is reporting 0% used. One test request costs about 4.2M ticks, roughly $0.0004 (1 tick = 1e-10 USD), so a few validation runs do not move the weekly percentage. When the allowance was used up, the same query returnedutilization: 100.0.Automated checks
Run in the Linux container on the same build:
cargo test --lib: 4626 passed, 0 failed, 2 ignored. This includesgrok_official_form_uses_built_in_quota_without_usage_queryandxai_oauth_form_binds_an_account_instead_of_an_api_key. The latter covers Claude and Codex: account field shown; Base URL, API key, API format and Usage Query hidden;authBindingsaved and reloaded.cargo test --test grokbuild: 17 passed.cargo fmt --checkpasses.cargo clippy --all-targetsadds no new findings compared withmain.main. I checked this by running the same subset on a pristine checkout. They are unrelated to this change.