Skip to content
Merged
20 changes: 20 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,19 @@ breaking changes may land in a minor release.

### Added

- **Dev-choosable multiplexer backend selection (#87).** `get_multiplexer()` now resolves by
precedence — `BMAD_LOOP_MUX_BACKEND` env var → the new machine-scoped `[mux] backend` key in
policy.toml → the platform default (win32: `psmux`, elsewhere: `tmux`) when installed → the first
registered backend that matches the platform _and_ is `available()` — so two same-platform
backends (psmux / tmux-windows) no longer collide by registration order. Forced names are trusted
(no availability gate) and fail loudly when unregistered, naming the policy file. New
`bmad-loop mux` lists registered backends (platform / available / version / selected + why);
`bmad-loop mux set <name>` persists the choice (`--clear` reverts to auto, `--force` allows a
name that only registers on the target machine); no interactive prompts anywhere. `validate`'s
preflight lists all detected backends when more than one is registered and notes an env/policy
forced selection. A tmux-less POSIX host still selects `TmuxMultiplexer` and reports it
unavailable, exactly as before.

- **Stories mode — a second planning pipeline that drives the loop off a typed `stories.yaml` (folder+id dispatch) instead of `sprint-status.yaml`.** Opt in with `[stories] source = "stories"` + `spec_folder`, or per run with `bmad-loop run --spec <folder>` (overrides policy); `--story` then filters by story id. Each entry dispatches by folder + id — the dev skill creates-or-resumes the story spec at `<folder>/stories/<id>-<slug>.md` and the orchestrator reads that id-keyed path back deterministically (no shared board to line-edit, no result-artifact mtime-scan). Strictly linear schedule (list order, no `depends_on`); `bmad-loop run --dry-run --spec <folder>` and `bmad-loop status` print the board (id · live disk state · checkpoint markers · title). Sprint mode is unchanged and remains the default. Requires a `bmad-dev-auto` new enough for folder+id dispatch — the run preflight checks and remediates.
- **Per-story human checkpoints (stories mode).** Independent `spec_checkpoint` (pause before code to review the plan — dev halts at `ready-for-dev`; approve to implement, or request a replan that resets the spec to `draft`) and `done_checkpoint` (pause after the story commits, skipped when it is the last story); both additive to `gates.mode`. A blocked story escalates + resolves as in sprint mode, with a pre-planning-halt sentinel auto-deleted (a copy preserved under the run dir) on re-arm.
- **TUI human-in-the-loop surface for stories mode.** The sprint tree is replaced by a stories board (id · live disk state · spec/done checkpoint markers · title) when a stories-mode run is selected; paused runs carry a per-run pause-kind badge and the run list shows a global _⚑ N need attention_ count; `p` opens the stage-appropriate viewer — plan-checkpoint spec review (Approve & resume / Request replan), story-checkpoint summary card (Continue / Stop), escalation with story context (Resolve / Re-arm & resume), and a gate spec viewer that the existing spec-approval/epic pauses reuse. The start-run modal gains a source select + spec-folder field with a live schedule preview. Every TUI action calls the same code paths as the CLI.
Expand All @@ -31,6 +44,13 @@ breaking changes may land in a minor release.

### Changed

- **`bmad-loop init` now gitignores `.bmad-loop/policy.toml`.** Policy is per-machine-per-repo —
it carries the machine-specific `[mux] backend` choice (and the TUI settings editor rewrites
it), so it must not travel to teammates on other machines or OSes. A `.gitignore` entry does not
untrack an already-committed file: existing repos run `git rm --cached .bmad-loop/policy.toml`
once (the local copy is kept; `init` prints this hint when it detects a tracked policy).
bmad-loop's own worktree-clean preflight already exempted policy.toml — this additionally stops
inner dev sessions and plain `git status` from reading a policy edit as a dirty tree.
- **The patch-restore seam is now one validator, one path normalizer, and one exclusion site.**
`runs.validate_restore_latch` holds every latch precondition (sentinel wedge, spec-less escalation,
worktree isolation) — the worktree check lived only in the CLI, so `rearm_escalation` called
Expand Down
9 changes: 5 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ Inspired by the original [bmad-automator](https://github.com/bmad-code-org/bmad-
## Requirements

- **Python 3.11+**, **tmux**, and a supported coding CLI — `claude` by default; `codex` and `gemini` via [profiles](#other-coding-clis).
- **Linux or macOS** (or **Windows via WSL**, which _is_ Linux — it runs as-is). tmux is the one terminal-multiplexer backend today, but it now sits behind a pluggable **registry** of OS seams (transport, process lifecycle, hook interpreter), so a native-Windows backend slots in as new files + a registration line each, with no engine edits — see [Porting bmad-loop to a new OS](docs/porting-to-a-new-os.md). Native Windows is not yet shipped.
- **Linux or macOS** (or **Windows via WSL**, which _is_ Linux — it runs as-is). tmux is the one bundled terminal-multiplexer backend today, but it sits behind a pluggable **registry** of OS seams (transport, process lifecycle, hook interpreter) with availability-aware selection — env var → persisted `[mux] backend` choice (`bmad-loop mux set <name>`) → platform default → first available platform match — so a native-Windows backend slots in as new files + a registration line each, with no engine edits — see [Porting bmad-loop to a new OS](docs/porting-to-a-new-os.md). Native Windows is not yet shipped.
- A **BMAD v6 project** (`_bmad/bmm/config.yaml`, a `sprint-status.yaml` from `bmad-sprint-planning`) with the upstream `bmad-dev-auto` skill (and the three review-hunter skills its step-04 invokes inline: `bmad-review-adversarial-general`, `bmad-review-edge-case-hunter`, `bmad-review-verification-gap`) and the bmad-loop skill module from this repo installed (`bmad-loop-resolve`, `bmad-loop-sweep` — see [Installing the skill module](#installing-the-skill-module)). Standard BMAD skills stay untouched.

## Quick start
Expand All @@ -61,8 +61,9 @@ bmad-loop tui # …or drive everything from the dashboard

| Command | What it does |
| -------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `bmad-loop init` | Install the bundled `bmad-loop-*` skills, the hook relay, `.bmad-loop/policy.toml`, and a runs-dir gitignore. `--cli <profile>` (repeatable) targets specific agents; `--no-skills` / `--force-skills` control skill copying. |
| `bmad-loop validate` | Preflight every prerequisite: BMAD config, sprint-status, git, CLI binary, hook registration, and a platform check that reports the selected multiplexer's readiness and process host. |
| `bmad-loop init` | Install the bundled `bmad-loop-*` skills, the hook relay, `.bmad-loop/policy.toml`, and a gitignore for the runs dir, plugin caches, and policy.toml itself (policy is per-machine — see the CHANGELOG migration note for repos initialized before this). `--cli <profile>` (repeatable) targets specific agents; `--no-skills` / `--force-skills` control skill copying. |
| `bmad-loop validate` | Preflight every prerequisite: BMAD config, sprint-status, git, CLI binary, hook registration, and a platform check that reports the selected multiplexer's readiness and process host (listing every registered backend when more than one is detected). |
| `bmad-loop mux` | List registered terminal-multiplexer backends — platform match, availability, version, and which one is selected (and why). `mux set <name>` persists a machine-scoped choice into `.bmad-loop/policy.toml` (`--clear` reverts to auto-select, `--force` allows a name that only registers on the target machine); the `BMAD_LOOP_MUX_BACKEND` env var outranks it. |
| `bmad-loop run` | Drive the dev → review → verify → commit loop. `--epic N`, `--story KEY`, `--max-stories N`, `--dry-run`. `--spec <folder>` forces **stories mode** (folder+id dispatch off `<folder>/stories.yaml`), overriding `[stories].source`; `--story` then filters by story id. |
| `bmad-loop sweep` | Triage + execute open `deferred-work.md` entries. `--no-prompt`, `--decisions-only`, `--max-bundles N`, `--repeat`, `--max-cycles N`, `--dry-run`. |
| `bmad-loop resume <run-id>` | Continue a run paused at a gate, escalation, or interruption. |
Expand Down Expand Up @@ -288,7 +289,7 @@ uv tool upgrade bmad-loop --reinstall # follows main or you
bmad-loop init --project /path/to/project --force-skills
```

Your `.bmad-loop/policy.toml` is left untouched on upgrade — new keys are optional and fall back to their defaults, so configs survive. Check the [CHANGELOG / releases](https://github.com/bmad-code-org/bmad-loop/releases) for what changed between tags.
Your `.bmad-loop/policy.toml` is left untouched on upgrade — new keys are optional and fall back to their defaults, so configs survive. `init` now also gitignores policy.toml (it is per-machine: it carries the `[mux] backend` choice); if yours is already committed, run `git rm --cached .bmad-loop/policy.toml` once to stop sharing it (your local copy is kept). Check the [CHANGELOG / releases](https://github.com/bmad-code-org/bmad-loop/releases) for what changed between tags.

To remove bmad-loop from a project, see [Uninstalling](docs/setup-guide.md#uninstalling) — it reverses what `init` laid down (state, skills, hooks, gitignore) and uninstalls the tool.

Expand Down
4 changes: 2 additions & 2 deletions docs/FEATURES.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ See [README.md](../README.md) for the narrative overview and [setup-guide.md](se
### Multi-CLI / multi-agent support

- Generic adapter drives any CLI fitting the injection + hook-signal transport; CLI specifics live in declarative TOML profiles. Two independent axes: the **CLI** (`CodingCLIAdapter` + profile) and the **terminal transport** (`TerminalMultiplexer`) — tmux is the only backend today, behind a pluggable seam so a native-Windows backend can be added without touching the engine (see the [adapter authoring guide](adapter-authoring-guide.md#two-axes-cli-vs-transport)).
- The OS is abstracted by a **registry of seams**, each selecting an implementation by platform (with a test-override env var) and extended by a single registration line: the terminal multiplexer (`register_multiplexer`), the process-lifecycle `ProcessHost` (`register_process_host` — `terminate`/`force_kill`/`is_alive`/`identity`), and the hook interpreter (`ProcessHost.hook_interpreter()`); `bmad-loop validate` runs a platform preflight over them. Porting to a new OS is new files + registrations, no core edits — see [Porting bmad-loop to a new OS](porting-to-a-new-os.md).
- The OS is abstracted by a **registry of seams**, each selecting an implementation by platform (with a test-override env var) and extended by a single registration line: the terminal multiplexer (`register_multiplexer`, with availability-aware selection: env var → persisted `[mux] backend` via `bmad-loop mux set` → platform default → first available platform match), the process-lifecycle `ProcessHost` (`register_process_host` — `terminate`/`force_kill`/`is_alive`/`identity`), and the hook interpreter (`ProcessHost.hook_interpreter()`); `bmad-loop validate` runs a platform preflight over them. Porting to a new OS is new files + registrations, no core edits — see [Porting bmad-loop to a new OS](porting-to-a-new-os.md).
- Supported, E2E-verified: `claude` (reference), `codex` (≥ 0.139), `gemini` (≥ 0.46), `copilot` (GitHub Copilot CLI ≥ 2026-02 — the `copilot` binary, not the VS Code extension; `agentStop` turn-end, `-i` interactive launch, `--allow-all-tools`; pin a capable model — the free GPT-5 mini default is unreliable for multi-step skills).
- Experimental, probe-required: `antigravity` (Google's `agy` ≥ 1.0.16) — `-i` interactive launch, `Stop` turn-end hook (flat handler in `.agents/hooks.json`, no SessionStart/SessionEnd), `--dangerously-skip-permissions` for unattended runs; `usage_parser = "none"` until a transcript parser is written. Verify against your `agy` build with `probe-adapter antigravity`.
- Per-stage CLI/model overrides: run dev on one CLI/model, review on another (`[adapter.dev]`, `[adapter.review]`, `[adapter.triage]`).
Expand Down Expand Up @@ -165,7 +165,7 @@ See [README.md](../README.md) for the narrative overview and [setup-guide.md](se

### Setup & install

- `bmad-loop init` installs the five `bmad-loop-*` skills (`.claude/skills/` and/or `.agents/skills/`), the hook relay, `.bmad-loop/policy.toml`, and a runs-dir gitignore. Flags: `--cli` (repeatable), `--no-skills`, `--force-skills`.
- `bmad-loop init` installs the five `bmad-loop-*` skills (`.claude/skills/` and/or `.agents/skills/`), the hook relay, `.bmad-loop/policy.toml`, and a gitignore covering the runs dir, plugin caches, and policy.toml itself (per-machine config). Flags: `--cli` (repeatable), `--no-skills`, `--force-skills`.
- `bmad-loop validate` preflights every prerequisite: BMAD config, sprint-status, git, tmux, CLI binary, hook registration.
- Non-invasive: drives the upstream `bmad-dev-auto` skill unmodified — there is no fork to keep in sync — and review is just a re-invocation of it on the `done` spec. Your standard BMAD install is never modified.

Expand Down
31 changes: 20 additions & 11 deletions docs/ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,11 @@ obtained from `get_multiplexer()`; the tmux backend — argv + spawn primitive i
`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`, selected by platform with a `BMAD_LOOP_MUX_BACKEND` override) rather
than being hardcoded into `get_multiplexer()`. The process-lifecycle POSIX-isms moved behind a
(`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`,
Expand All @@ -31,15 +34,21 @@ held by a CI portability guard (`tests/test_portability_guard.py`). **WSL alread
— it _is_ Linux, so it takes every fast path unchanged; this is purely about a future _native_
Windows host.

The remaining work is a real non-tmux backend (a "psmux"-style multiplexer) that implements
the `TerminalMultiplexer` contract on native Windows and registers itself for `win32`. The
seams are designed so this slots in as **new files + one registration line each, 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). 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](porting-to-a-new-os.md); the deep transport contract is in
the [adapter authoring guide](adapter-authoring-guide.md#the-transport-contract-for-a-backend-author).
The remaining work is the native-Windows backend itself. Two candidates are in flight, and
they are **sibling tmux-family backends**, not stages of one plan: `psmux` (drives psmux's
tmux-compatible shim via pwsh) and `tmux-windows` (#85; drives the tmux-windows port) — both
subclass `BaseTmuxBackend`, both register for `win32`, and both invoke a binary literally
named `tmux`, which is exactly why selection is availability-aware with discriminating
`available()` probes (psmux → `which("psmux") and which("tmux") and which("pwsh")`;
tmux-windows → `which("tmux") and not which("psmux")`) and an explicit
`bmad-loop mux set <name>` tie-break. The seams are designed so each 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). 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](porting-to-a-new-os.md); the deep transport
contract is in the
[adapter authoring guide](adapter-authoring-guide.md#the-transport-contract-for-a-backend-author).

**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
Expand Down
Loading
Loading