fix(mcp): pin PWD to cwd when spawning a local harness#542
Conversation
runLocalHarness spawns the coding CLI with `cwd` set to the worktree, but inherited the parent process's `PWD`. Harnesses that resolve their working directory from `$PWD` rather than getcwd() (opencode does) then edit the WRONG directory, so the worktree diff comes back empty and the delegation fails with a phantom "empty patch — no candidate passed validation". Merge `PWD: cwd` into the child env so the harness edits where it was placed.
tangletools
left a comment
There was a problem hiding this comment.
✅ Auto-approved drewstone PR — ce1ece28
This PR was opened by the trusted drewstone account.
The full PR reviewer audit still runs separately and will publish findings if it detects issues.
tangletools · auto-approval · reason: drewstone_author · 2026-07-13T06:18:10Z
tangletools
left a comment
There was a problem hiding this comment.
🟢 Value Audit — sound
| Verdict | sound |
| Concerns | 0 (none) |
| Heuristic | 0.0s |
| Duplication | 0.0s |
| Interrogation | 173.2s (2 bridge agents) |
| Total | 173.2s |
💰 Value — sound
Pins PWD=cwd in the harness spawn env so harnesses that read $PWD instead of getcwd() edit the worktree they were placed in — correct, minimal, well-placed.
- What it does: Sets
PWDto match thecwdspawn option in the child process environment forrunLocalHarness, so a harness CLI that resolves its working directory from the$PWDenv var (opencode does) operates in the correct worktree rather than the parent's directory. - Goals it achieves: Eliminates the 'empty patch / no candidate passed validation' failure where a harness runs and reports success but edits nothing, because it was editing the parent's directory (stale inherited PWD) while the executor diffed the worktree it was spawned into.
- Assessment: Correct one-line fix placed at exactly the right point —
baseEnvis the single source that feeds both the codex-isolated path (isolateCodexHome spreads it at line 1047, and PWD survives the sensitive-env stripping) and the plain-spawn else branch (line 429). TheNodeJS.ProcessEnvannotation is necessary, not decorative — without it the spread widens and laterenv.CODEX_HOMEreads inside isol - Better / existing approach: none — this is the right approach. Searched all spawn sites in src/ (in-process-executor.ts:233, worktree-harness.ts:299, runtime/supervise/runtime.ts:779, mcp-serve-verifier.ts:50, local-harness.ts:836) — none has PWD-pinning logic to reuse, and no shared spawn-env helper exists. The sh-based spawners use getcwd() so they don't need it; only harness CLIs that may read $PWD do. A shared helper wou
- Model: opencode/zai-coding-plan/glm-5.2
- Bridge attempts: 2
- Bridge warning: opencode/kimi-for-coding/k2p7: bridge stream ended without value-audit content
🎯 Usefulness — sound
Correct one-line fix that pins PWD to the spawn cwd at the single env source feeding every runLocalHarness consumer, closing a real bug where harnesses that read $PWD edit the parent dir instead of their worktree.
- Integration: Fully reachable. runLocalHarness is consumed by two production paths — runWorktreeHarness (src/mcp/worktree-harness.ts:192) and agenticGenerator (src/improvement/agentic-generator.ts:103) — and neither passes options.env, so both inherit process.env and land on the fixed baseEnv line. The in-process executor and worktree CLI executor both route through runWorktreeHarness, so the fix reaches every
- Fit with existing patterns: Matches the codebase's grain exactly. baseEnv at src/mcp/local-harness.ts:419 was already the one env source feeding both the codex-isolated path (isolateCodexHome, which re-spreads baseEnv at line 1047) and the plain-spawn fallback (line 429). Pinning PWD once at that source is the minimal, correct place — no competing pattern, no second env-construction site to keep in sync. The explicit NodeJS.
- Real-world viability: Holds on all paths. PWD:cwd is always correct because the spawn always uses cwd (line 473), so there is no input where the pin is wrong. options.env override is respected (spread first, PWD last wins). For codex reproducible mode the pin survives isolation since isolateCodexHome copies baseEnv into env at line 1047 and PWD is not in the sensitive-name exclude filter (line 1050). No concurrency sur
- Model: opencode/zai-coding-plan/glm-5.2
- Bridge attempts: 1
No concerns — sound change, no better or existing approach found. ✅
What this audit checks
It judges the change on its merits — not whether it was tasked out in an issue. Unticketed, fast-moving work is fine; the question is whether the change is good and whether a better or existing approach should be used instead.
| Pass | What it asks |
|---|---|
| Heuristic | Vague title? Whitespace-only or cruft-bearing diff? (content signals only) |
| Duplication | Do added function/class names already exist elsewhere in the repo? |
| Value Audit | What does it do? What goal does it achieve? Is it good? Better architecture or already-exists? |
| Usefulness Audit | Does it integrate and fit? Will it hold up in real use and actually get used? |
Findings are concerns, not blocks — the human reviewer decides what to do with them.
✅ No Blockers —
|
tangletools
left a comment
There was a problem hiding this comment.
✅ Approved — 2 non-blocking findings — ce1ece28
Full multi-shot audit completed 1/1 planned shots over 1 changed files. Global verifier still owns final merge decision.
Full immutable report for this review: trace
Summary comment for this run: full summary
tangletools · 2026-07-13T06:27:21Z · immutable trace
tangletools
left a comment
There was a problem hiding this comment.
✅ Auto-approved drewstone PR — ed7c6675
This PR was opened by the trusted drewstone account.
The full PR reviewer audit still runs separately and will publish findings if it detects issues.
tangletools · auto-approval · reason: drewstone_author · 2026-07-13T20:14:57Z
Root cause
runLocalHarnessspawns the coding CLI withcwdset to the target worktree, but it inherited the parent process'sPWD. Harnesses that resolve their working directory from$PWDrather thangetcwd()— opencode does; the others may — then read and edit the wrong directory (the parent's), not the worktree they were placed in.The worktree diff comes back empty and the delegation fails with a phantom
empty patch — no candidate passed validation, even though the harness ran and "succeeded" against the parent dir.Fix
Pin
PWDtocwdin the child env. Onmain, the spawn env isbaseEnv, which feeds both the codex-isolated path (isolateCodexHome) and the plain-spawn path, so pinning it once at the source covers everyrunLocalHarnessconsumer:The explicit
NodeJS.ProcessEnvannotation preserves theProcessEnvindex signature — without it the object-literal spread widens the type and laterenv.CODEX_HOMEreads on the isolated path stop type-checking.Proof
tsc --noEmit: zero errors insrc/mcp/local-harness.tswith the change.PWDpinned, the harness edits the worktree it was handed and the diff is non-empty — the delegation now delivers.origin/main(git merge-tree, zero conflicts).Notes
Origin: commit
8a4a1461onfeat/with-intelligence(a stale branch). That branch'slocal-harness.tspredatesmain'sbaseEnvrefactor, so this is a clean re-port of the same one-line intent onto currentmain, isolated on a fresh branch offorigin/main— no unrelatedfeat/with-intelligencework is dragged in.🤖 Generated with Claude Code