Repository navigation
Description
Follow-on from #152, and I think it undercuts that fix rather than contradicting it. The block is right to make the reader check instead of assume. The problem is what the check can actually tell them.
The conflation
resources/claude-instructions.md:18:
If it does not answer — command not found, no reply, or an error — then wmux
is not running for this session. Ignore the whole section and use your normal
tools.
Three symptoms, one conclusion. But they are not the same fact:
- no reply on the pipe: wmux is not running. Ignoring the section is correct.
- command not found: says nothing about whether wmux is running. It says this session cannot reach the CLI.
The block instructs the reader to treat the second as the first.
Why the second case is the common one, not the exotic one
Verified from source: src/main/pty-manager.ts:323-341 prepends the shim dirs to the environment of PTYs wmux spawns, with the comment "Make bare wmux resolvable in every spawned shell AND all its children". That is the only place PATH is touched. There is no setx, no registry write, nothing that persists PATH anywhere in src/.
So wmux resolves inside a pane and its children, and nowhere else unless the user put it on PATH by hand. Every session wmux did not spawn - the Claude Code desktop app, a plain terminal, an SSH session, a scheduled run, a session that was already open before wmux started - has no wmux on PATH by default.
That is precisely the population #152 rewrote the block for. The block loads globally so it can reach sessions that are not inside wmux, and then hands those sessions a probe that, for most of them, fails for a reason the block does not account for.
Live, on this machine
Verified: wmux 0.50.0 running (20 processes), pid 28680 listening on 127.0.0.1:9222, named pipe answering. And:
$ wmux ping
bash: wmux: command not found
PS> wmux ping
wmux : The term 'wmux' is not recognized as a name of a cmdlet, function, script file, or executable program.
Following the block, every agent on this machine concludes wmux is absent and stops using the browser panel. wmux is fine. Only the entry point is missing.
How it got there: I took the in-app update to 0.50.0, the installer re-offered the install location, and I chose "All Users of this computer" where the previous install had been per-user. The root moved from %LOCALAPPDATA%\Programs\wmux to C:\Program Files\wmux and the old directory was removed. The PATH entry pointing at the old resources\cli-bin was one I had added by hand, so the dangling entry is mine. The part that is not mine is that a probe the block presents as authoritative now returns a false negative and the reader has no way to notice.
Separable second point
build/installer.nsh opens with:
wmux installs to the same path on every update
With oneClick: false and allowToChangeInstallationDirectory: true (electron-builder.json:32-38) and no perMachine pin, an update can land in a different root than the install it replaces, because the assisted installer re-offers scope and directory mid-update. That is what happened here. It invalidates the stated invariant, and with it any absolute path anyone recorded: PATH entries, shortcuts, scripts, and the install path documented in wmux's own notes.
Whether that is a bug or a feature is your call, and it is genuinely separable from the probe question. Say the word and I will file it on its own rather than leave it buried here.
Options
- Interpolate the path the writer already knows.
ensureClaudeContext()(src/main/claude-context.ts:113) splices the block from a static file, and it runs in the main process, which knowsprocess.resourcesPath. A placeholder inclaude-instructions.mdreplaced at splice time would let the failure branch say: ifwmuxis not found, wmux may still be running, try<absolute cli-bin path>\wmux pingbefore concluding it is absent. - Persist PATH from the app, ideally with consent.
- Split the guidance only, no path: tell the reader that "not found" and "no reply" mean different things and that only the second is evidence of absence.
- Leave it.
I lean 1, and I want to flag why it does not repeat the mistake #152 fixed. That was a write-time fact read at an arbitrarily later time by someone else, which nothing at generation time could make true. This one is different in the way that matters: the writer is the installed build itself, it is writing its own location, and it rewrites the block on every startup. It self-heals across exactly the relocation that broke it here - the 0.50.0 instance that rewrote my CLAUDE.md today already knew its new resourcesPath while writing text that pointed the reader at PATH instead.
2 is heavier than the problem, cannot help sessions already running, needs uninstall cleanup, and sits badly next to 58f2301 asking before writing to ~/.claude. 3 is the honest minimum and pairs well with 1. 4 is defensible only if out-of-pane sessions are not meant to drive wmux at all, and #153 shipping --surface for callers with no WMUX_SURFACE_ID, now documented in the block, says otherwise.
Happy to send whichever you pick, including just 3 if you would rather not put a machine path in the block.
Activity
fix(context): stop reading "wmux: command not found" as "wmux is abse…
amirlehmam commentedon Aug 14, 2026
Fixed in 1.0.0. Option 1 and option 3 — you were right that they pair, and right that 3 alone would leave the reader with a distinction and no way to act on it.
You're right that this undercut #152 rather than contradicting it
That's the framing that made me take it seriously. #152's fix was to make the reader check instead of assume. If the check can't distinguish the two cases, the block has just moved the assumption one step later and made it look verified.
And the conflation runs in the worst possible direction for the population #152 was written for. Your source read is correct —
pty-manager.tsprepends the shim dirs to the environment of PTYs wmux spawns, and there is nosetx, no registry write, nothing persisted anywhere insrc/. Sowmuxresolves inside a pane and its children and nowhere else. Every session wmux did not spawn — the desktop app, a plain terminal, SSH, a scheduled run, anything already open before wmux started — gets "command not found" while wmux is running perfectly well. Those are exactly the sessions the block loads globally in order to reach. It was telling all of them to stand down.What the block says now
wmux ping # "pong" → wmux is herepong→ everything below is available"C:\...\resources\cli-bin/wmux" pingIf that answers, use the absolute path for everything below. If it too fails, wmux really is absent — and the "nothing here restricts what you may otherwise do" exit is unchanged, because the block must not become a machine for insisting wmux is present.
Why I agree this doesn't repeat #152's mistake
You articulated it better than I would have, and I've put your argument in the source so the next person to read it doesn't relitigate it:
It self-heals across precisely the relocation that broke your machine. The 0.50.0 instance that rewrote your
CLAUDE.mdalready knew its newresourcesPathwhile writing text that pointed you at PATH instead — which is a fairly damning way to put it, and correct.One structural consequence worth mentioning: the block is no longer static, so the three writers could no longer each read it for themselves.
claude-context.ts,opencode-context.tsandkiro-context.tsnow shareagent-instructions.ts(which also absorbs thegetInstructionsPath()each of them had a private copy of). The existing "is one file, so all three agents get the same fix" test is tightened to "one file AND one reader" — sharing the source is no longer sufficient to prevent drift when the source carries an interpolated fact. There are now four writers, incidentally: #165 added omp in the same release.Your separable second point — accepted, and deliberately not "fixed"
You were right to flag it and right that it's separable.
build/installer.nshopened by asserting an invariant:With
oneClick: false,allowToChangeInstallationDirectory: trueand noperMachinepin, that is false, and your upgrade proved it. I've corrected the comment to say so, with your mechanism spelled out, plus the consequence: nothing in wmux may treat its own install path as stable across updates.What I have not done is pin the scope. That would make the invariant true, but it changes upgrade behaviour for every existing install, and I can't verify it without running a real installer through a real per-user→per-machine upgrade — which is not something to ship as a side effect of a documentation fix in a 1.0.0. Please do file it on its own; I'd rather it get a real argument (and a real test matrix) than ride along here.
Worth noting the two halves interact in your favour: because the block now re-interpolates
resourcesPathon every startup, a future relocation costs you nothing even with the installer unchanged.On option 2
Agreed with your reasoning for rejecting it, and I'd add one thing: persisting PATH is a write outside
%APPDATA%\wmux, which since 0.40.0 means it belongs behind theagent-integration.tsconsent gate with an inverse for uninstall. That's a lot of machinery, and it still can't help a session that is already running — which is the case that motivated the report.Excellent issue. The install-relocation detail at the end is the sort of thing most people would have left out as "my own fault", and it's what turned a wording quibble into a real defect.
fix(nsis): pin the install scope on update (#167, #158)
fix(pack): ship the canonical agent instructions and the app icon