The README (and its Chinese mirror) said the Approvals Inbox queues every pending prompt and answers it from the bell or the phone. It holds prompts from Claude Code, Codex (screen-read) and DeepSeek Harness only, and only Claude's are answerable: Codex and DeepSeek items are alerts that say to answer in the terminal, with no Approve/Deny on the push or the phone strip. The wiki, the TUI guide and the phone guide now say the same. Keeping Agents Running, Troubleshooting and the API reference still said every CLI but Claude, Codex and DeepSeek falls back to output stabilization. OpenCode, Gemini CLI, Pi and OMP declare capabilities.workDetect too and get the same screen check; only Antigravity and Grok Build declare none. Core Concepts now mentions Codex's screen-read dialogs, and the respawn gotcha notes that DeepSeek's own end-of-turn report reaches the respawn controller. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
7.2 KiB
Grok Build (xAI) sessions
Codeman can drive Grok Build (xAI's grok
CLI, the agent behind docs.x.ai/build) as a session backend, alongside Claude Code,
OpenCode, Codex, Gemini, Antigravity and Pi. grok is a seventh run mode: its own
PTY, its own tmux session, its own tab identity (monochrome charcoal, gk badge). It
is not a location overlay like Docker or remote-SSH cases, and it is not a web tab.
The design rationale behind each decision below lives in
grok-integration-plan.md. Everything here was verified
against grok 1.0.5.
Install
curl -fsSL https://x.ai/cli/install.sh | bash
The installer places the binary in ~/.grok/bin and symlinks it into ~/.local/bin
(it also installs an agent alias Codeman ignores). grok update self-updates.
Codeman resolves the binary via the server PATH and then the usual install locations,
~/.grok/bin first. grok is a name with known squatters (the unrelated
@vibe-kit/grok-cli npm package also installs a grok bin), so like pi the
resolver does not trust a PATH hit on its own: it runs grok --version once and
requires version-shaped output (grok 1.0.5 (5115b46bc9)). Check what it resolved:
curl -s localhost:3000/api/grok/status | jq
# { "available": true, "path": "/home/you/.grok/bin", "version": "1.0.5" }
The endpoint carries version on top of the sibling /api/*/status shape precisely
so a misresolution is visible rather than presenting as "the mode just doesn't work".
Authenticate
- Browser OAuth (default): the first
grokrun opens a sign-in flow; in a Codeman pane you get the device-code screen with a URL to open elsewhere. Credentials land in~/.grok/auth.json(0600) and refresh automatically. - Device code:
grok login --device-auth, made for SSH boxes and headless hosts. - API key:
export XAI_API_KEY="xai-..."(console.x.ai). Used as a fallback when no session token exists. As a per-session CodemanenvOverrideit flows through socket-scopedtmux setenv, never the spawn command line. - Enterprise OIDC:
GROK_OIDC_ISSUER/GROK_OIDC_CLIENT_ID.
What Codeman wires up
GrokConfig (per session, persisted in state.json, round-trips through respawn):
| Field | Flag | Notes |
|---|---|---|
model |
--model <v> |
e.g. grok-4.5, or a custom [model.<name>] from config.toml |
alwaysApprove |
--always-approve |
Grok's bypassPermissions mode; deny rules still apply on top |
continueSession |
--continue |
Most recent session for the working directory; skipped when resuming |
resumeSessionId |
--resume <v> |
Ids only, never titles (grok's own --resume also matches titles) |
Every value is regex-validated and dropped (not escaped) if it fails, because the
result is interpolated into the pane's bash -c "..." command.
The Run button sends grokConfig: { alwaysApprove: true }, the same product decision
as Claude's --dangerously-skip-permissions default and Antigravity's
--dangerously-skip-permissions: Codeman sessions exist for autonomous work. Keep
hard limits as deny rules in ~/.grok/config.toml (they apply in every mode), and
in multi-user mode a non-granted owner's alwaysApprove is forced off
server-side; a bare grok spawn is grok's own ask-mode default.
Env overrides: the GROK_* prefix (GROK_HOME, GROK_CONFIG, GROK_MEMORY,
GROK_WORKFLOWS, GROK_SANDBOX, GROK_OIDC_*, ...) plus the XAI_* vendor
namespace (XAI_API_KEY) are allowlisted. Foreign provider keys are not, as ever.
What Codeman deliberately does NOT wire up
--permission-mode,--allow/--deny. The boolean covers the autonomous case; the full rule surface is a follow-up with UI.-p/headless,--output-format,--json-schema. Codeman drives the TUI.--worktree,--sandbox,--reasoning-effort,-s/--session-id,--fork-session,--agent/--agents. Tracked as follow-ups in the plan doc.
Terminal behavior
Grok renders a fullscreen alternate-screen TUI (scrollback pane + prompt, mouse
supported). Under Codeman it runs inside tmux like every external CLI, so the
fullscreen rendering stays inside the pane and the browser terminal shows tmux's
repaints; grok stays out of the alt-screen strip list on purpose (the opencode case,
not the Ink case). If a pane renders oddly, grok doctor checks terminal, color and
input support without starting a session, and ~/.grok/pager.toml can force
alt_screen = "inline".
On touch devices grok currently gets the buffered local-echo overlay like Claude,
Gemini, OpenCode and Pi. This is the fallthrough default and has not been measured
against an authenticated grok composer; if grok turns out per-keystroke reactive the
way codex was (issues #218/#219/#220/#222), the fix is the 'off' branch in
_updateLocalEchoState (terminal-ui.js).
Docker cases
The agent image installs grok in its own Dockerfile step (not npm; xAI's installer
targets $HOME/.grok/bin with no --dir override, so the binary is copied to
/usr/local/bin). Rebuild with the mandatory --no-cache:
node scripts/build-agent-image.mjs --no-cache
Credentials are seeded, not shared: auth.json, config.toml and pager.toml
are copied into the container's own ~/.grok, so an in-container grok never writes
refreshed OAuth tokens back to the host and docker commit exports stay secret-free.
Only those three files, because ~/.grok also holds sessions/, memory/ and the
~160MB binary under downloads/. Trade-off, same as pi: in-container sessions are
invisible host-side, so grok -c inside a Docker case only sees that container's own
history.
Remote SSH cases
grok mode is routed through an interactive login shell
(exec "$SHELL" -i -l -c 'grok'), because sshd's remote-command PATH does not include
~/.grok/bin. Per-session config and envOverrides do not cross ssh and are rejected
rather than silently ignored; use the per-host command override instead. For auth on
the remote host, grok login --device-auth exists for exactly this.
Known gaps
- No idle/completion hook yet. Idle detection falls back to output-stabilization,
as it does for Antigravity: the registry entry declares no
workDetectprompt marker or working line, which is what gives Codex, OpenCode, Gemini, Pi and OMP a screen check instead. Grok has a hooks system, so a Codeman hook POSTing to/api/hook-eventis the highest-value follow-up. - No response viewer. Grok writes ACP JSONL sessions under
~/.grok/sessions/<encoded-cwd>/<session-id>/updates.jsonl; nothing reads them yet. - Cron jobs mis-detect readiness. The readiness poll looks for
❯or a token count, neither of which grok prints, so a grok cron job burns its poll budget and then sends the prompt anyway. It works; it is just slower to start. - Ralph, respawn heuristics, token/CLI-info parsing and the
❯readiness probe are off for grok, as for every external CLI.