feat: add Grok Build as a first-class coding agent#195
Conversation
WalkthroughAdds ChangesGrok agent support
Estimated code review effort: 3 (Moderate) | ~25 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Greptile SummaryThis PR adds Grok Build (
Confidence Score: 5/5Safe to merge; no logic errors were found in the Grok model/effort/freeform delta or the shared session-control reconnect changes. The Grok provider's auth selection, reasoning-effort projection, and freeform-to-'Other' encoding are all correct and backed by comprehensive deterministic tests. The session identity binding is well-designed with proper generation tracking, intent deduplication, and stale-open fencing. The vendor resume publisher correctly coalesces concurrent writes and skips a redundant server round-trip for metadata-backed resumes. The single finding — the node budget in normalizeAskUserQuestionInput comparing against a string-length constant — is a code-clarity issue that does not create an exploitable gap because the string budget and array-length checks already provide equivalent coverage in every reachable path. apps/cli/src/agent/questions/normalizeAskUserQuestionInput.ts — accountNode uses maxTotalStringLength as the node limit instead of a dedicated constant; worth clarifying for future maintainability.
|
| Filename | Overview |
|---|---|
| apps/cli/src/agent/questions/normalizeAskUserQuestionInput.ts | Produces a bounded JSON-safe snapshot for AskUserQuestion publication. The accountNode helper compares budget.nodes against STRUCTURED_QUESTION_LIMITS.maxTotalStringLength (a string-byte limit) instead of a dedicated node count limit, making the node budget check redundant with the string budget. |
| apps/cli/src/agent/acp/runtime/sessionIdentityBinding.ts | New shared binding for ACP session identities: enforces intent deduplication, generation staleness fencing, pre-bind failure tracking, and waits for in-flight publication before completing reset. Well-designed with comprehensive test coverage. |
| apps/cli/src/session/metadata/createVendorResumeIdMetadataPublisher.ts | Replaces the deleted createProviderSessionIdMetadataUpdater with a generation-aware, in-flight-coalescing metadata publisher; correctly skips a redundant write for resume sessions whose ID already matches persisted metadata. |
| apps/cli/src/backends/grok/acp/extensionHandlers.ts | Handles x.ai/ask_user_question extension: parses/validates Grok payloads, builds SHA-256 correlation digest, maps freeform text to the 'Other' placeholder with annotations, and wires into the canonical permission handler. Logic is correct and well-guarded. |
| apps/cli/src/backends/grok/acp/auth.ts | Grok ACP auth selection: prioritizes XAI_API_KEY when advertised, falls through to defaultAuthMethodId-backed grok.com/cached_token, and correctly avoids auto-selecting a non-default grok.com (logged-out) method. |
| apps/cli/src/backends/grok/acp/modelControls.ts | Projects reasoning effort from Grok's model meta, validates that the current value is in the advertised set, and assembles requestMeta for set_model. Projection and validation logic is correct. |
| packages/agents/src/manifest.ts | Adds grok to AGENTS_CORE with vendorResume: 'experimental', runtime_checked policy, grokSessionId metadata field, and exclusive local-control topology — all consistent with the Grok ACP contract described in the PR. |
| packages/agents/src/models.ts | Adds grok to AGENT_MODEL_CONFIG with supportsSelection:true, dynamicProbe:'auto', and grok-build as the sole static fallback model; supportsFreeform:false is consistent with a structured-only effort control. |
| apps/cli/src/agent/runtime/runStandardAcpProvider.ts | Adds rebindOverrideSynchronizerSession to the session-swap hook so override synchronizers follow reconnects; swap failures from synchronizer rebind and provider hook are aggregated correctly before re-throwing. |
| apps/cli/src/agent/questions/normalizeStructuredQuestionAnswersV1.ts | Validates and normalizes structured question answers; includes a bounded legacy comma-string decoder with a state-explosion cap and strict exact-match round-trip for legacy downgrade detection. Logic is correct. |
Sequence Diagram
%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
participant GrokCLI as Grok CLI
participant AcpBackend as AcpBackend
participant IdentityBinding as SessionIdentityBinding
participant MetaPublisher as VendorResumeIdPublisher
participant ExtHandler as ExtensionHandler
participant PermHandler as PermissionHandler
GrokCLI->>AcpBackend: initialize (advertises authMethods)
AcpBackend->>AcpBackend: resolveGrokAcpAuthentication()
AcpBackend->>GrokCLI: authenticate(methodId)
GrokCLI->>AcpBackend: session/new or session/load + sessionId + models
AcpBackend->>IdentityBinding: open(intent, openSession)
IdentityBinding->>IdentityBinding: validateAcpOpenedSessionIdentity()
IdentityBinding->>MetaPublisher: persistBound(AcpBoundSessionIdentity)
MetaPublisher->>MetaPublisher: skip if resume already in metadata
MetaPublisher-->>IdentityBinding: published
IdentityBinding-->>AcpBackend: identity + result
Note over AcpBackend: sessionModelAdapter.projectModelOptions() injects reasoning_effort
GrokCLI->>ExtHandler: x.ai/ask_user_question (structured payload)
ExtHandler->>ExtHandler: parseGrokAskUserQuestionRequest() + SHA-256 digest
ExtHandler->>PermHandler: handleToolCall(toolCallId, AskUserQuestion, input)
PermHandler-->>ExtHandler: decision + StructuredQuestionAnswersV1
ExtHandler->>ExtHandler: buildGrokAskUserQuestionAcceptedResponse()
ExtHandler-->>GrokCLI: outcome accepted + answers + annotations
Note over AcpBackend,IdentityBinding: On reconnect/session-swap
AcpBackend->>IdentityBinding: reset() aborts active, increments generation
IdentityBinding->>IdentityBinding: await previous operation drain
AcpBackend->>IdentityBinding: open(intent resume, expectedVendorSessionId)
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
participant GrokCLI as Grok CLI
participant AcpBackend as AcpBackend
participant IdentityBinding as SessionIdentityBinding
participant MetaPublisher as VendorResumeIdPublisher
participant ExtHandler as ExtensionHandler
participant PermHandler as PermissionHandler
GrokCLI->>AcpBackend: initialize (advertises authMethods)
AcpBackend->>AcpBackend: resolveGrokAcpAuthentication()
AcpBackend->>GrokCLI: authenticate(methodId)
GrokCLI->>AcpBackend: session/new or session/load + sessionId + models
AcpBackend->>IdentityBinding: open(intent, openSession)
IdentityBinding->>IdentityBinding: validateAcpOpenedSessionIdentity()
IdentityBinding->>MetaPublisher: persistBound(AcpBoundSessionIdentity)
MetaPublisher->>MetaPublisher: skip if resume already in metadata
MetaPublisher-->>IdentityBinding: published
IdentityBinding-->>AcpBackend: identity + result
Note over AcpBackend: sessionModelAdapter.projectModelOptions() injects reasoning_effort
GrokCLI->>ExtHandler: x.ai/ask_user_question (structured payload)
ExtHandler->>ExtHandler: parseGrokAskUserQuestionRequest() + SHA-256 digest
ExtHandler->>PermHandler: handleToolCall(toolCallId, AskUserQuestion, input)
PermHandler-->>ExtHandler: decision + StructuredQuestionAnswersV1
ExtHandler->>ExtHandler: buildGrokAskUserQuestionAcceptedResponse()
ExtHandler-->>GrokCLI: outcome accepted + answers + annotations
Note over AcpBackend,IdentityBinding: On reconnect/session-swap
AcpBackend->>IdentityBinding: reset() aborts active, increments generation
IdentityBinding->>IdentityBinding: await previous operation drain
AcpBackend->>IdentityBinding: open(intent resume, expectedVendorSessionId)
Reviews (6): Last reviewed commit: "feat(grok): complete model effort and qu..." | Re-trigger Greptile
a01b809 to
af1d9f5
Compare
Findings Addressed:
|
…ect fixtures Verified against the shipping Antigravity (agy) and Grok Build (grok) CLIs: - grok login: use the real `grok login` subcommand (browser OIDC) instead of an interactive `/login` slash, which is not a Grok TUI command. - agy login: launch `agy` bare (auto Google Sign-In on first run); agy has no `auth` subcommand, so `agy auth login` never authenticated. - grok model: the CLI reports `grok-build` (default `grok-composer-2.5-fast`), not `grok-build-0.1`; drop the redundant `default` from allowedModes. - grok auth probe: the CLI only reads `XAI_API_KEY`; drop unused `GROK_API_KEY`. - CLI detect fixtures: add agy/grok entries so `Record<AgentId, DetectCliEntry>` typechecks after agy/grok were added to AGENT_IDS.
|
Pushed
Validation: |
|
Hi @jaylfc ! Thank you very much for your contribution! I don't see the
|
The Antigravity CLI (`agy`) has no native ACP mode: `agy --acp`, `--experimental-acp`, and an `acp` subcommand all fail, and the binary exposes no stdio JSON-RPC server. The upstream request to add it (google-antigravity/antigravity-cli#31) is still open, so agy cannot be driven as a generic ACP agent. The only working paths today (a third-party Bun DB-polling bridge, or a custom shim reading agy's private SQLite store) violate Google's ToS — which has led to real account bans — and depend on undocumented internals. Not shippable. Remove all agy wiring (types, acp, auth, localCli, manifest, models, sessionModes, providerCliRuntime, CLI catalog, detect fixtures, tests) and keep grok, which speaks ACP natively via `grok agent stdio`. agy can return once native ACP lands upstream.
|
Hi @leeroybrun — you're completely right, thanks for catching this. 🙏 I verified against the installed I've dropped Also fixed a couple of things I found while verifying grok against the real CLI: login now uses the |
|
@coderabbitai full review |
✅ Action performedFull review finished. |
|
@coderabbitai full review |
✅ Action performedFull review finished. |
|
@coderabbitai full review |
✅ Action performedFull review finished. |
|
@greptileai please review the current head e2a1ead, focusing on the test-lane relocation delta and any current-head regressions. |
|
@coderabbitai full review current head e2a1ead. If the service file-count limit still applies, please record that explicitly rather than implying a substantive review. |
|
✅ Action performedFull review finished. |
|
@greptileai please review current head 5f20d25, focusing on the Grok model/effort/freeform delta and shared session-control compatibility/reconnect changes. |
|
@coderabbitai full review current head 5f20d25. If the service file-count limit still prevents review, please record that explicitly. |
|
✅ Action performedFull review finished. |
|
Thank you very much @jaylfc, applied some additional changes on top, merging now :) |

Summary
Add Grok Build CLI (
grok) as a first-class Happier coding agent, including install/detection, ACP authentication, create/resume identity, permissions and xAI structured questions, provider-advertised model and reasoning-effort controls, canonical UI projection, and deterministic provider coverage.Grok Build is a coding agent. It remains separate from xAI voice support and any xAI/Grok model-provider profile.
Why
The original contribution established Grok's native ACP entry point. A production integration also needs authenticated ACP startup, durable continuation identity, lossless structured questions, canonical provider/UI projection, and deterministic provider coverage without introducing a second runtime stack or provider-specific policy in shared core.
Architecture and behavior
grok --no-auto-update agent stdio.initialize: advertised API-key auth wins only whenXAI_API_KEYis non-empty; otherwise an advertised cached-account method is used; logged-out interactive auth is never treated as cached readiness.Otherplusannotations[question].notesresponse contract.reasoning_effortcontrol.session/set_modelremains provider-authoritative; rejected switches do not falsify displayed state.Current capability boundary
x.ai/session/prompt_complete/_x.ai/session/prompt_completesettlement: evidence-backed follow-up on the evolved post-mergeremote-devACP owners, not duplicated in this older PR-basis runtime.Validation
Latest production delta (
5f20d257fa6811b51b82d90a0904c678be66a1d7):git diff --checkEarlier unchanged corridors also retain their recorded protocol, server, provider, browser-harness, import-cycle, and full-package evidence. The current source is reviewed as moving work; no freeze, reconstruction, candidate hash, or synthetic-conflict protocol is a merge gate.
Screenshots / recording (UI changes)
The implementation reuses existing Happier picker, settings, session, auth, and structured-question components; no Grok-specific visual system is introduced. Source-attested browser validation against the integrated managed stack remains open.
Open gates
The deterministic results above do not substitute for unavailable authenticated/provider/browser/platform evidence. GitHub
devintegration may defer those live gates to pre-preview only through an explicit authorized human decision.Post-merge work
remote-devACP, Cursor-question, and OpenCode-runtime owners; never resolve conflicts by restoring obsolete PR-basis files wholesale.../devas a thinhappier.agent.grokplugin only after the active plugin plan's G5 UI and G6 native ACP-composer contracts are admitted. Do not copy this large remote-dev diff or reuse the xAI voice plugin.Contributor credit
@jaylfc established the original Grok agent identity, native ACP launch path, initial provider facts, installer discovery, login command, and model identifier. Maintainer amendments complete authentication, runtime, structured-interaction, model/effort, persistence, UI, and validation contracts while preserving that contribution.
Checklist
dev(notmain)Note
Add Grok Build as a first-class coding agent with ACP backend, UI, and structured question support
grokas a recognized agent across the full stack: manifest, auth probe, model config, session modes, CLI runtime spec, and all language translations.grokTransport, reasoning effort model controls, andask_user_question/ MCP servers-updated extension handlers.AcpAuthenticationas a typed union replacing flatauthMethodId/authMetafields; all existing backends (Gemini, Codex, Cursor) are migrated to the new shape.AcpSessionIdentityBindingto enforce intent-aware session identity persistence across create/resume operations, replacing per-runtimeonSessionIdChangecallbacks across all catalog runtimes.AskUserQuestionhandling end-to-end: structured question descriptors are normalized and validated, answers are submitted via a newsession.structuredQuestion.respond.v1RPC, and legacy comma-separated answers are decoded with ambiguity detection.AskUserQuestionViewnow enforces per-question selection limits, shows inline guidance for CLI update requirements, and submits protocol-tagged payloads.updateMetadata, and surface failures viareportTerminalFailure.effectiveValuefor session config option controls now always reflects the provider-confirmedcurrentValuerather than a pending requested value, which changes what the UI displays while a change is in-flight.Macroscope summarized 937f521.