Skip to content

Windows: worker spawn fails with ENAMETOOLONG when agent system prompt is large (passed via cmdline arg) #612

Description

@HenryLach

Summary

On Windows, orchestrated worker spawns fail with spawn ENAMETOOLONG when the composed agent system prompt is large. The system prompt is passed as a command-line argument (--system-prompt <text> in agent-host.ts), and Windows caps a process command line at ~32,767 characters (CreateProcessW lpCommandLine). The base task-worker.md template alone is ~27 KB, leaving only a few KB of headroom before any project-specific .pi/agents/task-worker.md override — plus the segment prompt and the other args (--model, --tools, etc.) — pushes the total over the limit and the worker process never starts.

Observed in a real project (taskplane v0.30.4, pi 0.80.10, Windows 11):

base task-worker.md:  27,191 bytes
project override:      9,611 bytes
segment prompt:        1,936 bytes
                      ─────────────
composed:            ~38,738 bytes   > 32,767  → spawn ENAMETOOLONG

The batch fails at wave 1 in ~2s with:

[orch] lane-1/TP-XXX: Runtime V2 execution error: spawn ENAMETOOLONG
[orch] ... task TP-XXX spawn_failure — operator action required, NOT auto-retrying

Impact

  • Any Windows project with a non-trivial .pi/agents/task-worker.md override cannot run orchestrated batches. The base worker prompt (~27 KB) leaves only ~5 KB of headroom, which is easily consumed by legitimate project-specific guidance.
  • The failure is opaque unless you know ENAMETOOLONG = command-line-length limit. Operators reasonably suspect pi-resolution or config issues first.
  • Reviewer/merger prompts are smaller (bases ~11 KB / ~7 KB) so they usually survive, which makes the failure look worker-specific and confusing.
  • The deprecation warning in the logs (Passing args to a child process with shell option true) suggests shell: true is in play, which concatenates all args into one command string and makes the limit easier to hit.

Root cause

agent-host.ts:

if (opts.systemPrompt) piArgs.push("--system-prompt", opts.systemPrompt);

The entire composed system prompt (base template + local override + segment overlay) is passed inline on the command line. On Windows this is bounded by the ~32 KB CreateProcessW limit. (The task PROMPT/context is correctly sent via stdin — only the system prompt uses the size-limited cmdline path.)

Proposed fix

Pass the system prompt via a file instead of an inline arg. pi already supports file contents:

--append-system-prompt <text or file>  Append text or file contents to the system prompt (can be used multiple times)

Options (in rough order of preference):

  1. Write the composed system prompt to a temp file and pass it by path. Add/confirm a pi --system-prompt-file <path> flag (or reuse --append-system-prompt <file> with an empty base) and have agent-host.ts write the composed prompt to e.g. .pi/runtime/<batch>/<lane>-system-prompt.md, then pass the path. Removes the size ceiling entirely.
  2. Pipe the system prompt via stdin alongside the existing prompt message (a { type: "system_prompt", ... } control message), if pi supports it.
  3. Interim mitigation: detect when the composed prompt (plus estimated arg overhead) approaches the Windows limit and fail fast with an actionable error ("system prompt too large for Windows cmdline — reduce .pi/agents/<role>.md or upgrade to file-based prompt passing") instead of the opaque ENAMETOOLONG.

Fix #1 is the durable one — it lets projects ship rich per-role overrides on Windows without hitting an invisible ceiling.

Workaround (for affected users today)

Slim .pi/agents/task-worker.md so the composed prompt (base + override + segment + args) stays under ~32 KB. In practice the override must be ≲ 3–4 KB on top of the current base. Move detailed project guidance into docs referenced by taskRunner.standards.docs / the task's "Context to Read First" (the worker reads those at runtime via stdin instructions), keeping the system-prompt override to a thin pointer.

Environment

  • OS: Windows 11
  • taskplane: v0.30.4
  • pi: 0.80.10 (@earendil-works/pi-coding-agent)
  • Backend: Runtime V2 (subprocess spawn)

Acceptance criteria

  • A project with a ~10 KB .pi/agents/task-worker.md override runs orchestrated batches on Windows without ENAMETOOLONG.
  • System prompt size is no longer bounded by the OS command-line limit (file-based passing).
  • If a hard limit remains for any reason, the engine fails fast with an actionable message naming the offending role file, not raw ENAMETOOLONG.

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions