Skip to content

fix(claude_code): handle bypass permissions prompt on startup (#119)#120

Merged
haofeif merged 7 commits into
mainfrom
fix/claude-code-bypass-permissions-prompt
Mar 25, 2026
Merged

fix(claude_code): handle bypass permissions prompt on startup (#119)#120
haofeif merged 7 commits into
mainfrom
fix/claude-code-bypass-permissions-prompt

Conversation

@haofeif

@haofeif haofeif commented Mar 16, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Fixes Claude Code initialization timeout caused by the bypass permissions confirmation dialog (v2.1.41+)
  • Two-layer approach: settings-based prevention + tmux UI fallback
  • Renames _handle_trust_prompt_handle_startup_prompts to handle both bypass and trust prompts

Closes #119

Problem

Claude Code v2.1.41+ shows a "Bypass Permissions mode" confirmation dialog on every launch with --dangerously-skip-permissions unless skipDangerousModePermissionPrompt: true is persisted in ~/.claude/settings.json (ref: anthropics/claude-code#25503). The default selection is "No, exit" (option 1), so pressing Enter exits Claude Code. This causes CAO to timeout after 30 seconds during initialization.

WARNING: Claude Code running in Bypass Permissions mode
...
❯ 1. No, exit
2. Yes, I accept

Enter to confirm · Esc to cancel

What this adds on top of main

main already handles the bypass prompt via subprocess.run (raw escape sequence). This PR adds:

Change Why it matters
_ensure_skip_bypass_prompt_setting() Writes skipDangerousModePermissionPrompt: true to ~/.claude/settings.json before launch — prevents the prompt entirely instead of relying on the UI fallback
bypass_accepted flag + continue instead of return Fixes a bug: main returns after handling bypass, so if the trust prompt follows, it gets missed and causes a hang
BYPASS_PROMPT_PATTERN + get_status() exclusion Prevents bypass prompt from being misdetected as WAITING_USER_ANSWER

Fix

Layer What Why
Settings (preventive) Write skipDangerousModePermissionPrompt: true to ~/.claude/settings.json before launch Prevents the prompt from ever appearing — clean, no UI timing issues
UI fallback (defensive) Detect "Yes, I accept" in tmux buffer, send raw Down escape sequence + Enter via subprocess Handles edge cases where settings file was reset or didn't take effect
get_status() fix Exclude bypass prompt from WAITING_USER_ANSWER detection Prevents false status during init

Design decisions

  • Settings-based fix is the primary layer — deterministic, no timing dependency. The UI fallback is kept as defense-in-depth.

    • continue not return after accepting bypass prompt — the workspace trust prompt may follow
    • bypass_accepted flag prevents re-sending keystrokes when stale text remains in the tmux buffer
    • Raw escape sequence via subprocess (\x1b[B) for Down arrow — tmux send-keys "Down" doesn't work with Claude's Ink TUI
    • Settings write is non-destructive — reads existing ~/.claude/settings.json, merges the key, writes back (same pattern as Gemini CLI's ~/.gemini/settings.json MCP registration)

    Files Changed

    File Change
    src/cli_agent_orchestrator/providers/claude_code.py Added BYPASS_PROMPT_PATTERN, _ensure_skip_bypass_prompt_setting(), renamed _handle_trust_prompt_handle_startup_prompts with bypass prompt handling, updated get_status() exclusion
    test/providers/test_claude_code_unit.py Added tests for bypass prompt detection, settings management, bypass→trust prompt sequencing, and
    get_status() exclusion

    Testing

    • Unit tests: 45/45 passed (Claude Code provider)
    • E2E results (all providers, full suite):
    Provider assign handoff other Total
    Claude Code 3/3 ✅ 2/2 ✅ 5/5
    Kiro CLI 3/3 ✅ 2/2 ✅ 5/5
    Gemini CLI 3/3 ✅ 2/2 ✅ 5/5
    Kimi CLI 3/3 ✅ 2/2 ✅ 3/3 ✅ 8/8

haofeif and others added 2 commits March 16, 2026 13:56
Claude Code v2.1.41+ shows a "Bypass Permissions mode" confirmation
dialog on every launch with --dangerously-skip-permissions unless
skipDangerousModePermissionPrompt is persisted in ~/.claude/settings.json.
This blocks CAO initialization with a 30-second timeout.

Two-layer fix:
- Preventive: write skipDangerousModePermissionPrompt: true to
  ~/.claude/settings.json before launching Claude Code
- Defensive: detect "Yes, I accept" in tmux buffer and send Down+Enter
  as a fallback if the settings-based fix doesn't take effect

Also:
- Rename _handle_trust_prompt → _handle_startup_prompts to reflect it
  now handles both bypass permissions and workspace trust prompts
- Use continue (not return) after accepting bypass prompt so a
  subsequent trust prompt is still handled
- Exclude bypass prompt from WAITING_USER_ANSWER status detection

Closes #119

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@haofeif haofeif added the bug Something isn't working label Mar 16, 2026
haofeif and others added 5 commits March 16, 2026 17:08
Add startswith("/") guard after realpath() to satisfy CodeQL's
py/path-injection two-state taint model. CodeQL recognizes
str.startswith() as a SafeAccessCheck that clears NormalizedUnchecked
taint. The guard is always true after realpath() but explicitly
rejects relative paths and satisfies the static analysis requirement.

Regression was introduced in d22ebde (#110) which relaxed the home
directory containment check to allow paths outside ~/. This removed
the startswith(home_dir) guard that CodeQL relied on.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@haofeif haofeif merged commit fc445e6 into main Mar 25, 2026
21 checks passed
@haofeif haofeif deleted the fix/claude-code-bypass-permissions-prompt branch March 25, 2026 07:32
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.

Claude Code v2.1.74+ bypass permissions prompt not handled

1 participant