fix(claude): support root daemon permissions - #2703
Conversation
|
| Filename | Overview |
|---|---|
| packages/server/src/server/agent/providers/claude/agent.ts | Detects root execution, disables permission bypass consistently in catalogs and sessions, and omits the unsupported SDK launch capability. |
| packages/server/src/server/agent/create-agent-mode.ts | Excludes disabled modes from defaults and unattended-mode resolution while rejecting explicit or inherited disabled selections. |
| packages/server/src/server/agent/provider-registry.ts | Applies Claude runtime mode availability to decorated provider definitions, including derived providers. |
| packages/protocol/src/messages.ts | Adds the optional disabled-mode explanation to protocol validation without breaking peers that omit it. |
| packages/app/src/components/ui/combobox-keyboard.ts | Completes the prior keyboard-navigation fix by skipping disabled options in both directions and during initial activation. |
| packages/app/src/components/ui/combobox.tsx | Prevents disabled options from becoming active or being selected through desktop keyboard handling. |
| packages/app/src/components/ui/select-field.tsx | Propagates disabled state and explanation into combobox rendering and blocks disabled selections. |
| packages/app/src/provider-selection/resolve-agent-form.ts | Reconciles persisted and preferred modes against runtime-disabled catalog entries. |
| packages/app/src/composer/draft/workspace-tab.tsx | Prevents stale draft and auto-submit configuration from restoring a disabled mode. |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart LR
Root[Daemon runs as UID 0] --> Provider[Claude provider]
Provider --> Catalog[Catalog marks bypass disabled]
Provider --> Launch[SDK launch omits bypass capability]
Catalog --> Protocol[Optional disabledReason field]
Protocol --> UI[Composer and setup controls]
UI --> Enabled[Select an enabled fallback mode]
Catalog --> Validation[Server mode validation]
Validation --> Reject[Reject stale or inherited bypass requests]
Reviews (2): Last reviewed commit: "fix(claude): support root daemon permiss..." | Re-trigger Greptile
There was a problem hiding this comment.
Pull request overview
This PR updates the Claude provider end-to-end (daemon + protocol + app) to support root-hosted daemon environments by disabling Claude’s “Bypass permissions” mode at runtime (with an explanatory reason) and omitting the Claude SDK launch capability that Claude Code rejects under UID 0, while keeping non-root behavior unchanged.
Changes:
- Server: detect daemon running as root, disable
bypassPermissionsmode with adisabledReason, reject attempts to select it, and omitallowDangerouslySkipPermissionswhen root. - Protocol + UI: add optional
disabledReasonto agent modes and ensure app workflows don’t auto-select or allow selecting disabled modes (composer, drafts, workspace setup, schedules, provider selection). - Tests + docs: add coverage for root behavior and document the root restriction in provider docs.
Reviewed changes
Copilot reviewed 20 out of 20 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| packages/server/src/server/agent/providers/claude/agent.ts | Root detection, runtime mode availability gating, server-side enforcement, and SDK launch option omission under root. |
| packages/server/src/server/agent/providers/claude/agent.redesign.test.ts | Adds tests validating root behavior (disabled bypass mode + omitted SDK capability) and catalog reporting. |
| packages/server/src/server/agent/provider-registry.ts | Ensures runtime mode availability is applied when serving static modes (notably for replacement model scenarios). |
| packages/server/src/server/agent/create-agent-mode.ts | Filters disabled modes from selection defaults and rejects explicit/inherited disabled mode selection with provider explanation. |
| packages/server/src/server/agent/create-agent-mode.test.ts | Adds test coverage for disabled-mode rejection in default create-config resolution. |
| packages/server/src/server/agent/agent-sdk-types.ts | Extends server AgentMode type with optional disabledReason. |
| packages/protocol/src/messages.ts | Extends protocol AgentMode schema with optional disabledReason for compatibility-safe transport. |
| packages/protocol/src/agent-types.ts | Extends protocol AgentMode type with optional disabledReason. |
| packages/app/src/schedules/schedule-form-model.ts | Avoids selecting disabled modes when resolving schedule defaults. |
| packages/app/src/provider-selection/resolve-agent-form.ts | Avoids preferring/suggesting disabled modes when resolving provider form state. |
| packages/app/src/provider-selection/resolve-agent-form.test.ts | Adds test ensuring disabled preferred mode falls back appropriately. |
| packages/app/src/composer/draft/workspace-tab.tsx | Prevents draft submission/snapshot paths from selecting disabled modes. |
| packages/app/src/composer/agent-controls/mode.ts | Skips disabled modes when cycling modes. |
| packages/app/src/composer/agent-controls/mode.test.ts | Adds test ensuring mode cycling skips disabled modes. |
| packages/app/src/composer/agent-controls/mode-control.tsx | Disables UI options and blocks selection for disabled modes, showing the reason as the option description. |
| packages/app/src/components/workspace-setup-dialog.tsx | Prevents workspace setup from submitting disabled modes. |
| packages/app/src/components/ui/select-field.tsx | Adds disabled option support via disabledReason, blocks selecting disabled options, and surfaces reason in descriptions. |
| packages/app/src/components/ui/combobox-options.ts | Extends combobox option model to carry disabledReason. |
| packages/app/src/components/schedules/schedule-form-sheet.tsx | Threads disabledReason into schedule mode select options. |
| docs/providers.md | Documents Claude root constraint and reinforces app should rely on catalog-driven disabled state (not local root inference). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
a076607 to
7c8cb01
Compare
Fixed this in my Paseo fork, offering as PR if there is interest.
The issue: claude didn't work at all in my server setup, where paseo runs as root. This now detects if we're running as root and disables this behavior.
The rest of the text is AI generated.
Summary
allowDangerouslySkipPermissionslaunch capabilitydisabledReasonmode fieldWhy
Claude Code rejects both
--dangerously-skip-permissionsand--allow-dangerously-skip-permissionsunder root. Paseo currently always enables the latter SDK capability so that a session can switch into Bypass mode later, which prevents Claude from launching at all when the daemon runs as root.This keeps Claude available in normal permission modes while making the unsupported Bypass choice visible but inactive. Server-side validation remains authoritative, so stale clients and persisted configurations cannot reintroduce the rejected flag.
Verification
npx vitest run packages/server/src/server/agent/providers/claude/agent.redesign.test.ts packages/server/src/server/agent/create-agent-mode.test.ts packages/app/src/composer/agent-controls/mode.test.ts packages/app/src/provider-selection/resolve-agent-form.test.ts --bail=1(113 tests)npm run build:servernpm run typechecknpm run lintnpm run format:check