bmad-loop
A deterministic ralph-loop orchestrator for the BMAD-METHOD implementation phase
Plain Python drives the loop — pick story → implement → adversarially review → verify → commit — while LLMs do only the creative work, inside disposable, fresh-context coding-agent sessions you can attach to and watch.
!Status: early open beta
!Python
!CLIs
!No LLM in the loop
!License: MIT
The live TUI dashboard — run picker, sprint tree, deferred-work ledger, per-story task table, and a tailing journal. Jump to the TUI tour ↓
A tour of the dashboard — walking the runs table, unfolding the sprint tree, opening a deferred-work entry, answering a decision a past sweep left unanswered, typing a story into the start-run modal, a sweep blocked on a decision, and scrolling the policy editor out to its worktree-isolation + config-seeding knobs. More on the TUI ↓
⚠️ Early open beta — experimental, and moving fast. bmad-loop is a young project that
only just started shipping publicly. Expect rough edges, docs that lag the code, and
breaking changes in any release while it is pre-1.0 — CLI flags, policy keys, on-disk
run state, and skill contracts can all shift between versions. It also drives real coding
agents that write and commit in your repository, so point it at work you can review and
roll back ([scm] isolation = "worktree" keeps a failed attempt off your main checkout),
pin a release tag if you want a stable base, and read the CHANGELOG before
upgrading. Bug reports and feedback are what the beta is for — open an
issue with bmad-loop diagnose output
attached, or come talk to us on Discord.
Why bmad-loop
Inspired by the original bmad-automator (a separate, legacy project), it takes a token-optimized approach in which the orchestrator is ordinary code rather than an LLM session in the control loop:
- 🧠 No LLM in the control loop. Story selection, retry budgets, gates, and completion checks are code, not prompts — so they're deterministic, debuggable, and free.
- 📡 No pane-scraping. Coding-agent hooks (
Stop/SessionStart/SessionEnd/PreCompact) write structured event files the orchestrator watches; skills in automation mode write a machine-readableresult.jsonat the end of each workflow. - 🔍 Trust nothing, verify everything. After each session the orchestrator checks artifacts on disk: spec frontmatter status, baseline-commit validity, non-empty diff, sprint-status sync, and _your_ test/lint commands before any commit. An exact recorded baseline passes; so does a uniquely resolved immutable descendant that is reachable from
HEAD, but its proof is measured after that commit and must be tracked, staged, or committed — untracked-only residue does not count. Deferred-work bundles retain their older-ancestor exception. In the default shared checkout, later tracked changes prove work exists but cannot identify which session made it;[scm] isolation = "worktree"preserves that provenance. - 📒 One source of truth.
sprint-status.yamlis the workflow ledger: the loop's dev skill flips only its story spec's status, the orchestrator mirrors that onto the board through a single idempotent, never-regress writer, and verification re-checks the stage after every session. - 🪟 Fresh context per step. Dev and review are separate sessions — review never inherits the implementer's context, so there's no anchoring bias.
- ♻️ Resumable & multi-agent. Every run is a resumable state machine on disk, and a generic tmux adapter drives
claude,codex,gemini,copilot, orantigravity(mix per stage). - 🌿 Optional worktree isolation. Opt in (
[scm] isolation = "worktree") and each story runs in its own git worktree/branch and merges back locally — your main checkout stays free while a run is in flight.
Requirements
- Python 3.11+, a terminal multiplexer (tmux is the bundled default; 3.2 is the supported minimum, not enforced at selection), git 2.34 or newer (the supported minimum, and this one _is_ enforced —
run,sweepandresumerefuse to start below it andvalidatereports it as a problem), and a supported coding CLI —claudeby default;codex,gemini,copilot, andantigravity(agy) via profiles. - Linux or macOS (or Windows via WSL, which _is_ Linux — it runs as-is). tmux is the bundled terminal-multiplexer backend (externals like the herdr adapter co-install as packages and self-register — see Terminal multiplexer backends), and all of it sits behind a pluggable registry of OS seams (transport, process lifecycle, hook interpreter) with availability-aware selection — env var → persisted
[mux] backendchoice (bmad-loop mux set) → platform default (psmuxon Windows,tmuxelsewhere) → 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. Native Windows is not yet shipped. - A BMAD v6 project (
_bmad/bmm/config.yaml, asprint-status.yamlfrombmad-sprint-planning) on BMAD-METHOD ≥ 6.10.0, with three skill sets installed (standard BMAD skills stay untouched):
bmad-build-auto, or a complete bmad-dev-auto on pre-rename releases. bmad-loop drives whichever is on disk under that name, so either era works with no config edit; the bare forwarding shim the rename leaves behind is refused as incomplete — it has neither step-04-review.md nor customize.toml — because a session dispatched into it stalls on an interactive migration gate.
- the review-layer skills its step-04 invokes inline — bmad-review-adversarial-general + bmad-review-edge-case-hunter, or the merged bmad-review skill that supersedes them in newer releases.
- the bmad-loop skill module from this repo (bmad-loop-resolve, bmad-loop-sweep) — see Installing the skill module.
Quick start
uv sync --extra tui # core is pyyaml-only; [tui] adds the dashboard
cd /path/to/your/bmad/project
bmad-loop init # installs bmad-loop-* skills + hooks + .bmad-loop/policy.toml + gitignore
bmad-loop validate # preflight: config, sprint-status, git, tmux, CLI, hooks
bmad-loop run --dry-run # print the plan without spawning anything
bmad-loop run # go
bmad-loop tui # …or drive everything from the dashboard
One-time setup: if the coding CLI has never run in the target project, start it once (claude) and accept the workspace-trust dialog (and any hooks-approval prompt) beforebmad-loop run. Spawned sessions can't answer first-run dialogs, and a pending dialog reads as a session timeout to the orchestrator.
Command reference
| Command | What it does |
| -------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 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 (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). --spec validates that folder's stories.yaml for a stories-mode run instead of the sprint-status queue. --json emits the preflight as a stable machine-readable document (see Scripting validate). |
| bmad-loop mux | List registered terminal-multiplexer backends — platform match, availability, version, and which one is selected (and why). mux set 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 adapters | List registered coding-CLI adapter kinds — name, builtin/external, whether the family drives a multiplexer, and which profiles select each — the CLI axis's counterpart to mux. Unlike mux there is no global choice to persist: a kind is selected per profile by its adapter field. A profile naming an unregistered kind, and any out-of-tree adapter/profile package that failed to load, get a warning: on stderr. |
| bmad-loop run | Drive the dev → review → verify → commit loop. --epic N, --story KEY, --max-stories N, --dry-run. --spec forces stories mode (folder+id dispatch off ), overriding [stories].source; --story then filters by story id. |
| bmad-loop sweep | Triage + execute open deferred-work.md entries. --only DW-1,DW-3 or --min-severity high selects the pre-triage universe; also supports --no-prompt, --decisions-only, --max-bundles N, --repeat, --max-cycles N, --dry-run. --archive [--before DATE] instead moves closed ledger entries to deferred-work-archive.md, leaving id-preserving stubs. |
| bmad-loop resume | Continue a run paused at a gate, escalation, or interruption. The resume command rendezvouses with delete/archive on the run lifecycle lock; if cleanup removed the run while resume waited, resume reports it missing without recreating files or launching an engine. |
| bmad-loop resolve | Resolve a CRITICAL escalation: open an interactive resolve agent to fix the frozen spec, then re-arm the story and resume — the resume is held when the correction provably has not reached the tree the re-drive reads (see Resolving a CRITICAL escalation). On an _intent gap_ the re-drive can resume review on the attempted change instead of re-implementing it. --story KEY, --no-interactive, --restore-patch (intent-gap patch-restore), --adopt-branch (finish the story from its kept worktree branch as-is, without re-running review, [verify] commands or pre_commit_gate workflows), --reverify (replay verify on a DEFERRED story's kept work, or an env-fault escalated one's at a replayable fault site, no dev session), --resume / --no-resume, --force (proceed when engine liveness is unverifiable; a provably-live engine still blocks). |
| bmad-loop decisions | Answer deferred-work decisions earlier sweeps left unanswered (skipped by --no-prompt, or an abandoned interactive sweep). Recorded so the next sweep acts on them without re-asking. --list shows them without answering; --json emits them as a stable machine-readable document — id, question, context, recommendation, and every option's key/label/effect/intent/resolution/bundle-name with a derived recommended flag. It implies the listing and never prompts, so a script can select an option by policy instead of scraping the text. |
| bmad-loop confirm | Complete a story parked at awaiting-operator once you have carried out the external actions it owes (buy the domain, publish the DNS record). Acknowledges each action in turn, writes the spec's ## Operator Confirmation audit section, advances spec and board to done, and commits the pair — nothing is re-driven. --list shows every parked story and what it owes; --yes skips the prompts; --reverify re-runs the project's [verify] commands first and blocks the confirmation if they fail; --json emits the parked set as a stable machine-readable document. Every write is checked and the spec is read back from disk, so a story is never declared done over a write that did not land; a confirmation interrupted before its board write is finished by re-running the command, with no second prompt and no second audit section. The index it reads is machine-local, so a park is confirmed on the machine that ran it. |
| bmad-loop list (ls) | List every run/sweep with its short ref, type, and status — the handle you pass to the commands below. --json emits a stable machine-readable document instead — one entry per run, oldest first (short ref, run id, type, started-at, liveness-aware status, paused stage); an empty runs dir yields a valid empty document. |
| bmad-loop status [ | Run + sprint summary with per-story token totals — cost-weighted, with the raw count alongside — plus a count of decisions awaiting an answer. A stories-mode run instead prints its stories board — id, live on-disk state, checkpoint markers, title. --json replaces all of that with a stable machine-readable document (see Scripting status). |
| bmad-loop diagnose [ (diag) | Emit a sanitized diagnostic dump of a run/sweep to hand maintainers when reporting a bug — phase/token/session histograms, escalation counts, adapter/model, env, and run-dir file sizes, with no code, spec content, prompts, transcripts, paths, or PII. Identifiers are pseudonymized to stable per-dump aliases and the output is re-scanned by a fail-closed leak check before writing; a stray pseudonymized identifier is auto-substituted with its alias (disclosed in the report), while PII/secret hits still refuse to emit. Defaults to the latest run. --all, --out, --max-journal-entries N; --json emits the dump as a stable JSON document (one object on stdout, no fences) instead of the markdown report. |
| bmad-loop attach [ | tmux-attach to a run's live agent session. |
| bmad-loop stop | Stop a live run — the engine and its agent tmux session. --graceful instead finishes the in-flight item (a story through commit, a sweep bundle through commit), then stops cleanly and stays resumable, and suppresses pending auto-sweeps; --cancel-graceful withdraws a pending request. The hard stop is the default and always wins over a pending graceful one. |
| bmad-loop delete | Delete a run directory. --force stops the run first if it is still live, but cannot override a rival resume that becomes live before removal. Unknown liveness still warns and proceeds. |
| bmad-loop archive | Compress a run into .bmad-loop/archive and remove the run dir. --force stops the run first if it is still live, but cannot override a rival resume that becomes live before archival. Unknown liveness still warns and proceeds. |
| bmad-loop cleanup | Remove leftover tmux artifacts for the current project: kill bmad-loop- sessions for finished/stopped/interrupted runs (and orphans whose run dir is gone) and close parked bmad-loop-ctl windows. --dry-run lists without killing. Live runs — and any session/window belonging to another project — are never touched. --json emits a stable machine-readable document instead of the text — the run ids whose sessions were removed, the live ids left alone, the ctl windows closed, and a dry_run flag — so a preview and the real run share one schema and can be compared. |
| bmad-loop clean | Reclaim disk from concluded runs per [cleanup]: tear down git worktrees a mid-flight stop orphaned (freeing their Unity Library/ + MCP-server builds), trim the heavy worktrees/ tree from runs kept for history (they stay viewable in the TUI), and archive/delete runs past the retention window. Only finished/stopped runs are touched; a run that resumes during clean is recorded as protected or trimmed according to work already done, and siblings continue. --dry-run previews, --keep protects, --retain N overrides the window, --hard deletes instead of archiving. --json emits one stable machine-readable document instead of the text — the effective retention policy, freed_bytes as a raw integer, and the worktree paths and run ids reclaimed, trimmed, archived, deleted or protected. |
| bmad-loop tui | The interactive dashboard (needs the [tui] extra). --low-frame-rate caps it to 15fps + disables animations (fixes repaint tearing over slow/SSH links; also [tui] low_frame_rate). |
| bmad-loop probe-adapter (collect-adapter-data) | Collect + sanitize the data needed to finalize a CLI adapter profile (hook payload shape, transcript location/format, token schema). Default is a zero-launch scan; --probe opts into a live capture (--model picks the probe turn's model, --timeout bounds it, default 90s). --transcript, --session-dir, --binary (CLIs with no profile yet), --out; --json emits the finding as a stable JSON document instead of the report. See the adapter authoring guide. |
Every command takes --project (default: the current directory). Any may be a
partial — the tail after the last - (e.g. a1b2), shortened to any prefix that stays unique;
bmad-loop list shows each run's short ref.
One subcommand is deliberately left out of the table: bmad-loop relay writes a single
session event file from a coding-CLI hook payload on stdin. Its own help calls it "a hook target
for machines, not a command to run by hand" — it takes no--project, andbmad-loop init
registers this installed command with an absolute path. Never invoke it yourself.
The TUI
uv sync --extra tui # textual + tomlkit + pyte + rich
bmad-loop tui
A live, read-only dashboard over everything below — and a launcher for new runs. It's the fastest way to understand what the orchestrator is doing.
Dashboard
The left column stacks the runs table (newest auto-selected; paused runs carry a kind badge, and the title a global _⚑ N need attention_ count), an expandable sprint tree — replaced by a stories board in stories mode — and the severity-coloured deferred-work ledger. The right column shows the run header (status, epic, task counts, weighted token total, and the active agent driving the current stage), a per-story table (phase · agent · attempts · review cycles · tokens · commit/defer), and tabs tailing the journal, the session's pane log, and the ATTENTION file. Every pane boundary is resizable — drag a divider bar or press ctrl+w — and sizes persist per-project to [tui] in policy.toml (TUI guide). On a paused run, p opens the stage-appropriate HITL viewer, calling the exact code paths the CLI uses.
A sweep blocked on a human decision
Sweeps run as their own [sweep]-tagged runs. When an attended sweep hits a "needs human decision" item it blocks on its own terminal prompt; the dashboard spots the decision-pending journal event and raises a banner + toast — press a to attach to the sweep's window, answer, and detach.
Answering decisions a past sweep left unanswered
Unattended sweeps (--no-prompt) skip decisions, and an attended one can be abandoned mid-way — those answers would otherwise be lost. The Deferred Work pane shows the outstanding count (— N to answer (d)); press d (or run bmad-loop decisions) to walk each one. A close is applied immediately; a build / keep-open is saved to .bmad-loop/decisions.json and consumed by the next sweep with no re-prompt.
Deferred-work entry & the start-run modal
enter on any ledger row opens the full entry; r / s open modals to launch a run or sweep (epic, story, max-stories, dry-run). The start-run modal also carries a source select (sprint vs. stories mode, prefilled from [stories]) and a spec-folder field with a live schedule preview that validates stories.yaml and lists the linear schedule with checkpoint markers.
The policy editor
Press g to edit .bmad-loop/policy.toml in a form grouped by section — comment-preserving (tomlkit), validated with the engine's own parser before saving, with unset keys showing their defaults as placeholders. Every section starts collapsed with a one-line description; ctrl+e expands/collapses all at once.
Key bindings
| Key | Action |
| --------- | -------------------------------------------------------------------------------------------------------- |
| r / s | start a run / sweep (modal for epic, story, max-stories, dry-run…) |
| e | resume the selected paused/interrupted run |
| p | review the selected paused run in the stage-appropriate viewer (checkpoint, gate, escalation, env fault) |
| R | resolve a run paused at an escalation (interactive, then re-arm) |
| d | answer deferred-work decisions past sweeps left unanswered |
| a | attach to the live agent session (or the orchestrator window) |
| x | stop the selected live run immediately (engine + agent session) |
| S | graceful stop: finish the in-flight item (through commit), then stop cleanly — stays resumable |
| D / A | delete / archive the selected run (refuses while its engine is live) |
| c | clean up tmux sessions/windows for finished & stopped runs |
| v | run bmad-loop validate, output in a modal |
| g | settings editor for .bmad-loop/policy.toml |
| y | copy the active Log/Attention pane to the clipboard |
| ctrl+w | enter/leave pane resize mode (arrows resize, Tab picks the boundary) — or drag any divider bar |
| M / q | toggle theme (light/dark mode) / quit |
The TUI is an observer/launcher, never the engine. Runs started with r/s are detached bmad-loop processes in windows of a dedicated tmux session (bmad-loop-ctl; on psmux the name carries a per-project registry suffix), so they survive a TUI exit or crash; the dashboard watches runs purely through the run-dir artifacts the engine writes atomically, so runs started from a plain shell show up identically. Launch and attach need tmux; the dashboard itself does not. Pid-based liveness is local-only — a run whose engine died shows interrupted (press e); runs on other hosts show unknown.
📖 See docs/tui-guide.md for the full guide — layout, every key and modal, status glyphs, the settings field reference, and troubleshooting. Vector (SVG) versions of every screenshot live in docs/images/.
Two planning pipelines, one loop
bmad-loop drives the same dev → verify → review → commit loop from either of two story sources — chosen per project, or per run:
- Sprint mode (default). Stories come from
sprint-status.yaml(written bybmad-sprint-planningfrom your PRD/epics). The loop walks the board byready-for-devstatus, keyed by story ref (1-2-account-mgmt). This is what the rest of this README describes. - Stories mode (opt-in). Stories come from a typed
stories.yaml— the Story Breakdown output ofbmad-spec, a fixed-name sibling ofSPEC.mdin the epic's spec folder. The loop dispatches each entry by folder + id (/bmad-build-auto Spec folder:, spelled with whichever primitive name resolves on disk); the dev skill creates-or-resumes the story spec at. Story id: . , and the orchestrator reads that id-keyed path back deterministically — no shared board to line-edit, no mtime-scan of result artifacts./stories/ - .md
[stories] source = "stories" + spec_folder = "" , or per run with bmad-loop run --spec (which overrides the policy). Everything downstream — dev/verify/review/commit, worktree isolation, gates, crash resume, the TUI — is identical; only the story source and the per-story controls below differ.
Per-story human checkpoints (stories mode). Each stories.yaml entry carries two independent boolean flags:
spec_checkpoint— pause _before_ code, to review the plan. The dev session halts right after planning (Halt after planning.) with the spec atready-for-dev; the run pauses at a plan checkpoint. Approve to resume straight to implementation, or request a replan (resets the spec todraftso the next dispatch re-plans).done_checkpoint— pause _after_ the story commits, to review the result before the loop moves on (skipped automatically when it is the last story).
closes_deferred — the DW- ledger ids that story's work closes (see Deferred-work sweeps):
- id: '3-2'
title: Export digests
description: …
closes_deferred: [DW-5, DW-6]
Declaring it here rather than in the story spec is what lets the annotation happen without touching each generated spec: bmad-build-auto generates the spec and knows nothing of the ledger, whereas the breakdown is authored while the ledger is in view. A spec that _does_ carry the field in frontmatter is honored too — the two are unioned.
Like spec_checkpoint and done_checkpoint, this is a human-authored, caller-only field. Breakdown time, with the ledger open, is where it belongs — but it is not a deadline: the declaration is read when the story commits, so adding one to a story spec's frontmatter mid-run is honored, and withdrawing one before the commit means it is not closed. Upstream Story Breakdown does not emit it yet (BMAD-METHOD#2619), and re-deriving stories.yaml rewrites the file — so record the intent in .memlog.md alongside the story, or the declaration is lost on the next re-derive.
A story may set both checkpoints (it pauses twice); gates.mode pauses stack on top. A blocked story escalates exactly as in sprint mode — bmad-loop resolve, then re-arm + resume — now with the story's title/description and the blocking condition surfaced; a pre-planning-halt sentinel spec is auto-deleted (a copy preserved under the run dir) on re-arm for a clean re-dispatch.
bmad-loop run --dry-run --spec prints the linear schedule (list order, checkpoint markers, live on-disk state); bmad-loop status shows the same stories board.
Stories mode requires a dev primitive new enough to support folder+id dispatch; the run preflight (and bmad-loop validate) checks for it and tells you to update the BMAD module if it is missing. Sprint mode is unaffected and remains the default indefinitely.
How a story flows
This is sprint mode's flow. Stories mode swaps the story source (above) and adds the per-story plan/done checkpoints — the loop below is otherwise identical.
sprint-status.yaml: 1-2-account-mgmt: ready-for-dev
│
├─ DEV tmux window: claude "/bmad-build-auto 1-2-account-mgmt"
│ bmad-build-auto: plans a 1.5–4k-token spec, auto-approves it,
│ implements, self-reviews inline (parallel review layers),
│ commits, finalizes spec → done … Stop hook signals the orchestrator
├─ VERIFY spec exists · status done · baseline matches · diff non-empty
│ (except a park, which may legitimately have produced none)
│ · run [verify].commands in repo_root (pytest, ruff…) — a broken build never
│ reaches review; a failure spawns a fix session fed the output
├─ REVIEW fresh window: claude "/bmad-build-auto <done spec>" — re-invoking on a
│ (gated) done spec runs a fresh independent step-04 review pass (parallel review
│ layers → triage → auto-apply patches → ledger → defer ambiguity →
│ commit). Gated on the skill's followup_review_recommended flag
│ (review.trigger = "recommended") or every story ("always"); bounded
│ loop, default 3 cycles
├─ VERIFY spec done · sprint done · run [verify].commands again (repo_root) — a failure
│ routes a feedback-driven dev fix session, then a fresh review cycle
└─ COMMIT orchestrator squashes the iteration's commits into one story commit
(then, under [scm] isolation = "worktree", merges the unit branch
back into the target branch locally); epic boundary → gate / retro
Failure handling: bounded dev retries (verify-command failures keep the tree and feed the failing output to the next session via --feedback; other failures roll back to baseline), plateau-defer when review won't converge (story skipped, spec stashed into the run dir, deferred-work.md additions preserved, run continues), environment faults that pause instead of charging the attempt (a failing [environment] probe, or a verify command exiting with [verify] env_fault_rc — a probe failing before a session launch pauses at the environment stage, and a plain resume re-probes and launches it), and typed escalations — CRITICAL pauses the run and notifies you (desktop + ATTENTION file), PREFERENCE is journaled and the run continues. CRITICAL detail stays complete in state.json, journal.jsonl, session results, and status --json; human displays cap an overlong reason at 2,000 characters with a visible marker naming journal.jsonl as the complete source and, when present, the story spec as a separate recovery trail.
Resolving a CRITICAL escalation: the escalated story is parked in a terminal escalated phase — resume skips it. To un-stick it, run bmad-loop resolve (or press R in the TUI). That opens an interactive resolve agent seeded with the escalation and the frozen spec; you converse with it to disambiguate the spec, it records the resolution, and on your confirmation the orchestrator re-arms the story (escalated → pending, spec status reset to ready-for-dev) and resumes — a clean rebuild against the corrected spec, then on through the rest of the sprint. Already fixed the spec yourself? bmad-loop resolve skips straight to re-arm + resume.
Adopting the kept branch. Under [scm] isolation = "worktree" an escalated story keeps its worktree and branch. When the escalation was a false positive on finished work, bmad-loop resolve finishes the story from that branch instead of re-driving it: no agent session runs, the spec is set to done (or awaiting-operator when the story declared operator actions), and the branch is committed and merged and the sprint board advanced. Review, the [verify] commands and pre_commit_gate workflows are not re-run — you are vouching for the work, and resolve warns you so. It refuses (state untouched) for sweep runs, a story whose worktree is gone, or one with no spec; plain resolve re-arms those instead. --adopt-branch and --restore-patch are mutually exclusive.
Re-verifying kept work. When a story was deferred (or escalated as an environment fault) only because its environment was broken — a container or database was down while verify ran — fix the environment and run bmad-loop resolve . It keeps the attempt as it stands (HEAD plus any uncommitted changes in place, or the kept worktree unit under isolation), replays the [verify] commands on it, and on a pass reviews it per policy and commits it (a unit merges) — no dev session and no resolve agent. A failing replay re-defers or re-escalates without retrying. Anything you committed or changed since the pause is squashed into the story's commit, and resolve says so before it asks. A worktree unit is accepted under any pause when --story names it; sweep runs are refused, and so is an environment fault caught before a session launched or after a dev or fix session crashed or timed out (nothing finished to verify — use plain resolve, see Re-verifying kept work). Mutually exclusive with --adopt-branch and --restore-patch.
A plain resume past an unresolved escalation still runs the rest of the queue, but the run then pauses at that escalation rather than finishing, so resolve can still act on it and its kept worktree is not reclaimed. Plain resume re-pauses there every time; the way past it is bmad-loop resolve (re-arm, or --adopt-branch). (In stories mode a pick-time wedge you fixed by hand does not count.)
When the resume is held. Under [scm] isolation = "worktree" the re-drive mounts a fresh worktree cut from the committed target branch, so a correction living only in your working tree never reaches it. Where the re-arm can _prove_ that — the committed spec does not carry the status the re-drive routes on, or, for a pre-planning sentinel, the ref it mounts from does not hold this checkout's SPEC.md / stories.yaml — the re-arm still stands but the resume stops there, --resume notwithstanding, and both surfaces name the branch to commit on. Commit the correction, then bmad-loop resume . Every other re-arm warning stays advisory and resumes in the one gesture as before.
Intent-gap patch-restore. When review halted on an intent gap — the implementation was sound but read the spec differently than intended — bmad-build-auto saves the attempted change as a patch before reverting (BMAD-METHOD#2564). The escalation notice names that spec, whose Auto Run Result records the saved patch, so the recovery artifact is discoverable without searching terminal logs. If the attempted reading was in fact correct, resolve re-arms the spec to in-review and re-applies that patch onto baseline after every reset, so the re-driven session resumes *review
... (README truncated for length)