Skip to content

Multiplexer selection: per-platform default + detected, dev-chosen backend #87

Description

@dracic

Multiplexer selection: per-platform default + detected, dev-chosen backend

Problem

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 tmux and 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)

  1. 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").
  2. Per-platform default: each platform declares one default backend name — linux/macos → tmux, win32 → psmux or psmux-windows. Used only when available.

  3. 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.

  4. 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.
  • 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.

Example: adding herdr proves the seam generalizes

class HerdrMultiplexer(TerminalMultiplexer):
    def available(self) -> bool:
        return shutil.which("herdr") is not None
    ...

register_multiplexer("herdr", lambda p: p in ("linux", "darwin"), HerdrMultiplexer)

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

  1. 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.
  2. 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"?
  3. 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?
  4. 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions