mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-09-30 12:39:42 +02:00
SessionMode gains 'grok', a first-class backend alongside Claude Code,
shell, OpenCode, Codex, Gemini, Antigravity and Pi: its own PTY, tmux
session, charcoal tab identity ('gk' badge), welcome button, run-mode
entry, cron agentType, Docker and remote-SSH command defaults, and
clone-repo Brain option. Flag surface verified live against grok 1.0.5.
Grok mixes two existing shapes and the wiring follows from that:
- Codex-shaped on permissions: the bypass switch is GrokConfig.alwaysApprove
(--always-approve, grok's bypassPermissions mode; config-level deny rules
still apply on top). The Run button sends it true, like runAntigravity(),
and clampExternalCliBypassForOwner() puts grok in the only-if-sent branch:
a bare grok spawn is grok's own ask-mode default, which is already safe,
so only a sent config needs the flag forced off. Cron needs nothing for
the same reason.
- OpenCode-shaped on rendering: grok is a fullscreen alternate-screen TUI
with mouse support, so it stays OUT of isAltScreenStripMode() and lands
on the narrow tmux-attach strip and the 'buffer' local-echo fallthrough
(unmeasured against an authenticated composer; documented fallback is the
'off' branch).
- Pi-shaped on resolution: 'grok' has npm squatters (@vibe-kit/grok-cli
also installs a grok bin), so grok-cli-resolver.ts version-probes every
candidate (grok --version, killSignal SIGKILL, VITEST-gated) and
GET /api/grok/status surfaces path AND version; GROK_VERSION_REGEX is
shared with the dependency registry so doctor and run mode cannot drift.
Env allowlist gains GROK_* plus the XAI_* vendor namespace (XAI_API_KEY is
grok's documented headless auth var), the same narrow-vendor reasoning as
GOOGLE_* for gemini. Resume is id-regexed on purpose: grok's own --resume
also matches session titles, which are arbitrary user strings that must
never reach the bash -c spawn line.
Docker: grok is not on npm, so the agent image installs it in its own step
(xAI's installer has no --dir override; the binary is copied to
/usr/local/bin and root's ~/.grok dropped in the same layer), and
credentials are seeded per-file (auth.json, config.toml, pager.toml; the
dir also holds sessions/, memory/ and the ~160MB binary). Remote SSH routes
through the login-shell wrapper like the other agent CLIs.
Verified end to end on an isolated CODEMAN_INSTANCE with grok 1.0.5
installed: /api/grok/status resolves and reports the probed version,
quick-start spawns a pane whose command line ends in 'grok
--always-approve', the real TUI renders (OAuth device screen on an
unauthenticated box), and grokConfig round-trips through state.json.
Docs: docs/grok-integration.md (user guide) + docs/grok-integration-plan.md
(decisions, verification record, follow-ups).
Tests: test/grok-mode.test.ts, test/grok-cli-resolver.test.ts, plus
extended clamp/system-routes/render-index-html/run-mode-ui/mobile-overview/
local-echo-gating coverage. npm test (the CI gate) green: 5910 tests.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
107 lines
9.6 KiB
Markdown
107 lines
9.6 KiB
Markdown
# Grok Build (xAI) integration plan
|
|
|
|
> **Status**: Executed. This document records the plan, the decision behind each wiring
|
|
> point, and what was and was not verified. The user-facing guide is
|
|
> [`grok-integration.md`](./grok-integration.md); the per-decision invariants live in
|
|
> [`architecture-invariants.md#external-cli-modes-opencode-codex-gemini-antigravity-pi-grok`](./architecture-invariants.md#external-cli-modes-opencode-codex-gemini-antigravity-pi-grok).
|
|
> Template: the pi integration (`c5b5963`, [`pi-integration-plan.md`](./pi-integration-plan.md)),
|
|
> which was itself calibrated against the four follow-up commits the antigravity
|
|
> integration needed. All of grok's facts below were verified against **grok 1.0.5**
|
|
> (`grok 1.0.5 (5115b46bc9)`), installed live during the work.
|
|
|
|
## 1. What Grok Build is
|
|
|
|
[xai-org/grok-build](https://github.com/xai-org/grok-build) is xAI's coding agent: a
|
|
Rust fullscreen-TUI binary named `grok`, installed by
|
|
`curl -fsSL https://x.ai/cli/install.sh | bash` into `~/.grok/bin` (with symlinks into
|
|
`~/.local/bin`; the installer also ships an `agent` alias). Config lives in
|
|
`~/.grok/config.toml`, TUI appearance in `~/.grok/pager.toml`, credentials in
|
|
`~/.grok/auth.json` (0600), sessions under `~/.grok/sessions/`. Auth is browser OAuth
|
|
on first launch, `grok login --device-auth` for SSH boxes, or `XAI_API_KEY` for
|
|
headless use. It has Claude-style permission modes (`default`/`acceptEdits`/`auto`/
|
|
`dontAsk`/`bypassPermissions`/`plan`), allow/deny rules, hooks, MCP, subagents, and a
|
|
headless `-p` mode.
|
|
|
|
## 2. Shape decisions (why grok is wired the way it is)
|
|
|
|
Grok is a seventh run mode, alongside Claude Code, shell, OpenCode, Codex, Gemini,
|
|
Antigravity and Pi. Never a location overlay, never a web tab. Its wiring mixes two
|
|
existing shapes:
|
|
|
|
| Question | Decision | Why |
|
|
| --- | --- | --- |
|
|
| Permission bypass | `GrokConfig.alwaysApprove` -> `--always-approve` | Grok's real flag (verified via `--help`): "Auto-approve all tool executions", i.e. its `bypassPermissions` mode. Config-level deny rules still apply on top. The Run button sends `true`, matching `runAntigravity()` and Claude's own `--dangerously-skip-permissions` default: Codeman sessions exist for autonomous work. |
|
|
| Multi-user clamp branch | only-if-sent (codex/antigravity branch) | A bare `grok` spawn is grok's own ask-mode default, which is already safe, so the clamp only needs to force a SENT `alwaysApprove` off. Contrast pi, whose absent default is an answerable prompt and therefore needs the materialize branch. Cron needs nothing for grok for the same reason (`clampCronExternalCliConfigs`). |
|
|
| Alt-screen strip | OUT of `isAltScreenStripMode()` | Grok is a fullscreen alternate-screen TUI with mouse support (its own scrollback pane, `pager.toml [terminal] alt_screen`), i.e. the opencode case, not the Ink repaint case. It falls through to the narrow tmux-attach strip like opencode/antigravity/pi. |
|
|
| Resolver | version probe, like pi | `grok` has npm squatters (the unrelated `@vibe-kit/grok-cli` installs a `grok` bin). Candidates must pass `grok --version`; `GROK_VERSION_REGEX` is exported and shared with the dependency registry so doctor and run mode cannot disagree. The probe cannot tell two version-printing `grok`s apart, so `GET /api/grok/status` surfaces path AND version. Search dirs: `~/.grok/bin` first (installer target), then `~/.local/bin`, `/usr/local/bin`, `~/bin`. |
|
|
| Env allowlist | `GROK_*` + `XAI_*` prefixes | `GROK_*` covers grok's documented inputs (`GROK_HOME`, `GROK_CONFIG`/`GROK_CONFIG_PATH`, `GROK_MEMORY`, `GROK_WORKFLOWS`, `GROK_SANDBOX`, `GROK_OIDC_*`, `GROK_AUTH_PROVIDER_COMMAND`). `XAI_*` is xAI's vendor namespace and carries `XAI_API_KEY`, grok's documented headless auth var: the same narrow-vendor-namespace reasoning that admitted `GOOGLE_*` for gemini. Foreign provider keys stay out, as always. |
|
|
| Resume | `--resume <id>` / `--continue`, id-regexed | Grok's `--resume` also matches session TITLES (arbitrary user strings, case-insensitive). The `^[a-zA-Z0-9._-]+$` regex doubles as the no-titles rule, so nothing free-form can reach the `bash -c` spawn line. A valid explicit id wins over `-c`, mirroring pi. |
|
|
| Local echo | `'buffer'` via the `_updateLocalEchoState` fallthrough | UNMEASURED against an authenticated session (see §4). If grok's composer turns out per-keystroke reactive like codex's, the fallback is one `'off'` branch; teaching `PredictiveEchoAddon` grok's composer row is the larger follow-up. |
|
|
| Truecolor | `COLORTERM=truecolor` + `unset NO_COLOR` | Rust TUI with themes; joins the codex/gemini/antigravity/pi list in `buildEnvExports()` and `buildMuxAttachEnv()`. |
|
|
| Docker credentials | per-file seed: `auth.json`, `config.toml`, `pager.toml` | `~/.grok` also holds `sessions/`, `memory/`, `completions/`, `docs/` and the ~160MB binary under `downloads/`; a whole-dir seed would copy all of it on every container start. Same trade-off as pi: in-container sessions are invisible host-side, so `grok -c` in a Docker case sees only that container's history. |
|
|
| Docker install | own Dockerfile step | Not an npm package. xAI's installer has no `--dir` override, so the step copies `/root/.grok/bin/grok` (through the symlink, `cp -L`) into `/usr/local/bin` and removes root's `~/.grok` in the same layer. |
|
|
| Remote SSH | `exec "$SHELL" -i -l -c 'grok'` | sshd's remote-command PATH does not include `~/.grok/bin`; same login-shell fix as every other agent CLI. |
|
|
| What is NOT wired | `--permission-mode`, `--allow`/`--deny`, `-p` headless, `--worktree`, `--sandbox`, `--reasoning-effort`, `-s/--session-id`, `--fork-session`, `--agent`, `--output-format` | Follow-ups. The flag surface is kept minimal on purpose; grok is pre-1.0-style fast-moving and every flag added is a flag validated forever. |
|
|
|
|
## 3. Touch points (the checklist)
|
|
|
|
Backend: `types/session.ts` (SessionMode + GrokConfig + SessionState), `utils/grok-cli-resolver.ts` (new)
|
|
+ barrel, `tmux-manager.ts` (`buildGrokCommand`, dispatch, resume flag, PATH export, truecolor,
|
|
availability error, plumbing), `session.ts` (external-mode gate, label, config plumbing,
|
|
tmux-required error, attach env), `mux-interface.ts`, `schemas.ts` (prefixes, `GrokConfigSchema`,
|
|
both mode enums, remote command overrides, cron agentType), `session-routes.ts` (clamp + both
|
|
create paths), `system-routes.ts` (`GET /api/grok/status`), `server.ts` (availability inject +
|
|
mux restore), `docker-hosts.ts`, `remote-hosts.ts`, `config/dependency-registry.ts`,
|
|
`cron/cron-service.ts` (comment), `response-viewer-transcript.ts`, `tui/tui-client.ts` + `tui-app.ts`.
|
|
|
|
Frontend: `index.html` (welcome button, run-mode entry, cron option, clone Brain option),
|
|
`session-ui.js` (`runGrok()`, dispatch, availability, "Run GK" label, external-CLI gates,
|
|
runMode setter), `app.js` (label, `gk` tab badge, kill-menu), `settings-ui.js`,
|
|
`mobile-overview.js`, `home-sessions.js`, `panels-ui.js`, `i18n.js`, `styles.css` +
|
|
`mobile.css` (charcoal monochrome identity; the non-og skin block and the mobile
|
|
`!important` pair are both load-bearing, see the pi plan's §2.9 cascade trap).
|
|
|
|
Meta: `docker/agent.Dockerfile`, `install.sh`, `package.json` keyword, changeset,
|
|
`skills/codeman/reference/*`, CLAUDE.md, READMEs, `architecture-invariants.md`,
|
|
`remote-sessions.md`, `security-architecture.md`, `docker-cases.md`, `cron-guide.md`.
|
|
|
|
Tests: `test/grok-mode.test.ts` + `test/grok-cli-resolver.test.ts` (new);
|
|
`external-cli-bypass-clamp`, `system-routes`, `render-index-html`, `run-mode-ui`,
|
|
`mobile-overview`, `local-echo-codex-gating` (extended).
|
|
|
|
## 4. Verification performed
|
|
|
|
On this box, with grok 1.0.5 really installed and an isolated
|
|
`CODEMAN_INSTANCE=grokwt` server (own data dir, own tmux socket, port 5077):
|
|
|
|
1. `npm test` (the CI gate): green, 5900+ tests. `typecheck`, `lint`, `format:check`,
|
|
`check:frontend-syntax`, `check:public-assets`, `check:lockfile`: green.
|
|
2. `GET /api/grok/status` -> `{available: true, path: "/home/arkon/.local/bin", version: "1.0.5"}`
|
|
through the real resolver and probe.
|
|
3. `POST /api/quick-start {mode: "grok", grokConfig: {alwaysApprove: true}}` -> session
|
|
created, tmux pane spawned, real spawn line verified to end in `grok --always-approve`,
|
|
and the actual grok TUI rendered its OAuth device-approval screen in the pane
|
|
(unauthenticated box, so sign-in is exactly where a first run lands).
|
|
4. `grokConfig` persisted into the instance's `state.json`.
|
|
5. Session deleted by exact id; instance data dir and throwaway case removed.
|
|
|
|
**Not verified (honest gaps, all requiring an xAI account or more hardware):**
|
|
an authenticated conversation end to end; the local-echo buffer policy against grok's
|
|
real composer (§2); scrollback/repaint behavior of the fullscreen TUI under the narrow
|
|
strip during a long session; a Docker case with `mode: 'grok'` (needs a `--no-cache`
|
|
agent-image rebuild); a remote-SSH grok case; cron readiness degradation (expected:
|
|
same slow-start-then-send as pi, documented in `cron-guide.md`).
|
|
|
|
## 5. Follow-ups
|
|
|
|
- Idle/completion signal: grok has a hooks system (user-guide `10-hooks.md`); a hook
|
|
POSTing to `/api/hook-event` could give grok sessions real idle detection instead of
|
|
output-stabilization. Highest-value follow-up, same slot as pi's `agent_settled` idea.
|
|
- Response viewer: sessions are ACP JSONL under `~/.grok/sessions/<encoded-cwd>/<id>/updates.jsonl`;
|
|
`grok -p ... --output-format json | jq -r '.sessionId'` exists for correlation.
|
|
- Permission-mode picker (`--permission-mode`, `--allow`/`--deny`) in Session Options.
|
|
- Measure the local-echo policy and the fullscreen-TUI scrollback behavior against an
|
|
authenticated session; pin the result in `local-echo-codex-gating` the way pi did.
|
|
- `grok doctor` is a built-in terminal-support check worth pointing users at when a
|
|
pane renders oddly.
|