#19931: Config: merge PATH env vars and bootstrap Windows bins
size: S
Cluster:
Windows Path and Exec Fixes
## Summary
Describe the problem and fix in 2–5 bullets:
- Problem: `env.vars.PATH` was effectively ignored when `PATH` already existed (common on Windows), and Windows global bin locations were not included in PATH bootstrap candidates.
- Why it matters: users could configure PATH in OpenClaw but still fail to resolve `openclaw`/tooling binaries, especially in Windows/minimal-shell contexts.
- What changed: added PATH-specific merge/prepend + dedupe behavior in config env application (with case-insensitive `PATH`/`Path` handling), and added Windows candidate bin dirs (`%APPDATA%\npm`, `%LOCALAPPDATA%\pnpm`, `%LOCALAPPDATA%\Microsoft\WindowsApps`, `%LOCALAPPDATA%\Programs\Microsoft VS Code\bin`) in PATH bootstrap.
- What did NOT change (scope boundary): non-PATH env vars still do **not** override existing env vars; no changes to channels, routing, auth, or network behavior.
## Change Type (select all)
- [x] Bug fix
- [ ] Feature
- [ ] Refactor
- [ ] Docs
- [ ] Security hardening
- [ ] Chore/infra
## Scope (select all touched areas)
- [ ] Gateway / orchestration
- [x] Skills / tool execution
- [ ] Auth / tokens
- [ ] Memory / storage
- [ ] Integrations
- [ ] API / contracts
- [ ] UI / DX
- [x] CI/CD / infra
## Linked Issue/PR
- Closes #19910
- Related #19144, #19213
## User-visible / Behavior Changes
- `env.vars.PATH` now merges with existing process PATH (config entries are prepended, duplicates removed) instead of being skipped when PATH already exists.
- On Windows, PATH bootstrap now considers common global bin locations (`npm`, `pnpm`, `WindowsApps`, `VS Code bin`) when those directories exist.
## Security Impact (required)
- New permissions/capabilities? (`No`)
- Secrets/tokens handling changed? (`No`)
- New/changed network calls? (`No`)
- Command/tool execution surface changed? (`Yes`)
- Data access scope changed? (`No`)
- If any `Yes`, explain risk + mitigation:
- PATH precedence can change which binary is resolved first.
- Mitigation: only PATH handling changed (not arbitrary env override), entries are deduplicated, behavior is covered by targeted unit tests.
## Repro + Verification
### Environment
- OS: Windows (PowerShell session)
- Runtime/container: Node.js `v24.13.1`, pnpm `v10.23.0`
- Model/provider: N/A
- Integration/channel (if any): N/A
- Relevant config (redacted): `env.vars.PATH="<custom-bin>;..."`
### Steps
1. Set existing process PATH and configure `env.vars.PATH` in OpenClaw config.
2. Apply config env vars and bootstrap PATH on `win32`.
3. Inspect resulting PATH order and duplicate handling.
### Expected
- Config PATH entries are prepended and deduplicated.
- Existing Windows key casing (`Path`) is respected.
- Windows global bin dirs are prepended before existing PATH entries when present.
### Actual
- Before fix: existing PATH caused config PATH to be skipped; Windows bootstrap missed common Windows bin dirs.
- After fix: behavior matches expected.
## Evidence
Attach at least one:
- [ ] Failing test/log before + passing after
- [x] Trace/log snippets
- [ ] Screenshot/recording
- [ ] Perf numbers (if relevant)
Trace:
- `pnpm exec vitest run src/config/config.env-vars.test.ts src/infra/path-env.test.ts`
- Result: `2 passed` files, `12 passed` tests.
## Human Verification (required)
What you personally verified (not just CI), and how:
- Verified scenarios:
- PATH merge/prepend/dedupe from config env vars.
- Windows `Path` key handling (case-insensitive lookup, key preserved).
- Windows PATH bootstrap candidate dirs are included when present.
- Edge cases checked:
- Non-PATH env vars still keep existing-value precedence.
- Existing path-env tests remain passing.
- What you did **not** verify:
- Full end-to-end manual run through all OpenClaw runtime surfaces/channels.
- Cross-platform manual runtime validation on macOS/Linux.
## Compatibility / Migration
- Backward compatible? (`Yes`)
- Config/env changes? (`No`)
- Migration needed? (`No`)
- If yes, exact upgrade steps:
## Failure Recovery (if this breaks)
- How to disable/revert this change quickly:
- Revert commit `0e3cbfa1fbf26e0ed101d61fa46ce7241fc76da8`.
- Temporary workaround: remove `env.vars.PATH` from config.
- Files/config to restore:
- `src/config/env-vars.ts`
- `src/config/config.env-vars.test.ts`
- `src/infra/path-env.ts`
- `src/infra/path-env.test.ts`
- Known bad symptoms reviewers should watch for:
- Unexpected binary resolution order due to PATH precedence.
- PATH entries duplicated or missing expected Windows bin dirs.
## Risks and Mitigations
- Risk: PATH precedence may select a different executable than before.
- Mitigation: change is limited to explicit PATH handling, with deterministic prepend + dedupe and targeted tests.
- Risk: Windows env key casing mismatch (`PATH` vs `Path`) could create split values.
- Mitigation: case-insensitive key resolution, preserving existing key name when updating.
<!-- greptile_comment -->
<h3>Greptile Summary</h3>
This PR fixes PATH handling in two areas:
1. **Config env PATH merge** (`src/config/env-vars.ts`): `env.vars.PATH` from config now merges with (prepends to) the existing process PATH instead of being silently skipped when PATH already exists. Includes case-insensitive env key resolution to handle Windows `Path` vs `PATH` correctly, and deduplication of PATH entries.
2. **Windows PATH bootstrap** (`src/infra/path-env.ts`): Adds common Windows global bin directories (`%APPDATA%\npm`, `%LOCALAPPDATA%\pnpm`, `%LOCALAPPDATA%\Microsoft\WindowsApps`, `%LOCALAPPDATA%\Programs\Microsoft VS Code\bin`) as candidate dirs for PATH bootstrap on `win32`.
- Both changes are well-tested with targeted unit tests covering merge ordering, deduplication, and Windows key casing.
- The implementation is consistent with existing patterns (e.g., `mergePath` in `path-env.ts`, macOS/Linux candidate dir patterns).
- No issues found that would affect correctness or safety.
<h3>Confidence Score: 4/5</h3>
- This PR is safe to merge — changes are well-scoped to PATH handling with proper test coverage.
- Score of 4 reflects clean, well-tested changes that follow existing patterns. The PATH merge logic correctly handles edge cases (dedup, key casing, empty values). The only minor consideration is that PATH entry deduplication is case-sensitive which could miss duplicates on Windows file systems, but this is consistent with existing behavior in `path-env.ts` and not a regression.
- No files require special attention. All changes are straightforward and well-tested.
<sub>Last reviewed commit: 0e3cbfa</sub>
<!-- greptile_other_comments_section -->
<sub>(3/5) Reply to the agent's comments like "Can you suggest a fix for this @greptileai?" or ask follow-up questions!</sub>
<!-- /greptile_comment -->
Most Similar PRs
#10714: fix: handle Windows PATH case-sensitivity in node register invoke
by Yida-Dev · 2026-02-06
84.2%
#10708: fix: handle Windows PATH case-sensitivity in exec environment
by Yida-Dev · 2026-02-06
83.8%
#20330: Fix SSH tunnel startup on Windows by resolving ssh from PATH
by graysurf · 2026-02-18
80.6%
#23085: fix(workspace): respect OPENCLAW_STATE_DIR for workspace paths, fix...
by charojo · 2026-02-22
78.4%
#23142: fix(test): Windows CI — use path.join for XDG path assertions in qm...
by ihsanmokhlisse · 2026-02-22
78.1%
#21733: security(exec): platform-aware allowlist matching and restricted sa...
by Esubaalew · 2026-02-20
77.8%
#15615: fix(security): restrict PATH override to exact match in node-host s...
by AI-Reviewer-QS · 2026-02-13
77.8%
#5496: Fix: Windows path separators stripped in Gateway scheduled task
by giuliozelante · 2026-01-31
77.5%
#4709: fix(daemon): include user bin dirs in macOS LaunchAgent PATH
by ekson73 · 2026-01-30
76.9%
#12804: fix(daemon): use wrapper script for pnpm global installs in service...
by odinho · 2026-02-09
76.8%