fix(claude_code): echoed system prompt false-matches idle, blocking workspace-trust dialog#319
Conversation
…st dialog
The startup handler treated any "> "/"❯ " in the capture buffer as the idle
prompt and returned early. The injected --append-system-prompt contains a line
starting with "> `memory_store`", which the shell echoes into the capture
buffer ~300ms before the workspace-trust dialog renders. The handler matched
that marker, declared Claude Code ready, and returned before accepting the
trust dialog. initialize() then blocked on {IDLE, COMPLETED} for 30s and the
session was killed, so `cao launch` failed on every not-yet-trusted working
directory.
Remove the bare IDLE_PROMPT_PATTERN early-return. The version banner
("Welcome to" / "Claude Code v<n>") is the only ready signal that cannot appear
in the echoed launch command; the trust and bypass dialogs are still handled
explicitly above, and wait_until_status() remains the real readiness gate.
Add a regression test that returns the echoed command on the first poll and the
trust dialog on the second, asserting the trust dialog is accepted (the old
early-return would skip it).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #319 +/- ##
=======================================
Coverage ? 87.22%
=======================================
Files ? 92
Lines ? 10970
Branches ? 0
=======================================
Hits ? 9569
Misses ? 1401
Partials ? 0
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Pull request overview
Fixes Claude Code provider initialization in untrusted workspaces by preventing _handle_startup_prompts() from short-circuiting on an echoed "> " sequence from the launch command, so the workspace-trust dialog can be auto-accepted and initialization can proceed to the real readiness gate (wait_until_status).
Changes:
- Removed the
IDLE_PROMPT_PATTERNearly-return from Claude Code startup prompt handling, keeping only the version banner as the “no prompts needed” signal. - Added a regression test that simulates an echoed launch command frame followed by the trust dialog, asserting the trust dialog is accepted.
- Updated test module documentation to reflect the new coverage target.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
src/cli_agent_orchestrator/providers/claude_code.py |
Removes the idle-prompt early return and documents the echoed-command false-positive scenario; keeps version-banner early return. |
test/providers/test_claude_code_coverage.py |
Replaces the old idle-prompt early-return test with a regression test for echoed-command vs trust-dialog handling. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if re.search(r"Welcome to|Claude Code v\d+", clean_output): | ||
| logger.info("Claude Code started without prompts") |
|
@cdrury526 thanks for your PR. FindingsP2 - Copilot keeps URL access even when
|
haofeif
left a comment
There was a problem hiding this comment.
@cdrury526 thanks for the great contribution !
Summary
cao launch --provider claude_codefails to initialize in any working directory that Claude Code has not yet trusted. The session is created, Claude starts, but CAO kills it after 30s with:Reproduction
cao launch --agents code_supervisor --provider claude_code --headless ...(Pre-trusting the directory by launching
claudethere once and accepting the dialog works around it, which is what pointed to the root cause.)Root cause
_handle_startup_prompts()usesIDLE_PROMPT_PATTERN = r"[>❯][\s\xa0]"as an early-return "Claude is ready" signal. The supervisor system prompt injected via--append-system-promptcontains a line that starts with> `memory_store`(the memory-tools note). When the shell echoes the long launch command into the capture buffer, that>appears ~300ms after launch — well before the trust dialog renders.So the handler matches the echoed
>, logsClaude Code idle prompt detected, no prompts needed, and returns before the trust dialog exists.initialize()then waits for{IDLE, COMPLETED}, but the trust dialog reads asWAITING_USER_ANSWER, so it never becomes idle → 30s timeout →terminal_servicetears the session down.Observed in the server log:
Fix
Remove the bare
IDLE_PROMPT_PATTERNearly-return. The version banner (Welcome to/Claude Code v\d+) is the only "ready" signal that cannot appear in the echoed launch command, so it's kept; the trust and bypass dialogs are still handled explicitly above it; andwait_until_status()remains the real readiness gate. Note that anchoring the pattern to start-of-line would not help here, because the offending>is itself at the start of a line in the injected prompt.After the fix, the same launch in a fresh untrusted dir logs:
…and the worker runs to completion.
Test
Added a regression test (
test_echoed_prompt_does_not_short_circuit_trust) that returns the echoed command (with the> memory_storemarker, no dialog) on the first poll and the trust dialog on the second, asserting the dialog is accepted viaEnter. This fails on the old early-return and passes now. Full provider suite (114 tests) passes;black/isortclean.Environment
2.2.0(currentmain)2.1.183Happy to file a tracking issue per CONTRIBUTING if preferred.
🤖 Generated with Claude Code