Skip to content

fix: allow permissionMode to override yolo in claude_code provider#322

Merged
haofeif merged 4 commits into
awslabs:mainfrom
zz327455573:fix/claude-code-yolo-root
Jun 29, 2026
Merged

fix: allow permissionMode to override yolo in claude_code provider#322
haofeif merged 4 commits into
awslabs:mainfrom
zz327455573:fix/claude-code-yolo-root

Conversation

@zz327455573

Copy link
Copy Markdown
Contributor

Problem

When running CAO as root/sudo with a third-party model (e.g. LongCat via custom ANTHROPIC_BASE_URL), the yolo mode unconditionally passes --dangerously-skip-permissions to Claude Code. Claude Code refuses this flag under root privileges with:

--dangerously-skip-token-permissions cannot be used with root/sudo privileges for security reasons

This causes Claude Code initialization to hang and eventually time out (30s).

Root Cause

In claude_code.py line 167, the condition was:

if profile and profile.permissionMode and not yolo:

When yolo=True (allowedTools: ["*"] in profile), the code always fell through to the else branch which passed --dangerously-skip-permissions — a flag that Claude Code rejects under root.

Fix

Changed the condition so profile.permissionMode always takes precedence regardless of yolo mode:

if profile and profile.permissionMode:
    command_parts = ["claude", "--permission-mode", profile.permissionMode]
elif yolo:
    command_parts = ["claude"]
else:
    command_parts = ["claude", "--dangerously-skip-permissions"]

Users running as root can now set permissionMode: auto or permissionMode: bypassPermissions in their agent profile to avoid the blocked flag.

Test Plan

  • Verified on root user with LongCat (third-party Anthropic-compatible endpoint)
  • CAO headless task completes successfully (Claude Code auto-accepts tool calls)
  • Non-root user with --dangerously-skip-token-permissions still works (unchanged path)

When running as root/sudo, Claude Code refuses --dangerously-skip-permissions.
The yolo mode was unconditionally passing that flag, causing initialization to fail.
This change lets profile.permissionMode take precedence over yolo, so users can
configure 'auto' or 'bypassPermissions' to avoid the blocked flag.

Copilot AI 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.

Pull request overview

Adjusts how the Claude Code provider selects its base permission flags so agent profile permissionMode can override “yolo” behavior, avoiding Claude Code startup failures when run under root/sudo.

Changes:

  • Updates _build_claude_command() to prioritize profile.permissionMode even when allowedTools: ["*"] (yolo) is active.
  • Changes the yolo path to omit --dangerously-skip-permissions (intended to avoid root/sudo rejection).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +169 to +172
elif yolo:
# yolo mode: no --dangerously-skip-permissions flag because
# Claude Code refuses it under root/sudo. Let CAO handle permissions.
command_parts = ["claude"]
@haofeif haofeif added the bug Something isn't working label Jun 23, 2026
@codecov-commenter

codecov-commenter commented Jun 27, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
⚠️ Please upload report for BASE (main@b8b1897). Learn more about missing BASE report.

Additional details and impacted files
@@           Coverage Diff           @@
##             main     #322   +/-   ##
=======================================
  Coverage        ?   87.25%           
=======================================
  Files           ?       99           
  Lines           ?    12220           
  Branches        ?        0           
=======================================
  Hits            ?    10663           
  Misses          ?     1557           
  Partials        ?        0           
Flag Coverage Δ
unittests 87.25% <100.00%> (?)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@haofeif

haofeif commented Jun 27, 2026

Copy link
Copy Markdown
Collaborator

@zz327455573
Thanks for the fix. The root/sudo + third-party model use case is real, and making permissionMode take precedence over yolo is the right direction.

One concern with the new elif yolo branch: it drops --dangerously-skip-permissions for every yolo launch, not only root/sudo launches. Existing non-root profiles/API calls with allowedTools: ["*"] and no permissionMode now build plain claude, so Claude can prompt for tool approval inside headless tmux sessions and silently block handoff/assign flows.

I confirmed the current command builder output:

yolo_no_profile= ...; claude
yolo_profile_no_permission= ...; claude
yolo_profile_auto= ...; claude --permission-mode auto

Suggested fix: keep permissionMode highest priority, but only omit --dangerously-skip-permissions for the root/sudo case:

is_root = getattr(os, "geteuid", lambda: -1)() == 0

if profile and profile.permissionMode:
    command_parts = ["claude", "--permission-mode", profile.permissionMode]
elif yolo and is_root:
    command_parts = ["claude"]
else:
    command_parts = ["claude", "--dangerously-skip-permissions"]

Please also add regression tests for yolo/non-root, yolo/root, and yolo+permissionMode. That should also address the current Codecov patch coverage warning, which is pointing at the newly added yolo branch in claude_code.py.

Finally, please update the Claude Code docs because they still say yolo always forces --dangerously-skip-permissions regardless of permissionMode.

Focused checks pass locally: 108 passed; black/isort/diff-check pass.

Finding

P1 - Non-root yolo launches no longer bypass Claude tool prompts

src/cli_agent_orchestrator/providers/claude_code.py:169-176 now builds plain claude whenever allowed_tools=["*"] and the profile does not set permissionMode:

if profile and profile.permissionMode:
    command_parts = ["claude", "--permission-mode", profile.permissionMode]
elif yolo:
    command_parts = ["claude"]
else:
    command_parts = ["claude", "--dangerously-skip-permissions"]

That fixes the root/sudo case, where Claude rejects --dangerously-skip-permissions, but it also changes normal non-root yolo behavior. Existing profiles or API calls with allowedTools: ["*"] and no permissionMode now launch without --dangerously-skip-permissions or --permission-mode bypassPermissions, so Claude can prompt for tool approval inside a headless tmux pane. That breaks the documented yolo contract and can silently block handoff/assign flows.

I confirmed the current command builder output:

yolo_no_profile= ...; claude
yolo_profile_no_permission= ...; claude
yolo_profile_auto= ...; claude --permission-mode auto

Suggested fix: keep permissionMode highest priority, but only omit --dangerously-skip-permissions for the root/sudo case. For portability, guard os.geteuid with getattr if the project cares about non-POSIX platforms:

is_root = getattr(os, "geteuid", lambda: -1)() == 0

if profile and profile.permissionMode:
    command_parts = ["claude", "--permission-mode", profile.permissionMode]
elif yolo and is_root:
    command_parts = ["claude"]
else:
    command_parts = ["claude", "--dangerously-skip-permissions"]

Add regression tests for:

  • yolo + no permissionMode + non-root => includes --dangerously-skip-permissions
  • yolo + no permissionMode + root => omits --dangerously-skip-permissions
  • yolo + permissionMode => uses --permission-mode <value> and omits --dangerously-skip-permissions

Also update docs/claude-code.md and docs/agent-profile.md; they still say cao launch --yolo always forces --dangerously-skip-permissions regardless of permissionMode, which is no longer true after this PR.

Checks Run

uv run pytest test/providers/test_claude_code_unit.py -q
# 108 passed

uv run black --check src/cli_agent_orchestrator/providers/claude_code.py test/providers/test_claude_code_unit.py
# 2 files would be left unchanged

uv run isort --check-only src/cli_agent_orchestrator/providers/claude_code.py test/providers/test_claude_code_unit.py
# passed

git diff --check
# passed

…oot, not all yolo

Previously the elif-yolo branch dropped --dangerously-skip-permissions for every
yolo launch (allowedTools=["*"]), which broke non-root headless sessions by letting
Claude prompt for tool approval inside tmux panes and silently block handoff/assign.

Fix: add is_root guard so the flag is only omitted when running as root/sudo.
Priority order:
  1. profile.permissionMode set  => claude --permission-mode <value>
  2. yolo + is_root              => claude  (flag rejected by Claude under root)
  3. everything else             => claude --dangerously-skip-permissions

Also adds three regression tests covering yolo/non-root, yolo/root, and
yolo+permissionMode to address the Codecov patch coverage warning.

Updates docs/claude-code.md and docs/agent-profile.md to reflect correct priority
(permissionMode > yolo, root-only omission).

Fixes: awslabs#322
@zz327455573

Copy link
Copy Markdown
Contributor Author

@haofeif 我已经按照你的建议修复了,看看还有什么问题

@haofeif

haofeif commented Jun 29, 2026

Copy link
Copy Markdown
Collaborator

@zz327455573 thanks for your fixes. can you please address the 3 CI errors before we can approve the PR. Much appreciated for your help!

  • CI/Code Quality
  • Test Claude Code Provider
  • Test Q Cli Provider

@zz327455573 zz327455573 force-pushed the fix/claude-code-yolo-root branch from 45ef3c2 to 4c6414e Compare June 29, 2026 11:39

@haofeif haofeif left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Thank you @zz327455573 for your great contribution!

@haofeif haofeif merged commit e2412e7 into awslabs:main Jun 29, 2026
17 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants