Windows agents never receive the [Workspace] system-prompt section: workspace_section() gates on a POSIX-only starts_with('/') predicate
- Dominant language
- Rust
- Stars
- 32.7k
- Forks
- 4.3k
- Avg merge
- 1d 13h
- Merged PRs (30d)
- 253
Description
**Describe the bug**
`workspace_section()` gates the `[Workspace]` system-prompt block on a raw byte-prefix test for `/`, so it is silently omitted for every Windows agent. `crates/buzz-acp/src/pool.rs:1165-1177`:
```rust
fn workspace_section(cwd: &str) -> Option {
if cwd != "/" && cwd.starts_with('/') {
Some(format!(
"[Workspace]\nYour absolute working directory is `{cwd}`. All workspace \
files — `AGENTS.md`, `RESEARCH/`, `PLANS/`, `GUIDES/`, `WORK_LOGS/`, \
`OUTBOX/` — and any repositories you clone (under `{cwd}/REPOS/`) live \
here. This is where you already are; do not search `$HOME` or other \
directories for them."
))
} else {
None
}
}
```
`cwd` originates from `std::env::current_dir()` (`lib.rs:1547-1550`), which on Windows always returns drive-letter form (`C:\Users\\.buzz`). That fails `starts_with('/')`, so the block is dropped. There is no `cfg(windows)` branch and no compensating path (`rg 'cfg\(windows\)'` over `crates/buzz-acp/src` yields one unrelated hit, `acp.rs:1998`).
**Scoping this honestly, because the obvious reading overstates it:** this is *not* "Windows agents don't know about `REPOS/`/`OUTBOX/`." That information is delivered unconditionally on every platform:
- `base_prompt.md:84-98` — the full Workspace Layout table, `OUTBOX/` and `REPOS/` included.
- `base_prompt.md:100` — the anti-`$HOME`-scan instruction, i.e. the omitted section's own stated purpose, is *also* already unconditional.
- The agent's literal OS cwd **is** the workspace: the child inherits it (no `current_dir` call anywhere in `acp.rs`) from the harness spawn at `runtime.rs:566-569`, so `ls` works.
- `AGENTS.md` on disk repeats the layout (`nest.rs:190-194`, `nest_agents.md:13-14`).
So what Windows actually loses is one *reinforcing* statement of the absolute workspace root inside the system prompt. Expected symptom is a probabilistic uptick in path-guessing or wasted exploration on Windows, not a functional failure. Filing it as a correctness bug rather than a user-facing breakage: it's a one-line predicate fix with a trivially-added test, and a `starts_with('/')` path predicate left in the tree invites the same mistake again.
**Steps to reproduce**
The predicate is pure string logic, so this needs no Windows host — the following test fails today on Linux/macOS CI:
```rust
// crates/buzz-acp/src/pool.rs, mod tests
#[test]
fn test_workspace_section_windows_cwd_is_some() {
assert!(workspace_section(r"C:\Users\me\.buzz").is_some());
}
```
Verified by executing the identical predicate standalone:
```
/Users/me/.buzz -> true
C:\Users\me\.buzz -> false <-- Windows cwd
C:/Users/me/.buzz -> false
/ -> false (intended sentinel rejection)
```
End-to-end on Windows: spawn a managed agent and inspect the `session/new` `systemPrompt` (the desktop transcript observer renders the section — see `agentSessionTranscriptHelpers.test.mjs:327-349`). It begins at `[Base]` with no preceding `[Workspace]` block; the same setup on macOS begins `[Workspace]\nYour absolute working directory is /Users/.../.buzz...`.
**Expected behavior**
Windows agents receive the `[Workspace]` section with their real absolute workspace path, as macOS and Linux agents do.
**Version and platform**
- Buzz version: `main` @ `87b3fcd3`. Gate is unmodified since introduction, so every release since 2026-06-23 is affected.
- OS: Windows (all versions). macOS and Linux unaffected — their cwd passes the gate.
- Found by code inspection, not a field report. No user has reported the symptom.
**Logs / additional context**
**Origin.** Introduced in `1011cea2682a5e8cd92c9da255d5ba6c8f7ced78`, "fix(desktop): ground agent workspace, migrate legacy nest, configurable repos_dir" (#1194), 2026-06-23. Never modified since. The guard's own doc comment explains its intent — filtering relative paths and the `/` fallback that `current_dir()` produces on failure, because a `/`-rooted workspace line "would actively encourage the `$HOME`-wide scan this section exists to prevent." The motivating case in that diff was macOS TCC prompts. Windows appears simply not to have been in scope: every test added alongside it uses POSIX paths (`/`, `/Users/me/.buzz`, `relative/path`, `""`). *(That last point is inference from the absence of any Windows path in the diff, comment, or tests — nothing expresses an intent to exclude Windows.)*
**Existing tests** — five cover this gate, none with a Windows-style cwd: `pool.rs:3809-3822`, `:3824-3831`, `:3833-3838`, `:3840-3844`, plus the `framed_system_prompt` set at `:3783-3807`.
**Suggested fix** (one line + one test): replace the prefix test with `std::path::Path::new(cwd).is_absolute()`, keeping a root/sentinel rejection. `Path::parent().is_some()` rejects `/`, `C:\`, and `\\?\C:\` uniformly; retaining the literal `cwd != "/"` also works, since `lib.rs:1548`'s fallback hardcodes it.
`is_absolute`'s platform-dependence is correct here rather than a hazard: the string comes from `current_dir()` in the same process on the same host, so the compile-time platform always matches the path's origin. No caller supplies a cwd from elsewhere. Two caveats for whoever takes it:
1. On Windows `is_absolute()` is `has_root() && prefix().is_some()`, so drive-relative (`\foo`) and bare-drive (`C:`) forms stay `false`. Neither is producible by `current_dir()`, so it doesn't matter in practice — just don't describe the fix as "any Windows path works."
2. Do **not** fix this by normalizing the cwd string at `lib.rs:1547`. That same string is the ACP `session/new` cwd (`pool.rs:831`); changing it alters protocol behavior for every harness.
**Two follow-on notes**, both out of scope for the one-line fix:
- Once Windows agents start receiving the section, its `$HOME` phrasing (and `base_prompt.md:100`'s) reads wrong on Windows — `%USERPROFILE%` may be worth adding.
- `{cwd}/REPOS/` at `pool.rs:1170` will render `C:\Users\me\.buzz/REPOS/` — mixed separators, functional but ugly.
**Separate, larger gap found while confirming this** (platform-independent, not filed): `[Workspace]` rides only the `session/new` systemPrompt. `session_new_system_prompt` returns `None` for `protocol_version < 2` (`pool.rs:185-195`), and the legacy user-message framing path (`prepend_base_for_legacy`, `pool.rs:1090-1098`, `:1593`; `queue.rs:1431`) emits `[Base]` but never `[Workspace]`. So protocol-v1 harnesses lack the anchor on macOS and Linux too. Happy to split that out if maintainers want it tracked.
Duplicate search: searched issues for "workspace prompt", "OUTBOX", and PRs for "base_prompt workspace" — none found. Nearest is #2334 (base prompt shown as session title in harness UIs), which is a display concern, not this gate.
Contributor guide
Assessment
This issue has not been assessed yet.