Skip to content

Launch ACP agents directly on Windows - #175

Open
MLuc24 wants to merge 1 commit into
egoist:mainfrom
MLuc24:fix/windows-acp-launch
Open

Launch ACP agents directly on Windows#175
MLuc24 wants to merge 1 commit into
egoist:mainfrom
MLuc24:fix/windows-acp-launch

Conversation

@MLuc24

@MLuc24 MLuc24 commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

Closes #149.

Problem

Every ACP session is spawned through /usr/bin/env -C <cwd> <binary>. That path does not exist on native Windows, so process creation fails with os error 3 — "the system cannot find the path specified" — before the agent is ever started. @qiankun229 reported it against Grok Build and traced it to sdk_agent in crates/waku-core/src/driver/acp.rs; since that function builds the launch for every ACP provider, none of them can start on Windows.

Why env -C is there, and why Windows can do without it

env -C is not incidental — it is how the child gets the session working directory. AcpAgentConfig carries only a command, arguments and environment:

pub struct AcpAgentConfig {
    command: PathBuf,
    args: Vec<String>,
    env: BTreeMap<String, String>,
}

and spawn_process builds std::process::Command::new(&self.config.command) without ever calling current_dir, so there is no field to route a cwd through. Windows has no env equivalent that sets a working directory while keeping argument boundaries intact — cmd /C cd /d … && would mean going through a shell, which is exactly what the comment above that code says the current approach avoids.

It turns out nothing needs to be routed. The session cwd already travels in the ACP session request, and this file sends it on all three paths:

.send_request(NewSessionRequest::new(cwd))
.send_request(ResumeSessionRequest::new(existing.to_owned(), cwd))
.send_request(LoadSessionRequest::new(existing.to_owned(), cwd))

So on Windows the resolved binary is launched directly, and the agent learns where to work over the protocol. Unix keeps env -C unchanged, including the process-group lifecycle behaviour the SDK relies on there.

The platform split is a runtime cfg!(windows) rather than #[cfg] blocks so both branches stay type-checked on every target.

Checks

  • cargo test -p waku-core --lib — 340 passed, 0 failed
  • cargo check — clean
  • cargo fmt --package waku --package waku-protocol --package waku-client --package waku-core --package waku-daemon -- --check — reports pre-existing diffs in about 40 places (src/app.rs, src/input.rs, src/md/highlight.rs, crates/waku-core/src/driver/codex.rs and others) on an unmodified checkout of main; nothing in driver/acp.rs, the only file this touches
  • The bun protocol and client checks were not run: no Rust wire type changes here, so packages/waku-client/src/generated is untouched

The new test asserts the launch configuration per platform. It fails on main when run on Windows, which is the point of keeping it:

---- driver::acp::tests::acp_launch_skips_env_on_windows stdout ----
assertion `left == right` failed
  left: "/usr/bin/env"
 right: "/opt/grok/grok"

Known limitations

  • The Windows child inherits the daemon's working directory rather than the project directory. An agent that reads the ACP cwd — which is the contract — is unaffected, but one that quietly relies on its process cwd instead would see a different directory. If that turns out to matter for a specific provider, the fix belongs upstream in agent-client-protocol as a cwd on AcpAgentConfig, and I'd be glad to open that.
  • I could not reproduce the original failure end to end: I have no Grok Build installation to launch. What I verified on Windows is that the launch configuration is now the binary rather than /usr/bin/env, that the same configuration on Unix is byte-for-byte what it was, and that the whole waku-core suite still passes. The claim that AcpAgentConfig has no working-directory field was read out of the vendored agent-client-protocol-2.0.0 source rather than assumed. The reporter's own validation — routing /usr/bin/env to Git for Windows' env.exe and watching the same command succeed — is the evidence that removing that hop is what unblocks the spawn.

Every ACP session was spawned through /usr/bin/env -C <cwd> <binary>, which
does not exist on native Windows, so process creation failed with "the system
cannot find the path specified" before the agent started.

env -C is there to give the child the session working directory, because
AcpAgentConfig carries only a command, arguments and environment, and the SDK
never calls current_dir when it spawns. Windows has no equivalent that keeps
argument boundaries intact without going through a shell.

It does not need one: the session cwd already travels in the ACP session
request, which NewSessionRequest, ResumeSessionRequest and
LoadSessionRequest all carry. On Windows the resolved binary is launched
directly and the agent is told where to work over the protocol.

Closes egoist#149
Copilot AI lite review requested due to automatic review settings August 25, 2026 03:59

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

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.

Windows: ACP providers fail because sdk_agent hardcodes /usr/bin/env

2 participants