UCG vs bmad-loop
Both UltraCode Goal (UCG) and bmad-loop (formerly bmad-auto; renamed at v0.8.0, with the rename shims removed at v0.10.0: a project still on bmad-auto migrates via v0.9.1, the last release carrying them) automate the BMAD implementation phase without a babysitter. They are siblings, not clones: they make opposite bets on where the control loop lives and how completion is judged. This page compares them honestly, including the places where bmad-loop is the better tool.
Snapshot: UCG v2.2.0 (released 2026-08-15) and bmad-loop v0.10.0 (released 2026-08-14). Both projects are young and moving fast.
bmad-loopâs v0.10.0 is a substantive release cut from main, which its own notes say has not been released since v0.9.0 and does not descend from v0.9.1; the 0.9.x hotfix line (the bmad-build-auto primitive resolution and the skills.base-shim refusal of upstreamâs interactive forwarding shim) is brought forward onto main alongside new capability. The headlines: a story owing human-only external actions (a DNS record, an API key) can commit what an agent can do, park at awaiting-operator, and be completed later by a new bmad-loop confirm command, with the park record traveling in the storyâs own commit so confirm works from any clone; a deferred-work entryâs gate: line now hard-blocks the stories it names in both validate and run, and a story can close ledger entries at its commit via closes_deferred:; hook events (the runâs control plane) and resumeâs config baseline move out of the agent-writable project tree into XDG state, part of an agent-tamper defense family the notes candidly call incomplete against a deliberate bypass; coding-CLI adapter classes can ship out-of-tree against a registry, listed by a new adapters command; the per-story token budget is re-checked at every session boundary (still advisory); and confirm joins the schema-versioned --json family. UCG is not affected by the BMAD-METHOD primitive rename either way: it orchestrates bmad-dev-story, not the auto primitive.
UCG reached v2.2.0 on 2026-08-15. The release is re-loop economics, distilled from a measured story that took seven gate cycles: the re-loop route now generalizes each finding to its defect class against a per-Epic ledger before fixing (five of that storyâs six reviews had re-found one class, one seam over each time); mid-loop sweeps may scope to the affected set while the gate refuses to advance any story whose marker does not prove a full-scope sweep; Stage-5 assessors measure a git worktree of the commit under assessment instead of the shared tree, with outputs pinned to the main tree; a delta cycle profile re-runs only the previously failed assessor dimension and is capped so it can never advance; a tracked mutation runner (mutate_check.py) proves every new guard red-able before the gate, its ledger leading with survivors; and heartbeat/stall sidecars timestamp every loop boundary so dead air becomes a record. The new gate flags are additive: their JSON keys appear only when the flags are passed, so pre-flag invocations print the shape they always did. (v2.1.0 and v2.0.0, the computed epic roll-up and the nine-defect fail-open closure, are in the changelog.)
Treat every line below as a point-in-time reading of two released versions, and verify the current state for yourself (links at the bottom); both projectsâ main branches run well ahead of their tags.
The one difference everything else follows from
Section titled âThe one difference everything else follows fromâbmad-loop puts the control loop in plain Python, outside the agent. A deterministic orchestrator picks the next story, spawns a fresh, disposable coding-agent session (over tmux by default) for each step, watches structured hook events the session writes, and decides retries, gates, and completion in code. No LLM sits in the control loop.
UCG puts the control loop inside Claude Code. The run is a Claude Code skill that composes /goal, Auto Mode, Auto Memory, and runtime hooks. The per-story loop is paced by Claude Codeâs /goal evaluator (an LLM), while the binding completion verdict is a deterministic script (gate_eval.py) that reads the Test Architectâs (TEA) gate artifact.
The consequence cascades: bmad-loop is a tool you run beside any supported agent; UCG is a capability that lives within one specific agent.
At a glance
Section titled âAt a glanceâ| Dimension | bmad-loop | UltraCode Goal (UCG) |
|---|---|---|
| Runtime | External Python process plus a terminal multiplexer, tmux being the bundled default (the OpenCode profile runs over HTTP with no multiplexer window); Linux, macOS, or WSL; native Windows in progress (a psmux backend ships in-tree behind a real-Windows live gate, not yet claimed as shipped) | A skill inside Claude Code; no daemon, no multiplexer, no session to attach to. Runs wherever Claude Code does, given Python 3.11+, uv, and git, and a Claude Code new enough for /goal, dynamic workflows, and Auto Memory, the three versions preflight pins and refuses to launch below. One optional exception: a ~900-line driver script that runs one session per story on long Epics |
| Control loop | Deterministic Python, no LLM in the loop | LLM-paced /goal spine with a deterministic completion gate |
| Agent / CLI | claude, codex, gemini, copilot, antigravity, opencode (mix per stage) | Claude Code only |
| Scope | Implementation phase: backlog and ready-for-dev stories from sprint-status.yaml, or opt-in from a typed stories.yaml, through dev, review, verify, commit | Whole Epic, six stages: ingest and scope, planning-readiness preflight, ATDD (acceptance-test-driven development) test generation, execute, TEA gate, finalize, whose terminal step is a workflow health check that the skillâs own table numbers as a seventh stage |
| Completion authority | Checks on the spec and result artifacts, a proof-of-work diff, and your test and lint commands; opt-in TEA gate steps via a bundled plugin (advisory by default) | TEA quality gate: gate-decision.json (P0/P1/overall), combined in the default profile with NFR and test-review artifacts, read fail-closed by gate_eval.py; since v2.2.0 the verdict is also capped by evidence scope, so a story only advances off a full-scope sweep (--tests-ran) and a delta-profile mid-loop gate can never advance (--cycle-profile) |
| Test strategy | Your [verify].commands plus adversarial review hunters; opt-in TEA test-design and ATDD workflows via the bundled plugin | ATDD: acceptance criteria become executable red-phase tests driven to green; TEA traceability; a tracked mutation runner (mutate_check.py) proves every guard a story adds red-able before the gate, with a generated ledger that leads with the mutations that survived |
| Pre-launch gate | validate, a registry of named checks whose id families at v0.10.0 span BMAD config, adapter (binary, profile, kind, out-of-tree), deferred work (including an unreadable ledger now failing rather than warning), git, hooks, host, multiplexer, notifications, operator park records, policy, queue (sprint-status and stories manifest), and skills, where skills.base-shim still refuses the forwarding shim BMAD-METHODâs rename left behind | A mechanical preflight script plus a readiness check and a semantic scan that refuse to launch on an undecided product or architecture decision |
| Observability | A live terminal dashboard (built with Textual): runs table, attach to live sessions, journal, cost-weighted token totals, an active-agent indicator naming what is driving the current stage, plus schema-versioned --json documents for scripted readers | Files plus a read-only renderer: .decision-log.md, a run-status.json heartbeat, per-step .heartbeat/.stall sidecars that timestamp every story-loop boundary and turn an unexplained gap into a record at resume, a transcript ticker that prints each gate verdict, a gate-trail.md evidence trail at finalize, and /ucg-status to assemble all of it on demand |
| Deferred work | A triage-and-execute sweep engine plus a decisions workflow; since v0.10.0 a ledger entryâs gate: line hard-blocks the stories it names in both validate and run, and a story can close entries at its commit via closes_deferred: | A ledger the gate only appends to, surfaced at finalize and readable mid-run through /ucg-status, with /ucg-resolve able to mark an answered decision row resolved; no execute engine |
| Escalation | Typed (CRITICAL / PREFERENCE) plus an interactive resolve agent that re-arms the spec and re-applies the saved patch, so review resumes on the restored diff; v0.10.0 adds a third outcome with no UCG equivalent, where a story owing human-only external actions commits what an agent can do, parks at awaiting-operator, and bmad-loop confirm completes it later from any clone | An escalate verdict, a typed escalation-<story-id>.json sidecar (source, kind, decision_needed, evidence), an on_escalation hook, a path-pinned run-result.json for every headless terminal exit that got far enough to resolve its artifacts path, not only blocked ones, and /ucg-resolve to answer what is pending; resume from the decision log |
| Isolation | In place by default; opt-in git worktree per story or bundle, merged back locally | At the gate: since v2.2.0, Stage-5 assessors measure a git worktree of the commit under assessment, with assessor outputs pinned to the main tree. Story execution itself stays sequential in one tree (the experimental --parallel worktree mode was retired) |
| Extensibility | A plugin system (observe, veto, mutate) with bundled TEA and Unity plugins | customize.toml knobs, planning-shaping fragments, and two optional third-party integrations configured there, both off by default and neither able to touch a gate verdict: claude-mem recall and a graphify knowledge-graph refresh |
| Self-improvement | Not shipped | A health check that files deduplicated GitHub issues about its own friction |
| Maturity | First-party (bmad-code-org); v0.10.0, a substantive release bringing the 0.9.x hotfix line onto main plus operator parking, enforced deferred-work gates, and agent-tamper defenses; rich docs; CI + test suite | Community module; v2.2.0, re-loop economics from a measured seven-cycle post-mortem (defect-class generalization, scope-capped sweeps, worktree-isolated gating, a tracked mutation runner), additive over the v1.0.0 SemVer contract; docs site; CI + test suite |
| License | MIT | MIT |
Where bmad-loop is stronger
Section titled âWhere bmad-loop is strongerâThis is a genuinely strong tool; pretending otherwise would make this page useless.
- A deterministic control loop. Story selection, retry budgets, gates, and completion checks are ordinary Python, so they are debuggable, reproducible, and cost no tokens. UCGâs
/goalpacing is LLM-driven; its deterministic pieces (the per-story and epic-level gate reads, the preflight scripts, the commit-guard and budget hooks) bound the loop rather than run it. If you want zero LLM judgment in the orchestration itself, bmad-loop is the cleaner model. - Agent portability. It drives claude, codex, gemini, GitHub Copilot CLI, antigravity, or OpenCode, and can run dev on one model and review on another via per-stage profiles. UCG is deliberately Claude Code only.
- Observability and control. A live terminal UI (built with Textual) gives you a runs dashboard, a sprint tree, the deferred-work ledger, per-story token totals, attach-to-session, and a policy editor. UCGâs window is files, the transcript, and a read-only
/ucg-statusrender assembled from those same files: there is still no live view and no session to attach to. - A deferred-work engine, not just a ledger.
bmad-loop sweeptriages the ledger against the real code, bundles cohesive work, executes it, and has a decisions workflow for the human calls. UCG appends to a ledger, surfaces it at the end, and can render it mid-run through/ucg-status; acting on it is still manual, and there is no execute engine. - Extensibility and reach. It has a real plugin system (observe, veto, mutate the cycle) with bundled plugins: a TEA plugin that can add Test Architect workflows to its pipeline, and a Unity game-engine integration. UCG exposes configuration knobs, not a plugin API.
- Operational maturity. It ships disk reclamation (clean and archive, retention windows, worktree teardown), cost-weighted token budgets that discount cache reads, and an adapter-authoring path for new CLIs (out-of-tree adapter classes against a registry since v0.10.0), and it carries the backing of the bmad-code-org org.
Where UCG is stronger
Section titled âWhere UCG is strongerâ-
The TEA gate is the default, binding completion authority, not an opt-in layer. UCGâs completion authority is the Test Architectâs gate: a traceability matrix that holds acceptance criteria to hard thresholds (P0 coverage at 100%, P1 at 90% or above, overall at 80% or above). UCGâs default profile combines that verdict with an NFR (non-functional requirements) assessment and a test-review score, and
gate_eval.pyreads the result fail-closed: a missing or unreadable signal downgrades the verdict, never upgrades it. Since v0.5.0 the default sequential path also re-runs the test, lint, and build suite on each storyâs committed HEAD before advancing, so a story that is green pre-commit but red once its new files are tracked cannot slip through to the gate; since v2.2.0 that re-verify runs at the cycleâs declared scope, with the gate refusing to advance any story whose.tests-ranmarker does not prove a full-scope sweep.bmad-loop can reach similar territory, but differently. Its default gate is checks on the spec and result artifacts, a proof-of-work diff (the commit must contain real changes since the storyâs baseline), and your test and lint commands; its bundled TEA plugin can add trace, NFR, and test-review steps before every commit. That plugin is opt-in, its gate steps ship advisory (non-blocking), and they fail open when an artifact is missing or unparseable. That gap narrowed in v0.9.0: at v0.8.1 bmad-loopâs independent baseline-commit cross-check could not actually fire, because it read a spec key the dev skill does not write, so a spec claiming a stale or foreign baseline sailed through; v0.9.0 fixed it to accept either key and re-cut the test fixture that had been fabricating the missing one. The advisory-by-default and fail-open-on-missing-artifact properties of the TEA pluginâs gate steps are unchanged. If you want acceptance-criterion-to-test traceability enforced by default, fail-closed, with nothing to configure, that is UCGâs defining bet.
-
ATDD-first. UCG turns each storyâs acceptance criteria into executable acceptance tests (scaffolded as red-phase
test.skipplaceholders) before any code is written, then un-skips them and drives them to green. The acceptance tests are a first-class generated artifact, not a by-product. One scope note, about what the generator emits rather than what it accepts: the TEA release installed here does detect a backend stack, but its scaffolds are Playwright and TypeScript, and the browser-recording path loads only for a frontend or fullstack project, so a stack with no JS or TS harness still gets nothing runnable. UCGâs preflight therefore steers those runs to--light, where the storyâs acceptance criteria (not generated tests) are the trace oracle, or you author the acceptance tests in the stackâs own harness. bmad-loopâs default pipeline relies on whatever tests the dev skill writes while implementing, plus the test commands you supply; TEA test generation exists there only as an opt-in plugin step that runs after dev, not as the default path. -
A planning-readiness gate that can refuse to launch. UCGâs preflight hands the PRD, the architecture, and the stories to a throwaway subagent that hunts for undecided product or architecture decisions, contradictions between the PRD and the architecture, and any story whose âdoneâ cannot be pinned down. The scan grades what it finds, and any RED verdict stops the run rather than letting an unattended agent guess; the one way past a RED is an operator recording a
closefor it, since adeferdoes not clear one and an unreadable decisions file clears nothing. That scan is itself LLM judgment, the very thing bmad-loop keeps out of its loop; the difference is that it can only block a launch, never pass one, and the readiness kernel beside it is deterministic. That kernel has been the moduleâs most defect-prone surface, and the honest reading is that it took three releases to make it fail closed: v1.0.0 closed three fail-opens where an Epic with no stories, a story with no acceptance criteria, and a partially seeded story set each scoredready, and v2.0.0 closed two more, where a present-but-unparseable sprint board emptied the in-scope set (silencing both guards that exist to catch exactly that), and where a citation in a story counted as its own declaration, so a dangling reference could never be reported and the judgment branch was unreachable. bmad-loopâs preflight is mechanical and assumes the sprintâs stories are already ready to build. -
Almost no moving parts outside the agent. The autonomous run is a skill: no daemon, no multiplexer, no session to attach to. For a Claude Code user that is a smaller operational surface, and it is also exactly why UCG cannot run anywhere else. Two qualifiers, added honestly. Three companion skills ship alongside the run and none is required by one:
ucg-formalize(the standalone readiness gate),ucg-status(the read-only run view), anducg-resolve(the decide-surface for a stopped run). Worth recording rather than quietly fixing: until v2.0.0 all three shipped one directory too deep for the skill loader, which enumerates a single level, so every one of them returnedUnknown skillwhen invoked. Every check the project had verified they were present, and they were; none tested whether they were reachable. And a long Epic accumulates every storyâs transcript in one session, so UCG ships an optional driver script that spawns oneclaude -pper story; use it and you are running a loop outside the agent after all, which is bmad-loopâs model in miniature. The difference is that it is opt-in and about 900 lines, where bmad-loopâs orchestrator is the product; skip it and the skill still runs standalone, since--max-storiesis a flag on the skill rather than something the script provides. -
A self-improvement loop. UCGâs finalize step can file deduplicated GitHub issues about friction in its own workflow, so the tool reports its own rough edges.
What they share
Section titled âWhat they shareâ- A deterministic completion authority the model cannot talk its way past: bmad-loopâs artifact, diff, and command checks; UCGâs TEA gate read. One caveat on the UCG side, narrowed but not removed in v2.0.0: on a non-web stack, under either profile, the trace artifacts are agent-authored under strict honesty rules, so on that path the model writes the file the gate then reads and the guarantee is procedural rather than mechanical. What changed is that the substitution is no longer invisible: the gate now records
gate-provenance: teaorhand-authoredper story and the run report carries it, so a reader can tell which verdicts rested on artifacts the run produced for itself. Before that, an Epic could complete entirely on hand-authored gate files and read identically to one gated on TEA output. - Proof that the commit is real work, not a claim about work. bmad-loop cross-checks the diff against the storyâs baseline commit; UCG enforces the equivalent one layer down, in a
PreToolUsehook that denies thegit commitoutright unless a tests-ran marker exists whose recorded baseline SHA matches the storyâs character for character, and unless the staged index is non-empty. That hook is only as good as its command parsing, which is worth stating because until v2.0.0 it was not: a commit wrapped in any shell compound form (if, a loop body, a subshell, a brace group) or placed after a background&classified as carrying no git write at all, skipping the protected-branch, marker, freshness and empty-index gates in one go. On a production run it also refuses a commit whose staged acceptance tests are still skipped, though that check readstest.skip(and so does nothing on the non-web stacks the ATDD note above steers to--light. Both projects are also hardening the same flank from opposite sides: v0.10.0 moved bmad-loopâs hook events and resume baselines out of the agent-writable tree, a tamper-defense family its notes call incomplete against a deliberate bypass, and UCGâs guard carries its own bypass history (the v2.0.0 compound-form fix). - Fresh-context review separated from implementation, to kill self-review anchoring bias, on both defaults with a caveat each: bmad-loopâs separate session is gated by
review.trigger, which defaults torecommended(set it toalwaysfor every story), and UCG runs a code-review pass on its production profile but none under--light. - Adversarial review passes, bounded so they cannot oscillate forever: bmad-loop by
max_review_cycles(default 3), UCG bymax_turns_per_story, where a re-loop that would exceed the budget escalates instead. - Git worktree use, aimed differently: bmad-loopâs opt-in isolation runs each story or sweep bundle in its own worktree and merges back locally; UCGâs Stage-5 gate measures a worktree of the commit under assessment while story execution stays in the main tree.
- Resumable runs with a per-story budget: bmad-loopâs is a cost-weighted per-story budget that discounts cache reads (advisory, re-checked at every session boundary since v0.10.0) beside a per-session cap that can terminate; UCGâs is a turn cap, encoded in the
/goalcondition and enforced at the gate. UCG adds a second axis,--max-stories N, a per-invocation work bound whose exhaustion still ends the runcompletewith stories remaining, so that status means âthis invocation finishedâ, not âthe Epic is doneâ. Note the asymmetry: UCG has no token or cost bound at all, andstory_token_budgetis now a deprecated no-op. sprint-status.yamlas the shared planning ledger, and both build on BMAD-METHOD. Neither leaves it write-only to the BMAD skills any more: UCGâs gate writes the storyâsdonerow at theadvanceroute, and bmad-loopâs orchestrator syncs the board itself.
Which to reach for
Section titled âWhich to reach forâChoose bmad-loop if you use codex, gemini, or GitHub Copilot CLI (or want to mix models per stage), you want a code-only orchestrator you can step through and debug, you want a live dashboard and attach-to-session control, you have a backlog of deferred work to triage and sweep, you need plugin extensibility or game-engine support, or you prefer a first-party tool maintained under the bmad-code-org org.
Choose UCG if you are on Claude Code and any of these fit: you want the Test Architectâs gate as the default, binding, fail-closed completion authority (every P0 criterion traced to a passing test, with P1 at 90% or above and overall at 80% or above) rather than an opt-in layer; you want acceptance criteria compiled into executable tests up front; you want a run that refuses to start while a product or architecture decision is still undecided; or you want the autonomous run itself to be a single skill with no daemon and no session to attach to (the three optional companion skills and the per-story driver above are all opt-in, and a run needs none of them).
They are not mutually exclusive. Both read the same sprint-status.yaml and BMAD artifacts, so an Epic planned and gated UCGâs way is a board bmad-loop can pick up. Their deferred-work ledgers are not interchangeable, though: they share the path but not the schema, since bmad-loop sweep parses ### DW-<n>: sections and UCG never writes one, so a sweep will not see UCGâs parked rows.
Verify this yourself
Section titled âVerify this yourselfâBoth tools change weekly, so re-check before you rely on anything above:
- bmad-loop: its README, docs/FEATURES.md, and docs/ROADMAP.md.
- UCG: How It Works and the Gate Model.
This snapshot was re-cut on 2026-08-15 against bmad-loop v0.10.0 (released 2026-08-14) and UCG v2.2.0 (released 2026-08-15). Earlier cuts: 2026-08-02 (bmad-loop v0.9.1, UCG v2.0.0, both released that day), 2026-07-28 (bmad-loop v0.9.0, UCG v1.0.0), 2026-07-12 (bmad-loop v0.8.1, UCG v0.5.1), and 2026-06-28 (bmad-auto v0.7.4, UCG v0.4.0), which predates the bmad-auto rename.
One deliberate omission in this cut. Previous versions of this page stated a count of bmad-loopâs registered validate checks. That number could not be reproduced from the pinned source without running their tool, so it has been replaced by the list of check families, which can be (this cut re-derived that list from the check ids in the v0.10.0 source). A number nobody re-derives is a number that quietly goes stale, and this page has no business asserting a precise figure about someone elseâs project that its own author cannot check.