You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The transport seam (TerminalMultiplexer registry in adapters/multiplexer.py) currently selects a backend by matches(sys.platform) alone, with an env-var escape hatch (BMAD_LOOP_MUX_BACKEND). That breaks down the moment a platform has more than one viable multiplexer:
Native Windows already has two tmux-family backends in flight — psmux and tmux-windows (Add native Windows tmux backend #85). Both register matches == "win32" and both drive a binary literally named tmux, so:
selection is decided by registration order (a collision), and
tmux -V cannot tell them apart — psmux's tmux.exe reports plain tmux 3.3.6, identical to a real tmux version string.
This is not Windows-specific. On Linux a dev may have tmuxand for example herdr (an agent multiplexer, same use-case as bmad-loop) installed at once. The seam should let them pick.
Availability is a machine property (which binaries are on PATH), and the repo is shared by teammates on different OSes. So the choice must NOT be a committed project setting.
Proposal (no behavior forced; opt-in choice, sane default)
Each adapter already self-reports installation via available() (checks its binaries on PATH). Make Windows available()discriminating so overlapping backends don't both claim the host:
psmux.available() → which("psmux") and which("tmux") and which("pwsh") (psmux ships a distinctly-named psmux.exe; tmux-windows does not).
tmux-windows.available() → which("tmux") and not which("psmux").
Per-platform default: each platform declares one default backend name — linux/macos → tmux, win32 → psmux or psmux-windows. Used only when available.
Selection precedence:BMAD_LOOP_MUX_BACKEND (env) → mux_backend in user/machine config (~/.config/bmad-loop/, %APPDATA%\bmad-loop\) → per-platform default if available() → first matches(platform) && available() → tmux fallback.
The persisted choice lives in machine-scoped config, never the committed project tree — a psmux pick by a Windows dev must not reach a Linux teammate.
Setup detection UX: enumerate registered backends eligible for the platform, call available() + version() on each. If >1 is available and no choice is persisted, prompt the dev and persist the pick; otherwise take the platform default silently.
New: detect_multiplexers(platform) -> [(name, version, available)] (~10 LOC, loops the registry), an available()-aware pass in get_multiplexer() (~5 LOC), one machine-config key + a setup prompt.
Windows available() discriminator: one line per Windows backend.
No core edit: on a Linux box with both tmux and herdr, tmux stays the platform default, and a dev who prefers herdr sets it once at setup (persisted to ~/.config/bmad-loop/), leaving the teammate on the same repo unaffected.
Non-goals
Not merging psmux + tmux-windows into one leaf — their dialects diverge too much (pwsh -EncodedCommand + Read-Host + in-source env vs powershell.exe -Command + [Console]::ReadLine() + -e flags + -c rewrite). Two leaves.
Not auto-guessing between two installed Windows tmux drop-ins beyond the which("psmux") discriminator — ambiguity resolves via the explicit choice.
Open questions for discussion
Config format / location for the machine-scoped store — a dedicated ~/.config/bmad-loop/config.toml (+ %APPDATA%\bmad-loop\config.toml on Windows), or lean on an existing bmad config mechanism? This fixes what the mux_backend example above looks like.
Per-project override — do we also want an optional project-level override (gitignored), or keep the choice strictly per-machine to avoid scope confusion between "installed here" and "chosen for this repo"?
Setup prompt trigger — should the "multiple detected, please choose" prompt fire from bmad-loop validate, a dedicated bmad-loop mux command, or first-run init? And is the platform default silently applied when only one backend is available, with the prompt reserved for the >1 case?
Relationship of Add native Windows tmux backend #85 and the psmux backend — land both as sibling win32 backends behind this selection logic, or does one supersede the other? Note the psmux backend is itself tmux-family (subclasses BaseTmuxBackend, invokes tmux), so the "interim tmux-windows vs future non-tmux psmux" framing in the ROADMAP doesn't quite hold — they're siblings.
Multiplexer selection: per-platform default + detected, dev-chosen backend
Problem
The transport seam (
TerminalMultiplexerregistry inadapters/multiplexer.py) currently selects a backend bymatches(sys.platform)alone, with an env-var escape hatch (BMAD_LOOP_MUX_BACKEND). That breaks down the moment a platform has more than one viable multiplexer:psmuxandtmux-windows(Add native Windows tmux backend #85). Both registermatches == "win32"and both drive a binary literally namedtmux, so:tmux -Vcannot tell them apart — psmux'stmux.exereports plaintmux 3.3.6, identical to a real tmux version string.tmuxand for exampleherdr(an agent multiplexer, same use-case as bmad-loop) installed at once. The seam should let them pick.Availability is a machine property (which binaries are on PATH), and the repo is shared by teammates on different OSes. So the choice must NOT be a committed project setting.
Proposal (no behavior forced; opt-in choice, sane default)
Each adapter already self-reports installation via
available()(checks its binaries on PATH). Make Windowsavailable()discriminating so overlapping backends don't both claim the host:psmux.available()→which("psmux") and which("tmux") and which("pwsh")(psmux ships a distinctly-namedpsmux.exe; tmux-windows does not).tmux-windows.available()→which("tmux") and not which("psmux").Per-platform default: each platform declares one default backend name — linux/macos →
tmux, win32 →psmuxorpsmux-windows. Used only when available.Selection precedence:
BMAD_LOOP_MUX_BACKEND(env) →mux_backendin user/machine config (~/.config/bmad-loop/,%APPDATA%\bmad-loop\) → per-platform default ifavailable()→ firstmatches(platform) && available()→ tmux fallback.The persisted choice lives in machine-scoped config, never the committed project tree — a
psmuxpick by a Windows dev must not reach a Linux teammate.Setup detection UX: enumerate registered backends eligible for the platform, call
available()+version()on each. If >1 is available and no choice is persisted, prompt the dev and persist the pick; otherwise take the platform default silently.What this needs (small; most already exists)
available()/version()/ registry / env-override: already present.detect_multiplexers(platform) -> [(name, version, available)](~10 LOC, loops the registry), anavailable()-aware pass inget_multiplexer()(~5 LOC), one machine-config key + a setup prompt.available()discriminator: one line per Windows backend.Example: adding herdr proves the seam generalizes
No core edit: on a Linux box with both tmux and herdr,
tmuxstays the platform default, and a dev who prefers herdr sets it once at setup (persisted to~/.config/bmad-loop/), leaving the teammate on the same repo unaffected.Non-goals
-EncodedCommand+Read-Host+ in-source env vspowershell.exe -Command+[Console]::ReadLine()+-eflags +-crewrite). Two leaves.which("psmux")discriminator — ambiguity resolves via the explicit choice.Open questions for discussion
~/.config/bmad-loop/config.toml(+%APPDATA%\bmad-loop\config.tomlon Windows), or lean on an existing bmad config mechanism? This fixes what themux_backendexample above looks like.bmad-loop validate, a dedicatedbmad-loop muxcommand, or first-run init? And is the platform default silently applied when only one backend is available, with the prompt reserved for the >1 case?BaseTmuxBackend, invokestmux), so the "interim tmux-windows vs future non-tmux psmux" framing in the ROADMAP doesn't quite hold — they're siblings.