Skip to content

bmad-loop mux renders a broken table when a backend's version() is multi-line (psmux) #321

Description

@pbean

Summary

TerminalMultiplexer.version() may return a multi-line string, and two of its four consumers
render it as if it were one line. Observed on a native-Windows host during the #310/#315 live
verification (psmux 3.3.7, 05cc5d4).

psmux -V prints two lines — the tmux X.Y.Z compatibility line plus its own — and
BaseTmuxBackend.version() (adapters/tmux_base.py:455) returns proc.stdout.strip(), which
removes surrounding whitespace but not the embedded newline:

tmux 3.3.7
psmux 3.3.7 (05cc5d4 2026-07-20)

What breaks

bmad-loop mux on that host:

NAME   PLATFORM  AVAILABLE  VERSION                                      SELECTED
tmux   no        yes        tmux 3.3.7
psmux 3.3.7 (05cc5d4 2026-07-20)
psmux  yes       yes        tmux 3.3.7
psmux 3.3.7 (05cc5d4 2026-07-20)  * platform default for win32

cmd_mux (cli.py:400-414) computes column widths with len() and pads with ljust. The
VERSION cell is 43 chars, so every row's VERSION column is padded to 43 — hence the gap in the
header — and the embedded newline then splits each data row across two printed lines, stranding
SELECTED on the second. The table is unreadable, and * platform default for win32 looks like it
belongs to a version string.

The consumers disagree about this already

  • diagnostics.py:218defends: sanitize.scrub_text(raw, max_lines=1). Someone hit this before.
  • cli.py:407 (bmad-loop mux) — no defense; the breakage above.
  • runsetup.py:183 (bmad-loop validate preflight) — no defense. The finding message becomes
    multiplexer PsmuxMultiplexer available (tmux 3.3.7\npsmux 3.3.7 (…)), and the raw value also
    lands in the structured {"version": version} payload.
  • multiplexer.py:477 (forced-backend warning) — safe by accident: it uses {version!r}, so
    the newline renders escaped.

One defended caller and two undefended ones says the invariant belongs at the seam, not at each
call site. The ABC docstring (multiplexer.py:290) still says "Used by the diagnostic dump",
which is now stale — there are four consumers.

Suggested shape (not prescriptive)

Normalise in BaseTmuxBackend.version() so every consumer gets one line, and state the
single-line guarantee in the ABC docstring. One tension worth deciding rather than defaulting:
first-line-wins yields tmux 3.3.7 for psmux, which is exactly the string
PsmuxMultiplexer.available()'s regex parses (psmux_backend.py:426) but a confusing thing to
display — it hides which binary is actually running. So psmux may want to override version()
to report its own line, or the seam may need to separate "parseable version" from "display label".

Second, smaller thing on the same output

The tmux row reports psmux's version and AVAILABLE yes, because psmux ships a
tmux-named binary and TmuxMultiplexer.version() runs tmux -V.

Selection is not affected — tmux registers with platform != "win32" so it never matches on
win32, and the historical fallback (precedence step 5) picks the platform match, which is psmux.
It is purely misleading in the listing. Whether the AVAILABLE column should be gated on
matches_platform for display is a judgement call; flagging it here because it shows up in the
same two lines of output.

Refs: #315, #310

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:adaptersCoding-CLI adapters and profilesarea:psmuxpsmux terminal-multiplexer backendbugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions