Summary
On Windows, bmad-loop tui shows every run in the st column as ? (unknown status), regardless of whether the engine is alive, dead, or finished.
Root cause
psutil is only declared in the optional non-linux extra. But on win32 it is load-bearing, not optional:
- There is no
/proc, and os.kill(pid, 0) on win32 is destructive (CTRL_C_EVENT), so WindowsProcessHost — the host selected on win32 — probes liveness/identity exclusively through psutil.
- When psutil is absent,
_psutil() raises ProcessHostError, runs.probe_liveness() swallows it to "unknown", _classify() returns UNKNOWN, and status_cell() renders the ? glyph.
The default install path never pulls it: the bmad-loop-setup skill installs bmad-loop[tui], which does not include the non-linux extra. So a stock Windows setup always ends up with a TUI that cannot distinguish running/dead/finished — everything is ?.
Reproduction (with the tool's own interpreter, no psutil present)
pid,identity= 32592 None
probe_liveness= unknown # -> UNKNOWN -> `?`
The same probe from an environment that has psutil returns dead/alive correctly.
Fix
Make psutil a platform-scoped core dependency so every install path (pip, uv tool, the setup skill's [tui] extra) pulls it automatically on Windows:
dependencies = [
"pyyaml>=6.0",
"psutil>=7.2.2; sys_platform == 'win32'",
]
This keeps the Linux core dep-free and leaves the non-linux extra as the macOS opt-in (where psutil only improves identity/force-kill and liveness degrades gracefully to alive/dead without it). PR incoming from fix/win32-psutil-hard-dep.
Environment
- bmad-loop 0.8.1, Windows 11, installed via
uv tool install "bmad-loop[tui] @ git+..."
Summary
On Windows,
bmad-loop tuishows every run in thestcolumn as?(unknown status), regardless of whether the engine is alive, dead, or finished.Root cause
psutilis only declared in the optionalnon-linuxextra. But on win32 it is load-bearing, not optional:/proc, andos.kill(pid, 0)on win32 is destructive (CTRL_C_EVENT), soWindowsProcessHost— the host selected on win32 — probes liveness/identity exclusively through psutil._psutil()raisesProcessHostError,runs.probe_liveness()swallows it to"unknown",_classify()returnsUNKNOWN, andstatus_cell()renders the?glyph.The default install path never pulls it: the
bmad-loop-setupskill installsbmad-loop[tui], which does not include thenon-linuxextra. So a stock Windows setup always ends up with a TUI that cannot distinguish running/dead/finished — everything is?.Reproduction (with the tool's own interpreter, no psutil present)
The same probe from an environment that has psutil returns
dead/alivecorrectly.Fix
Make psutil a platform-scoped core dependency so every install path (pip,
uv tool, the setup skill's[tui]extra) pulls it automatically on Windows:This keeps the Linux core dep-free and leaves the
non-linuxextra as the macOS opt-in (where psutil only improves identity/force-kill and liveness degrades gracefully to alive/dead without it). PR incoming fromfix/win32-psutil-hard-dep.Environment
uv tool install "bmad-loop[tui] @ git+..."