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

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions