Skip to content

feat(native-chat): each Claude/Codex chat gets its own permission mode - #26116

Merged
brennanb2025 merged 10 commits into
mainfrom
brennanb2025/sta-8261-permission-picker
Oct 12, 2026
Merged

brennanb2025 merged 10 commits into
mainfrom
brennanb2025/sta-8261-permission-picker

Conversation

@brennanb2025

@brennanb2025 brennanb2025 commented Oct 7, 2026 •

Copy link
Copy Markdown
Contributor
Files Added Deleted Net
Test 45 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​1968 $\color{#cf222e}{\Huge{\mathbf{−}}}$​363 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​1605
Prod 91 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​1453 $\color{#cf222e}{\Huge{\mathbf{−}}}$​437 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​1016

ELI5

Before this PR, a native Claude or Codex chat always used the global Agent Permissions setting (Yolo or Manual), and there was no way to see or change it from the chat. Now every Claude and Codex chat has a button right after "+" in the composer that shows its mode and lets you change it: Ask for approval, Accept edits (Claude only), Approve for me, or Full access. New chats start from a default you set in Settings → Chat. A change applies before your next message, never in the middle of a reply.

What Changed

Before: Claude and Codex chats always ran with the global Agent Permissions setting. A chat couldn't run differently from it, and nothing in the chat showed what the agent was allowed to do.

After:

  • Button: each Claude/Codex chat shows its permission mode right after "+" in the composer. You can change it any time, including while the agent is starting or replying.
  • When a change applies: the reply that's running finishes under the old mode. Before your next message is handed to the agent, Orca quietly restarts the agent with the new mode and it resumes the same conversation. There's no notice and no stop row, and the button never flashes back.
  • Modes per agent:
    • Claude: Ask for approval, Accept edits, Approve for me (only on models Claude lists as supporting it; on others, e.g. Haiku, the chat runs Ask), and Full access.
    • Codex: Ask for approval, Approve for me, and Full access.
    • Other agents have no button and keep following Agent Permissions.
  • Default for new chats: Settings → Chat → Permissions. It's copied once from Agent Permissions (Yolo becomes Full access, otherwise Ask) and doesn't follow it afterwards. Changing it affects only new chats.
  • Phone: shows the same mode as its own pill and can change it.
  • Older chats: chats created before this change start as Ask.

Mechanism:

  • Storage: the mode is one more saved chat option, stored and written exactly like the model choice. No new ordering counter or RPC.
  • When it's read: the mode only takes effect when the agent starts. Claude gets launch flags (--permission-mode default|acceptEdits|auto, or --dangerously-skip-permissions for Full access). Codex gets its approval policy, sandbox mode and reviewer on thread/start/thread/resume.
  • The restart: main already replaces a signed-out agent before the next message is delivered. That check now also restarts an idle agent whose launch mode no longer matches the chat. An agent with any open work (a running reply, background work, a pending prompt, or an owed follow-up turn) is kept, so a reply is never cut off.
  • Who decides: one shared rule on the host decides which mode an agent actually runs with, including whether the model supports "Approve for me". The button shows exactly that.
  • Every screen: the chat's status summary now carries the mode beside the model, so desktop and phone re-read options when either changes.
  • Default for new chats: the host adds it to the options it already seeds at chat creation, so chats created from desktop, web, phone, orchestration or the CLI all get it.

Why

This replaces an earlier version of this PR (about 4,500 product lines) that switched Claude's mode live and needed its own ordering counter, a separate empty-chat setting, and per-turn Codex overrides. The common pattern is simpler: a mode change restarts the agent and resumes the conversation. This version reuses Orca's existing option storage and its existing "replace the agent before the next message" step, at about 1,350 product lines.

Differences from the common pattern:

  • Intended: the restart happens before the next message rather than the moment you change the mode. Orca starts agents only for work that needs them, and this never interrupts a reply or background work.
  • Intended: Codex restarts too, rather than restating its permissions on every message. A per-message Codex sandbox setting must be a whole policy, which would silently drop the extra writable folders and network access users set in their own Codex config. Thread start/resume accepts a sandbox mode that keeps them.
  • Intended: Codex's Ask is on-request + workspace-write, main's existing Manual posture.
  • Intended: Claude's "Approve for me" is offered and launched only on models Claude lists as supporting it, so an unsupported mode is never handed to the CLI.
  • Intended: the default is one setting per host, because Orca has no per-project chat settings. It is seeded once from Agent Permissions so nobody's new chats change behaviour on upgrade.
  • Temporary: while an agent has background work running, a mode change waits until that work ends. Follow-up: apply it when the background work settles.
  • Temporary: on a desktop connected to a remote server, Settings → Chat edits the desktop's own default. Each new remote chat's button still shows the server's real mode at once. Follow-up: route that setting to the server.
  • Temporary: for an SSH chat that hasn't picked a model, "Approve for me" stays hidden until a model is known, because the default model is resolved from the chat's folder. It errs safe.
  • Temporary: Grok and other agents keep following Agent Permissions (STA-9763).

Linked Issue

STA-8261. Merge after #26684: Codex's per-thread reviewer setting needs Codex 0.136.0, which #26684 requires.

Visual Proof

Claude chat menu Codex chat menu Settings → Chat default
claude codex settings

Captured in a hidden Electron app with stand-in Claude and Codex CLIs, which record the exact launch flags and protocol frames.

Testing

  • I manually tested these changes locally (macOS)
  • Automated tests added/updated

Live (hidden Electron, stand-in Claude/Codex logging argv and frames, timestamps checked against the stand-in logs):

  • Picking Accept edits before the first message launched Claude with --permission-mode acceptEdits.
  • Switching mid-reply:
    • Claude, Ask → Full access mid-reply: the reply finished in the same process. The next message started a new process with --dangerously-skip-permissions resuming the same session. No notice, and across 38 samples the button never flashed back.
    • Codex, Ask → Approve for me mid-reply: the next message's thread/resume had the same thread with on-request, workspace-write and approvalsReviewer: auto_review. turn/start carried no reviewer.
    • Codex, Full access → Ask: thread/resume carried a sandbox mode, never a sandboxPolicy object.
  • During a 15-second start: the button stayed usable the whole time, never disabled, and the agent switched before the first message.
  • Changing the Settings → Chat default changed only new chats.
  • Fresh profiles seeded Full access from Yolo and Ask from Manual.
  • Claude "Approve for me":
    • offered about 0.5 s after a new chat opened;
    • launched with --permission-mode auto, one process for two messages;
    • switching the model to Haiku showed Ask and relaunched with --permission-mode default.

Automated:

  • the restart check (kept during open work, no restart loops, model alias vs resolved id);
  • picks write only the chat record and never wait for the agent;
  • create seeding and the one-time Settings seed;
  • Codex thread policy;
  • the button and Settings row;
  • a phone-side test;
  • an end-to-end test of a chat opened before Claude's model list arrives;
  • the real Claude CLI tests (Accept edits and Full access launches), 14/14.

After the final merge with main: typechecks, mobile typecheck and ratchet, changed-code quality, localization and max-lines all pass locally.

Not verified: the phone and the web app live (unit tests only), Windows, Linux, SSH.

Agent skill upstream boundary

  • Not applicable, or this change copies or mechanically translates no upstream skill-installer source, tests, fixtures, registry entries, path tables, comments, or documentation.

Notes

  • Security:
    • Full access is never applied by surprise: it applies only when picked or set as the default, and the button shows it in the warning colour.
    • A permission flag typed into Arguments is still stripped.
  • Mixed versions: every new wire field is optional. A host that doesn't publish a chat's mode shows no button.
  • Mobile: same descriptor and pill; the mode labels are English-only there, since the phone has no translations.
  • Cross-platform: no platform-specific code.

Checklist

  • This PR is small and focused (a full feature: per-chat mode, restart on change, default setting, desktop + phone)
  • I explained what changed and why (ELI5, the user-facing before/after, the mechanism, and why over the alternatives)
  • Before/after screenshots or videos attached for UI changes, or N/A with reason
  • Self-reviewed for correctness, security, and performance
  • Cross-platform, SSH/remote, and path/shortcut impact considered (or N/A)
  • pnpm lint, pnpm typecheck, pnpm test, and pnpm build pass (or CI will cover; local preferred)

@brennanb2025
brennanb2025 force-pushed the brennanb2025/sta-8261-permission-picker branch from 66d4ff4 to da54347 Compare October 7, 2026 21:07
@brennanb2025
brennanb2025 changed the base branch from brennanb2025/sta-8902-typed-permission-mode to main October 7, 2026 21:12
@brennanb2025 brennanb2025 changed the title feat(native-chat): choose a chat's permission mode from the composer feat(native-chat): chats get their own permission mode, with a composer button and a setting for new chats Oct 7, 2026
@brennanb2025

brennanb2025 commented Oct 8, 2026 •

Copy link
Copy Markdown
Contributor Author

Review and readiness summary

Reviews. Eight adversarial review rounds by Codex gpt-6.1-sol at xhigh. Each round reviewed the whole diff against main, re-ran the previous rounds' reproductions, and checked every merge from main. The findings per round were 5, 5, 2, 1, 1, 2, 1 and 0. Everything found is fixed, and round 8 was clean.

What the reviews found and fixed, in plain terms:

  • The shown mode could differ from the real one.
    • A lost reply could leave Claude or Codex in Full access while the chat showed Ask. Now a lost reply makes the mode unknown, and the chat's mode is applied again before the next message.
    • Two permission changes to one Claude could overlap. They now go through one queue per Claude process.
    • Desktop could apply an older read over a newer one, and dropped mode updates when it merged several updates. Both are fixed.
    • The phone treated an unconfirmed change as applied. It now keeps the last confirmed mode until the host confirms the change.
  • Mode intent.
    • A new chat now saves its starting mode at creation. Before, stopping it during startup let a later change to the new-chat default reach it.
    • Codex's older separate reviewer option no longer overrides the chat's mode. A saved value is migrated to the matching mode.
    • A stopped chat shows its saved mode instead of Ask. Re-picking the shown mode always applies it.
  • Liveness.
    • Stop could hang behind a Claude that never finished starting. It no longer does.
    • Picking Full access during a reply could make the follow-up fail. Now the follow-up runs under the current mode, and Claude restarts at the next idle message.
    • Accept edits had stopped launching directly, which delayed the first message. It launches directly again, so the first message doesn't wait for Claude to start.
  • Wording. The descriptions now say what each agent actually does. Codex's Ask works inside its workspace sandbox. Claude's modes follow Claude's own rules and sandbox. Full access keeps its warning.
  • Approve for me is offered only when the agent has confirmed support.

Live QA. Electron QA on macOS desktop passed every row, including a final round on the final branch. That round covered the new descriptions, Accept edits launching directly, and Full access picked during a reply. Not verified live: a real Codex automatic-review session, Windows/Linux, SSH, and the phone. The mobile paths are covered by hook-level tests only.

Tests.

  • 347 related test files (3,523 tests) pass, plus the mobile permission tests.
  • The real Claude CLI tests pass (12/12) on the final branch.
  • Typecheck, lint, localization and the other CI static checks pass on the branch merged with current main.

CI. On 06163c3454b, everything passed except two tests:

  • config/scripts/vitest-sqlite-runtime-boundary.test.ts: two new SQLite-backed tests weren't on the Node-runtime list. Fixed in cd9428f3190.
  • src/main/terminal-history-gc.test.ts, a main-thread timing test: this PR doesn't touch that code.

CI is re-running on cd9428f3190.

Not changed. Terminal launches and Settings → Agents → Agent Permissions behave as before. Grok and other agents' chats show no button; the follow-up for Grok is STA-9763.

@brennanb2025
brennanb2025 marked this pull request as ready for review October 8, 2026 05:52
@coderabbitai

coderabbitai Bot commented Oct 8, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 10 seconds.

Check out review usage here.

View limit details

Limit details: You’ve used all 10 included reviews currently available.

Learn how review limits work.

Review configuration:

⚙️ Run configuration
  • Configuration used: Repository UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 1a5424de-e9a1-41fa-a828-e734cbe282e3
📥 Commits

Reviewing files that changed from the base of the PR and between 7e29652 and 598f31f.

⛔ Files ignored due to path filters (1)
  • src/main/runtime/__snapshots__/structured-agent-launch-parity.test.ts.snap is excluded by !**/*.snap
📒 Files selected for processing (135)
  • config/scripts/vitest-node-runtime-files.mjs
  • mobile/src/session/MobileNativeChatSessionOptionPickers.test.ts
  • mobile/src/session/MobileNativeChatSessionOptionPickers.tsx
  • mobile/src/session/MobileNativeChatSessionOptionRows.tsx
  • mobile/src/session/use-mobile-host-model-catalog-upgrade.ts
  • mobile/src/session/use-mobile-structured-agent-options.permission-mode.test.ts
  • mobile/src/session/use-mobile-structured-agent-options.ts
  • mobile/src/session/use-mobile-structured-agent-session.ts
  • mobile/src/session/use-mobile-structured-session-option-stamp.ts
  • src/main/acp/acp-structured-compaction.test.ts
  • src/main/claude/claude-agent-sdk-contract-pins.test.ts
  • src/main/claude/claude-model-catalog-probe.test.ts
  • src/main/claude/claude-model-catalog-probe.ts
  • src/main/claude/claude-structured-acquisition-launch.ts
  • src/main/claude/claude-structured-catalog-listing.ts
  • src/main/claude/claude-structured-effort-default-at-rest.test.ts
  • src/main/claude/claude-structured-launch-resolution.test.ts
  • src/main/claude/claude-structured-launch-resolution.ts
  • src/main/claude/claude-structured-model-catalog.ts
  • src/main/claude/claude-structured-options-context-window.test.ts
  • src/main/claude/claude-structured-options.ts
  • src/main/claude/claude-structured-permission-mode.test.ts
  • src/main/claude/claude-structured-permission-mode.ts
  • src/main/claude/claude-structured-real-cli.test.ts
  • src/main/claude/claude-structured-session-adapter.test.ts
  • src/main/claude/claude-structured-session-state.ts
  • src/main/claude/claude-structured-spawn-options.test.ts
  • src/main/claude/claude-structured-spawn-options.ts
  • src/main/claude/claude-supervised-stop-real-cli.test.ts
  • src/main/codex/codex-structured-launch-resolution.test.ts
  • src/main/codex/codex-structured-launch-resolution.ts
  • src/main/codex/codex-structured-permission-policy.test.ts
  • src/main/codex/codex-structured-permission-policy.ts
  • src/main/codex/codex-structured-real-cli-visuals.test.ts
  • src/main/codex/codex-structured-session-acquire.ts
  • src/main/codex/codex-structured-session-adapter.test.ts
  • src/main/codex/codex-structured-session-state.ts
  • src/main/codex/codex-structured-thread-open.test.ts
  • src/main/codex/codex-structured-turn-start.ts
  • src/main/codex/codex-structured-visuals.test.ts
  • src/main/native-chat/agent-model-catalog/agent-model-catalog-persistence.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-acquisition.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-attach-flow.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-attach-orchestration.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-host-delivery.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-host-mutations.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-host-types.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-host.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-launch-permission.test.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-launch-permission.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-options-read.test.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-options-read.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-outgrown-child.test.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-outgrown-child.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-permission-mode.test.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-registered-definition.test.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-startup-attempt-contract.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-startup-attempt.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-status-summary-equality.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-status-summary.ts
  • src/main/native-chat/native-chat-inline-visuals-setting.test.ts
  • src/main/persistence/loading-store/normalize-loaded-global-settings.test.ts
  • src/main/persistence/loading-store/normalize-loaded-global-settings.ts
  • src/main/runtime/claude-structured-startup-fault-is-not-an-exit.test.ts
  • src/main/runtime/claude-structured-startup-unanswered-control-request.test.ts
  • src/main/runtime/orca-runtime-get-structured-agent-session-create-support.ts
  • src/main/runtime/orca-runtime-get-worktree-ps.ts
  • src/main/runtime/orca-runtime-pty-foreground-process-reads.ts
  • src/main/runtime/orca-runtime-structured-agent-session-create-intent.test.ts
  • src/main/runtime/rpc/methods/structured-agent-session-create-message.test.ts
  • src/main/runtime/rpc/methods/structured-agent-session-create.ts
  • src/main/runtime/runtime-client-settings-shape.ts
  • src/main/runtime/runtime-client-settings.ts
  • src/main/runtime/runtime-store-contract.ts
  • src/main/runtime/structured-agent-launch-composition.test-support.ts
  • src/main/runtime/structured-agent-launch-composition.ts
  • src/main/runtime/structured-agent-launch-parity.test.ts
  • src/main/runtime/structured-agent-new-chat-effort-at-rest.test.ts
  • src/main/runtime/structured-agent-runtime-registrations.ts
  • src/main/runtime/structured-agent-session-runtime.ts
  • src/renderer/src/components/native-chat/NativeChatComposer.tsx
  • src/renderer/src/components/native-chat/NativeChatComposerActions.tsx
  • src/renderer/src/components/native-chat/NativeChatComposerField.tsx
  • src/renderer/src/components/native-chat/NativeChatPermissionModePicker.test.tsx
  • src/renderer/src/components/native-chat/NativeChatPermissionModePicker.tsx
  • src/renderer/src/components/native-chat/NativeChatSessionOptionPickers.tsx
  • src/renderer/src/components/native-chat/NativeChatStructuredSession.tsx
  • src/renderer/src/components/native-chat/StructuredAgentSessionStatusBridge.tsx
  • src/renderer/src/components/native-chat/native-chat-permission-mode-labels.ts
  • src/renderer/src/components/native-chat/native-chat-session-option-surface-call.ts
  • src/renderer/src/components/native-chat/use-host-model-catalog-upgrade.ts
  • src/renderer/src/components/native-chat/use-structured-agent-session-option-state.ts
  • src/renderer/src/components/native-chat/use-structured-agent-session-options.permission-mode.test.tsx
  • src/renderer/src/components/native-chat/use-structured-agent-session-options.ts
  • src/renderer/src/components/native-chat/use-structured-agent-session.ts
  • src/renderer/src/components/settings/ChatPermissionSetting.test.tsx
  • src/renderer/src/components/settings/ChatPermissionSetting.tsx
  • src/renderer/src/components/settings/ChatSettingsSection.inline-visuals.test.tsx
  • src/renderer/src/components/settings/ChatSettingsSection.navigation.test.tsx
  • src/renderer/src/components/settings/ChatSettingsSection.test.tsx
  • src/renderer/src/components/settings/ChatSettingsSection.tsx
  • src/renderer/src/components/settings/chat-naming-persistence.test.tsx
  • src/renderer/src/components/settings/chat-permission-search.ts
  • src/renderer/src/hooks/settings-navigation-interface-sections.ts
  • src/renderer/src/i18n/en-runtime-required.json
  • src/renderer/src/i18n/locales/en.json
  • src/renderer/src/i18n/locales/es.json
  • src/renderer/src/i18n/locales/fr.json
  • src/renderer/src/i18n/locales/ja.json
  • src/renderer/src/i18n/locales/ko.json
  • src/renderer/src/i18n/locales/zh.json
  • src/renderer/src/lib/launch-structured-agent-session.test.ts
  • src/renderer/src/lib/launch-structured-agent-session.ts
  • src/renderer/src/lib/structured-agent-session-launch-options.ts
  • src/renderer/src/web/preload-api/web-preference-normalization.ts
  • src/renderer/src/web/preload-api/web-preferences-store.ts
  • src/shared/agent-chat-permission-mode.test.ts
  • src/shared/agent-chat-permission-mode.ts
  • src/shared/agent-session-option-catalog-types.ts
  • src/shared/agent-session-wire.ts
  • src/shared/claude-model-list-probe.test.ts
  • src/shared/claude-model-list-probe.ts
  • src/shared/commit-message-agent-spec.ts
  • src/shared/commit-message-model-parsers.ts
  • src/shared/default-global-settings.ts
  • src/shared/global-settings-types.ts
  • src/shared/native-chat-session-option-defaults.ts
  • src/shared/native-chat-session-option-snapshot.ts
  • src/shared/rpc-contract/client-settings-params.ts
  • src/shared/structured-agent-session-discovered-model.ts
  • src/shared/structured-agent-session-option-view.ts
  • src/shared/structured-agent-session-options.ts
  • src/shared/structured-agent-session-permission-option.test.ts
  • src/shared/structured-agent-session-permission-option.ts
  • tests/e2e/claude-auto-mode-host-catalog.unit.test.ts

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Repository UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 6c6e08c0-d952-45c8-8e87-b4041916949a
📥 Commits

Reviewing files that changed from the base of the PR and between 85dc0d0 and 7e29652.

⛔ Files ignored due to path filters (1)
  • src/shared/__snapshots__/native-chat-terminal-launch-isolation.test.ts.snap is excluded by !**/*.snap
📒 Files selected for processing (38)
  • config/scripts/vitest-sqlite-runtime-files.mjs
  • mobile/src/session/mobile-native-chat-permission-composition.test.ts
  • mobile/src/session/mobile-permission-composition.test-fixture.ts
  • mobile/src/session/mobile-structured-options-read.ts
  • mobile/src/session/mobile-structured-permission-lifecycle.test.ts
  • mobile/src/session/mobile-structured-permission-tab-reconciliation.test.ts
  • mobile/src/session/use-mobile-host-model-catalog-upgrade.ts
  • mobile/src/session/use-mobile-structured-agent-options.test.ts
  • mobile/src/session/use-mobile-structured-agent-options.ts
  • mobile/src/session/use-mobile-structured-agent-permission-refresh.test.ts
  • mobile/src/session/use-mobile-structured-permission-state.ts
  • src/main/claude/claude-structured-effort-default-at-rest.test.ts
  • src/main/claude/claude-structured-session-acquisition.ts
  • src/main/claude/claude-structured-session-adapter-turns.test.ts
  • src/main/claude/claude-structured-session-options.ts
  • src/main/claude/claude-structured-session-startup.ts
  • src/main/claude/claude-structured-session-state.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-adapter.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-lifecycle-events.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-option-restoration.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-options-read.test.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-options-read.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-provider-started.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-provisional-permission.test.ts
  • src/main/runtime/structured-agent-runtime-registrations.ts
  • src/main/runtime/structured-claude-runtime-adapter.ts
  • src/renderer/src/components/native-chat/NativeChatComposerActions.test.tsx
  • src/renderer/src/components/native-chat/NativeChatComposerActions.tsx
  • src/renderer/src/components/native-chat/NativeChatPermissionModePicker.tsx
  • src/renderer/src/components/native-chat/use-structured-agent-option-write.ts
  • src/renderer/src/components/native-chat/use-structured-agent-session-option-state.ts
  • src/renderer/src/components/native-chat/use-structured-agent-session-options.ts
  • src/shared/agent-session-model-catalog-wire.ts
  • src/shared/agent-session-wire.ts
  • src/shared/rpc-contract/client-settings-params.ts
  • src/shared/structured-agent-session-option-view.ts
  • src/shared/structured-agent-session-options.ts
  • src/shared/structured-agent-session-permission-state.test.ts
💤 Files with no reviewable changes (2)
  • src/main/runtime/structured-agent-runtime-registrations.ts
  • src/main/runtime/structured-claude-runtime-adapter.ts

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 1 remain after this review.

📝 Walkthrough

Walkthrough

Adds chat permission modes for Claude and Codex, with settings, session persistence, and host publications carrying current mode and revision data. Adds permission controls to desktop and mobile chat interfaces. Provider handling applies supported modes during launch, live updates, or child relaunches. The change also adds mode-aware session creation and empty-chat reuse, host-specific settings ownership, and tests for persistence, ordering, recovery, and provider behavior.

Priority: ➖ Normal

Merge Risk: 🟡 Moderate · up to 7e296

Chats now carry their own Claude and Codex permission mode across desktop and mobile. Two problems remain from earlier review. If Claude fails to start while a permission change is being prepared, queued messages are marked as generic host failures and the real error is hidden. On mobile, the permission control can disappear when no other chat options are loaded. Fix both, or explicitly accept them, before merging.

Pre-merge checks | Passed 3 | Failed 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 33.57% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 140 functions across 99 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check Warning The description is detailed and covers the user impact, implementation, rationale, visual proof, testing, limitations, and checklist. However, the Linked Issue section names STA-8261 without providing… Add a clickable link to the actual STA-8261 issue. Complete the Review section if required by repository policy.
✅ Passed checks (3 passed)
Check name Status Explanation
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Title check Passed The title clearly identifies the main change: separate permission modes for Claude and Codex native chats.
Full details: Description check

Explanation

The description is detailed and covers the user impact, implementation, rationale, visual proof, testing, limitations, and checklist. However, the Linked Issue section names STA-8261 without providing the required clickable issue link.

✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Commit to this branch
  • Create a new PR
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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.

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to GitHub limitations.

⚠️ Outside diff range comments (1)

🟡 Minor · Show the permission pill even when the option… · use-mobile-native-chat-session-option-controller.ts:87

mobile/src/session/use-mobile-native-chat-session-option-controller.ts:87
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Show the permission pill even when the option snapshot is empty.

structuredController is null whenever structuredSnapshot.length === 0. In that case, nativeChatSessionOptions is null, and structured.permissionPicker is dropped. MobileNativeChatSessionOptionPickers already returns the permission pill alone when no model descriptor exists, and its test covers this case with snapshot: []. That path cannot be reached from this controller. A Claude or Codex chat whose host reports permission modes but has no model descriptor yet shows no permission control on mobile.

Return picker props when structured.permissionPicker exists, even if the snapshot is empty.

Proposed fix
-      activeChatStructured && structuredSnapshot.length > 0
+      activeChatStructured && (structuredSnapshot.length > 0 || structured.permissionPicker)

Also add structured.permissionPicker to the memo dependencies.


ℹ️ Review info
⚙️ Run configuration
  • Configuration used: Repository UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: d66bd2d8-5df4-405e-88e6-ecad71aba3d3
📥 Commits

Reviewing files that changed from the base of the PR and between b41e273 and 06163c3.

⛔ Files ignored due to path filters (1)
  • src/shared/__snapshots__/native-chat-terminal-launch-isolation.test.ts.snap is excluded by !**/*.snap
📒 Files selected for processing (148)
  • config/scripts/vitest-sqlite-runtime-files.mjs
  • mobile/src/session/MobileNativeChatPermissionPicker.test.ts
  • mobile/src/session/MobileNativeChatPermissionPicker.tsx
  • mobile/src/session/MobileNativeChatSessionOptionPickers.test.ts
  • mobile/src/session/MobileNativeChatSessionOptionPickers.tsx
  • mobile/src/session/MobileNativeChatSessionOptionRows.tsx
  • mobile/src/session/mobile-native-chat-session-option-persistence.ts
  • mobile/src/session/mobile-structured-agent-session-rpc.ts
  • mobile/src/session/mobile-structured-session-controller.ts
  • mobile/src/session/use-mobile-native-chat-controller.ts
  • mobile/src/session/use-mobile-native-chat-session-option-controller.ts
  • mobile/src/session/use-mobile-structured-agent-mutation.ts
  • mobile/src/session/use-mobile-structured-agent-options.test.ts
  • mobile/src/session/use-mobile-structured-agent-options.ts
  • mobile/src/session/use-mobile-structured-agent-permission-refresh.test.ts
  • mobile/src/session/use-mobile-structured-agent-session.ts
  • mobile/src/session/use-mobile-structured-permission-write.test.ts
  • mobile/src/session/use-mobile-structured-session-host-stopping.ts
  • src/main/claude/claude-agent-sdk-contract-pins.test.ts
  • src/main/claude/claude-structured-acquisition-launch.ts
  • src/main/claude/claude-structured-fast-mode-support.ts
  • src/main/claude/claude-structured-initial-permission-intent.test.ts
  • src/main/claude/claude-structured-launch-resolution.test.ts
  • src/main/claude/claude-structured-launch-resolution.ts
  • src/main/claude/claude-structured-model-catalog.ts
  • src/main/claude/claude-structured-options-context-window.test.ts
  • src/main/claude/claude-structured-options.ts
  • src/main/claude/claude-structured-permission-application.ts
  • src/main/claude/claude-structured-permission-mode-option.test.ts
  • src/main/claude/claude-structured-permission-mode.test.ts
  • src/main/claude/claude-structured-permission-mode.ts
  • src/main/claude/claude-structured-permission-option.ts
  • src/main/claude/claude-structured-permission-owner.test.ts
  • src/main/claude/claude-structured-permission-reconciliation.test.ts
  • src/main/claude/claude-structured-real-cli.test.ts
  • src/main/claude/claude-structured-session-acquisition.ts
  • src/main/claude/claude-structured-session-adapter-turns.test.ts
  • src/main/claude/claude-structured-session-adapter.test.ts
  • src/main/claude/claude-structured-session-adapter.ts
  • src/main/claude/claude-structured-session-options.ts
  • src/main/claude/claude-structured-session-publication.ts
  • src/main/claude/claude-structured-session-startup.ts
  • src/main/claude/claude-structured-session-state.ts
  • src/main/claude/claude-structured-spawn-options.test.ts
  • src/main/claude/claude-structured-spawn-options.ts
  • src/main/claude/claude-structured-start-permission-mode.test.ts
  • src/main/claude/claude-structured-start-permission-mode.ts
  • src/main/claude/claude-supervised-stop-real-cli.test.ts
  • src/main/codex/codex-structured-agent-definition.ts
  • src/main/codex/codex-structured-launch-resolution.test.ts
  • src/main/codex/codex-structured-launch-resolution.ts
  • src/main/codex/codex-structured-permission-mode.test.ts
  • src/main/codex/codex-structured-permission-mode.ts
  • src/main/codex/codex-structured-permission-policy.test.ts
  • src/main/codex/codex-structured-permission-policy.ts
  • src/main/codex/codex-structured-permission-reconciliation.test.ts
  • src/main/codex/codex-structured-permission-test-support.ts
  • src/main/codex/codex-structured-real-cli-visuals.test.ts
  • src/main/codex/codex-structured-session-acquire.ts
  • src/main/codex/codex-structured-session-adapter.test.ts
  • src/main/codex/codex-structured-session-options.ts
  • src/main/codex/codex-structured-session-state.ts
  • src/main/codex/codex-structured-thread-open.test.ts
  • src/main/codex/codex-structured-thread-open.ts
  • src/main/codex/codex-structured-turn-start.ts
  • src/main/codex/codex-structured-visuals.test.ts
  • src/main/codex/codex-structured-visuals.ts
  • src/main/native-chat/agent-chat-permission-mode-setting.test.ts
  • src/main/native-chat/agent-chat-permission-mode-setting.ts
  • src/main/native-chat/agent-session-wire/agent-session-subscriber-catch-up.ts
  • src/main/native-chat/agent-session-wire/agent-session-subscriber-frame-fields.ts
  • src/main/native-chat/agent-session-wire/structured-agent-definition.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-acquire-aborts.test.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-acquire-aborts.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-adapter-router.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-adapter.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-child-relaunch.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-claude-hung-start-stop.test.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-claude-permission-order.test.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-claude-permission-relaunch.test.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-client-delivery.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-delivery-loop.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-dispatch-preparation.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-ended-child-failure.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-host-delivery.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-host-types.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-host.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-options-read.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-permission-mode.test.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-permission-publication.test.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-provisional-permission.test.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-stopped-permission-intent.test.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-subscribers.ts
  • src/main/persistence/loading-store/loaded-chat-permission-setting.test.ts
  • src/main/persistence/loading-store/loaded-chat-permission-setting.ts
  • src/main/persistence/loading-store/normalize-loaded-global-settings.ts
  • src/main/persistence/loading-store/normalize-loaded-profile-state.ts
  • src/main/runtime/claude-structured-startup-fault-is-not-an-exit.test.ts
  • src/main/runtime/claude-structured-startup-unanswered-control-request.test.ts
  • src/main/runtime/orca-runtime-get-structured-agent-session-create-support.ts
  • src/main/runtime/orca-runtime-get-worktree-ps.ts
  • src/main/runtime/orca-runtime-structured-agent-session-create-intent.test.ts
  • src/main/runtime/structured-agent-runtime-registrations.ts
  • src/main/runtime/structured-agent-session-runtime.ts
  • src/main/runtime/structured-claude-runtime-adapter.ts
  • src/renderer/src/components/native-chat/NativeChatComposer.tsx
  • src/renderer/src/components/native-chat/NativeChatComposerActions.tsx
  • src/renderer/src/components/native-chat/NativeChatComposerField.tsx
  • src/renderer/src/components/native-chat/NativeChatPermissionModePicker.test.tsx
  • src/renderer/src/components/native-chat/NativeChatPermissionModePicker.tsx
  • src/renderer/src/components/native-chat/native-chat-composer-types.ts
  • src/renderer/src/components/native-chat/native-chat-permission-mode-labels.ts
  • src/renderer/src/components/native-chat/use-structured-agent-session-option-state.ts
  • src/renderer/src/components/native-chat/use-structured-agent-session-options.ts
  • src/renderer/src/components/native-chat/use-structured-agent-session-permission-picker.test.tsx
  • src/renderer/src/components/native-chat/use-structured-agent-session.ts
  • src/renderer/src/components/native-chat/use-structured-permission-write.test.tsx
  • src/renderer/src/components/settings/AgentsPane.tsx
  • src/renderer/src/components/settings/ChatPermissionSetting.tsx
  • src/renderer/src/components/settings/ChatSettingsSection.navigation.test.tsx
  • src/renderer/src/components/settings/ChatSettingsSection.test.tsx
  • src/renderer/src/components/settings/ChatSettingsSection.tsx
  • src/renderer/src/components/settings/chat-naming-persistence.test.tsx
  • src/renderer/src/components/settings/chat-permission-search.ts
  • src/renderer/src/hooks/settings-navigation-interface-sections.ts
  • src/renderer/src/i18n/en-runtime-required.json
  • src/renderer/src/i18n/locales/en.json
  • src/renderer/src/i18n/locales/es.json
  • src/renderer/src/i18n/locales/fr.json
  • src/renderer/src/i18n/locales/ja.json
  • src/renderer/src/i18n/locales/ko.json
  • src/renderer/src/i18n/locales/zh.json
  • src/renderer/src/lib/structured-agent-session-launch-options.test.ts
  • src/renderer/src/lib/structured-agent-session-launch-options.ts
  • src/shared/agent-chat-permission-mode.test.ts
  • src/shared/agent-chat-permission-mode.ts
  • src/shared/agent-session-wire.ts
  • src/shared/default-global-settings.ts
  • src/shared/global-settings-types.ts
  • src/shared/native-chat-session-option-defaults.ts
  • src/shared/native-chat-terminal-launch-isolation.test.ts
  • src/shared/structured-agent-session-coalescer.ts
  • src/shared/structured-agent-session-option-picks.test.ts
  • src/shared/structured-agent-session-option-picks.ts
  • src/shared/structured-agent-session-options.ts
  • src/shared/structured-agent-session-permission-coalescing.test.ts
  • src/shared/structured-agent-session-permission-state.test.ts
  • src/shared/structured-agent-session-reducer.ts

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 6 remain after this review.

Comment on lines +101 to +105
const ready = session.startup.state === 'pending' ? session.startup.settled : Promise.resolve()
return ready.then(async () => {
if (session.startup.state !== 'proven') {
throw session.startup.failure ?? new Error('claude startup did not complete')
}

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.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🔎 Supported by static analysis

🏁 Script executed:

#!/bin/bash
rg -nP -C4 "startup\.(state|failure)" src/main/claude/claude-structured-dispatch.ts src/main/claude/claude-structured-session-startup.ts
rg -nP -C3 "state:\s*'(failed|proven|pending)'" src/main/claude

Repository: stablyai/orca

Length of output: 13488


🏁 Script executed:

#!/bin/bash
set -e
printf '%s\n' '--- permission application ---'
nl -ba src/main/claude/claude-structured-permission-application.ts | sed -n '1,180p'
printf '%s\n' '--- dispatch references ---'
rg -n -F --glob '*.ts' -- 'dispatchClaudeTurn' src/main/claude src/main | head -80
rg -n -F --glob '*.ts' -- 'prepareClaudePermissionMode' src/main
printf '%s\n' '--- dispatch definitions and relevant callers ---'
rg -n -F --glob '*.ts' -- 'prepareStructuredAgentSessionDispatch' src/main
rg -n -F --glob '*.ts' -- 'StructuredAgentSessionDeliveryLoop' src/main
printf '%s\n' '--- startup state and failure helpers ---'
nl -ba src/main/claude/claude-structured-session-startup-state.ts | sed -n '1,180p'
rg -n -P -C8 "failClaudeStartup|startup\.failure|startup\.state" src/main/claude/claude-structured-dispatch.ts src/main/claude/claude-structured-session-startup.ts

Repository: stablyai/orca

Length of output: 31295


🏁 Script executed:

#!/bin/bash
set -e
printf '%s\n' '--- dispatch preparation ---'
nl -ba src/main/native-chat/agent-session-wire/structured-agent-session-dispatch-preparation.ts | sed -n '1,220p'
printf '%s\n' '--- delivery loop ---'
nl -ba src/main/native-chat/agent-session-wire/structured-agent-session-delivery-loop.ts | sed -n '1,280p'
printf '%s\n' '--- host delivery ---'
nl -ba src/main/native-chat/agent-session-wire/structured-agent-session-host-delivery.ts | sed -n '1,180p'
printf '%s\n' '--- Claude session adapter around preparation ---'
nl -ba src/main/claude/claude-structured-session-adapter.ts | sed -n '210,270p'
printf '%s\n' '--- Claude dispatch ---'
nl -ba src/main/claude/claude-structured-dispatch.ts | sed -n '90,280p'

Repository: stablyai/orca

Length of output: 34275


🏁 Script executed:

#!/bin/bash
set -e
printf '%s\n' '--- handover submission ---'
rg -n -F --glob '*.ts' -- 'export async function handOverSubmission' src/main/native-chat/agent-session-wire
nl -ba src/main/native-chat/agent-session-wire/structured-agent-session-turns.ts | sed -n '1,260p'
printf '%s\n' '--- Claude adapter dispatch binding ---'
rg -n -P -C8 "dispatch\s*[:=]|dispatch\(" src/main/claude/claude-structured-session-adapter.ts | head -120
printf '%s\n' '--- adapter contract ---'
rg -n -P -C8 "dispatch\??:" src/main/native-chat/agent-session-wire/structured-agent-session-adapter.ts

Repository: stablyai/orca

Length of output: 13259


Do not convert failed Claude startup into a host fault.

When prepareClaudePermissionMode rejects with session.startup.failure, the rejection reaches StructuredAgentSessionDeliveryLoop.run, which records { hostFault: true }. This hides the provider startup diagnostic.

If startup has failed, return without preparing. The next handover dispatch checks claudeStartupFailureFact(session) and records the provider startup failure instead. The early return also prevents repeated preparation attempts.

Proposed fix
--- "a/src/main/claude/claude-structured-permission-application.ts"
+++ "b/src/main/claude/claude-structured-permission-application.ts"
@@ -91,17 +91,21 @@
 }
 
 /** Runs outside the mutation lane so Stop can cancel startup or reconciliation. */
 export function prepareClaudePermissionMode(
   session: ClaudeSession,
   timeoutMs: number | undefined
 ): Promise<void> | undefined {
+  // A failed start is the child's to report; preparation must not turn it into a host fault.
+  if (session.startup.state !== 'pending' && session.startup.state !== 'proven') {
+    return undefined
+  }
   if (!claudePermissionNeedsPreparation(session) && !permissionOwners.get(session)?.pending) {
     return undefined
   }
   const ready = session.startup.state === 'pending' ? session.startup.settled : Promise.resolve()
   return ready.then(async () => {
     if (session.startup.state !== 'proven') {
-      throw session.startup.failure ?? new Error('claude startup did not complete')
+      return
     }
     let preparing = true
     while (preparing) {

@brennanb2025

Copy link
Copy Markdown
Contributor Author

Review summary

This PR went through many adversarial review rounds and live QA rounds, each in a hidden, isolated Orca with stand-in agents. Every finding above minor was fixed before the next round.

How the design changed during review

  • The mode is fixed at creation. A chat used to follow the new-chat default until its agent started. That needed a second revision counter and writes at start time, and it overwrote older Codex chats' saved reviewer choice. Now each chat saves its starting mode when it is created and never follows the default again. Older chats get a fixed mode from their own saved options, without any rewrite.
  • The default lives on the machine that runs the chats. "Permissions for new chats" reads and writes the setting on the execution host: this machine, a remote Orca server, or the web client's host. A confirmed write wins over a read still in flight.
  • Updates arrive in order. Each chat keeps a permission revision, saved in the same transaction as the mode. Desktop and phone apply updates through one shared ordering rule, so after a reconnect or restart an older update can't win.
  • No waiting. Every mode is offered as soon as a chat opens, even while the agent starts. A mode the agent turns out not to support falls back to Ask and is saved.

Found late and fixed

  • "New chat" handed back an old empty chat after a default change (live QA). Reuse now compares the starting mode the empty chat was created with (initialPermissionMode, saved once at creation) with today's. It still reuses a chat that fell back to Ask, and doesn't reuse one the user widened.
  • The Codex button was missing during startup for new local chats, until Codex answered. An earlier QA pass had wrongly approved this, with a screenshot taken 0.4 s after startup. A local launch now carries the host's starting mode. Live QA on the final build confirmed it against the stand-in log's timestamps.
  • After merging main:
    • two mobile boundary checks (stream inventory and request port);
    • a tab-list crash when a permission read fails;
    • a desktop test that imported mobile code;
    • a re-render loop in a permission read.

Verified:

  • full CI;
  • the real Claude CLI contract (13 tests);
  • composed tests across desktop-local, desktop-remote and web;
  • the live rows in the PR body.

Not verified:

  • a real Codex automatic-review session;
  • Windows and Linux;
  • SSH;
  • the phone app on a device.

Known limits are listed in the PR body. They are three minor cases plus one temporary follow-up: focus returning to the message box after picking a mode.

@brennanb2025
brennanb2025 marked this pull request as ready for review October 9, 2026 07:15
@brennanb2025

Copy link
Copy Markdown
Contributor Author

Update since the review summary (now at 7e296520983, CI green):

  • Main merged again to clear conflicts. Almost all of them came from Show model and effort choices for every agent before its session starts #26407, which shows model and effort choices before a chat starts. The permission behaviour now builds on main's new code for that.
  • The permission button moved to the left of the message box, directly after the attach (+) button, as requested. The phone already used that order.
  • Live QA on the final build:
    • Codex and Claude placement; the menu opens from the button.
    • The full label still fits in a 460 px chat column.
    • The button is present while Codex is still starting, checked against the stand-in's timestamps.

Each Claude and Codex chat now has its own permission mode (Ask for approval,
Accept edits, Approve for me, Full access), saved as one more chat option and
picked from a button after "+" on desktop or a pill on the phone. The mode
takes effect when the agent starts: Claude gets launch flags, Codex gets the
thread policy on start and resume. A change restarts an idle agent before the
next message, never during a reply. New chats take the host's default from
Settings > Chat, seeded once from Agent Permissions.
The restart check, the start and the options read now share one host
derivation, so a running agent whose mode differs from what a start would
launch is replaced, and the button shows what the host runs. A permission
pick shows at once and never locks the picker while its write waits behind
a starting agent. One shared table names each agent's modes; the phone
shows its permission pill even without a model pill.
…uns Approve for me

The menu and the host now call the same function: the chat's listed model
row, or the row the CLI default resolves to when the chat names none. The
model-catalog probe now marks that default row, as a live listing already
does, so a new chat can offer Approve for me before its first message.
…ng lands

A chat opened before its account's first model listing read its options at
rest from the agent's built-in list, which names no Approve for me support.
The client takes that answer as the session's own list, so the host list that
landed a moment later was ignored until the first turn. When a waited listing
lands, the chat now reads its options again, on desktop and phone.
…mission-modes-v2

# Conflicts:
#	mobile/src/session/MobileNativeChatSessionOptionPickers.tsx
#	src/main/claude/claude-structured-acquisition-launch.ts
#	src/main/claude/claude-structured-launch-resolution.ts
#	src/main/claude/claude-structured-session-state.ts
#	src/main/codex/codex-structured-launch-resolution.test.ts
#	src/main/codex/codex-structured-launch-resolution.ts
#	src/main/codex/codex-structured-session-acquire.ts
#	src/main/codex/codex-structured-session-state.ts
#	src/main/native-chat/agent-session-wire/structured-agent-session-options-read.test.ts
#	src/main/native-chat/agent-session-wire/structured-agent-session-options-read.ts
#	src/main/runtime/structured-agent-runtime-registrations.ts
#	src/main/runtime/structured-claude-runtime-adapter.ts
@brennanb2025
brennanb2025 force-pushed the brennanb2025/sta-8261-permission-picker branch from 7e29652 to f467d20 Compare October 12, 2026 08:39
@brennanb2025 brennanb2025 changed the title feat(native-chat): chats get their own permission mode, with a composer button and a setting for new chats feat(native-chat): each Claude/Codex chat gets its own permission mode Oct 12, 2026
@brennanb2025

Copy link
Copy Markdown
Contributor Author

Rebuilt on the simpler design and force-pushed (head f467d20). The previous version is kept on branch brennanb2025/sta-8261-permission-picker-v1-backup.

  • What it does: the mode is now an ordinary saved chat option. A change takes effect by restarting the agent before the next message, using main's existing "replace the agent before the next message" step. Live Claude switching, the ordering counter and the empty-chat setting are gone.
  • Size: about 1,350 product lines instead of about 4,500.
  • Merge order: this needs feat(native-chat): require Codex 0.136.0 for chats #26684 (Codex 0.136.0) to merge first.
  • Live QA results and screenshots are in the description.

@brennanb2025
brennanb2025 merged commit 2233fd3 into main Oct 12, 2026
39 checks passed
ggrafhalfbrick added a commit to ggrafhalfbrick/orca that referenced this pull request Oct 13, 2026
…#26116)

Upstream stablyai#26116 ships the same capability provider-neutrally (via
structured-agent-session-permission-mode) and deleted this branch's
claude-specific claude-structured-permission-mode.ts + test. Per plan, this
branch is retired rather than reconciled line-by-line: the merge resolves to
main's tree exactly, dropping the superseded permission-mode implementation.
The branch contributes nothing further; integration can treat it as main.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
ggrafhalfbrick added a commit to ggrafhalfbrick/orca that referenced this pull request Oct 14, 2026
… permission-mode code

Full access still prompted for every tool. Orca always attaches its own
canUseTool permission callback (the SDK pairs it with --permission-prompt-tool
stdio), so a bare --dangerously-skip-permissions never stopped the CLI routing
each tool back to that callback, which had no bypass path. The callback now
auto-approves tool-permission requests when the chat is in full access, while
still surfacing genuine questions (AskUserQuestion) and plan proposals
(ExitPlanMode).

Also drops our superseded "System B" permission-mode code now that upstream's
per-chat permission mode (stablyai#26116) is in integration: the provider-neutral report
types, the top-level AgentSessionOptionsResult.permissionMode field and its
readRestingPermissionMode producer, CLAUDE_ALLOW_BYPASS_FLAG, the dead
allowDangerouslySkipPermissions option, the reference doc, and the related
AGENTS.md/.gitignore entries. Upstream's System A (AgentChatPermissionMode,
current.permissionMode, the picker) is untouched.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@brennanb2025
brennanb2025 deleted the brennanb2025/sta-8261-permission-picker branch October 14, 2026 17:38
registered2nd pushed a commit to registered2nd/orca that referenced this pull request Oct 14, 2026
stablyai#26116)

Each native Claude and Codex chat now has its own permission mode (Ask for approval, Accept edits for Claude, Approve for me, Full access), shown and changed from a button right after "+" in the composer. A change takes effect before the next message: the agent restarts quietly and resumes the same conversation, never interrupting a reply or background work. New chats start from Settings → Chat → Permissions, which is seeded once from Agent Permissions. The mode is stored as an ordinary chat option, and the restart reuses the existing "replace the agent before the next message" step.

(cherry picked from commit 2233fd3)
brennanb2025 added a commit that referenced this pull request Oct 15, 2026
#26116)

Each native Claude and Codex chat now has its own permission mode (Ask for approval, Accept edits for Claude, Approve for me, Full access), shown and changed from a button right after "+" in the composer. A change takes effect before the next message: the agent restarts quietly and resumes the same conversation, never interrupting a reply or background work. New chats start from Settings → Chat → Permissions, which is seeded once from Agent Permissions. The mode is stored as an ordinary chat option, and the restart reuses the existing "replace the agent before the next message" step.

(cherry picked from commit 2233fd3)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant