Skip to content

fix(server): V2 Grok launches in the thread's permission mode - #13616

Merged
juliusmarminge merged 2 commits into
t3code/codex-turn-mappingfrom
v2/grok-runtime-mode
Sep 25, 2026
Merged

juliusmarminge merged 2 commits into
t3code/codex-turn-mappingfrom
v2/grok-runtime-mode

Conversation

@juliusmarminge

@juliusmarminge juliusmarminge commented Sep 25, 2026 •

Copy link
Copy Markdown
Member

V2 Grok ignored the thread's permission mode. AcpAdapterV2RuntimeInput had no runtime mode, so GrokAdapterV2 always launched plain grok agent stdio. Every Grok thread therefore ran in Grok's ask mode, and T3 imitated the other modes by auto-answering Grok's prompts. V1 passed the mode at launch (GrokAdapter.ts:1009 on main).

What changed

  • AcpAdapterV2RuntimeInput now carries the session's runtimePolicy, and GrokAdapterV2 maps it to Grok's launch flags. Only Grok reads it. A runtime-mode change already detaches Grok sessions (supportsRuntimeModeSwitchInSession: false), so the next turn reopens the session with the new flags. The replay recorder launches the same way as production.
  • When a thread has an explicit approval or sandbox policy override, Grok launches asking. Otherwise --always-approve or Grok's auto classifier would skip the permission prompts that T3's policy checks.
  • Auto-accept edits no longer passes --permission-mode acceptEdits, because grok agent ignores it. Grok launches in default mode, and T3's ACP client policy approves edit, delete and move prompts while commands and other actions still ask. Grok's prompts carry no locations, so this rule cannot confine edits to the workspace. Registry agents on Auto-accept edits get the same rule: before this change they were auto-approved for everything, including commands.

What each mode does in Grok (source at xai-org/grok-build f0e3be1, CLI 1.0.41)

T3 mode Grok launch Behavior
Supervised --permission-mode default agent stdio Grok asks for writes and non-safe shell commands; reads and safe-listed shell run without asking. T3 surfaces the prompts. Putting the mode on the argv overrides a configured [ui] permission_mode = "always-approve".
Auto-accept edits --permission-mode default agent stdio Same as Supervised inside Grok. T3 approves edit prompts and surfaces the rest.
Auto --permission-mode auto agent stdio Grok's classifier decides. Blocks the classifier makes are silent denials for ACP clients.
Full access agent --always-approve stdio Grok stops sending permission prompts. Deny rules and hooks still apply.

Source citations:

  • --always-approve (alias --yolo) is an AgentArgs flag: crates/codegen/xai-grok-pager/src/app/cli.rs:274-276. --permission-mode is a top-level flag validated against PermissionMode::VALID_VALUES: cli.rs:671-679, crates/codegen/xai-grok-agent/src/config.rs:919-941. The enum comment there reads "Only BypassPermissions is wired at spawn".
  • run_agent_command uses --permission-mode only to decide yolo and auto: crates/codegen/xai-grok-pager-bin/src/main.rs:1316-1331. resolve_effective_yolo treats only bypassPermissions/always-approve as yolo (crates/codegen/xai-grok-shell/src/util/config/permissions.rs:234-245), and effective_auto_for_launch returns mode == "auto" (permissions.rs:187-216). acceptEdits is consumed only by headless -p (crates/codegen/xai-grok-pager/src/headless.rs:861-873). A live probe on 1.0.41 confirmed it: writes asked identically under acceptEdits and default.
  • In yolo mode the permission manager approves every request before prompting, except shell- or hook-forced prompts: crates/codegen/xai-grok-workspace/src/permission/manager/mod.rs:778-786. Deny rules run first (:762-775).
  • The launch default seeds every session/new and session/load (crates/codegen/xai-grok-shell/src/agent/mvp_agent/session_setup.rs:450-455, :1106-1110), so resumed sessions get the new mode too.
  • Plan approval (x.ai/exit_plan_mode) is intercepted whatever the yolo state (crates/codegen/xai-grok-shell/src/session/acp_session_impl/tool_calls.rs:119-131), so Plan mode still reaches T3 under Full access.

Unchanged but worth knowing: rejecting a Grok prompt ends the whole turn (stopReason: "cancelled", cancellationCategory: "PermissionRejected").

Fixtures

No fixture changed. The replay harness swaps in its own makeRuntime, so spawn args are never part of replay. Every Grok fixture's thread is Full access. Only tool_call_read_only_on_request contains a permission prompt, and it carries an on-request override, which still launches asking. I re-recorded simple (now --always-approve; Grok reports "yolo":true) and tool_call_read_only_on_request (still asking, still one prompt) live with Grok 1.0.41. Both replayed green through the orchestrator. Their non-streaming frame sequences match the committed fixtures, apart from nondeterministic session-summary notifications. I kept the committed transcripts because a re-record would only add churn in model text.

Verification

  • GrokAdapterV2.test.ts: new tests open a session through the real Grok makeRuntime path with a spawner that records the argv and then fails the spawn. They cover each of the four modes plus the override case. With the runtimeMode line removed, all 5 fail (expected [['agent','stdio']]).
  • vp test run on GrokAdapterV2.test.ts, GrokAcpSupport.test.ts, AcpClientPolicy.test.ts: 57 passed.
  • vp test run on AcpAdapterV2.test.ts, AntigravityAdapterV2.test.ts, AcpRegistryAdapterV2.test.ts, AntigravityAcpSupport.test.ts: 154 passed.
  • OrchestratorReplayFixtures.integration.test.ts -t "grok|acpRegistry": 19 passed.
  • Live recordings of simple and tool_call_read_only_on_request through record-grok-acp-replay-fixture.ts (Grok 1.0.41), replayed green (not committed).
  • tsc --noEmit -p apps/server: no error TS or warning TS. vp run knip:check: clean. vp lint on touched files: no new warnings.
  • Not run: the full replay suite, repo-wide checks, or a UI pass.

Model: Claude Opus 5.5 (Claude Code)

🤖 Generated with Claude Code


Devin Review

The V2 ACP runtime input carried no runtime mode, so GrokAdapterV2 always
launched `grok agent stdio` and every thread ran in Grok's ask mode. The
ACP runtime input now carries the session's runtime policy and Grok maps it
to its launch flags. Auto-accept edits launches asking (Grok's agent ignores
`--permission-mode acceptEdits`) and T3's ACP policy approves edit prompts
while asking for everything else.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@github-actions github-actions Bot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:M 30-99 changed lines (additions + deletions). labels Sep 25, 2026
@macroscopeapp

macroscopeapp Bot commented Sep 25, 2026 •

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — The production path now maps thread policies to Grok launch permissions and changes shared ACP decisions for filesystem mutations, terminal commands, and other operations. Tests cover the mappings, but the permission-sensitive runtime behavior and cross-provider ACP impact require careful human validation.

You can add or adjust custom eligibility rules. Learn more.

@github-actions

github-actions Bot commented Sep 25, 2026 •

Copy link
Copy Markdown
Contributor

Thread transfer impact

✅ Thread transfer remains within every enforced ceiling.

ℹ️ No successful main baseline artifact is available yet. This run establishes the initial measurement.

Provider Metric Main baseline This PR Impact PR ceiling
Codex Total thread wire — 4.9 KiB — 6.8 KiB ✅
Codex Thread snapshot wire — 3.7 KiB — 4.9 KiB ✅
Codex Live turn WebSocket wire — 1.1 KiB — 2.0 KiB ✅
Codex Live turn WebSocket decoded — 20.4 KiB — 29.3 KiB ✅
Codex Live turn messages — 1 — 8 ✅
Claude Total thread wire — 4.9 KiB — 6.8 KiB ✅
Claude Thread snapshot wire — 3.7 KiB — 4.9 KiB ✅
Claude Live turn WebSocket wire — 1.2 KiB — 2.0 KiB ✅
Claude Live turn WebSocket decoded — 20.8 KiB — 29.3 KiB ✅
Claude Live turn messages — 2 — 8 ✅

Baseline: unavailable · PR result: 5ac7a41 · Source CI: success

Scenario and decoded snapshot size

10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.

  • Codex decoded thread snapshot: 106.1 KiB
  • Claude decoded thread snapshot: 106.4 KiB

Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@juliusmarminge
juliusmarminge merged commit 541b6b9 into t3code/codex-turn-mapping Sep 25, 2026
23 checks passed
@juliusmarminge
juliusmarminge deleted the v2/grok-runtime-mode branch September 25, 2026 22:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M 30-99 changed lines (additions + deletions). vouch:trusted PR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant