Skip to content

fix(native-chat): never run a chat on an older host with more access than Ask for approval allows - #29442

Merged
nwparker merged 5 commits into
mainfrom
nwparker/native-chat-ask-mode-capability
Oct 16, 2026
Merged

nwparker merged 5 commits into
mainfrom
nwparker/native-chat-ask-mode-capability

Conversation

@nwparker

@nwparker nwparker commented Oct 16, 2026 •

Copy link
Copy Markdown
Contributor
Files Added Deleted Net
Test 10 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​410 $\color{#cf222e}{\Huge{\mathbf{−}}}$​6 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​404
Prod 23 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​568 $\color{#cf222e}{\Huge{\mathbf{−}}}$​83 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​485

ELI5

If your SSH host or paired machine is still running an Orca server from 1.4.224 or earlier, that server doesn't know about the chat setting "Ask for approval". It runs Claude and Codex chats with its own old Agent Permissions, which by default skip every approval. This desktop showed "Ask for approval" anyway, so a remote chat could run commands without asking. Now Orca checks what the host will actually do first. If the host would give the agent more access than you asked for, Orca won't start the chat or send the message, and it tells you to update Orca on that host.

What Changed

Before: with Settings → Chat → "Permissions for new chats" set to Ask for approval, a new Claude chat on a 1.4.224 host started with --dangerously-skip-permissions (the QA run on openclaw ran touch … with no prompt). The composer showed no permission button and nothing in the chat said approvals were off.

After (desktop):

  • New chat on that host: Orca doesn't start it. A toast says "Orca did not start a Claude chat. This host runs an older Orca that ignores chat permissions, so Claude would run here without asking. Update Orca on this host to use Ask for approval." Its first prompt isn't sent either.
  • Chat already open on that host:
    • Send is disabled and its tooltip gives that reason.
    • The same sentence shows as a warning above the composer.
    • Enter does nothing.
    • Everything else that would start a turn is held too:
      • commands such as /compact and /clear, and a /goal objective;
      • the Continue button on a reply that was cut off;
      • a queued message's Send now (including Cmd/Ctrl+Enter) and the queue's Resume;
      • Resume goal, and a Claude goal Clear;
      • Retry on a failed start.
    • Commands that only change options, like /model, still work.
  • Older host that won't give more access than asked: the chat works as before. That covers a host set to Manual (it asks too) and Full access chosen on this desktop.
  • Newer hosts: no change.
  • Host doesn't answer the check: nothing starts, and the chat says Orca couldn't confirm the host's permissions. This doesn't count as a verdict that the host is old.
  • When Orca checks again:
    • Each time contact with the host comes back. Until the new answer arrives, the chat is held again rather than trusting the old answer.
    • Every 30 seconds while a chat is held, so switching the host to Manual or updating it lets the chat through without a reload.

After (phone): a Claude or Codex chat on such a host now shows a read-only Host's Agent Permissions pill where the permission picker would be. Its one entry explains that the host applies its own Agent Permissions and must be updated to choose a mode per chat. The phone never asked for a stricter mode, so this only shows what the host does and doesn't block anything.

Mechanism:

  • Capability: hosts now advertise agent-session.permission-modes.v1.
    • 1.4.225 and 1.4.226 already apply per-chat modes but don't advertise it. They're recognised because their settings.get reply always includes nativeChatPermissionMode. 1.4.224 never sends it.
  • Old host's actual mode: for a host with neither signal, the client reads its Agent Permissions arguments (agentDefaultArgs) the same way that host's launch code did.
    • Bypass flag present (the default) → Full access; otherwise Ask.
    • It counts as bypass if the flag is present under any shell's parsing.
  • Rule: chatPermissionHostVerdict in src/shared/agent-chat-permission-host-support.ts allows a chat only when the host grants no more access than requested. The request is this client's Settings → Chat value. A missing or unknown value counts as Ask.
  • Where the rule runs (desktop):
    • before a paired chat is created (structured-agent-session-launch-admission.ts);
    • in the composer, through a new optional sendBlockedReason on the structured transport.
  • Phone: reads the same capability, and adds the read-only pill only after the host's options reply states no mode.
  • Host side: unchanged, apart from advertising the capability.

Compatibility:

  • Old host + new client: handled above.
  • New host + old client: already host-owned. The host seeds its own permission default into a create that carries none, covered by legacy attach-shaped permission creation in structured-agent-session-wire-contracts.test.ts. An old client just ignores the new capability.
  • Wire: no new RPC fields or stream opcodes. Clients only read the new capability and an existing settings key.

Why

  • A new capability alone isn't enough. It would treat 1.4.225 and 1.4.226, which already apply modes, as old. The settings key is a fact those versions already publish, and the capability keeps detection explicit from now on.
  • Mapping to "the strictest mode the old host supports" isn't possible. An old host takes no per-chat mode at all; only its host-wide Agent Permissions decide. Changing those from the client would silently change every terminal agent on that host.
  • Blocking every old host would break working setups. It would stop chats on hosts that already ask (Manual), and for people who chose Full access. Reading the host's real mode blocks only the dangerous case.
  • Unknown blocks. When the host can't be read, the client refuses rather than assume the safe answer.

Linked Issue

Linear STA-10671. Related: STA-10426 (the 1.4.225 permission-mode PRs #26116, #26684, #28099, #28100, #28212, #28268).

Visual Proof

N/A for screenshots: the change is a refusal toast, a disabled Send with a warning line in the composer, and a read-only phone pill. They only appear against a 1.4.224 host, which can't run in this sandbox. Unit tests cover what each surface shows.

Testing

  • I manually tested these changes locally
  • Automated tests added/updated
    • src/shared/agent-chat-permission-host-support.test.ts: what an old host runs, by its arguments; the verdict for each pair of requested and actual mode; an unreadable host refused; the capability advertised.
    • src/renderer/src/runtime/structured-chat-host-permission.test.ts:
      • advertised capability allowed without a settings read;
      • a 1.4.225-shaped settings reply allowed;
      • a 1.4.224 Yolo host refused for Ask and Accept edits, but allowed for Full access;
      • a Manual host allowed;
      • a failed read reported as unverified;
      • local and non-Claude/Codex never probed.
    • structured-agent-session-launch-admission.test.ts: a refused or unverified paired host gets no chat, no terminal and exactly one toast; this machine is never probed.
    • use-native-chat-structured-composer-send.test.tsx: a held host takes no message and no /compact, but /model still runs.
    • Mobile: host support reads the capability; the read-only pill shows on a host stating no mode, not before the probe answers, and not on a 1.4.225-shaped host that states one.
  • pnpm tc, mobile tsc --noEmit, and pnpm run check:code-quality:changed pass.

Review

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

  • Platforms: the old host's arguments are parsed for POSIX, PowerShell and cmd, so it doesn't matter which OS the host runs.
  • SSH: the decision is the host's own published facts. Losing contact gives "unverified", never a verdict about the host.
  • Mobile: covered above.
  • Performance: one cached capability lookup per chat. Only hosts without the capability also get one settings.get.

Checklist

  • This PR is small and focused
  • 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)

@coderabbitai

coderabbitai Bot commented Oct 16, 2026 •

Copy link
Copy Markdown
Contributor

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 3 minutes.

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: 55f76b11-d6a5-41d7-b143-41ae8ee5a272
📥 Commits

Reviewing files that changed from the base of the PR and between da099c3 and 4b76e1f.

📒 Files selected for processing: 33
  • mobile/src/session/mobile-structured-agent-session-host-support.test.ts
  • mobile/src/session/mobile-structured-agent-session-host-support.ts
  • mobile/src/session/use-mobile-structured-agent-options.first-frame.test.ts
  • mobile/src/session/use-mobile-structured-agent-options.permission-mode.test.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-session.ts
  • mobile/src/session/use-mobile-structured-option-surface.ts
  • src/renderer/src/components/native-chat/NativeChatComposer.tsx
  • src/renderer/src/components/native-chat/NativeChatInterruptedContinue.tsx
  • src/renderer/src/components/native-chat/NativeChatStructuredGoalStrip.tsx
  • src/renderer/src/components/native-chat/NativeChatStructuredSession.orca-stop-continue.test.tsx
  • src/renderer/src/components/native-chat/NativeChatStructuredSession.tsx
  • src/renderer/src/components/native-chat/NativeChatThreadGoalBanner.tsx
  • src/renderer/src/components/native-chat/native-chat-composer-types.ts
  • src/renderer/src/components/native-chat/native-chat-structured-session-notices.ts
  • src/renderer/src/components/native-chat/use-native-chat-host-permission-gate.ts
  • src/renderer/src/components/native-chat/use-native-chat-structured-composer-send.test.tsx
  • src/renderer/src/components/native-chat/use-native-chat-structured-composer-send.ts
  • src/renderer/src/components/native-chat/use-native-chat-structured-composer-transport.ts
  • src/renderer/src/components/native-chat/use-structured-native-chat-submit-reveal.test.ts
  • src/renderer/src/components/native-chat/use-structured-native-chat-submit-reveal.ts
  • src/renderer/src/i18n/locales/en.json
  • src/renderer/src/lib/structured-agent-session-launch-admission.test.ts
  • src/renderer/src/lib/structured-agent-session-launch-admission.ts
  • src/renderer/src/lib/structured-agent-session-launch-permission-notice.ts
  • src/renderer/src/runtime/structured-chat-host-permission.test.ts
  • src/renderer/src/runtime/structured-chat-host-permission.ts
  • src/shared/agent-chat-permission-host-support.test.ts
  • src/shared/agent-chat-permission-host-support.ts
  • src/shared/agent-session-permission-modes-capability.ts
  • src/shared/protocol-version.ts
  • src/shared/structured-agent-session-permission-option.ts
  • Autofix · 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.

@nwparker
nwparker force-pushed the nwparker/native-chat-ask-mode-capability branch from 6ef2ee0 to 8cfe1ad Compare October 16, 2026 05:10
@nwparker
nwparker merged commit 6ae1386 into main Oct 16, 2026
32 of 33 checks passed
nwparker added a commit that referenced this pull request Oct 16, 2026
… permission tests (#29891)

#29335 gave Grok chats their own permission modes, so on a paired host
that predates per-chat modes a Grok chat is now checked like Claude and
Codex; that is intended. #29442's tests, merged a day earlier, used Grok
as the agent without modes. Use Gemini, which still has none.
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