Skip to content

fix(server): Grok's Auto mode asks you about commands its classifier blocks - #13732

Merged
juliusmarminge merged 1 commit into
t3code/codex-turn-mappingfrom
v2/grok-auto-prompts
Sep 26, 2026
Merged

juliusmarminge merged 1 commit into
t3code/codex-turn-mappingfrom
v2/grok-auto-prompts

Conversation

@juliusmarminge

@juliusmarminge juliusmarminge commented Sep 26, 2026 •

Copy link
Copy Markdown
Member

In T3's Auto mode, Grok silently denied every command its classifier held (rm -rf /tmp/…, curl … | sh, sudo -n id). The tool call failed with "Auto mode blocked this action" and you were never asked. Two layers caused it, and fixing only the first would have been worse than today.

Layer 1: Grok never asked T3

Grok asks the client about a classifier Block only if client_type.can_present_permission_prompt(). Otherwise it returns a PolicyDeny, and keeps doing so until 3 consecutive or 20 total denials (permission/manager/mod.rs:1000-1060). That check is false only for ClientType::Generic (permission/types.rs:105). The type comes from initialize _meta.clientType or _meta.clientIdentifier (acp_agent.rs:180-200). T3 sent neither, so it was Generic.

T3 now sends _meta: { clientType: "extension" } on Grok's initialize (Grok runtime only, through a new initializeMeta option on AcpSessionRuntime).

Why extension. I checked every place Grok branches on client type:

  • Prompting: every non-Generic type prompts.
  • Permission options (prompter.rs:48-53, 519, 573-612, 671-727): extension gets the same generic bash and fallback options Generic gets today (always-allow / allow-once / reject-once / reject-always). T3 already maps these by kind. grok_desktop (like TUI and Pager) adds an enable-always-approve option first, with kind allow_once. T3 picks the first allow_once for "accept", so approving once would pick that option instead. It also adds allow-always-command / reject-always-command, which persist per-command grants in Grok's own project state.
  • code_nav.rs:49: only GrokWeb. extension is unaffected.
  • Telemetry only: feedback label (spawn.rs:1470-1479), the User-Agent origin product grok-code-extension (xai-grok-http/src/lib.rs:205-225), and the review-comment record. Leader-mode yolo scoping keys on clientIdentifier, which T3 still does not send.

So extension is the prompting type with the fewest side effects.

Layer 2: T3 would have approved the prompt itself

Every session/request_permission goes through acpPermissionDisposition. With no explicit sandbox, that returns allow in T3's Auto mode, so T3 would have picked the allow option and the blocked rm -rf would have run. A new permissionDisposition hook on the ACP flavor lets the Grok flavor return ask whenever it launched Grok with --permission-mode auto. In that mode Grok has already decided the routine actions, so anything it still asks about goes to you. Other modes keep the shared policy:

  • Supervised: already asked through the existing path.
  • Full access: Grok launches with --always-approve and sends no prompts.
  • Explicit approval or sandbox overrides: these launch Grok asking, and T3's policy decides as before.

Registry and other ACP flavors are unchanged.

Proof: live replay fixture grok_auto_blocked_command

Recorded from Grok 1.0.41 (grok-4.7-build-fast) with T3 in Auto mode. Grok runs echo grok-auto-routine-ok with no request, then rm -rf ~/grok-auto-probe-does-not-exist (the path never exists). Grok's classifier holds that and sends session/request_permission. T3 shows it as a pending runtime request (captured in the shell snapshot while pending). The fixture approves it (harmless, the path is absent), Grok answers allow-once, and the turn completes end_turn. I also tried declining, but Grok ends the turn cancelled (PermissionRejected), so the fixture approves.

With either layer removed, the fixture fails:

  • No _meta (live run): Grok emits Tool run_terminal_command was not executed: Auto mode blocked this action (Recursive rm of a home-directory path is an irreversible non-scratch delete and must wait). It sends no session/request_permission, the run completes, and the approve step finds no request. Replaying that transcript fails the same way.
  • No T3 hook (replaying the recorded fixture): T3 answers the prompt itself and never creates a pending request, so the replay never finishes.

The 12 existing Grok transcripts now expect the new initialize _meta. The recorder pins _meta alongside clientCapabilities. Fixtures can now set the thread's runtime mode (default stays full access).

Verification

  • vp test run src/orchestration-v2/testkit/OrchestratorReplayFixtures.integration.test.ts -t grok: 13 passed (all Grok replays, including the new one).
  • vp test run GrokAdapterV2.test.ts AcpAdapterV2.test.ts GrokAcpSupport.test.ts: 150 passed.
  • vp exec tsc --noEmit -p . (apps/server): no errors or warnings.
  • vp run knip:check: clean.
  • vp lint on touched files: only 4 warnings that already existed.
  • Live recording twice with the fix and once without _meta. ~/grok-auto-probe-does-not-exist never existed.
  • Not run: repo-wide checks, the web/mobile clients, or other providers' replays.

Model: Claude Opus 5.5 (Claude Code)

🤖 Generated with Claude Code


Devin Review

…blocks

Grok only prompts for a classifier-blocked action when the ACP client
declares a type that can show prompts; T3 declared none, so Grok denied
those commands silently. T3 now initializes Grok as clientType
"extension". Grok's prompt in Auto mode also no longer goes through
T3's own policy, which would have approved it: the Grok flavor surfaces
every Auto-mode permission request to the user.

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:L 100-499 changed lines (additions + deletions). labels Sep 26, 2026
{"type":"emit_inbound","label":"notification:session/update:agent_thought_chunk:t3-xai-prompt-1","frame":{"kind":"notification","method":"session/update","params":{"sessionId":"00000000-0000-4000-8000-000000000001","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" to"}},"_meta":{"totalTokens":23049,"eventId":"00000000-0000-4000-8000-000000000001-74","agentTimestampMs":1790383233408,"promptId":"t3-xai-prompt-1","streamStartMs":1790383232746,"turnStartMs":1790383223110,"updateType":"AgentThoughtChunk","chunkId":10}}}}
{"type":"emit_inbound","label":"notification:session/update:agent_thought_chunk:t3-xai-prompt-1","frame":{"kind":"notification","method":"session/update","params":{"sessionId":"00000000-0000-4000-8000-000000000001","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" reply"}},"_meta":{"totalTokens":23049,"eventId":"00000000-0000-4000-8000-000000000001-75","agentTimestampMs":1790383233408,"promptId":"t3-xai-prompt-1","streamStartMs":1790383232746,"turnStartMs":1790383223110,"updateType":"AgentThoughtChunk","chunkId":11}}}}
{"type":"emit_inbound","label":"notification:session/update:agent_thought_chunk:t3-xai-prompt-1","frame":{"kind":"notification","method":"session/update","params":{"sessionId":"00000000-0000-4000-8000-000000000001","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":" exactly"}},"_meta":{"totalTokens":23049,"eventId":"00000000-0000-4000-8000-000000000001-76","agentTimestampMs":1790383233408,"promptId":"t3-xai-prompt-1","streamStartMs":1790383232746,"turnStartMs":1790383223110,"updateType":"AgentThoughtChunk","chunkId":12}}}}
{"type":"emit_inbound","label":"notification:session/update:agent_thought_chunk:t3-xai-prompt-1","frame":{"kind":"notification","method":"session/update","params":{"sessionId":"00000000-0000-4000-8000-000000000001","update":{"sessionUpdate":"agent_thought_chunk","content":{"type":"text","text":":"}},"_meta":{"totalTokens":23049,"eventId":"00000000-0000-4000-8000-000000000001-77","agentTimestampMs":1790383233408,"promptId":"t3-xai-prompt-1","streamStartMs":1790383232746,"turnStartMs":1790383223110,"updateType":"AgentThoughtChunk","chunkId":13}}}}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Medium grok_auto_blocked_command/grok_transcript.ndjson:118

The NDJSON record on line 118 is malformed, so readProviderReplayTranscript fails during JSON decoding before the replay reaches the permission approval flow. The text field has an extra colon instead of a JSON value; replace it with the intended string value so the regression test can execute.

🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @apps/server/src/orchestration-v2/testkit/fixtures/grok_auto_blocked_command/grok_transcript.ndjson around line 118:

The NDJSON record on line 118 is malformed, so `readProviderReplayTranscript` fails during JSON decoding before the replay reaches the permission approval flow. The `text` field has an extra colon instead of a JSON value; replace it with the intended string value so the regression test can execute.

@github-actions

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.2 KiB — 2.0 KiB ✅
Codex Live turn WebSocket decoded — 20.4 KiB — 29.3 KiB ✅
Codex Live turn messages — 2 — 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.7 KiB — 29.3 KiB ✅
Claude Live turn messages — 1 — 8 ✅

Baseline: unavailable · PR result: 7dae42b · 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.

@juliusmarminge
juliusmarminge merged commit fd4d3f0 into t3code/codex-turn-mapping Sep 26, 2026
24 of 25 checks passed
@juliusmarminge
juliusmarminge deleted the v2/grok-auto-prompts branch September 26, 2026 01:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L 100-499 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