grok-cli-runtime ยท diff
git:20260801.51a49fa to git:20260807.d13beb6
2 added, 2 removed. Audit B to B.
---
name: grok-cli-runtime
description: Internal helper contract for calling the grok-companion runtime from Claude Code
user-invocable: false
---
# Grok runtime
Primary helper:
- `node "${CLAUDE_PLUGIN_ROOT}/scripts/grok-companion.mjs" <subcommand> [flags]`
Subcommand surface:
- `task [--prompt-file <path>] [--write] [--web] [--memory] [--background] [--resume <uuid>] [--resume-last] [--fresh] [--model <id>] [--effort <level>] [--max-turns <n>] [--cwd <dir>] [--json-schema <schema>] [--json] [--] [prompt]`
- The upstream Grok CLI has no default turn limit. An unset limit is unlimited, and one turn is one main-agent model call plus its tool cycle, excluding subagent calls. The companion defaults consult and write to `--max-turns 60`; consult previously defaulted to 25. When the limit is reached, Grok prints the complete final JSON envelope to stdout, including partial text, usage, `num_turns`, and `modelUsage`, then exits 1 with stderr `Error: max turns reached`. The companion salvages that envelope and records `failureKind: "turn_limit"`.
- Grok headless JSON has no top-level `model` field. Model names are available only as keys in `modelUsage` when usage attaches, so model capture depends on that map and on error-path salvage. Missing `modelUsage` leaves the resolved model unavailable.
- `review [--base <ref>] [--focus <text>] [--cwd <dir>] [--background] [--json]`
- `status [job-id] [--cwd <dir>] [--json]`
- `history [--all] [--limit <n>] [--cwd <dir>] [--json]`
- `result <job-id> [--cwd <dir>] [--wait] [--wait-timeout-ms <ms>] [--json]`
- `cancel <job-id> [--cwd <dir>] [--json]`
- `stats [--all] [--cwd <dir>] [--json]`
- `setup [--continuity <manual|claude-session>] [--enable-stop-gate] [--disable-stop-gate] [--json]`
- `stop-gate`
Execution rules:
- Slash commands stage their complete raw arguments through `transport-create`, one Read of the allocated empty file, Write to that same file, and a fixed `--raw-args-token` invocation. The token transport applies to task, review, status, history, result, cancel, stats, and setup. Raw request bytes never enter Bash, shell arguments, environment variables, redirections, substitutions, encoded literals, or heredocs. A transport is private, bounded, validated, and consumed once. Never delete, rename, recreate, or change the permissions of the transport file; use `transport-discard` when Read or Write fails or when the allocated file is not empty.
- The companion always invokes Grok with `--prompt-file /dev/stdin` and pipes the complete prompt to the child. Never pass a private staging path to Grok. Headless installs the sandbox before it reads `--prompt-file`, so a brief under Claude plugin data can be unreadable even when the companion already consumed it successfully.
- Task and review options must precede the first positional text. Once prompt or focus text starts, every remaining token is data, including option shaped words such as `--background`, `--write`, `--cwd`, and `--json`.
- Background has three distinct layers. The Grok rescue Agent and every helper `Bash` call remain foreground. Parallel orchestration starts multiple foreground Agent calls in one message. The Grok CLI runs in its own supervised process group, which is not itself a detached user job.
- Ordinary delegations use one foreground helper call with timeout `600000`. Only an explicit incoming user `--background` detaches a task and creates a manual receipt that crosses the Agent boundary. The dedicated review runner is the sole managed worker exception because it owns and collects the review before returning. Native Grok background tool waiting is a fourth, internal lifecycle. Ordinary calls pass `--no-wait-for-background`. That setting does not authorize companion detachment.
- Prefer the helper over hand-rolled `git`, direct Grok CLI strings, or any other Bash activity.
- - Consult mode is the default. Consult, write, and review pin `--sandbox strict`; never downgrade to workspace. Consult overrides inherited always approve mode with `--permission-mode default` and hard filters built in tools to file read, list, and search. `--web` additionally exposes Grok's web search and fetch tools. Strict's upstream `system_read` roots include `/var` and `/tmp` on Linux, and `/private` plus the entire `~/Library` on macOS, so shared temporary content and substantial user application configuration and caches may be readable. Its write roots include the workspace and entire Grok home, always include `/tmp` and `/var/tmp`, and on macOS also include `/private/tmp`, `/private/var/tmp`, and all of `/private/var/folders`; the unique private run `TMPDIR` is the adapter's preferred and verified path, not the only temporary write surface. Its configuration requests child process network restriction, which Linux enforces through seccomp while macOS currently treats network blocking as a no-op; a write shell can reach the network on macOS, and `--web` controls only built in web tools. The hard tool filter and deny set provide the consult no-write model contract. Shell commands, tests, git, builds, file edits, MCP tools, and subagents are unavailable. `--write` keeps strict, enables auto approval, and uses `read_file`, `grep`, `list_dir`, `search_replace`, and `run_terminal_cmd`; `search_replace` creates files, and Grok has no `write` tool id. Denies for common direct grok, claude, and codex commands do not cover absolute paths, aliases or functions, or indirect scripts. They are not hard confinement while `run_terminal_cmd` remains enabled; that requires removing the terminal tool or an OS-level executable or network policy. User toolchains outside strict's readable roots may be unavailable, which is a reroute or environment problem rather than permission to weaken the profile.
- - Every consult and write call explicitly denies `search_tool`, `use_tool`, `ask_user_question`, and all MCP tools. Every ordinary call also passes bare `--disallowed-tools Agent` and `GROK_SUBAGENTS=0`. Cross-session memory is force-disabled with `GROK_MEMORY=0` unless an ordinary task explicitly supplies `--memory`, in which case the child receives `GROK_MEMORY=1`. Review and stop gate always keep memory off. Published headless Grok parses `--experimental-memory` and `--no-memory` without forwarding them through the single-turn path, so the companion uses the environment variable as the effective control and never trusts an inherited value. When memory is enabled, upstream first-turn injection may read relevant global or workspace memory and place it in the model context sent to xAI. That internal injection is not a model `read_file` call and is not blocked by the companion's Read denies for `~/.grok/memory/**`. Upstream automatic saving normally requires at least three real user prompts in the same resumed session and enough content, so a single Fusion task usually only reads existing memory and does not guarantee that new memory is saved. Upstream parses `--no-subagents`, but the single-turn and agent resolvers do not forward it, while the interactive TUI does apply it; the hard Agent tool deny and `GROK_SUBAGENTS=0` are the effective headless controls. The child sets all eighteen `GROK_CLAUDE_*_ENABLED`, `GROK_CURSOR_*_ENABLED`, and `GROK_CODEX_*_ENABLED` bridge variables to false; upstream currently consumes the six Claude and six Cursor cells plus the Codex sessions cell and reserves the other five Codex cells, and the child also pins `GROK_MANAGED_MCPS_ENABLED=false` because that variable has highest precedence over `[managed_mcps]` in `~/.grok/config.toml` and remote settings. It removes inherited `CLAUDE_CODE_*` and `CLAUDE_PLUGIN_*` variables plus `_GROK_CLAUDE_MARKER_OVERRIDE`, and broadly scrubs secret-bearing variables except required xAI authentication. The entire Grok home remains read-write, and the sandbox permits consult `read_file` to reach `~/.grok/auth.json`, config, and sessions while a write shell can receive retained xAI authentication variables. The companion adds best-effort Read denies for `auth.json`, `mcp_credentials.json`, `config.toml`, `sessions`, `memory`, `logs`, and `debug` through absolute paths and standard `**/.grok` patterns. Raw path variants, symbolic links, and shell or indirect scripts can bypass those rules, so environment scrubbing and path-pattern denies do not isolate the credentials. The model-facing meta-tool denies cannot prove that native MCP servers, plugins, or hooks configured under `~/.grok` did not start during agent construction or had no side effects; those bridge variables do not disable native Grok configuration. Narrower exposure needs a dedicated sandbox profile, an isolated Grok home, an authentication broker, or upstream path-level authorization. The child passes `--no-auto-update`; grok 0.2.112+ still enforces hard version requirements at startup (organization message, exit 1 before any envelope), the companion classifies that death as `setup`, and the soft update floors it also introduced only steer auto-update.
+ - Consult mode is the default. Consult, write, and review pin `--sandbox strict`; never downgrade to workspace. Consult overrides inherited always approve mode with `--permission-mode default` and hard filters built in tools to file read, list, and search. `--web` additionally exposes Grok's web search and fetch tools. Strict's upstream `system_read` roots include `/var` and `/tmp` on Linux, and `/private` plus the entire `~/Library` on macOS, so shared temporary content and substantial user application configuration and caches may be readable. Its write roots include the workspace and entire Grok home, always include `/tmp` and `/var/tmp`, and on macOS also include `/private/tmp`, `/private/var/tmp`, and all of `/private/var/folders`; the unique private run `TMPDIR` is the adapter's preferred and verified path, not the only temporary write surface. Its configuration requests child process network restriction, which Linux enforces through seccomp while macOS currently treats network blocking as a no-op; a write shell can reach the network on macOS, and `--web` controls only built in web tools. Hosted `x_search` stays outside managed runs because the fixed `--tools` allowlist governs the toolset (live verified on 1.0.0), and the companion adds no speculative disallow entries because Grok 1.0.0 warns when a `disallowedTools` entry matches nothing and tracing fails closed on that warning. The hard tool filter and deny set provide the consult no-write model contract. Shell commands, tests, git, builds, file edits, MCP tools, and subagents are unavailable. `--write` keeps strict, enables auto approval, and uses `read_file`, `grep`, `list_dir`, `search_replace`, and `run_terminal_cmd`; `search_replace` creates files, while upstream 1.0.0's OpenCode-compatible `write` tool id remains outside the fixed allowlist. Denies for common direct grok, claude, and codex commands do not cover absolute paths, aliases or functions, or indirect scripts. They are not hard confinement while `run_terminal_cmd` remains enabled; that requires removing the terminal tool or an OS-level executable or network policy. User toolchains outside strict's readable roots may be unavailable, which is a reroute or environment problem rather than permission to weaken the profile.
+ - Every consult and write call explicitly denies `search_tool`, `use_tool`, `ask_user_question`, and all MCP tools. Every ordinary call also passes bare `--disallowed-tools Agent` and `GROK_SUBAGENTS=0`. Cross-session memory is force-disabled with `GROK_MEMORY=0` unless an ordinary task explicitly supplies `--memory`, in which case the child receives `GROK_MEMORY=1`. Review and stop gate always keep memory off. Published headless Grok parses `--experimental-memory` and `--no-memory` without forwarding them through the single-turn path, so the companion uses the environment variable as the effective control and never trusts an inherited value. When memory is enabled, upstream first-turn injection may read relevant global or workspace memory and place it in the model context sent to xAI. That internal injection is not a model `read_file` call and is not blocked by the companion's Read denies for `~/.grok/memory/**`. Upstream automatic saving normally requires at least three real user prompts in the same resumed session and enough content, so a single Fusion task usually only reads existing memory and does not guarantee that new memory is saved. Upstream parses `--no-subagents`, but the single-turn and agent resolvers do not forward it, while the interactive TUI does apply it; the hard Agent tool deny and `GROK_SUBAGENTS=0` are the effective headless controls. The child sets all eighteen `GROK_CLAUDE_*_ENABLED`, `GROK_CURSOR_*_ENABLED`, and `GROK_CODEX_*_ENABLED` bridge variables to false; upstream currently consumes the six Claude and six Cursor cells plus the Codex sessions cell and reserves the other five Codex cells, and the child also pins `GROK_MANAGED_MCPS_ENABLED=false` because that variable has highest precedence over `[managed_mcps]` in `~/.grok/config.toml` and remote settings. It removes inherited `CLAUDE_CODE_*` and `CLAUDE_PLUGIN_*` variables plus `_GROK_CLAUDE_MARKER_OVERRIDE`, and broadly scrubs secret-bearing variables except required xAI authentication. The entire Grok home remains read-write, and the sandbox permits consult `read_file` to reach `~/.grok/auth.json`, config, and sessions while a write shell can receive retained xAI authentication variables. The companion adds best-effort Read denies for `auth.json`, `mcp_credentials.json`, `config.toml`, `sessions`, `memory`, `logs`, and `debug` through absolute paths and standard `**/.grok` patterns. Raw path variants, symbolic links, and shell or indirect scripts can bypass those rules, so environment scrubbing and path-pattern denies do not isolate the credentials. The model-facing meta-tool denies cannot prove that native MCP servers, plugins, or hooks configured under `~/.grok` did not start during agent construction or had no side effects; those bridge variables do not disable native Grok configuration. Narrower exposure needs a dedicated sandbox profile, an isolated Grok home, an authentication broker, or upstream path-level authorization. The child passes `--no-auto-update`; Grok enforces hard version requirements at startup (introduced in 0.2.112, verified through 1.0.0; organization message, exit 1 before any envelope), the companion classifies that death as `setup`, and the soft update floors it also introduced only steer auto-update.
- The companion probes the installed binary before using source-derived flags. Every run requires `--prompt-file`, `--output-format`, `--sandbox`, `--tools`, `--disallowed-tools`, `--deny`, `--max-turns`, `--no-auto-update`, and `--no-wait-for-background`. Consult also requires `--permission-mode` and `--allow`; no-web runs require `--disable-web-search`; write requires `--always-approve`; review requires `--json-schema`. A missing applicable capability fails before launch with failure kind `setup`. Every managed run forces builder tracing. Upstream initializes tracing only after it consumes the complete stdin prompt, so it is not a pre-prompt or pre-side-effect attestation. Fallback, unmappable, or unmatched-policy warnings trigger early verified termination, and a successful close is rejected without positive `tools allowlist applied` evidence. Before sending stdin, the companion creates a unique private `TMPDIR` and requires a new `ProfileApplied` record in the incremental shared `sandbox-events.jsonl` delta that contains that path and matches the canonical workspace, strict profile, enforced state, and requested `restrict_network: true` configuration. Upstream supplies no run id or pid, so unrelated `ProfileApplied` and `ApplyFailed` records are not attributed; failure events are auxiliary diagnostics. The matching event proves profile and configuration application, not platform-level network isolation. A matching owned-stderr warning, handshake timeout, missing or malformed matching evidence, shared-log disappearance or rotation, or matching field mismatch fails closed.
- `--background` detaches `task` or `review` into a companion worker; the helper prints the job id plus `/grok:status` and `/grok:result` hints. A task accepts it only from an explicit incoming user flag and creates manual delivery. The dedicated review runner sets `GROK_COMPANION_BACKGROUND_DELIVERY=managed`, owns that review job, and collects it with repeated `result <job-id> --wait` calls before returning. The runner accepts only a 32 character lowercase hexadecimal job id and omits the raw launch `--cwd` because companion job ids resolve globally across workspaces; an original `--json` stays on both launch and result. Text collection continues only after a zero exit whose output ends in `state: running`; JSON collection continues only after a zero exit with top level `status: "running"` and `cleanupRequired` not true. A text `phase: cleanup-required` or JSON `cleanupRequired: true` result is returned as a nonterminal failure receipt instead of looping. Terminal result collection records successful companion output, not later Agent message delivery. The monitor suppresses collected managed jobs and emits a delayed fallback after the grace period when a terminal managed job remains uncollected, as a best effort owner loss fallback.
- `result --wait` blocks while a job is running, refreshes liveness on each poll, and prints the same terminal output as `result` when the job finishes. If its bounded wait budget elapses first, it prints a compact running render ending in `state: running` and exits zero so the forwarder can issue another foreground wait call. If verified cleanup cannot complete, it exits nonzero and returns the explicit cleanup-required receipt even though the durable record remains running for a later cleanup retry.
- A user asking to resume maps to the companion's `--resume <uuid>` or `--resume-last`. Never invent a session uuid; only uuids recorded by finished ordinary companion tasks are resumable. Every mode records strict, so legacy workspace or unknown profiles fail closed and require a fresh task. Resume also requires the same mode and memory boundary as the source task. A memory-enabled session must be resumed with `--memory`, a memory-disabled session must be resumed without it, and inconsistent recorded memory modes fail closed. `--resume-last` selects the newest compatible terminal task and requires the current Claude session when one is available. Resolved metadata for a short cwd uses only its exact URL-encoded directory. A long cwd may scan bounded session-id candidates but accepts only an exact decoded or `.cwd` match; it never falls back to a sole candidate from another cwd.
- Continuity policy defaults to `manual`, which never resumes without `--resume` or `--resume-last`. `/grok:setup --continuity claude-session` persists automatic affinity for an ordinary task that has a prompt, does not request explicit resume, and does not pass `--fresh`. Affinity selects only the newest `done` ordinary task from the same Claude session, exact resolved cwd, mode, strict profile, and memory boundary. Fusion routed briefs identified by their routing header do not receive automatic affinity and stay fresh unless explicitly resumed. `--fresh` starts a new session for one task and cannot be combined with either resume option. `GROK_COMPANION_CONTINUITY_POLICY` may override the persisted policy with `manual` or `claude-session`.
- `history` exposes a safe canonical projection of companion job metadata and resumable session identifiers. It defaults to the current workspace and 50 newest records, `--all` includes every recorded workspace, `--limit` accepts 1 to 500, and `--cwd` selects an exact workspace when `--all` is absent. It does not read native Grok conversation contents, briefs, stored results, or logs.
- Leave `--model` and `--effort` unset so Grok's own config rules apply, unless the user explicitly asks for a specific model or effort level.
- `--cwd` scopes the workspace for task, review, status, history, result, cancel, and stats. Status, result, and cancel search all recorded workspaces by strict job id when `--cwd` is omitted, while history remains workspace-scoped unless `--all` is explicit. A bad working directory, or an implicit task or review working directory below its Git repository root, fails before a job record is created. Worktree isolation means creating a real Git worktree before launch and supplying that canonical path as the actual cwd. Headless `--worktree` and `--worktree-ref` are not a substitute.
- `--json` returns structured output for task, review, status, history, result, cancel, stats, and setup. Preflight failures with `--json` return a structured error object on stderr. Headless stdout is captured through a 0600 file that is unlinked immediately after a successful open, parsed in full through the still open descriptor under a total size limit, and reduced to a bounded tail for diagnostics.
- Review requires and passes one `--json-schema` contract and consumes `structuredOutput` from the same Grok call. A reported structured output error or explicit null result fails the review. Compatibility parsing of `text` is limited to a response that completely omits the structured output field and never triggers a second call.
- The stop gate is primarily toggled by the plugin's `Stop gate review` setting in Claude Code's plugin configuration; `setup --enable-stop-gate` and `setup --disable-stop-gate` persist the same toggle locally as a scripting fallback and only take effect when that setting is left unset. The Stop hook reads the first nonempty reply line: `ALLOW` permits stopping and `BLOCK: <reason>` blocks it; a preamble before `BLOCK` and infrastructure failures fail open. Stop gate runs are always fresh and memory-disabled. After collection, the hook adds a non-blocking advisory when collected workers remain acceptance unverified. SessionEnd attempts verified process cleanup for jobs owned by that Claude session and removes verified unused raw transports; it does not delete the terminal companion ledger.
- `cancel` accepts active foreground or background job ids. It waits for process cleanup before rendering the cancelled record.
- Job outcomes carry a `state:` line (`done`, `error`, or `cancelled`). JSON records keep `status` and `transportStatus` equal, keep semantic acceptance at `semanticStatus: "unverified"`, distinguish delivery mode from delivery status, and record the observed resolved model and effort when Grok exposes them. They also preserve reported request id, session id, turn count, structured output, aggregate and per-model usage, total cost, cost ticks, partial cost, and incomplete billing indicators without inventing missing values. Upstream `model_usage` rows contain only `input`, `output`, `cacheRead`, and `modelCalls`, plus optional `costUSD`; never synthesize aggregate reasoning or total token channels from them. The upstream map is named `modelUsage` in the headless envelope, and its keys are the only source for model names when usage attaches. Error and cancelled outcomes carry a `failure: <kind>` line; cancelled jobs use `failure: cancelled`.
- Stats aggregate reported turn counts separately from coverage. `usage_is_incomplete` means the upstream usage ledger may have missed open subagents, usage application, or a drain timeout. Reported token fields then remain observed lower bounds, but job-total token and cost coverage both fail closed to incomplete and those values stay out of exact totals. Exact cost otherwise requires a finite positive top-level USD and tick pair with neither partial marker set; ticks are authoritative at 10000000000 per USD.
- Native Grok session storage is independent from the companion ledger. Upstream native sessions are retained for 30 days by default. `~/.grok/config.toml` accepts a positive integer at `[storage] cleanup_ttl_days`; `0` falls back to the default 30 days. The companion promises no automatic garbage collection for job records, briefs, or logs under `~/.claude/plugins/data/grok-claude-code-fusion/`; remove that data directory manually only after no running job, uncollected result, history entry, or resume evidence is needed.
- Upstream ships ACP today, but the companion has not adopted it and continues per-call invocation. Any future companion implementation pools processes by canonical cwd plus sandbox profile and launches each directly as `grok --cwd <canonical> --sandbox <profile> agent --no-leader stdio`, because the sandbox is installed once at process start and a reused leader can retain the wrong cwd or sandbox.
- Return the helper output exactly as-is, whether the Bash tool reports it from stdout or stderr.
- If the Bash call fails or Grok cannot be invoked, surface the failure instead of hiding it; the grok-rescue agent returns exactly one `grok unavailable: <reason>` line for the orchestrator's circuit breaker.