bmad-loop roadmap
August 19, 2026 · View on GitHub
Forward-looking work for the orchestrator itself — design intent and rationale for features we've deliberately deferred, so the "why" survives between sessions.
Status legend: planned (agreed, not started) · in progress (started; some pieces shipped, the headline goal not yet met) · exploring (shape still open) · blocked (waiting on an external dependency).
Native Windows multiplexer backend
Status: in progress — the platform seams and a native-Windows backend (psmux, held by a real-Windows live gate) have shipped in-tree; still open are the second tmux-family backend tmux-windows (#85), herdr's win32 launch path, and the open questions at the end of this section · Foundation: the full platform-seam series landed (multiplexer registry + BaseTmuxBackend + ProcessHost + hook interpreter + validate preflight, v0.7.6; availability-aware backend selection + bmad-loop mux, #87; out-of-tree backend discovery via bmad_loop.mux_backends entry points; original seam v0.7.0) · a first non-tmux-family, native-Windows-capable backend — herdr — ships end-to-end on POSIX as the external bmad-loop-adapter-herdr (the win32 agent.start launch path is tracked there)
The orchestrator no longer fuses tmux into the engine. All session/window/pane operations
go through a single TerminalMultiplexer ABC (src/bmad_loop/adapters/multiplexer.py),
obtained from get_multiplexer(); the tmux backend — argv + spawn primitive in
BaseTmuxBackend (adapters/tmux_base.py), POSIX leaf TmuxMultiplexer
(adapters/tmux_backend.py) — is the only place allowed to shell out to tmux, and it
quarantines the POSIX sh -c parked-window trailer. Backends now self-register
(register_multiplexer) rather than being hardcoded into get_multiplexer(), and selection
(#87) is availability-aware with a dev-choosable persisted pick: BMAD_LOOP_MUX_BACKEND env
var → the machine-scoped [mux] backend policy key (bmad-loop mux set <name>; policy.toml
is gitignored) → the platform default (win32: psmux, elsewhere: tmux) when installed →
the first registered platform match that is available(). The process-lifecycle POSIX-isms moved behind a
matching seam, ProcessHost (src/bmad_loop/process_host.py): terminate / force_kill /
is_alive / identity (a PID-reuse guard) plus hook_interpreter() (so hook registration
never branches on platform), registered the same way (register_process_host,
BMAD_LOOP_PROCESS_HOST); WindowsProcessHost already ships. bmad-loop validate runs a
_platform_preflight(project) that reports the selected backend's readiness and names the process
host — so a new OS surfaces in preflight by registering, not by a validate edit. The Unity
plugin's /proc//tmp/cp -a/symlink primitives degrade off Linux (with psutil from the
optional non-linux extra) and its pid lifecycle now delegates to ProcessHost; everything is
held by a CI portability guard (tests/test_portability_guard.py). WSL already works today
— it is Linux, so it takes every fast path unchanged; this is purely about a future native
Windows host.
Three native-Windows candidates now exist, and they are not stages of one plan.
Two are sibling tmux-family backends: psmux has shipped in-tree (drives
psmux's tmux-compatible CLI through its own psmux binary, via pwsh) while
tmux-windows (#85; drives the tmux-windows port) is still in flight — both subclass
BaseTmuxBackend and both register for win32, which is why selection is
availability-aware with discriminating available() probes (psmux →
which("psmux") and which("pwsh") plus a version gate requiring psmux 3.3.8 or newer
(why); tmux-windows →
which("tmux") and not which("psmux")) and an explicit bmad-loop mux set <name> tie-break.
The third — herdr — has shipped end-to-end on POSIX (engine run path +
TUI-launch surface), and now lives out-of-tree as the reference external adapter,
pbean/bmad-loop-adapter-herdr
(developed in-tree in #136/#137, extracted pre-release per core-team direction; it
co-installs with bmad-loop and self-registers via the bmad_loop.mux_backends
entry-point group). It is a different-binary-family backend: it implements
TerminalMultiplexer fresh over herdr's workspace/tab/pane model rather than
subclassing BaseTmuxBackend, and probes which("herdr"), so it is
pairwise-discriminating against the tmux family by construction (no mux set
tie-break needed to tell them apart). It registers with matches = True (all
platforms), which keeps the door open for native Windows without disturbing POSIX. On
POSIX, tmux stays the platform default, so herdr activates only on an explicit
BMAD_LOOP_MUX_BACKEND=herdr / bmad-loop mux set herdr. On win32,
_PLATFORM_DEFAULTS is untouched — psmux remains the declared win32 default — so
herdr is picked only by first-match (the fourth precedence step) when installed and
available() and no higher-priority backend is: once psmux (or tmux-windows) ships and
registers for win32, the win32 default reasserts and outranks herdr's first-match
automatically, no code change. herdr's exec launch is POSIX-only for now; the Windows
launch path (herdr's agent.start) is tracked in
the adapter repo's issues,
and the Phase-0 characterization must be re-run on a real Windows host before #92 is claimed.
The seams are designed so each backend slots in as new files plus one registration line,
with no change to the adapters, runs.py, tui/launch.py, probe.py, tui/data.py, or
cli.py's validate (WindowsProcessHost and its hook interpreter are already in place
and registered; herdr proved this end to end — one registration line and one sanctioned
probe.py gate fix, zero portability-guard allowlist changes; the extraction then proved
the fully external path — the same registration arriving via entry-point discovery,
zero core files). The end-to-end port path —
both build options, the test-override env vars, and exactly what a native-Windows port costs —
is documented in Porting bmad-loop to a new OS; the deep transport
contract is in the
adapter authoring guide.
Open questions: what hosts the windows on native Windows (Windows Terminal panes, a ConPTY-based manager, a headless process supervisor?); how attach/detach and the parked exit-status window map without a POSIX shell; and the Windows-Unity cache-path correctness left as a documented follow-up in Phase 4.
Parallel unit execution ([scm] max_parallel)
Status: planned · Foundation: landed with worktree isolation (v0.4.0)
Worktree isolation ([scm] isolation = "worktree") already gives each story/bundle its own
worktree and branch, and the max_parallel knob is parsed and validated in
src/bmad_loop/policy.py (ScmPolicy). But it is clamped to 1 in loads() — merge-back
is serialized, one unit at a time — because the internal fan-out scheduler isn't built yet. The
knob exists so the config surface is stable; it stays inert until this phase lands.
The goal is to drive N units concurrently (each in its own worktree, independent tmux session), then serialize only the merge-back into the target branch. Then lifting the clamp activates the existing knob with no config change for users.
Open questions: how to bound concurrent CLI sessions vs. token/cost budgets; merge-back ordering and conflict handling when several units finish close together; how the TUI surfaces multiple in-flight units per run.
Automate epic retro action items
Status: planned · Blocked-by: retro-item detail isn't standardized yet
The parser now recognizes epic-{N}-retro-item-{M}-{slug} keys in sprint-status.yaml
(src/bmad_loop/sprintstatus.py → RetroItem / SprintStatus.retro_items), so the
sprint-status-unknown-keys warning no longer fires. They are tracked but not driven as work.
The goal is to run actionable (backlog) retro items through the dev → review → commit pipeline,
the same way deferred-work sweeps already run.
Approach (designed, not built): a separate bmad-loop retro run type that mirrors the
SweepEngine (src/bmad_loop/sweep.py) end-to-end — RetroEngine, a retro CLI command + resume
branch, a retro-item intent fed to the bmad-build-auto primitive, and verify helpers paralleling
the bundle verifiers. Story runs stay untouched.
Why blocked: retro-item detail is scattered — some lives in the epic retro-doc Action-Items
table (epic-N-retro-YYYY-MM-DD.md), some in deferred-work.md (DW-N) entries, some in ad-hoc
spec-*.md files; only one epic has an epic-N-action-items.md. A deterministic key→file map isn't
viable, so automation needs an LLM triage step (like sweep's) to locate/extract each item's intent
and classify out the non-code items (research, docs). Prerequisite: standardize where
retro-item detail is written at retrospective time (a future BMAD update) — that makes the triage
reliable enough to trust unattended.
Integrate BMAD test-design + test-automation runs (TEA / testarch)
Status: exploring · Foundation: experimental opt-in tea plugin landed (v0.5.1)
The bundled, experimental tea plugin ([plugins] enabled = ["tea"], see the
TEA plugin guide) now wires the BMAD Test Architect (TEA) suite —
bmad-testarch-test-design, -automate, -atdd, -nfr, -trace, -test-review, and the
bmad-tea agent — into every run and sweep as advisory-by-default quality steps (the three
gate steps can be flipped to blocking). It's experimental: the workflows ride the generic
[workflows.<name>] session-injection layer rather than being first-class orchestrated runs.
The remaining work is to drive test design (derive a test plan / coverage map for a feature or
backlog) and test automation (generate + run the actual tests) as first-class orchestrated runs —
closing the loop that retro items like epic-5-retro-item-1-test-design-and-backfill-prior-epics
currently call out by hand.
Open questions: is this a new test run type, or a phase wired into the existing story/review
pipeline? How does generated-test output feed verification (gate a story on its test plan / coverage)?
Which testarch skills become orchestrated vs. stay interactive?
Integrate BMAD GDS game-test items
Status: exploring · Foundation: opt-in game-engine layer landed (Unity, shared + per_worktree), now riding the general plugin system
The opt-in Unity plugin (docs/FEATURES.md → "Game-engine projects"), enabled with
[plugins] enabled = ["unity"], already lets a Unity project run its dev/sweep cycle against a
live Editor MCP in shared mode (agent works in place on the operator's open Editor; a readiness
gate blocks until the Editor + MCP are up) and in per_worktree mode (one managed Editor per
worktree, with reflink/CoW Library priming, setup/teardown hooks, and MCP-skill seeding via
seed_globs). The game-engine layer is no longer bespoke core code — it's a plugin built on the
general plugin system (the legacy [engine] block is a deprecated
compatibility shim, folded onto [plugins.unity] at load time). Next steps: batchmode verify_cmd
and Godot/Unreal plugins on the same plugin.toml+scripts shape — the authoring path is documented
in Writing a Game Engine plugin and
Writing a plugin for a specific Editor MCP.
The BMAD GDS module (game dev — Unity / Unreal / Godot) carries its own testing track via the
gametest workflow (_bmad/gds/workflows/gametest). For game projects, the testarch/TEA pipeline
above doesn't map cleanly; GDS has its own design → technical → production → gametest flow.
The goal is to let bmad-loop recognize and drive GDS game-test items the same way it drives sprint stories and (eventually) retro items, so game projects get the same unattended implement → test → review loop.
Open questions: how do GDS workflow artifacts map onto the orchestrator's sprint-status/work-item model? Does GDS need its own run type, or can the test-design/automation integration above generalize to cover it? Depends on the testarch integration landing first.