Skip to content

Release 0.7.6#23

Merged
pbean merged 9 commits into
mainfrom
release/0.7.6
Jun 29, 2026
Merged

Release 0.7.6#23
pbean merged 9 commits into
mainfrom
release/0.7.6

Conversation

@pbean

@pbean pbean commented Jun 28, 2026

Copy link
Copy Markdown
Collaborator

Release 0.7.6 — the platform-seam closeout series (multiplexer registry + ProcessHost) plus its documentation.

Changed

  • OS abstracted behind a registry of seams — a non-tmux/native-Windows port is now new files + one registration line each, no core edits. Multiplexer selected via register_multiplexer (BMAD_AUTO_MUX_BACKEND override) instead of hardcoded in get_multiplexer(); tmux split into a reusable BaseTmuxBackend extension point (one overridable _run() primitive) + thin TmuxMultiplexer POSIX leaf.
  • Process lifecycle behind a ProcessHost seam — terminate / force-kill / liveness / PID-reuse-identity route through get_process_host() (BMAD_AUTO_PROCESS_HOST override); WindowsProcessHost ships ready to register. Hook registration takes its interpreter prefix from ProcessHost.hook_interpreter() (no hardcoded python3), and bmad-auto validate runs a platform preflight. Linux/macOS/WSL behavior unchanged.
  • Unity plugin teardown delegates pid lifecycle to ProcessHost and helper scripts run under sys.executable (may import automator seams).

Added

  • Consolidated porting guide mapping the four OS seams, their registries + test-override env vars, and what a native-Windows port costs end to end; adapter-/plugin-authoring guides, ROADMAP, README, and FEATURES updated to the post-registry world.

Release mechanics

  • Version stamped to 0.7.6 across all files; CHANGELOG curated; uv.lock + skill forks reseeded; screenshots/demo regenerated (tui touched by the seam refactors).
  • trunk check clean; release + portability-guard + module-skills-sync tests pass.

Once merged to main, the Release workflow auto-creates the v0.7.6 tag and GitHub release from the CHANGELOG.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Introduced a pluggable OS-seam registry for terminal multiplexer and process lifecycle selection (with override via env vars).
    • validate now performs a platform preflight that reports backend readiness and the selected process host.
  • Bug Fixes
    • Improved run stopping and Unity teardown to guard against PID reuse before escalating to force-kill.
    • Hook/helper scripts now run under the app’s Python interpreter for consistent behavior.
  • Documentation
    • Added a “Porting bmad-auto to a new OS” guide and refreshed setup/feature/adapter/plugin/roadmap references.
  • Chores
    • Bumped version to 0.7.6 across the package and manifests.

pbean and others added 7 commits June 28, 2026 13:13
Phase A of the adapter-seam close-out: funnel every tmux invocation through
one overridable spawn primitive so a tmux-family backend (a future native-
Windows psmux) can subclass it without editing tmux_backend.py.

- New adapters/tmux_base.py :: BaseTmuxBackend holds all argv construction and
  every contract method, routed through a single _run() primitive (_tmux uses
  check=True; the ~14 tolerant sites use check=False, keeping their existing
  which-guards and exception handling). TmuxError/TMUX_TIMEOUT_S/
  PARKED_RETURN_DETACH move here.
- tmux_backend.py slims to TmuxMultiplexer(BaseTmuxBackend) plus back-compat
  re-exports (subprocess/shutil/TmuxError/TMUX_TIMEOUT_S/PARKED_RETURN_DETACH).
- Portability guard: TMUX_BACKEND string -> TMUX_BACKENDS set covering both
  files; the sole ["tmux", ...] literal now lives in tmux_base._run.
- Retarget test monkeypatches tmux_backend.{subprocess,shutil} -> tmux_base
  (the spawn seam moved modules).

Behavior-preserving on POSIX. Full suite green (1119 passed); trunk clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replace the hardcoded TmuxMultiplexer construction in get_multiplexer() with a
tiny registry: backends self-register via register_multiplexer(name, matches,
factory) and are selected by platform match or forced by name through the
BMAD_AUTO_MUX_BACKEND env var. The tmux backend registers itself; tmux stays the
default everywhere except win32, with a safe tmux fallback, so POSIX behavior is
unchanged.

Phase B of the adapter-seam close-out: an out-of-tree backend now registers at
import with zero core edits, and a bundled one (the in-flight psmux) costs only
its own registration line plus one import — no edit to the selection policy.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The kill/liveness primitives branched on sys.platform inline in
platform_util, and stop_run had no way to force-kill a wedged engine — so a
native-Windows backend (PR #19) would have to edit core. Introduce a
ProcessHost seam (terminate / force_kill / is_alive / identity) with per-OS
impls and a name-keyed registry mirroring the multiplexer backend selection,
so adding an OS is a new subclass + one registration line.

stop_run now escalates: an engine that ignores SIGTERM past the grace window
is SIGKILL'd — but only while host.identity(pid) still matches the value
recorded at stop-time (a pid-reuse guard); otherwise it raises the new
StopRunError rather than risk an unrelated process. This is a deliberate POSIX
behavior change, pinned by new tests. The graceful-first / single-writer-of-
stopped invariant is unchanged.

platform_util keeps terminate_pid/pid_alive as thin back-compat shims over the
host; detach_kwargs stays put. The TUI worker widens its except to surface
StopRunError/ProcessHostError. The portability guard swaps platform_util for
process_host in KILL_PROBE_ALLOW and allows its Linux /proc identity read.

Unity teardown de-dup is deferred: unity_teardown.py runs under a bare python3
and can't reliably import the package.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The hook-registration sites in install/probe hardcoded `python3`, and
`cmd_validate` hardcoded a `tmux` PATH check — two more axes a native
backend (psmux PR #19) would have to branch on `sys.platform` to cross.

Route both through the platform-selected seams so a new OS registers
rather than edits core:

- Add `ProcessHost.hook_interpreter()` (POSIX `python3`; Windows
  `uv run --no-project python`); install/probe interpolate it instead
  of a `python3` literal. POSIX output is byte-for-byte unchanged.
- Extract `_platform_preflight()` in cli.py: ask the multiplexer
  backend (`available()`/`version()`) and name the process host,
  replacing the hardcoded `tmux` probe in `cmd_validate`.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The Unity teardown re-implemented `_terminate_pid`/`_hard_kill_pid`/
`_alive`/`_taskkill` — the duplication the ProcessHost seam was meant
to retire. Delegate to `get_process_host()` and keep only the
Unity-specific `_lingering_pids*` worktree-discovery in the file.

To make the import safe from the spawned helper, run plugin scripts
under the orchestrator's own interpreter (`sys.executable`) instead of
a PATH-resolved `python3` — otherwise a pipx-style install (PATH
`python3` lacks the package) would crash the best-effort teardown.

Deltas: Windows force-kill now adds `/T` (reaps the leaked MCP
server's child tree); `pid <= 0` is guarded. The sweep keeps its exact
terminate -> poll -> force-kill-survivors shape. Drops the now-unused
unity entry from the portability guard's KILL_PROBE_ALLOW.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…cessHost)

Add docs/porting-to-a-new-os.md mapping the four OS seams (terminal
multiplexer, ProcessHost lifecycle, hook interpreter, validate preflight),
their registries and override env vars, and the end-to-end native-Windows
port cost. Refresh the adapter- and plugin-authoring guides, ROADMAP,
setup-guide, README, docs index, and FEATURES to the post-registry world:
register_multiplexer/register_process_host instead of "return from
get_multiplexer()", helper scripts running under sys.executable and using
get_process_host() for pid lifecycle, and the BMAD_AUTO_MUX_BACKEND /
BMAD_AUTO_PROCESS_HOST overrides.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jun 28, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@pbean, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 30 minutes and 31 seconds. Learn how PR review limits work.

Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file).

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits.

🚦 How do rate limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 20e9ea0f-0d27-451f-b46b-b40b29da54a2

📥 Commits

Reviewing files that changed from the base of the PR and between dcf04ed and f69b6d8.

📒 Files selected for processing (2)
  • src/automator/cli.py
  • tests/test_cli.py

Walkthrough

Adds ProcessHost and multiplexer registries, refactors tmux into a shared base, routes hook and lifecycle operations through the new seams, adds CLI platform preflight, updates tests and docs, and bumps versions to 0.7.6.

Changes

OS Seam Registry

Layer / File(s) Summary
Docs and version bump
CHANGELOG.md, README.md, docs/*, module.yaml, pyproject.toml, src/automator/__init__.py, .claude-plugin/marketplace.json, src/automator/data/skills/bmad-auto-setup/assets/module.yaml
Release notes, docs, porting guide content, and version fields were updated to 0.7.6.
Multiplexer registry and tmux base
src/automator/adapters/multiplexer.py, src/automator/adapters/tmux_base.py, src/automator/adapters/tmux_backend.py
Backend selection now uses a registry and env override, and the tmux implementation is split into a shared base plus a thin adapter subclass.
ProcessHost seam and consumers
src/automator/process_host.py, src/automator/platform_util.py, src/automator/runs.py, src/automator/tui/app.py, src/automator/tui/data.py, src/automator/data/plugins/unity/unity_teardown.py
Process lifecycle is routed through ProcessHost, including identity-checked stop escalation, liveness checks, and Unity teardown cleanup.
Hook interpreter routing
src/automator/install.py, src/automator/probe.py, src/automator/data/plugins/unity/unity_plugin.py
Hook and helper-script command generation now uses the selected process host interpreter, and Unity helpers run under sys.executable.
CLI platform preflight
src/automator/cli.py
Validation now probes the selected multiplexer backend and process host, and stop/delete/archive commands catch process-host failures.
Tests for new seams
tests/test_process_host.py, tests/test_backend_registry.py, tests/test_runs.py, tests/test_cli.py, tests/test_install.py, tests/test_engine_plugin.py, tests/test_tui_launch.py, tests/test_tui_data.py, tests/test_multiplexer.py, tests/test_generic_tmux.py, tests/test_platform_util.py, tests/test_portability_guard.py
New and updated tests cover host selection, backend registry behavior, stop-run escalation, CLI preflight, hook interpreter selection, Unity teardown, seam migration, and portability allowlists.

Sequence Diagram(s)

sequenceDiagram
  participant cli.py
  participant multiplexer.py
  participant process_host.py
  participant validate
  cli.py->>multiplexer.py: get_multiplexer()
  cli.py->>process_host.py: get_process_host()
  multiplexer.py-->>validate: available()/version()
  process_host.py-->>validate: selected host
  validate-->>cli.py: notes/problems
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • bmad-code-org/bmad-auto#11: Introduces the initial multiplexer seam that this PR expands into a registry with backend selection overrides.
  • bmad-code-org/bmad-auto#6: Touches probe-mode hook registration, which this PR updates to use the process-host hook interpreter.
  • bmad-code-org/bmad-auto#13: Changes tui/data.py, which this PR also updates for liveness routing and matching tests.

Poem

🐇 I hopped through seams with a tidy little thump,
New hosts and backends now give each OS its jump.
The hooks all listen to the chosen interpreter’s tune,
And tmux keeps its secrets in a base-made moon.
With docs and tests aligned, the release bell rings clear,
0.7.6 is here! 🎉

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 28.25% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title correctly identifies this PR as the 0.7.6 release and is concise and clear.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch release/0.7.6

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@augmentcode

augmentcode Bot commented Jun 28, 2026

Copy link
Copy Markdown
🤖 Augment PR Summary

Summary: This PR publishes the 0.7.6 release, completing the “platform seams” work to make OS-specific behavior pluggable without editing core engine code.

Changes:

  • Bumped version references across packaging/metadata to 0.7.6 and updated the changelog.
  • Introduced a registry-based multiplexer selection API (register_multiplexer/get_multiplexer) with an env override (BMAD_AUTO_MUX_BACKEND) and cache invalidation.
  • Refactored tmux into a shared BaseTmuxBackend (single spawn primitive) plus a thin POSIX TmuxMultiplexer leaf.
  • Added a new ProcessHost seam for terminate/force-kill/liveness/identity, including a Windows host and override (BMAD_AUTO_PROCESS_HOST).
  • Routed run stopping and Unity teardown through ProcessHost with PID-reuse identity guards to avoid unsafe force-kills.
  • Updated hook registration to use the platform-selected interpreter/quoting via ProcessHost, and added a validate preflight that reports backend readiness + selected host.
  • Added/updated tests covering registry selection, cache behavior, preflight reporting, and stop/teardown escalation safety.
  • Expanded documentation (new OS porting guide; refreshed setup/roadmap/authoring guides) to reflect the new seam/registry model.

Technical Notes: Both seam selectors are lru_cached; registration invalidates the cache so late registrations take effect, and forced overrides now fail fast when unknown.

🤖 Was this summary useful? React with 👍 or 👎

@augmentcode augmentcode Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review completed. 5 suggestions posted.

Fix All in Augment

Comment augment review to trigger a new review at any time.

Comment thread src/automator/runs.py
Comment thread src/automator/process_host.py
Comment thread src/automator/cli.py Outdated
Comment thread src/automator/adapters/multiplexer.py Outdated
Comment thread docs/setup-guide.md

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 8

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/automator/adapters/multiplexer.py`:
- Around line 185-194: `register_multiplexer()` currently only appends to
`_BACKENDS`, so a previously cached result from `get_multiplexer()` can block
later-registered backends from being selected. Update `register_multiplexer()`
in `multiplexer.py` to invalidate the cached singleton when a new backend is
added, so the registry API works regardless of call order. Use the existing
`_BACKENDS` and `get_multiplexer()`/cache mechanism as the integration points.

In `@src/automator/adapters/tmux_base.py`:
- Around line 168-174: The shell trailer built in the tmux base adapter
interpolates return_opt directly into sh -c text, which allows the option key to
affect the command string. Update the return_trailer construction in the
tmux_base adapter to safely quote or shell-escape return_opt before embedding
it, keeping the rest of the logic in the trailer unchanged. Use the existing
return_trailer assembly near the tmux show-options / detach-client /
switch-client flow as the place to apply the fix.

In `@src/automator/cli.py`:
- Around line 111-140: The _platform_preflight() probe should not let
multiplexer readiness checks abort validation if the selected backend
misbehaves. In the backend block that calls get_multiplexer(), available(), and
version(), wrap the probe in a try/except Exception and append the exception
text to problems instead of letting it propagate. Keep the existing
notes/problems behavior intact, and reference _platform_preflight(),
get_multiplexer(), available(), and version() when updating the flow.

In `@src/automator/data/plugins/unity/unity_teardown.py`:
- Around line 162-176: The teardown logic in the process-killing loop can
accidentally act on a reused PID because `host.is_alive(pid)` only checks
existence. In the `unity_teardown.py` flow around `get_process_host()`,
`terminate()`, and `force_kill()`, snapshot `host.identity(pid)` before sending
terminate, then during the grace-period polling and final escalation only
proceed if the current identity still matches the saved one. This keeps the
`pids` cleanup logic from killing an unrelated process that reused the same PID.

In `@src/automator/install.py`:
- Around line 96-101: The hook command formatting in install/probe is using
POSIX quoting directly, which can break on Windows paths with spaces. Move the
hook-command string निर्माण behind ProcessHost so each host can apply its own
quoting rules, and update the call sites in install.py’s hook setup and
probe.py’s hook command generation to use that shared helper instead of
shlex.quote. Use the existing hook-related symbols like get_process_host(),
hook_interpreter(), and the hook command construction around HOOK_SCRIPT_REL to
locate and refactor the logic.

In `@src/automator/process_host.py`:
- Around line 235-240: The host चयन logic that reads BMAD_AUTO_PROCESS_HOST
should fail fast when the override is set but does not match any registered
host. In the host-selection helper that iterates over _HOSTS and currently falls
back to PosixProcessHost(), first check whether forced is set and, if so, raise
an explicit error when no factory name matches instead of silently returning the
POSIX default. Keep the normal platform-based matching path unchanged when
BMAD_AUTO_PROCESS_HOST is unset.

In `@tests/test_engine_plugin.py`:
- Around line 386-387: The lingering-PID test setup in the _force_kill_lingering
path uses a hardcoded PID that can match the test runner and get filtered out by
os.getpid(), causing flaky failures. Update the affected tests around
_lingering_pids to generate a PID dynamically from the current process id (for
example, a value guaranteed to differ from os.getpid()) instead of using 4242.
Keep the monkeypatching of mod.time.sleep and the same test flow, but ensure the
fake lingering PID cannot collide with the active process.

In `@tests/test_process_host.py`:
- Around line 73-76: The default-host test is hardcoded to PosixProcessHost, but
get_process_host() picks the first matching host based on sys.platform, so the
assertion must be platform-aware. Update test_default_host_is_posix_on_posix to
branch on sys.platform and assert PosixProcessHost on POSIX platforms and
WindowsProcessHost on Windows, while keeping the monkeypatch and
get_process_host.cache_clear() setup intact.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: f8b3f588-2a01-4f16-9813-3f1b400717ba

📥 Commits

Reviewing files that changed from the base of the PR and between 8f21f10 and b58fe59.

⛔ Files ignored due to path filters (9)
  • docs/images/dashboard.png is excluded by !**/*.png
  • docs/images/dashboard.svg is excluded by !**/*.svg
  • docs/images/demo.gif is excluded by !**/*.gif
  • docs/images/settings.svg is excluded by !**/*.svg
  • docs/images/start-run-modal.png is excluded by !**/*.png
  • docs/images/start-run-modal.svg is excluded by !**/*.svg
  • docs/images/sweep-decision.png is excluded by !**/*.png
  • docs/images/sweep-decision.svg is excluded by !**/*.svg
  • uv.lock is excluded by !**/*.lock
📒 Files selected for processing (39)
  • .claude-plugin/marketplace.json
  • CHANGELOG.md
  • README.md
  • docs/FEATURES.md
  • docs/README.md
  • docs/ROADMAP.md
  • docs/adapter-authoring-guide.md
  • docs/plugin-authoring-guide.md
  • docs/porting-to-a-new-os.md
  • docs/setup-guide.md
  • module.yaml
  • pyproject.toml
  • src/automator/__init__.py
  • src/automator/adapters/multiplexer.py
  • src/automator/adapters/tmux_backend.py
  • src/automator/adapters/tmux_base.py
  • src/automator/cli.py
  • src/automator/data/plugins/unity/unity_plugin.py
  • src/automator/data/plugins/unity/unity_teardown.py
  • src/automator/data/skills/bmad-auto-setup/assets/module.yaml
  • src/automator/install.py
  • src/automator/platform_util.py
  • src/automator/probe.py
  • src/automator/process_host.py
  • src/automator/runs.py
  • src/automator/tui/app.py
  • src/automator/tui/data.py
  • tests/test_backend_registry.py
  • tests/test_cli.py
  • tests/test_engine_plugin.py
  • tests/test_generic_tmux.py
  • tests/test_install.py
  • tests/test_multiplexer.py
  • tests/test_platform_util.py
  • tests/test_portability_guard.py
  • tests/test_process_host.py
  • tests/test_runs.py
  • tests/test_tui_data.py
  • tests/test_tui_launch.py

Comment thread src/automator/adapters/multiplexer.py
Comment thread src/automator/adapters/tmux_base.py
Comment thread src/automator/cli.py
Comment thread src/automator/data/plugins/unity/unity_teardown.py
Comment thread src/automator/install.py Outdated
Comment thread src/automator/process_host.py
Comment thread tests/test_engine_plugin.py Outdated
Comment thread tests/test_process_host.py Outdated
… seams

Validated the Augment/CodeRabbit review on PR #23 and fixed the 10 valid
findings (1 was a false positive — the balanced parens in setup-guide.md).

- cli: catch StopRunError/ProcessHostError in stop/delete/archive so a
  pid-reuse refusal returns a clean error instead of a traceback (A)
- cli: guard _platform_preflight's backend available()/version() probe so a
  misbehaving backend surfaces as a problem, not a crashed `validate` (C)
- multiplexer: set _BUILTINS_LOADED only after a successful load so a
  transient failure retries instead of latching an empty registry (D)
- process_host/multiplexer: fail fast when BMAD_AUTO_PROCESS_HOST /
  BMAD_AUTO_MUX_BACKEND names no registered backend, instead of a silent
  (and on Windows unsafe) POSIX/tmux fallback (B)
- process_host/multiplexer: register_* now invalidate the get_* lru_cache so
  a later registration is honored regardless of call order (F)
- tmux_base: shlex.quote return_opt before embedding it in the sh -c trailer (G)
- unity teardown: snapshot identity() before terminate and only force-kill on
  a still-matching identity, mirroring runs.stop_run's pid-reuse guard (H)
- process_host: add a shell_quote() seam (POSIX shlex / Windows list2cmdline)
  and route the install/probe hook-command quoting through it (I)
- tests: derive the fake lingering PID from os.getpid() (J); make the
  default-host assertion platform-aware (K); add regression tests for the
  invalid-override, cache-invalidation, identity-mismatch, and shell_quote paths

Also moved tmux's registration from an import side effect into
_load_builtin_backends (inline, like process_host._load_builtin_hosts) so the
registry can be cleared and re-loaded deterministically in tests.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@pbean

pbean commented Jun 28, 2026

Copy link
Copy Markdown
Collaborator Author

@CodeRabbit review
augment review

@coderabbitai

coderabbitai Bot commented Jun 28, 2026

Copy link
Copy Markdown

@pbean Reviewing the latest changes now.

✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/automator/cli.py (1)

121-141: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Catch seam-selection errors in preflight.

Line 127 calls get_multiplexer() and Line 141 calls get_process_host() outside the probe's error handling. Both selectors can raise on an invalid BMAD_AUTO_MUX_BACKEND / BMAD_AUTO_PROCESS_HOST, so bmad-auto validate still aborts instead of surfacing a preflight problem.

Proposed fix
 def _platform_preflight() -> tuple[list[str], list[str]]:
-    from .adapters.multiplexer import get_multiplexer
+    from .adapters.multiplexer import MultiplexerError, get_multiplexer
     from .process_host import get_process_host
 
     notes: list[str] = []
     problems: list[str] = []
 
-    backend = get_multiplexer()
-    label = type(backend).__name__
     try:
-        if backend.available():
-            version = backend.version()
-            notes.append(f"multiplexer {label} available" + (f" ({version})" if version else ""))
-        else:
-            problems.append(
-                f"multiplexer {label} unavailable — its transport binary is not on PATH; "
-                f"see `bmad-auto diagnose`"
-            )
-    except Exception as e:  # noqa: BLE001 — a misbehaving backend must not abort validate
-        problems.append(f"multiplexer {label} readiness check failed: {e}")
-
-    notes.append(f"process host: {type(get_process_host()).__name__}")
+        backend = get_multiplexer()
+    except MultiplexerError as e:
+        problems.append(str(e))
+    else:
+        label = type(backend).__name__
+        try:
+            if backend.available():
+                version = backend.version()
+                notes.append(f"multiplexer {label} available" + (f" ({version})" if version else ""))
+            else:
+                problems.append(
+                    f"multiplexer {label} unavailable — its transport binary is not on PATH; "
+                    f"see `bmad-auto diagnose`"
+                )
+        except Exception as e:  # noqa: BLE001 — a misbehaving backend must not abort validate
+            problems.append(f"multiplexer {label} readiness check failed: {e}")
+
+    try:
+        notes.append(f"process host: {type(get_process_host()).__name__}")
+    except ProcessHostError as e:
+        problems.append(str(e))
     return notes, problems
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/automator/cli.py` around lines 121 - 141, Catch selector failures in the
preflight probe so invalid BMAD_AUTO_MUX_BACKEND or BMAD_AUTO_PROCESS_HOST
values do not abort validate. Move the get_multiplexer() and get_process_host()
lookups in src/automator/cli.py into the existing preflight error handling
around the readiness checks, and record a problem message instead of letting
exceptions escape. Keep the current notes/problems flow in the validate probe
and ensure backend/process host selection errors are reported through problems
using the existing get_multiplexer, get_process_host, and bmad-auto validate
path.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@src/automator/cli.py`:
- Around line 121-141: Catch selector failures in the preflight probe so invalid
BMAD_AUTO_MUX_BACKEND or BMAD_AUTO_PROCESS_HOST values do not abort validate.
Move the get_multiplexer() and get_process_host() lookups in
src/automator/cli.py into the existing preflight error handling around the
readiness checks, and record a problem message instead of letting exceptions
escape. Keep the current notes/problems flow in the validate probe and ensure
backend/process host selection errors are reported through problems using the
existing get_multiplexer, get_process_host, and bmad-auto validate path.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 281cd66d-e91b-4a91-83e5-b1a5cb42ecfe

📥 Commits

Reviewing files that changed from the base of the PR and between b58fe59 and dcf04ed.

📒 Files selected for processing (11)
  • src/automator/adapters/multiplexer.py
  • src/automator/adapters/tmux_backend.py
  • src/automator/adapters/tmux_base.py
  • src/automator/cli.py
  • src/automator/data/plugins/unity/unity_teardown.py
  • src/automator/install.py
  • src/automator/probe.py
  • src/automator/process_host.py
  • tests/test_backend_registry.py
  • tests/test_engine_plugin.py
  • tests/test_process_host.py
🚧 Files skipped from review as they are similar to previous changes (5)
  • src/automator/probe.py
  • src/automator/data/plugins/unity/unity_teardown.py
  • src/automator/install.py
  • src/automator/adapters/tmux_base.py
  • src/automator/process_host.py

@augmentcode augmentcode Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review completed. 1 suggestion posted.

Fix All in Augment

Comment augment review to trigger a new review at any time.

Comment thread src/automator/cli.py Outdated
notes: list[str] = []
problems: list[str] = []

backend = get_multiplexer()

@augmentcode augmentcode Bot Jun 28, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

src/automator/cli.py:127: _platform_preflight() calls get_multiplexer() (and later get_process_host()) outside the try/except, so a misconfigured override (e.g. unknown BMAD_AUTO_MUX_BACKEND / BMAD_AUTO_PROCESS_HOST) can crash bmad-auto validate with an uncaught exception instead of reporting it as a preflight problem.

Severity: medium

Other Locations
  • src/automator/cli.py:141

Fix This in Augment

🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Valid — fixed in f69b6d8. Both seam selection calls (get_multiplexer() and get_process_host()) are now inside per-seam try blocks, so a bad BMAD_AUTO_MUX_BACKEND/BMAD_AUTO_PROCESS_HOST is reported as a preflight problem instead of aborting validate. Verified end-to-end: BMAD_AUTO_MUX_BACKEND=bogus … validate now prints multiplexer preflight failed: …matches no registered backend; known: tmux and exits cleanly. Regression tests added.

Round-1's fail-fast change (get_multiplexer/get_process_host raise on an
unknown BMAD_AUTO_MUX_BACKEND/BMAD_AUTO_PROCESS_HOST) combined with a guard
that only wrapped available()/version() left both *selection* calls outside
the try, so a bad override crashed `bmad-auto validate` with an uncaught
traceback instead of reporting it — the very thing the preflight exists to do
gracefully. Flagged by both reviewers (Augment inline, CodeRabbit outside-diff).

Wrap each seam (multiplexer, process host) in its own try so a selection or
readiness failure becomes a reported problem and one seam's failure still lets
the other report. Broad Exception (matching the existing readiness guard) keeps
validate crash-proof without new imports.

Adds regression tests that a raising get_multiplexer()/get_process_host() is
surfaced in problems rather than propagated.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@pbean

pbean commented Jun 29, 2026

Copy link
Copy Markdown
Collaborator Author

@coderabbitai Addressed your outside-diff finding on _platform_preflight() (cli.py 121-141, "Catch seam-selection errors in preflight") in f69b6d8. Both get_multiplexer() and get_process_host() selection calls are now wrapped per-seam so a bad override surfaces as a validate problem rather than an uncaught traceback. I used a broad except Exception (matching the existing readiness guard) rather than the specific-type diff — note the proposed diff referenced ProcessHostError in an except clause without importing it, which would NameError.

@coderabbitai

coderabbitai Bot commented Jun 29, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

@pbean Thanks — that addresses my concern.

Catching seam-selection failures per seam in _platform_preflight() and surfacing bad overrides as validate problems is the right behavior here. Using except Exception for consistency with the existing readiness guard also makes sense, and you're right that my example diff should have imported ProcessHostError or it would have raised a NameError.

🐇👍


✏️ Learnings added
Learnt from: pbean
URL: https://github.com/bmad-code-org/bmad-auto/pull/23

Timestamp: 2026-06-29T00:02:56.143Z
Learning: In `src/automator/cli.py`, `_platform_preflight()` is intended to catch backend/host seam-selection failures from both `get_multiplexer()` and `get_process_host()` per seam and report bad override configuration as `validate` problems rather than allowing an uncaught traceback; using broad `except Exception` there matches the existing readiness guard pattern.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.


If you found this review helpful, would you consider giving us a shout-out on X?

Thank you for using CodeRabbit!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant