Skip to content

Fix claude-code brain on Windows: pass long system prompts via file, not argv - #28

Open
TheMythologist wants to merge 1 commit into
JailbrokenAI:mainfrom
TheMythologist:main
Open

Fix claude-code brain on Windows: pass long system prompts via file, not argv#28
TheMythologist wants to merge 1 commit into
JailbrokenAI:mainfrom
TheMythologist:main

Conversation

@TheMythologist

Copy link
Copy Markdown

Problem

Every claude-code brain call fails on Windows with a misleading error:

[error] claude CLI not found (looked for 'C:\Users\...\claude.EXE').
        Install Claude Code or set WALLBREAKER_CLAUDE_BIN to its path.

The binary is installed, on PATH, and shutil.which("claude") resolves it correctly — spawning that exact path by hand works fine. The lookup was never the problem.

Root cause

_run_cli passed the whole harness system prompt as a single argv value to claude --system-prompt. compose_system(endpoint, DEFAULT_SYSTEM) is 43,629 characters, and Windows CreateProcess caps the entire command line at 32,767 characters. The overflow comes back as WinError 206 ("The filename or extension is too long"), which CPython maps to errno 2 / ENOENT — so Python raises FileNotFoundError, indistinguishable from a missing executable, and the provider's except FileNotFoundError branch reported it as such.

Verified directly: spawning claude with a 32,000-char argument succeeds; at 33,000 it raises FileNotFoundError [WinError 206].

POSIX is unaffected (ARG_MAX is ~2 MB there), which is why this stayed hidden.

Fix

  • _prompt_flag() inlines prompts up to _MAX_INLINE_PROMPT (8000 chars) and spills anything longer to a temp file, delivered via --system-prompt-file / --append-system-prompt-file. Both flags are accepted by the CLI (confirmed against 2.1.220).
  • _run_cli() now wraps _spawn_cli() and unlinks every spilled temp file in a finally, so nothing leaks per call. The sink is per-call, so concurrent calls don't clobber each other.
  • A WinError 206 spawn failure now reports the actual command-line length instead of claiming the binary is missing.

Short prompts keep the exact previous argv, so behaviour is unchanged for existing callers and on POSIX. The conversation prompt already went over stdin and was never affected.

Testing

  • 4 new regression tests in tests/test_claude_code.py: long system prompt spills to a file with matching content; long appended doctrine uses --append-system-prompt-file while the operator file still leads; the argv built by a real _run_cli call stays under 32,767 chars and the temp file is deleted afterwards; a WinError 206 failure surfaces as "command line too long" rather than "not found".

The harness system prompt (~44K chars) was passed as a single argv value to
`claude --system-prompt`, but Windows CreateProcess caps the whole command line
at 32767 chars. Python maps that overflow (WinError 206) to errno ENOENT, so it
surfaced as FileNotFoundError and the provider mislabelled it "claude CLI not
found" — every claude-code brain call failed on Windows regardless of where the
binary lived.

- `_prompt_flag` inlines prompts up to 8000 chars and writes anything longer to
  a temp file, handing it over via `--system-prompt-file` /
  `--append-system-prompt-file` (both accepted by the CLI).
- `_run_cli` now wraps `_spawn_cli` and deletes the spilled temp files in a
  `finally`, so nothing leaks per call.
- A WinError 206 spawn failure reports the actual command-line length instead of
  claiming the binary is missing.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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