ZCode coding-CLI adapter for
bmad-loop — the deterministic
BMAD-METHOD implementation-phase orchestrator. Shipped out-of-tree: co-install
the package, and a zcode profile + adapter kind appear with zero bmad-loop
core edits.
Verified against bmad-loop 0.11.1 and zcode 0.16.5 (macOS, Apple silicon).
Every bmad-loop session launches ZCode headless one-shot in a tmux window:
zcode --prompt "Use the bmad-build-auto skill now: <story instructions>"
ZCode runs the single prompt at its default yolo permission mode and the
process exits when the turn ends — that exit is the completion signal. Dev
and review sessions synthesize their verdict from the bmad-build-auto spec
the run leaves on disk (the same _DevSynthesisMixin machinery the built-in
adapters use), gated by the pane-log proof-of-work check.
Prerequisites:
-
bmad-loop ≥ 0.11.1 (the adapter registry and
profile.adapterfield landed in the 0.10/0.11 line) -
A
zcodelauncher on PATH. The desktop app ships its CLI as a node script; wrap it once:# ~/.local/bin/zcode (adjust to your install location) #!/bin/sh exec node /Applications/ZCode.app/Contents/Resources/glm/zcode.cjs "$@"
The indirection absorbs app auto-updates rewriting the bundle.
Then co-install:
uv tool install bmad-loop --with git+https://github.com/iptton-ai/bmad-loop-adapter-zcodePoint a project's .bmad-loop/policy.toml at the profile:
[adapter]
name = "zcode"bmad-loop adapters should list zcode as a registered (external) kind, and
bmad-loop validate checks the reference against the live registry.
The adapter subclasses the built-in generic tmux adapter and reuses its
session lifecycle (task directory contract, cycle-artifact reset, pane tee,
grace-window teardown with straggler reaping) plus the upstream
_ResultFileMixin / _DevSynthesisMixin / EnvFaultMixin verdict machinery.
What it replaces is exactly the hook-driven wait loop, because of one pinned
fact:
zcode's headless
--promptruntime never fires workspace hooks. ZCode implements Claude-style hooks (zcode.json/.zcode/config.json,SessionStart/Stop/...), but they are wired into app-server/desktop sessions only — verified with trust granted viazcode hooks trust grantand withhooks.enabledat user level. The interactive TUI, for its part, cannot launch from the standalonezcode.cjsat all (@zcode/tuiresolves only inside the app bundle). Headless one-shot with process-exit completion is therefore the only transport an orchestrator can drive.
Known limitations (also recorded in the module docstring's degradation ledger):
- No mid-session token accounting. ZCode keeps model IO under
~/.zcode/cli/rollout/but exposes no per-session transcript path, so the profile shipsusage_parser = "none"— a blessed final answer upstream (antigravity is the precedent). A parser can ride a later release. - No nudges. A one-shot process reads no input after launch;
send_textis a documented no-op. - macOS-first. Developed and verified on macOS. Linux should work wherever the desktop app installs its CLI at a known path — reports welcome.
uv sync --extra dev # pytest into a venv alongside bmad-loop (from git)
uv run pytest -q # unit tests: fake binary over real tmux
uv run pytest -q tests/test_live.py # live smoke: skipped without a real zcodeThe unit suite drives a scripted fake zcode (absolute-path launcher, so no
tmux-server PATH games) through real tmux windows: completion-on-exit,
dead-on-arrival verdicts, timeout clock labels, task-id reuse resets, the dev
synthesis path, and the #261 proof-of-work refusal.
MIT. This is a community adapter, not an official ZCode or bmad-code-org
project — it registers against bmad-loop's documented out-of-tree seams
(bmad_loop.adapters / bmad_loop.profiles entry points).