block / block/buzz

BYOH cannot reach a WSL-hosted harness on Windows: env is severed at the wsl.exe boundary and cwd is never translated

Open
#3,122 1 comment 0 reactions 0 assignees View on GitHub
Dominant language
Rust
Stars
32.7k
Forks
4.3k
Avg merge
1d 13h
Merged PRs (30d)
253

Description

**Motivation**

Since #2773 landed the BYOH seam, a Windows user can point Buzz at any ACP-over-stdio binary. But if that binary lives inside a WSL distro — along with their repos, toolchain, auth, and skills — it still cannot work. Nothing *rejects* the attempt; it fails a few hops later for reasons unrelated to BYOH itself.

Who hits it: Windows developers who do all their work in WSL. For them the managed-agent story currently requires a second, Windows-native install of every CLI, re-authenticated, whose filesystem view does not match where their repos actually are.

Worth stating up front, because it narrows the ask: **`command: "wsl.exe"` is already accepted.** `validate_harness_definition` (`custom_harnesses.rs:160-205`) checks only non-empty id/label/command, comma-free args, env-key safety, and URL scheme — no allowlist, no extension check, no WSL guard. Readiness takes the unknown-runtime branch and requires only that the command resolve (`readiness.rs:415-428`), and `wsl.exe` resolves from System32. Auth probes are skipped entirely for custom harnesses (`discovery.rs:1772-1774`). The arg transport also holds up: `BUZZ_ACP_AGENT_ARGS` is comma-delimited, and `["-d","Ubuntu","--","claude-agent-acp"]` round-trips byte-exact through clap, `--` included (verified against clap 4.6.1). So this is not an arg-mangling or validation problem.

One structural note that shapes everything below: the desktop **never spawns the harness command**. It spawns `buzz-acp` (`runtime.rs:522,566`) and passes the harness command/args as `BUZZ_ACP_AGENT_COMMAND` / `BUZZ_ACP_AGENT_ARGS` (`runtime.rs:580-581`). `wsl.exe` is spawned one process deeper, by buzz-acp (`crates/buzz-acp/src/acp.rs:416`). So inheritance questions resolve against buzz-acp's environment and cwd, not the Tauri process's.

**What actually breaks**, most-immediate first:

1. **Environment is not forwarded across the `wsl.exe` boundary.** buzz-acp relies on inheritance plus `extra_env` (`acp.rs:450-458`), but `wsl.exe` forwards nothing without `WSLENV`. Verified: `FOO=bar wsl.exe -e printenv | grep FOO` → no output; adding `WSLENV=FOO` → `FOO=bar`. The agent loses `BUZZ_PRIVATE_KEY`, `BUZZ_RELAY_URL`, `BUZZ_AUTH_TAG`, the augmented PATH, and all definition/persona env.
2. **`session/new` sends an untranslated Windows `cwd`** — `C:\Users\\.buzz` (built at `lib.rs:1547-1550`, sent at `acp.rs:565-570`). That path does not exist inside the distro. This is the first failure *after* a successful `initialize`.
3. **Skill directories are written into the Windows home.** `nest.rs:473,518-535` creates `~/.buzz/.agents/skills/buzz-cli` plus a `.claude/skills/buzz-cli` symlink there; a WSL agent's `$HOME` is the distro home, so skills are invisible.
4. **`REPOS/` / `OUTBOX/` are reachable only through the broken cwd** (`repos.rs:77,146,159`), and all prompt references to them are cwd-relative (`base_prompt.md:86-100`).
5. **Teardown may orphan the agent.** `process_lifecycle.rs:17-60` uses a Win32 Job Object with `KILL_ON_JOB_CLOSE`; that kills `wsl.exe`, but the Linux-side agent is not a Win32 descendant. *(Inference from WSL interop process ownership, not verified.)*

**No Windows↔Unix path translation exists anywhere in the desktop backend.** A grep for `/mnt/` across `desktop/src-tauri/src`, `crates/buzz-acp/src`, and `crates/buzz-dev-mcp/src` returns nothing, and the one place the backend meets POSIX paths on Windows it deliberately declines them: `discovery.rs:840-843` refuses the Git Bash login-shell PATH because `/mingw64/bin:/c/...` "poisons native Windows children."

Not broken, so as not to over-claim: **relay connectivity is fine.** All Nostr I/O stays in buzz-acp on the Windows side; the agent only speaks ACP over stdio. stdio also survives the boundary byte-exact — no CRLF mangling of JSON-RPC lines (verified with `printf '{...}\n' | wsl.exe -e cat | od -c`).

**Proposed solution**

Smallest viable version, in dependency order:

1. **Path translation at the ACP boundary** — `C:\Users\x` → `/mnt/c/Users/x`, applied on the desktop side before `cwd` and any path-bearing env leave the process. This is the bulk of the work and is unavoidable in any variant.
2. **Env forwarding** — either document `WSLENV` as the mechanism or set it automatically for a WSL-targeted harness. `WSLENV` is not in `RESERVED_ENV_KEYS` (`env_vars.rs:58-90`), so a BYOH definition's `env` can already set it today; definition env lands on buzz-acp's process (`runtime.rs:847-849`) and is therefore in `wsl.exe`'s parent environment. Verified working. This is a real if undocumented workaround for breakage 1 — it does not touch 2-4.
3. **Skill/nest placement** for a distro-hosted `$HOME`.
4. **Teardown** that reaps the in-distro process rather than only the `wsl.exe` shim.
5. **Keep the #2328 guards intact.** Implicit `bash.exe` resolution must keep rejecting WSL stubs. Opt-in WSL *targeting* and accidental WSL *resolution* are different things; only the first should become possible.

Scoping question for maintainers: is the intended answer "BYOH plus a documented WSL recipe" (items 1-2, docs-heavy) or first-class WSL support with its own discovery (all five)? Item 1 is required either way.

**Alternatives considered**

- **Install native Windows CLIs** — what Buzz implicitly expects today (`discovery.rs:111,143` ship PowerShell installers). Works, but means duplicate installs, duplicate auth, and an agent whose filesystem view does not match the user's actual repos.
- **Run Buzz desktop inside WSL (WSLg)** — sidesteps the boundary, but is a different platform target and loses the native Windows shell.
- **Reuse #1169's `msys_to_windows`** (`buzz-dev-mcp/src/paths.rs:62-97`) — prior art, not a dependency. It goes Unix→Windows, handles cygdrive form rather than `/mnt/c`, and runs in-process inside the MCP file tools. A WSL seam needs the opposite direction in a different place. The drive-letter algorithm is analogous (~15 lines).
- **Close as out of scope** — a legitimate outcome, worth stating explicitly, since the current state reads as an oversight rather than a decision.

**Additional context**

- **Verification status, stated plainly.** The static path was read end to end; the WSL boundary behaviors (env, stdio, arg transport) were verified empirically from inside a WSL distro. Not verified: that `resolve_command("wsl.exe")` succeeds on a real Windows install (`#[cfg(windows)]`), that `initialize` completes end to end, the exact error surface at `session/new`, and the teardown-orphan claim.
- **No-GUI repro path** for anyone picking this up: install `@agentclientprotocol/claude-agent-acp` inside the distro, then from Windows run `buzz-acp models --json` with `BUZZ_ACP_AGENT_COMMAND=wsl.exe` and `BUZZ_ACP_AGENT_ARGS='-d,Ubuntu,--,claude-agent-acp'`. That exercises the spawn and handshake hops without the desktop app (`commands/agent_models.rs:199-219`).
- #2328 (closed) — "[Bug] WSL terminals spawned by Buzz (Windows)": produced the exclusion guards.
- #2685 (open) — Windows console flashes from discovery/auth probes; overlaps item 4's process handling.
- #2773 (merged) — the BYOH seam this builds on.
- Duplicate search: searched open and closed issues for "WSL" and "Windows Subsystem", and PRs for "WSL", "custom harness", "BYOH", and "path translation". None found requesting WSL harness support. All 13 WSL-mentioning PRs are rejection work (#2587 merged, #1119 merged, #2541/#2355 closed, #2689 open).

Contributor guide

Open the contributing guide

Research direction

Read crates/buzz-acp/src/acp.rs, desktop/src-tauri/src/runtime.rs, lib.rs, nest.rs, repos.rs, and process_lifecycle.rs to map the harness boundary and affected paths. Reproduce the handshake with the stated buzz-acp models command and WSL arguments, then determine the intended scope with maintainers. Done should cover the selected WSL path, environment, skill, repository, and teardown behavior without weakening the #2328 guards.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
desktop-dev, devtools, operating-systems
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
42/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.