Repository navigation
Description
wmux version: 0.42.0
OS: Windows 11 Pro 10.0.26200
Shell in pane: powershell.exe
Two CLI correctness problems found while verifying the #141 fix (which is fixed — details in a comment there). Both matter mainly to scripts and agents driving wmux from inside a pane.
1. WMUX_SURFACE_ID resolves to the wrong window once a second window exists
The 0.42.0 release note says "V2 commands now use caller's WMUX_SURFACE_ID to identify owning window". With a single window this appears to work. As soon as a second window exists, passing WMUX_SURFACE_ID makes commands resolve to a constant, wrong window — and the caller's own surface is not in the result.
Setup
- Caller shell lives in
surf-360768cf-…, in panepane-c36f0826-…, in workspace "Workspace 3", in windowwin-fda7feb5-…. - A second window
win-2806cd6c-…was opened withwmux new-window. - There is also a workspace "Session 1" containing three terminal panes (
pane-f45f55c3,pane-b11e7cf2,pane-89504319).
Observed
| Focused window | Call | Panes returned by tree |
Contains caller's pane c36f0826? |
|---|---|---|---|
| original | wmux tree (with WMUX_SURFACE_ID) |
f45f55c3, b11e7cf2, 89504319 | ❌ |
| original | wmux tree (env var removed) |
c36f0826, 48d68481 | ✅ |
| new | wmux tree (with WMUX_SURFACE_ID) |
f45f55c3, b11e7cf2, 89504319 | ❌ |
| new | wmux tree (env var removed) |
f45f55c3, b11e7cf2, 89504319 | ❌ |
Grepping the WMUX_SURFACE_ID result for the caller's own surface id returns 0 matches. The result is byte-stable across focus changes: it always resolves to "Session 1", a workspace the caller is not in.
So the env var makes resolution worse: removing it at least follows the focused window.
tree and list-surfaces now agree with each other (that part of #141 is fixed) — they are simply wrong together.
Reproduce
# from a shell inside a wmux pane, with at least one other workspace present
echo "$WMUX_SURFACE_ID" # note this id
wmux tree # ✓ shows your pane
wmux new-window
wmux tree # ✗ different window; your surface id is absent
env -u WMUX_SURFACE_ID wmux tree # ✓ shows your pane againWhy it matters
A script running inside a pane always has WMUX_SURFACE_ID set — there is no way to opt out short of scrubbing the environment. So any agent or script that inspects or mutates surface state starts operating on someone else's window the moment the user opens a second one, and it looks successful. Scrubbing the variable is not a fix either, since the result then depends on which window happens to be focused.
What I would expect: caller should resolve to the window/workspace that actually contains that surface id, and fall back to the focused window only when the id is unknown.
2. There is no --help, and unknown flags are silently ignored — the command runs anyway
wmux new-surface --help # creates a terminal surface
wmux split --help # splits the panegetFlag() in resources/cli/wmux.js picks out the flags it knows and ignores everything else, so a typo or an exploratory flag becomes "run with defaults". Only bare wmux prints usage.
This is a small thing for a human, but for an agent it means probing the CLI mutates the user's layout, and the JSON response looks like success. I hit it while investigating issue 1 and accidentally created a surface and split a pane.
Suggestion: reject unknown flags with an error and print that subcommand's usage, and/or support --help / -h per subcommand.
Activity
fix(cli): scope V2 commands to the caller's workspace, reject unknown…
amirlehmam commentedon Aug 4, 2026
Thanks — both are real, and the first one was worse than it looked. Fixed in #144, shipping in v0.43.0.
1. Caller resolution
Your diagnosis was right, and there were two independent bugs stacked on top of each other.
The window was resolved; the workspace was not.
windowForCallerasked each window "do you hold this surface?" and stopped at the first yes. But that check scans every workspace in a window, whiletree/list-panes/list-surfacesanswer about the active one. So resolution could be entirely right about the window and still describe a workspace you had never seen — which is exactly your "always resolves to Session 1, a workspace the caller is not in".Resolution now returns the surface's window and its workspace, and that workspace is the default for every method that would otherwise guess.
--workspacestill wins when you pass it. This applies with one window too: a caller sitting in a background workspace was already getting the wrong answer before any second window existed.The cache was authoritative. Once a caller probed successfully it was pinned to that window for the rest of the session, which is why you saw a byte-stable result across focus changes. It is now only a probe-order hint — a stale entry heals on the next call.
And your surface id existed in two windows at once. This is what made the wrong window win the probe. A window opened mid-run gets no session slot, which the renderer read as "nothing saved" and answered by cloning the newest named session — same workspace, pane and surface ids as the window that already had them. Since PTY id is surface id in wmux, that clone's terminals were also re-attaching to the original window's PTYs.
session:load-autonow says "come up empty" explicitly for mid-run windows instead of leaving it to be inferred.Behaviour now matches what you asked for: resolve to the window/workspace that actually contains the surface id, and fall back to the focused window only when the id is unknown.
While in there,
close-surface/focus-surface/rename-surface/close-panenow find their target anywhere in the window rather than only in the active workspace. Ids are uuids so the search can't hit the wrong thing, whereas the old scope silently did nothing and still reportedok.2.
--helpand unknown flagsAgreed, and sorry about the surface and the split you didn't ask for.
Every command now declares its flags. Anything else is an error with that command's usage, and
--help/-hprints usage without sending a single byte to the pipe:A value flag with no value is rejected too (
wmux tree --workspace→Flag '--workspace' needs a value.) — that was the same silent default in a different costume.One deliberate exception: commands whose arguments are free-form text or belong to another program —
send,notify,log,ssh,browser,markdown,rename-surface,rename-workspace— are not flag-checked, becausewmux send --helphas to type--helpinto the pane rather than print usage. For those there is nowwmux help <command>, which works for every command:The command table is type-checked against the usage table, so a command can no longer ship without usage text.
Thanks for testing #141 through and finding these — the "it looks successful" framing is what made the first one worth digging past the symptom.
fix(cli): register fork-local a2a command in COMMAND_SPECS
merge(upstream): bring amirlehmam/wmux master (0.46.0) into oh-my-pi
fix(agent): derive a spawn's workspace from the pane that owns it (#242)
fix(agent): spawn defaults to the caller's workspace, and the CLI ref…
feat(remote): P1 console core — guards, devices, session, tap, server…