Skip to content

fix: map runtime modes to correct permission levels#1587

Open
oski646 wants to merge 7 commits intopingdotgg:mainfrom
oski646:fix/permission-mode-bypass
Open

fix: map runtime modes to correct permission levels#1587
oski646 wants to merge 7 commits intopingdotgg:mainfrom
oski646:fix/permission-mode-bypass

Conversation

@oski646
Copy link
Copy Markdown

@oski646 oski646 commented Mar 30, 2026

What Changed

I fixed running Claude in Supervised mode. Fixing that also made me think we should adjust it for the Codex adapter. I also introduced a new mode inspired by the Claude CLI called “Auto accept edits”. I did not know how to handle the fix without adding this mode because having just "Supervised" which should be read only or full accept mode for the user (to my understanding), and "Full Access" which is a full bypass mode, is probably not enough for some users. Adding this one more mode was low hanging fruit for me, so I thought I could do it here as well. I tried to keep everything simple and focus only on fixing the bug and adding this one mode.

I am not sure if the change to the test, running it in a for loop, is necessary. I am open to suggestions about this and, of course, other changes I made.

I also noticed some other things that could be improved related to that change, but I did not want to make this PR big and difficult to review.

Why

Sessions launched without --dangerously-skip-permissions (Claude) crashed when switching away from full-access because the fallback always tried to restore bypassPermissions. Map each runtime mode to its proper Codex approval policy / sandbox pair and Claude SDK permission mode, and expose the new auto-accept-edits option in the UI.

Fixes #1437
Fixes #1241
Fixes #1609

UI Changes

The only change to UI is new "Auto-accept edits" mode added. Nothing else.

CleanShot 2026-03-30 at 21 34 00

Checklist

  • This PR is small and focused
  • I explained what changed and why
  • I included before/after screenshots for any UI changes
  • I included a video for animation/interaction changes

Note

Medium Risk
Changes runtime-mode-to-permission/sandbox mappings for both Codex and Claude, including a stricter supervised mode and new intermediate mode; mistakes could unintentionally over-restrict or over-grant tool/file access.

Overview
Fixes runtime mode permission mapping across providers and the UI by introducing a third RuntimeMode (auto-accept-edits) between supervised and full access.

On the server, Codex runtimeMode now maps to explicit approvalPolicy/sandbox pairs (with approval-required becoming untrusted + read-only), and Claude sessions map runtimeMode to SDK permissionMode (acceptEdits for auto-accept-edits) while restoring interaction mode back to default instead of incorrectly falling back to bypassPermissions.

The web composer UI now cycles through the three access modes with updated labels/icons, the compact controls menu supports selecting auto-accept-edits, and persisted drafts validate/accept any schema-valid RuntimeMode.

Written by Cursor Bugbot for commit a4f6644. This will update automatically on new commits. Configure here.

Note

Add auto-accept-edits runtime mode with correct permission level mappings

  • Adds 'auto-accept-edits' as a valid RuntimeMode across contracts, store, UI, and server, sitting between 'approval-required' and 'full-access' in a three-state cycle.
  • Fixes permission mappings in codexAppServerManager.ts: 'approval-required'approvalPolicy: 'untrusted' + sandbox: 'read-only'; 'auto-accept-edits''on-request' + 'workspace-write'; 'full-access''never' + 'danger-full-access'.
  • Updates ClaudeAdapter.ts to set SDK permissionMode to 'acceptEdits' for 'auto-accept-edits', and fixes the fallback from 'bypassPermissions' to 'default' when restoring base permission mode after plan interaction.
  • The chat UI in ChatView.tsx and CompactComposerControlsMenu.tsx now cycles through all three modes with distinct icons and labels.
  • Behavioral Change: 'approval-required' previously mapped to different approval/sandbox values; existing sessions using that mode will see corrected (stricter) permission behavior after this change.

Macroscope summarized a4f6644.

…pt-edits mode

Sessions launched without --dangerously-skip-permissions crashed when
switching away from full-access because the fallback always tried to
restore bypassPermissions. Map each runtime mode to its proper Codex
approval policy / sandbox pair and Claude SDK permission mode, and
expose the new auto-accept-edits option in the UI.

Fixes pingdotgg#1437
Fixes pingdotgg#1241
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 30, 2026

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 57671dde-328d-42d5-95e0-d44d588d7c28

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions github-actions bot added size:M 30-99 changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list. labels Mar 30, 2026
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.

🔴 Critical

"auto-accept-edits": {

The new "auto-accept-edits" runtime mode is silently discarded by setRuntimeMode in composerDraftStore.ts, which only recognizes "approval-required" and "full-access" as valid values. When cycleRuntimeMode transitions to "auto-accept-edits", the call setComposerDraftRuntimeMode(threadId, "auto-accept-edits") converts the value to null, causing the mode to fall back to the thread default instead of persisting the user's selection.

🤖 Copy this AI Prompt to have your agent fix this:
In file apps/web/src/components/ChatView.tsx around line 259:

The new `"auto-accept-edits"` runtime mode is silently discarded by `setRuntimeMode` in `composerDraftStore.ts`, which only recognizes `"approval-required"` and `"full-access"` as valid values. When `cycleRuntimeMode` transitions to `"auto-accept-edits"`, the call `setComposerDraftRuntimeMode(threadId, "auto-accept-edits")` converts the value to `null`, causing the mode to fall back to the thread default instead of persisting the user's selection.

Evidence trail:
packages/contracts/src/orchestration.ts lines 65-69: RuntimeMode is defined with three literal values: "approval-required", "auto-accept-edits", "full-access"
apps/web/src/components/ChatView.tsx lines 250-270: RUNTIME_MODE_CONFIG includes all three modes in the UI cycle
apps/web/src/composerDraftStore.ts lines 1800-1805: setRuntimeMode function implementation only recognizes "approval-required" and "full-access" in the condition `runtimeMode === "approval-required" || runtimeMode === "full-access"`, converting any other value (including "auto-accept-edits") to null

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

This commit fixes that

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.

Sorry, I'm unable to act on this request because you do not have permissions within this repository.

oski646 added 3 commits March 30, 2026 21:50
setRuntimeMode had an explicit allowlist that missed "auto-accept-edits",
converting it to null. Replace with nullish coalescing since TypeScript
already constrains the parameter to RuntimeMode | null | undefined.
Copy link
Copy Markdown
Contributor

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Copy link
Copy Markdown
Member

@juliusmarminge juliusmarminge left a comment

Choose a reason for hiding this comment

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

seems mostly fine apart from the test

Comment on lines +2496 to +2501
for (const [runtimeMode, expectedBase] of [
["full-access", "bypassPermissions"],
["approval-required", "default"],
["auto-accept-edits", "acceptEdits"],
] as const) {
it.effect(`restores ${expectedBase} permission mode after plan turn (${runtimeMode})`, () => {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

it.each or similar

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Done 🙌

@oski646
Copy link
Copy Markdown
Author

oski646 commented Apr 1, 2026

Julius, I also noticed that adding this mode caused the MCP tool approval bug to appear. I asked Claude if it is actually connected with the change I made, and here is the response:

The issue is NOT caused by your runtime mode fix. It's a pre-existing gap in MCP tool call handling:

  1. Server side: classifyRequestType() returns "dynamic_tool_call" for MCP tools (line 462 of ClaudeAdapter.ts)
  2. Server side: requestKindFromCanonicalRequestType() doesn't handle "dynamic_tool_call" — returns undefined (line 156 of ProviderRuntimeIngestion.ts)
  3. Activity payload: requestKind is omitted when undefined (line 192: ...(requestKind ? { requestKind } : {}))
  4. Web side: derivePendingApprovals() requires requestKind to be one of "command" | "file-read" | "file-change" — when it's missing, the approval is silently dropped (line 208 of session-logic.ts)

The approval panel never renders → the agent waits forever for a decision that can never come.

Why your PR surfaces this: Before your fix, "auto-accept-edits" wasn't properly mapped, so everything likely fell through to "full-access" behavior (auto-approve all). Now that "auto-accept-edits" correctly maps to permissionMode: "acceptEdits", MCP tools that aren't file-edits actually hit the canUseTool callback and need manual approval — exposing this existing gap.

The fix needs to happen in two places:

  1. Add "dynamic_tool_call" handling to both requestKindFromCanonicalRequestType (server) and requestKindFromRequestType (web) — or better, add a new request kind like "mcp" or "other"
  2. Update the PendingApproval type and ComposerPendingApprovalPanel to handle this new kind

Would you like me to fix that here as well, or create a new PR focusing on fixing the pre existing bug?

@juliusmarminge
Copy link
Copy Markdown
Member

File a new PR please 🙏🏽

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:unvouched PR author is not yet trusted in the VOUCHED list.

Projects

None yet

2 participants