bmad-module-ultracode-goal 0.5.1 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +1 -1
- package/README.md +11 -9
- package/docs/_internal/RELEASING.md +4 -1
- package/docs/_internal/STABILITY.md +20 -6
- package/docs/architecture.md +23 -15
- package/docs/comparison.md +45 -42
- package/docs/cross-session-recall.md +2 -2
- package/docs/gate-model.md +4 -2
- package/docs/getting-started.md +28 -8
- package/docs/health-check.md +2 -2
- package/docs/how-it-works.md +45 -11
- package/docs/index.md +2 -1
- package/docs/knowledge-graph-refresh.md +66 -0
- package/docs/parallel-mode.md +5 -5
- package/docs/troubleshooting.md +5 -5
- package/docs/why-ultracode-goal.md +5 -5
- package/package.json +13 -8
- package/skills/ultracode-goal/SKILL.md +9 -3
- package/skills/ultracode-goal/assets/execute-epic.workflow.js +3 -2
- package/skills/ultracode-goal/assets/module-help.csv +3 -1
- package/skills/ultracode-goal/assets/module-setup.md +1 -1
- package/skills/ultracode-goal/customize.toml +25 -2
- package/skills/ultracode-goal/references/define-done.md +3 -1
- package/skills/ultracode-goal/references/execute.md +62 -8
- package/skills/ultracode-goal/references/finalize.md +76 -5
- package/skills/ultracode-goal/references/gate.md +7 -5
- package/skills/ultracode-goal/references/health-check.md +21 -1
- package/skills/ultracode-goal/references/ingest-and-scope.md +6 -4
- package/skills/ultracode-goal/references/preflight.md +33 -6
- package/skills/ultracode-goal/scripts/drive_epic.py +896 -0
- package/skills/ultracode-goal/scripts/formalize_check.py +129 -0
- package/skills/ultracode-goal/scripts/gate_eval.py +65 -9
- package/skills/ultracode-goal/scripts/gate_trail.py +555 -0
- package/skills/ultracode-goal/scripts/headless_envelope.py +116 -8
- package/skills/ultracode-goal/scripts/health_check_fp.py +42 -6
- package/skills/ultracode-goal/scripts/hooks/budget_stop.py +28 -37
- package/skills/ultracode-goal/scripts/hooks/guard_pretooluse.py +526 -15
- package/skills/ultracode-goal/scripts/red_ids.py +302 -0
- package/skills/ultracode-goal/scripts/status_render.py +471 -0
- package/skills/ultracode-goal/skills/ucg-resolve/SKILL.md +225 -0
- package/skills/ultracode-goal/skills/ucg-status/SKILL.md +136 -0
- package/tools/cli/commands/status.js +109 -2
- package/tools/cli/lib/ide-skills.js +1 -1
- package/tools/cli/lib/installer.js +20 -8
- package/tools/cli/lib/skill-parity.js +165 -0
- package/tools/ucg-npx-wrapper.js +0 -0
- package/tools/validate-docs-links.js +502 -0
- package/tools/validate-fixtures.js +161 -0
- package/website/README.md +1 -1
- package/website/astro.config.mjs +2 -1
- package/website/src/rehype-markdown-links.js +147 -70
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"name": "bmad-module-ultracode-goal",
|
|
20
20
|
"source": "./",
|
|
21
21
|
"description": "Supercharges BMAD with Claude Code Goal Mode, Auto Mode, and Auto Memory: autonomous Epic execution to a machine-checked, TEA-gated Definition-of-Done. Execute Epics. Accumulate Knowledge. Deliver Outcomes.",
|
|
22
|
-
"version": "0.
|
|
22
|
+
"version": "1.0.1",
|
|
23
23
|
"author": {
|
|
24
24
|
"name": "Armel"
|
|
25
25
|
},
|
package/README.md
CHANGED
|
@@ -6,17 +6,17 @@
|
|
|
6
6
|
|
|
7
7
|
**Run a BMAD Epic autonomously to a machine-checked Definition-of-Done.**
|
|
8
8
|
|
|
9
|
-
[](https://
|
|
9
|
+
[](https://claude.com/product/claude-code)
|
|
10
10
|
[](https://github.com/armelhbobdad/bmad-module-ultracode-goal/actions/workflows/quality.yaml)
|
|
11
11
|
[](https://www.npmjs.com/package/bmad-module-ultracode-goal)
|
|
12
|
-
[](https://opensource.org/
|
|
12
|
+
[](https://opensource.org/license/MIT)
|
|
13
13
|
[](https://github.com/bmad-code-org/BMAD-METHOD)
|
|
14
|
-
[](https://www.python.org)
|
|
15
15
|
[](https://docs.astral.sh/uv/)
|
|
16
16
|
[](https://armelhbobdad.github.io/bmad-module-ultracode-goal/)
|
|
17
17
|
[](https://github.com/armelhbobdad/bmad-module-ultracode-goal/stargazers)
|
|
18
18
|
|
|
19
|
-
**Built for [Claude Code](https://
|
|
19
|
+
**Built for [Claude Code](https://claude.com/product/claude-code), and only Claude Code.** UCG composes `/goal`, Auto Mode, Auto Memory, and runtime hooks; the autonomous run itself requires Claude Code.
|
|
20
20
|
|
|
21
21
|
_UCG is a standalone [BMAD](https://github.com/bmad-code-org/BMAD-METHOD) module that delivers a BMAD Epic end to end without a babysitter. It preflights to a remediated green light, turns acceptance criteria into executable tests with the Test Architect (TEA), and advances a story only when a deterministic script reads `PASS` from TEA's gate artifact, not when the model decides it feels done._
|
|
22
22
|
|
|
@@ -61,7 +61,7 @@ The `gate_status` comes straight from TEA's artifact: `gate_eval.py` never re-de
|
|
|
61
61
|
|
|
62
62
|
## Install
|
|
63
63
|
|
|
64
|
-
Requires [Claude Code](https://
|
|
64
|
+
Requires [Claude Code](https://claude.com/product/claude-code) (the runtime UCG conducts), [Node.js](https://nodejs.org/) >= 22, [Python](https://www.python.org/) >= 3.11, [uv](https://docs.astral.sh/uv/), plus `git` and `gh` on PATH.
|
|
65
65
|
|
|
66
66
|
```bash
|
|
67
67
|
npx bmad-module-ultracode-goal install
|
|
@@ -80,6 +80,7 @@ Invoke the skill in natural language: "run this epic autonomously," "execute thi
|
|
|
80
80
|
- `--yes`: skip Stage 1's open-floor invite and the launch confirm. It **never** skips the hard preflight gate.
|
|
81
81
|
- `-H`: headless: run non-interactively and emit the five-key status JSON at every exit point.
|
|
82
82
|
- `--retro`: run the close-out retrospective (interactive runs offer it anyway; headless runs it only when this flag is passed).
|
|
83
|
+
- `--max-stories N`: drive at most **N** stories in this invocation, then finish normally through the report and the terminal JSON. It bounds the work, not the scope: the Epic's in-scope set is untouched, so the next invocation resumes where this one stopped. `scripts/drive_epic.py` uses it to run one story per process, so a long Epic's context dies with each story.
|
|
83
84
|
|
|
84
85
|
See [How It Works](./docs/how-it-works.md) for the full six-stage walkthrough, routing conditions, and the headless contract.
|
|
85
86
|
|
|
@@ -97,13 +98,13 @@ A skeptical reader is probably already running one of these. Here is the honest
|
|
|
97
98
|
|
|
98
99
|
The alternatives aren't bad; they solve different problems. **UCG solves exactly one: advancing an epic only when a deterministic script confirms the gate passed, and giving you the verdict JSON to check it yourself.**
|
|
99
100
|
|
|
100
|
-
UCG's closest peer is [bmad-
|
|
101
|
+
UCG's closest peer is [bmad-loop](https://github.com/bmad-code-org/bmad-loop) (formerly bmad-auto, published under the bmad-code-org org), which makes the opposite architectural bet (a deterministic Python loop driving any CLI from outside the agent). For a side-by-side look at where each one wins, see [UCG vs bmad-loop](https://armelhbobdad.github.io/bmad-module-ultracode-goal/comparison/).
|
|
101
102
|
|
|
102
103
|
## Verifying
|
|
103
104
|
|
|
104
105
|
You don't have to take the gate's word for it. The deterministic pieces ship with a test suite, and you can run the evaluator on a real artifact yourself.
|
|
105
106
|
|
|
106
|
-
Run the Python suite (
|
|
107
|
+
Run the Python suite (600+ tests across the preflight, gate, hook, readiness, memory, and customization scripts):
|
|
107
108
|
|
|
108
109
|
```bash
|
|
109
110
|
uv run --with pytest pytest skills/ultracode-goal/scripts/tests/ -v
|
|
@@ -137,6 +138,7 @@ The docs are organized into three buckets: **Why** (start here), **Try** (do stu
|
|
|
137
138
|
- **[Gate Model](./docs/gate-model.md)**: how `gate_eval.py` maps `gate_status` to a verdict, and the production AND-signals.
|
|
138
139
|
- **[Health Check](./docs/health-check.md)**: the terminal self-improvement loop: what it sends, privacy, and how to disable it.
|
|
139
140
|
- **[Cross-Session Recall](./docs/cross-session-recall.md)**: the optional claude-mem integration: touchpoints, trust model, and how to enable it.
|
|
141
|
+
- **[Knowledge-Graph Refresh](./docs/knowledge-graph-refresh.md)**: the optional graphify integration: preconditions, what it sends where, and what it never touches.
|
|
140
142
|
- **[Troubleshooting](./docs/troubleshooting.md)**: real failure modes and their remediations.
|
|
141
143
|
|
|
142
144
|
Every run that reaches Finalize ends with a self-improvement check that can file a deduplicated GitHub issue with your approval, so **please let runs finish through Finalize**, or [open an issue](https://github.com/armelhbobdad/bmad-module-ultracode-goal/issues/new/choose) directly. If UCG shipped an epic while you slept, a ⭐ helps others find it.
|
|
@@ -148,8 +150,8 @@ UCG is a conductor over primitives it does not replace. It builds on:
|
|
|
148
150
|
| Tool | Role in UCG |
|
|
149
151
|
| ---------------------------------------------------------------------- | ------------------------------------------------------------------------------ |
|
|
150
152
|
| [BMAD Method](https://github.com/bmad-code-org/BMAD-METHOD) | The epic toolbox UCG orchestrates (sprint planning, story creation, dev, review) |
|
|
151
|
-
| [TEA Test Architect](https://github.com/bmad-code-org/
|
|
152
|
-
| [Claude Code](https://
|
|
153
|
+
| [TEA Test Architect](https://github.com/bmad-code-org/bmad-method-test-architecture-enterprise) | Machine-checked quality gates: test-design, ATDD, NFR, trace; the gate artifact |
|
|
154
|
+
| [Claude Code](https://claude.com/product/claude-code) | `/goal`, Auto Mode, Auto Memory, hooks, and git worktrees, the primitives UCG composes |
|
|
153
155
|
|
|
154
156
|
## Contributing
|
|
155
157
|
|
|
@@ -51,7 +51,7 @@ These must exist before the first `main`-dispatch release. Order matters.
|
|
|
51
51
|
|
|
52
52
|
### 1. Required-check contexts must exist
|
|
53
53
|
|
|
54
|
-
Branch-protection rulesets can only require status checks that have reported at least once. Open any PR (or dispatch `quality.yaml` manually) so these
|
|
54
|
+
Branch-protection rulesets can only require status checks that have reported at least once. Open any PR (or dispatch `quality.yaml` manually) so these eight contexts exist:
|
|
55
55
|
|
|
56
56
|
```text
|
|
57
57
|
prettier
|
|
@@ -61,8 +61,11 @@ validate (ubuntu-latest)
|
|
|
61
61
|
validate (windows-latest)
|
|
62
62
|
python (ubuntu-latest)
|
|
63
63
|
python (windows-latest)
|
|
64
|
+
docs-links
|
|
64
65
|
```
|
|
65
66
|
|
|
67
|
+
This list is the setup seed, not the source of truth: the ruleset is. Whenever `quality.yaml` gains or renames a job, add the new context to the ruleset as well, or `main` silently loses that protection while every release still passes (the wait-for-checks step below reads the ruleset, so it waits only on what the ruleset names).
|
|
68
|
+
|
|
66
69
|
### 2. Main-branch ruleset
|
|
67
70
|
|
|
68
71
|
Create a ruleset on `main` requiring the seven contexts above, with `bypass_actors` = Admin RepositoryRole, `bypass_mode: pull_request`. Then record its id in the repo variable the workflow reads:
|
|
@@ -20,11 +20,13 @@ The installer CLI is invoked via `npx bmad-module-ultracode-goal <subcommand>`.
|
|
|
20
20
|
|
|
21
21
|
### The `[workflow]` customize.toml keys
|
|
22
22
|
|
|
23
|
-
The keys in the shipped `[workflow]` block of `customize.toml` (including `persistent_facts`, `tea_config_path`, `trace_output_dir`, `implementation_artifacts`, `deferred_work_path`, `epic_branch_prefix`, `protected_branches`, `max_turns_per_story`, `story_token_budget
|
|
23
|
+
The keys in the shipped `[workflow]` block of `customize.toml` (including `persistent_facts`, `tea_config_path`, `trace_output_dir`, `implementation_artifacts`, `deferred_work_path`, `epic_branch_prefix`, `protected_branches`, `max_turns_per_story`, `story_token_budget` (**deprecated, no-op**), `parallel_max_concurrency`, `allowlist_commands`, `on_epic_complete`, and `on_escalation`) are the supported override surface. Teams and users override them in `_bmad/custom/ultracode-goal.toml` (and `.user.toml`) with base → team → user resolution (scalars override, tables deep-merge, arrays append). Renaming or removing a key, or changing how it resolves, is a contract change. See [architecture](../architecture.md).
|
|
24
|
+
|
|
25
|
+
`story_token_budget` is **deprecated** as of the deprecation note in `CHANGELOG.md`: it is still shipped, still accepted, and still resolves, so existing overrides keep working and nothing errors. It is a no-op; no layer reads it any more. The runaway bound is turns only, via `max_turns_per_story`. The key stays enumerated here (and stays in `customize.toml`) precisely because removing it would be the contract break this section forbids.
|
|
24
26
|
|
|
25
27
|
### The headless five-key JSON emit shape
|
|
26
28
|
|
|
27
|
-
Every headless (`-H`) exit point emits one object with exactly these five keys, always present, `null` when an artifact was not produced, `reason
|
|
29
|
+
Every headless (`-H`) exit point emits one object with exactly these five keys, always present, `null` when an artifact was not produced, plus a conditional sixth, `reason`, carrying a one-line cause only when blocked. A **complete** emit omits `reason` entirely; it is not present-and-`null`, so read it only when `status` is `blocked`:
|
|
28
30
|
|
|
29
31
|
```json
|
|
30
32
|
{"status": "complete|blocked",
|
|
@@ -32,10 +34,21 @@ Every headless (`-H`) exit point emits one object with exactly these five keys,
|
|
|
32
34
|
"decision_log": "<path>",
|
|
33
35
|
"report": "<path or null>",
|
|
34
36
|
"deferred_work": "<path or null>",
|
|
35
|
-
"reason": "<one line when blocked
|
|
37
|
+
"reason": "<one line, present only when blocked; omitted on a complete emit>"}
|
|
36
38
|
```
|
|
37
39
|
|
|
38
|
-
An automator parses this one schema regardless of where the run stopped. Changing a key name, adding or removing a key,
|
|
40
|
+
An automator parses this one schema regardless of where the run stopped. Changing a key name, adding or removing a key, changing the `null`-when-absent guarantee, or making `reason` present on a complete emit is a contract change.
|
|
41
|
+
|
|
42
|
+
### The headless result file
|
|
43
|
+
|
|
44
|
+
A headless run writes that same object to `{workflow.implementation_artifacts}/run-result.json`, byte-identical to what it emitted on stdout, so an automator reads a pinned file path instead of scraping a transcript. Covered:
|
|
45
|
+
|
|
46
|
+
- **The path**: the basename `run-result.json` directly inside the resolved `{workflow.implementation_artifacts}`, with no run-id suffix and no subdirectory.
|
|
47
|
+
- **The contents**: the headless five-key emit shape above, unchanged.
|
|
48
|
+
|
|
49
|
+
- **The guarantee**: once a headless run resolves `{workflow.implementation_artifacts}` it clears any prior `run-result.json`, before any stage work. From that point on the file's presence means **this** run reached a terminal. The guarantee is scoped to that moment, so a consumer should still prefer a parseable stdout envelope when the file is absent.
|
|
50
|
+
|
|
51
|
+
Four documented exceptions, none of which is a contract break: a block that fires **before** `{workflow.implementation_artifacts}` resolves (the "not a BMAD project" stop) neither writes nor clears, so it leaves the stdout envelope as its sole output and is the one case where a prior run's file can survive; a terminal whose best-effort write failed leaves no file while still printing its envelope; a headless run that has not yet reached a terminal (still running, crashed, or killed) has no file, because startup cleared any prior one; and an **attended** run writes no file at all and clears none. The file is overwrite-in-place, so it carries no cross-run history, and under the experimental `--parallel` mode each worktree agent sees its own artifacts path, so no single `run-result.json` describes a fan-out run.
|
|
39
52
|
|
|
40
53
|
### The skill name and invocation phrases
|
|
41
54
|
|
|
@@ -45,8 +58,9 @@ The skill name `ultracode-goal` and its documented invocation phrases ("run an e
|
|
|
45
58
|
|
|
46
59
|
`scripts/gate_eval.py` is the deterministic completion authority. Covered:
|
|
47
60
|
|
|
48
|
-
- **CLI flags**: `--trace-output` (required), `--profile` (`light` | `production`, required), `--nfr`, `--test-review` (production only).
|
|
61
|
+
- **CLI flags**: `--trace-output` (required), `--profile` (`light` | `production`, required), `--story`, `--nfr`, `--test-review` (production only).
|
|
49
62
|
- **Verdict vocabulary**: the `verdict` values `advance` / `defer` / `reloop` / `escalate`, and the `gate_status` values `PASS` / `CONCERNS` / `FAIL` / `WAIVED` / `NOT_EVALUATED`, plus the mapping between them. See the [gate model](../gate-model.md).
|
|
63
|
+
- **`--story` fail-closed resolution**: when `--story` matches no artifact in a trace dir whose reports or gate-decision files are named per story, the result is `NOT_EVALUATED` (so, `escalate`), never a fallback to another story's gate. A trace dir whose candidates are all generically named (`trace.md`, `gate-decision.json`) still resolves unscoped. Which file the resolver picks, and how it decides that a name carries a story id, are internal.
|
|
50
64
|
|
|
51
65
|
The contractual mapping each `gate_status` resolves to:
|
|
52
66
|
|
|
@@ -71,7 +85,7 @@ Everything not enumerated above is `@internal` and may change in any `0.x` relea
|
|
|
71
85
|
- **Reference file structure**: the `references/*.md` stage files' internal structure, step ordering, prose, and section headings. The stage *names* are referenced by the health-check fingerprint (see below) but the file contents are an authoring surface.
|
|
72
86
|
- **Script internals**: the internal functions, regexes, and intermediate behavior of `preflight_check.py`, `gate_eval.py`, `health_check_fp.py`, and the hook scripts. The covered surface is `gate_eval.py`'s CLI and verdict vocabulary above; everything else (the `preflight_check.py` JSON shape, the fingerprint tuple format, the hook env-var names) is internal and may change.
|
|
73
87
|
- **The experimental `--parallel` workflow**: `assets/execute-epic.workflow.js`, the `/ultracode-goal-execute` registration, its args binding, its return shape, and `parallel_max_concurrency`'s runtime behavior are explicitly experimental and excluded from the contract. See [parallel mode](../parallel-mode.md).
|
|
74
|
-
- **`_bmad-output/` artifact layout
|
|
88
|
+
- **`_bmad-output/` artifact layout**, with one exception: run folders, the decision log, `run-report.md`, `run-status.json`, the deferred-work ledger, and the improvement queue are run outputs, not a downstream-consumable schema. **`run-result.json` is the exception and is covered** (see [the headless result file](#the-headless-result-file)); it is the one artifact in that tree an automator may pin against. The headless emit shape (covered above) is the supported way to locate the rest of these paths programmatically.
|
|
75
89
|
|
|
76
90
|
## SemVer note
|
|
77
91
|
|
package/docs/architecture.md
CHANGED
|
@@ -17,24 +17,24 @@ Because it is a conductor, the truth of "is this done" lives in the artifacts it
|
|
|
17
17
|
|
|
18
18
|
## The three enforcement layers
|
|
19
19
|
|
|
20
|
-
These are the module's non-negotiables. Each exists because the documented mechanics make the intuitive shortcut wrong (see [why](why-ultracode-goal.md)).
|
|
20
|
+
These are the module's non-negotiables. Each exists because the documented mechanics make the intuitive shortcut wrong (see [why](./why-ultracode-goal.md)).
|
|
21
21
|
|
|
22
22
|
### 1. Deterministic gate truth
|
|
23
23
|
|
|
24
|
-
`scripts/gate_eval.py` reads TEA's `gate-decision.json` and maps its gate status to a routing verdict (`PASS`/`WAIVED` → advance, `CONCERNS` → defer, `FAIL` → reloop, `NOT_EVALUATED` → escalate). It never re-derives TEA's thresholds and never reads the transcript. The `/goal` evaluator that drives execution can only see what the run surfaces, it cannot open the gate file, so it is structurally incapable of being the completion authority. The script is. In production, two extra signals can only downgrade an `advance`, never lift a lower verdict. See the [gate model](gate-model.md) for the full mapping diagram, thresholds, and the fail-closed contract.
|
|
24
|
+
`scripts/gate_eval.py` reads TEA's `gate-decision.json` and maps its gate status to a routing verdict (`PASS`/`WAIVED` → advance, `CONCERNS` → defer, `FAIL` → reloop, `NOT_EVALUATED` → escalate). It never re-derives TEA's thresholds and never reads the transcript. The `/goal` evaluator that drives execution can only see what the run surfaces, it cannot open the gate file, so it is structurally incapable of being the completion authority. The script is. In production, two extra signals can only downgrade an `advance`, never lift a lower verdict. See the [gate model](./gate-model.md) for the full mapping diagram, thresholds, and the fail-closed contract.
|
|
25
25
|
|
|
26
26
|
### 2. Hooks as invariants
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
A set of invariants must hold before the runtime lets a tool call through, and none of them can live in memory, which is context the model may or may not weigh:
|
|
29
29
|
|
|
30
|
-
- **`scripts/hooks/guard_pretooluse.py`** (PreToolUse): inspects each `git commit`/`git push
|
|
31
|
-
- **`scripts/hooks/budget_stop.py`** (Stop): counts turns
|
|
30
|
+
- **`scripts/hooks/guard_pretooluse.py`** (PreToolUse): inspects each `git commit`/`git push` and enforces six invariants. It denies the command on a protected branch; denies a `git commit` when no tests-ran marker (`<impl-artifacts>/.tests-ran-<story_id>`) exists for the current story; denies it when that marker's `baseline=<sha>` does not match the SHA the story recorded at start; denies it when the staged index is empty or unreadable; and denies it, when armed with `ULTRACODE_TEST_ARTIFACTS`, while the staged content of a checklist-enumerated acceptance test still contains `test.skip(`. A sixth invariant is not about git at all: it runs for every tool call, and while a run is active it denies claude-mem MCP calls and filesystem reach into `.claude-mem` unless the Cross-Session Recall latch is green. It returns a `deny` decision in the hook JSON and also exits 2 with the reason on stderr so older clients that ignore the JSON still block. The marker, freshness, staged-index, and recall-latch checks fail **closed**, denying on an input they cannot read. Two do not: the protected-branch check fails **open** when `git rev-parse` cannot report a branch, and the un-skip proof is out of scope entirely when `ULTRACODE_TEST_ARTIFACTS` is unset. The protected-branch check is also scoped to the **session's** working directory rather than the repository the command names, so it denies a `git commit`/`git push` aimed at another checkout whenever the session's own repo is on a protected branch.
|
|
31
|
+
- **`scripts/hooks/budget_stop.py`** (Stop): counts turns for the current story against `max_turns_per_story`. On overrun it writes an escalation marker and surfaces a message, then **lets the stop proceed**. Its documented limitation: a Stop hook fires only when Claude is already trying to stop, so it cannot interrupt a `/goal` condition mid-turn. The in-condition "stop after N turns" clause and the gate's re-loop budget are the real bounds; this hook is the third, defensive layer.
|
|
32
32
|
|
|
33
|
-
Both hooks read their config from env first (so the conductor injects per-run values) and fall back to hardcoded defaults (`main`/`master`, `25`, `
|
|
33
|
+
Both hooks read their config from env first (so the conductor injects per-run values) and fall back to hardcoded defaults (`main`/`master`, `25`, `ultracode/epic-`). Because of that fallback, a `customize.toml` override **silently no-ops at the enforcement layer** unless the conductor passes it through the hook env, so preflight injects `ULTRACODE_PROTECTED_BRANCHES`, `ULTRACODE_IMPL_ARTIFACTS`, `ULTRACODE_MAX_TURNS`, `ULTRACODE_EPIC_BRANCH_PREFIX`, and `ULTRACODE_TEST_ARTIFACTS`.
|
|
34
34
|
|
|
35
35
|
### 3. Budget enforcement
|
|
36
36
|
|
|
37
|
-
A runaway story is bounded by three layers in order of authority: the **in-condition** "…or stop after N turns" clause inside the `/goal` condition (the real in-loop bound), the **gate re-loop budget** (a `reloop` that would exceed `max_turns_per_story`
|
|
37
|
+
A runaway story is bounded by three layers in order of authority: the **in-condition** "…or stop after N turns" clause inside the `/goal` condition (the real in-loop bound), the **gate re-loop budget** (a `reloop` that would exceed `max_turns_per_story` becomes `escalate`), and the **Stop hook** as the defensive backstop described above. Rollback is git, not `/rewind` (an Epic branch off a protected branch, one commit per green story, worktree isolation under `--parallel`) because `/rewind` checkpoints miss the Bash-driven changes that make up the run.
|
|
38
38
|
|
|
39
39
|
## File layout
|
|
40
40
|
|
|
@@ -56,7 +56,11 @@ skills/ultracode-goal/
|
|
|
56
56
|
├── scripts/ # Deterministic truth (run via `uv`)
|
|
57
57
|
│ ├── preflight_check.py # mechanical preflight facts + blocker budget
|
|
58
58
|
│ ├── gate_eval.py # gate status -> verdict (the completion authority)
|
|
59
|
+
│ ├── gate_trail.py # per-story evidence trail (gate-trail.md) at finalize
|
|
59
60
|
│ ├── formalize_check.py # readiness kernel behind the /ucg-formalize gate
|
|
61
|
+
│ ├── status_render.py # read-side render behind /ucg-status
|
|
62
|
+
│ ├── red_ids.py # preflight-RED identity (the resolve join key)
|
|
63
|
+
│ ├── drive_epic.py # one `claude -p` per story (--max-stories work bound)
|
|
60
64
|
│ ├── headless_envelope.py # the one five-key headless-envelope adapter
|
|
61
65
|
│ ├── health_check_fp.py # health-check fingerprint + seen-cache plumbing
|
|
62
66
|
│ ├── mem_observation.py # Cross-Session Recall write path (build/spill/drain)
|
|
@@ -67,26 +71,30 @@ skills/ultracode-goal/
|
|
|
67
71
|
│ ├── lib/mem_common.py # shared Cross-Session Recall primitives
|
|
68
72
|
│ └── hooks/
|
|
69
73
|
│ ├── guard_pretooluse.py # commit invariants (PreToolUse)
|
|
70
|
-
│ └── budget_stop.py # turn
|
|
74
|
+
│ └── budget_stop.py # turn budget (Stop)
|
|
71
75
|
├── skills/
|
|
72
|
-
│
|
|
76
|
+
│ ├── ucg-formalize/ # Standalone readiness gate
|
|
77
|
+
│ ├── ucg-resolve/ # Decide-surface for a blocked or escalated run
|
|
78
|
+
│ └── ucg-status/ # Read-only status view over a run
|
|
73
79
|
└── assets/
|
|
74
80
|
├── execute-epic.workflow.js # EXPERIMENTAL --parallel worktree fan-out
|
|
75
81
|
├── module.yaml · module-setup.md · module-help.csv # install metadata
|
|
76
82
|
└── ucg-awareness/ # shift-left planning customization fragments
|
|
77
83
|
```
|
|
78
84
|
|
|
79
|
-
`SKILL.md` carries the routing and the contract; the `references/*.md` files carry each stage's procedure and testable routing conditions; the `scripts/*.py` files carry the deterministic facts the model cannot fudge (the gate, preflight, readiness kernel, hooks, and the install-time/recall plumbing); the `skills
|
|
85
|
+
`SKILL.md` carries the routing and the contract; the `references/*.md` files carry each stage's procedure and testable routing conditions; the `scripts/*.py` files carry the deterministic facts the model cannot fudge (the gate, preflight, readiness kernel, hooks, and the install-time/recall plumbing); the `skills/` subskills are the operator-facing surfaces (`ucg-formalize` the standalone readiness gate, `ucg-resolve` the decide-surface for a stopped run, `ucg-status` the read-only run view); and the `assets/` hold the experimental `--parallel` workflow plus install metadata and the planning-customization fragments. See [how it works](./how-it-works.md) for the stages and [parallel mode](./parallel-mode.md) for the workflow asset.
|
|
80
86
|
|
|
81
87
|
## Customization resolution
|
|
82
88
|
|
|
83
89
|
Configuration resolves in three layers, base → team → user, via `resolve_customization.py`:
|
|
84
90
|
|
|
85
|
-
1. **Base**: `customize.toml` in the skill root (the shipped `[workflow]` block).
|
|
86
|
-
2. **Team**: `{project-root}/_bmad/custom/ultracode-goal.toml
|
|
87
|
-
3. **User**: `{project-root}/_bmad/custom/ultracode-goal.user.toml`.
|
|
91
|
+
1. **Base**: `customize.toml` in the skill root (the shipped `[workflow]` block). In an installed project that file is `{project-root}/_bmad/ucg/ultracode-goal/customize.toml`, a verbatim copy of the shipped one; it is the layer to read (every knob is there with its comment), not the layer to edit.
|
|
92
|
+
2. **Team**: `{project-root}/_bmad/custom/ultracode-goal.toml`, committed.
|
|
93
|
+
3. **User**: `{project-root}/_bmad/custom/ultracode-goal.user.toml`, gitignored by the `*.user.toml` rule that ships in `_bmad/custom/.gitignore`.
|
|
88
94
|
|
|
89
|
-
|
|
95
|
+
Neither override file is created by any installer, and a missing one is not an error: the resolver loads it non-required and treats absence as an empty table, so a fresh project resolves the base layer alone. You create them when you first need to override something. Do not mistake them for the `config.toml` and `config.user.toml` already sitting in that directory: those are BMAD's own configuration, and a UCG knob written there resolves to nothing.
|
|
96
|
+
|
|
97
|
+
Merge semantics: **scalars override**, **tables deep-merge**, **arrays append**. At activation the skill runs `resolve_customization.py --skill {skill-root} --key workflow`; if that fails, it resolves the three files itself in the same order. The shipped base layer defines the run's knobs: the TEA/artifact paths (`tea_config_path`, `trace_output_dir`, `implementation_artifacts`, `deferred_work_path`), the git guardrails (`epic_branch_prefix`, `protected_branches`), the turn budget (`max_turns_per_story`; `story_token_budget` remains as a deprecated no-op key), the experimental `parallel_max_concurrency`, the `allowlist_commands`, the two lifecycle hooks (`on_epic_complete`, `on_escalation`), the [health check](./health-check.md) family (`health_check_repo`, `health_check_seen_cache`, `health_check_queue_path`, `health_check_autosubmit`), and the two optional third-party integrations, both off by default: [`cross_session_recall`](./cross-session-recall.md) and [`graphify_integration`](./knowledge-graph-refresh.md). Teams and users override without editing the shipped file. Remember that a budget or branch override only reaches the *enforcement* layer because preflight threads it into the hook env (see layer 2 above).
|
|
90
98
|
|
|
91
99
|
The three TOML layers merge once, but a branch or budget value then travels two ways: the conductor reads it directly, while the hooks only see it if preflight re-injects it as env:
|
|
92
100
|
|
|
@@ -108,4 +116,4 @@ flowchart LR
|
|
|
108
116
|
|
|
109
117
|
## Why the hooks live in settings.local.json
|
|
110
118
|
|
|
111
|
-
The PreToolUse and Stop hooks are auto-merged into `{project-root}/.claude/settings.local.json` (machine-local, gitignored, honored after the workspace trust dialog), not into a committed settings file or memory. The reasoning: these hooks are **enforcement, not context**. A committed hook would impose this module's commit guard on every contributor and every unrelated session in the repo; a hook in memory would not block a commit at all. The machine-local file scopes enforcement to the machine actually running the unattended Epic, and the gitignore keeps it out of shared history. The skill re-merges them every run (idempotently) and asserts they are active before the run goes unattended; it does not assume a prior run left them in place. Because the file is machine-local and executes on your machine, review what is merged; see [SECURITY.md](
|
|
119
|
+
The PreToolUse and Stop hooks are auto-merged into `{project-root}/.claude/settings.local.json` (machine-local, gitignored, honored after the workspace trust dialog), not into a committed settings file or memory. The reasoning: these hooks are **enforcement, not context**. A committed hook would impose this module's commit guard on every contributor and every unrelated session in the repo; a hook in memory would not block a commit at all. The machine-local file scopes enforcement to the machine actually running the unattended Epic, and the gitignore keeps it out of shared history. The skill re-merges them every run (idempotently) and asserts they are active before the run goes unattended; it does not assume a prior run left them in place. Because the file is machine-local and executes on your machine, review what is merged; see [SECURITY.md](https://github.com/armelhbobdad/bmad-module-ultracode-goal/blob/main/SECURITY.md).
|
package/docs/comparison.md
CHANGED
|
@@ -1,81 +1,84 @@
|
|
|
1
1
|
---
|
|
2
|
-
title: UCG vs bmad-
|
|
3
|
-
description: An honest, side-by-side comparison of UltraCode Goal and bmad-code-org's bmad-
|
|
2
|
+
title: UCG vs bmad-loop
|
|
3
|
+
description: An honest, side-by-side comparison of UltraCode Goal and bmad-code-org's bmad-loop orchestrator (formerly bmad-auto), including where bmad-loop is the better choice and which to reach for when.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
Both UltraCode Goal (UCG) and [bmad-
|
|
6
|
+
Both UltraCode Goal (UCG) and [bmad-loop](https://github.com/bmad-code-org/bmad-loop) (formerly bmad-auto; renamed at v0.8.0) 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.
|
|
7
7
|
|
|
8
|
-
Snapshot: UCG
|
|
8
|
+
Snapshot: UCG v1.0.0 and bmad-loop v0.9.0, as of 2026-07-28, both released versions. Both projects are young and moving fast. bmad-loop's v0.9.0 (released 2026-07-21) shipped four of the five items the previous snapshot listed as unreleased work on main: a `stories.yaml` planning mode with per-story checkpoints, patch-restore escalation recovery, a pluggable multiplexer-backend registry, and the integrity fixes to its verify gate. The fifth was this page's error rather than a gap in the release: those adversarial review layers are BMAD-METHOD's, declared in `bmad-dev-auto` and run against BMAD-METHOD's own review skills, and what v0.9.0 added was a preflight that refuses to start when they are missing. It also added a graceful stop that finishes the in-flight item before ending a run, an active-agent indicator in the dashboard, an OpenCode adapter driven over HTTP rather than a multiplexer, and stable, schema-versioned `--json` documents for six more commands: `status`, `list`, `validate`, `decisions`, `clean`, and `cleanup`. Eight commands now emit versioned documents, `diagnose` and `probe-adapter` having been converted from a JSON block appended to a text report; most of what is left is action commands with no document to emit. UCG reached v1.0.0 on 2026-07-28. 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.
|
|
9
9
|
|
|
10
10
|
## The one difference everything else follows from
|
|
11
11
|
|
|
12
|
-
bmad-
|
|
12
|
+
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.
|
|
13
13
|
|
|
14
|
-
UCG puts the control loop **inside Claude Code**. The run is a Claude Code skill that composes `/goal`, Auto Mode, runtime hooks, and
|
|
14
|
+
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 experimental `--parallel` fan-out additionally uses a dynamic workflow, and degrades to the sequential spine when one is unavailable. 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.
|
|
15
15
|
|
|
16
|
-
The consequence cascades: bmad-
|
|
16
|
+
The consequence cascades: bmad-loop is a tool you run beside any supported agent; UCG is a capability that lives within one specific agent.
|
|
17
17
|
|
|
18
18
|
## At a glance
|
|
19
19
|
|
|
20
|
-
| Dimension | bmad-
|
|
20
|
+
| Dimension | bmad-loop | UltraCode Goal (UCG) |
|
|
21
21
|
|---|---|---|
|
|
22
|
-
| Runtime | External Python process plus tmux; Linux, macOS, or WSL | A skill inside Claude Code; no
|
|
22
|
+
| 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 is planned) | 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 |
|
|
23
23
|
| Control loop | Deterministic Python, no LLM in the loop | LLM-paced `/goal` spine with a deterministic completion gate |
|
|
24
|
-
| Agent / CLI | claude, codex, gemini, copilot (mix per stage) | Claude Code only |
|
|
25
|
-
| Scope | Implementation phase: `ready-for-dev` stories through dev, review, verify, commit | Whole Epic: planning-readiness preflight, ATDD test generation, execute, TEA gate, finalize |
|
|
26
|
-
| Completion authority |
|
|
27
|
-
| Test strategy | Your `[verify].commands` plus adversarial review hunters | ATDD: acceptance criteria become executable red-phase tests driven to green; TEA traceability |
|
|
28
|
-
| Pre-launch gate | `validate
|
|
29
|
-
| Observability |
|
|
30
|
-
| Deferred work | A triage-and-execute **sweep** engine plus a decisions workflow |
|
|
31
|
-
| Escalation | Typed (CRITICAL / PREFERENCE) plus an interactive resolve agent | An escalate verdict
|
|
32
|
-
| Isolation |
|
|
33
|
-
| Extensibility | A plugin system
|
|
24
|
+
| Agent / CLI | claude, codex, gemini, copilot, antigravity, opencode (mix per stage) | Claude Code only |
|
|
25
|
+
| 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 |
|
|
26
|
+
| 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` |
|
|
27
|
+
| 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 |
|
|
28
|
+
| Pre-launch gate | `validate`: 26 registered checks at v0.9.0 (BMAD config, policy, sprint-status, git, multiplexer and process host, CLI binary and profile, hook registration, base skills, stories-mode manifest and dispatch) | A mechanical preflight script plus a readiness check and a semantic scan that refuse to launch on an undecided product or architecture decision |
|
|
29
|
+
| 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 on the sequential spine (the `--parallel` fan-out uses the `/workflows` view instead and writes no heartbeat), 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 |
|
|
30
|
+
| Deferred work | A triage-and-execute **sweep** engine plus a decisions workflow | 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 |
|
|
31
|
+
| 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 | 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 |
|
|
32
|
+
| Isolation | In place by default; opt-in git worktree per story or bundle, merged back locally | None by default (stories run sequentially in one session); an experimental `--parallel` mode fans stories out into git worktrees |
|
|
33
|
+
| 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](./cross-session-recall.md) and a [graphify knowledge-graph refresh](./knowledge-graph-refresh.md) |
|
|
34
34
|
| Self-improvement | Not shipped | A health check that files deduplicated GitHub issues about its own friction |
|
|
35
|
-
| Maturity | First-party (bmad-code-org); v0.
|
|
35
|
+
| Maturity | First-party (bmad-code-org); v0.9.0, whose headline is stable schema-versioned `--json` contracts that evolve additively; rich docs; CI + test suite | Community module; v1.0.0, which binds an already-stated contract (the headless envelope and `gate_eval.py`'s verdict vocabulary were covered at 0.x) under SemVer and adds `run-result.json` to it; docs site; CI + test suite |
|
|
36
36
|
| License | MIT | MIT |
|
|
37
37
|
|
|
38
|
-
## Where bmad-
|
|
38
|
+
## Where bmad-loop is stronger
|
|
39
39
|
|
|
40
40
|
This is a genuinely strong tool; pretending otherwise would make this page useless.
|
|
41
41
|
|
|
42
|
-
1. **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 `/goal` pacing is LLM-driven
|
|
43
|
-
2. **Agent portability.** It drives claude, codex, gemini,
|
|
44
|
-
3. **Observability and control.** A live Textual
|
|
45
|
-
4. **A deferred-work engine, not just a ledger.** `bmad-
|
|
46
|
-
5. **Extensibility and reach.**
|
|
47
|
-
6. **Operational maturity.**
|
|
42
|
+
1. **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 `/goal` pacing 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.
|
|
43
|
+
2. **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.
|
|
44
|
+
3. **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-status` render assembled from those same files: there is still no live view and no session to attach to.
|
|
45
|
+
4. **A deferred-work engine, not just a ledger.** `bmad-loop sweep` triages 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.
|
|
46
|
+
5. **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.
|
|
47
|
+
6. **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, and it carries the backing of the bmad-code-org org.
|
|
48
48
|
|
|
49
49
|
## Where UCG is stronger
|
|
50
50
|
|
|
51
|
-
1. **
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
51
|
+
1. **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.py` reads 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 full 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.
|
|
52
|
+
|
|
53
|
+
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.
|
|
54
|
+
2. **ATDD-first.** UCG turns each story's acceptance criteria into executable acceptance tests (scaffolded as red-phase `test.skip` placeholders) 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.
|
|
55
|
+
3. **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 `close` for it, since a `defer` does 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 (v1.0.0 closed three fail-opens there, where an Epic with no stories, a story with no acceptance criteria, and a partially seeded story set each used to score `ready`). bmad-loop's preflight is mechanical and assumes the sprint's stories are already ready to build.
|
|
56
|
+
4. **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), and `ucg-resolve` (the decide-surface for a stopped run). And a long Epic accumulates every story's transcript in one session, so UCG ships an optional driver script that spawns one `claude -p` per 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-stories` is a flag on the skill rather than something the script provides.
|
|
55
57
|
5. **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.
|
|
56
58
|
|
|
57
59
|
## What they share
|
|
58
60
|
|
|
59
|
-
- A deterministic completion authority the model cannot talk its way past: bmad-
|
|
60
|
-
-
|
|
61
|
-
-
|
|
61
|
+
- A deterministic completion authority the model cannot talk its way past: bmad-loop's artifact, diff, and command checks; UCG's TEA gate read (on a non-web stack, under either profile, the trace artifacts are agent-authored under strict honesty rules, so the guarantee there is procedural rather than mechanical).
|
|
62
|
+
- 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 `PreToolUse` hook that denies the `git commit` outright 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. On a production run it also refuses a commit whose staged acceptance tests are still skipped, though that check reads `test.skip(` and so does nothing on the non-web stacks the ATDD note above steers to `--light`.
|
|
63
|
+
- 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 to `recommended` (set it to `always` for every story), and UCG runs a code-review pass on its production profile but none under `--light`.
|
|
64
|
+
- Adversarial review passes, bounded so they cannot oscillate forever: bmad-loop by `max_review_cycles` (default 3), UCG by `max_turns_per_story`, where a re-loop that would exceed the budget escalates instead.
|
|
62
65
|
- Optional git worktree isolation.
|
|
63
|
-
- Resumable runs
|
|
64
|
-
- `sprint-status.yaml` as planning
|
|
66
|
+
- Resumable runs with a per-story budget: bmad-loop's is a cost-weighted token ceiling that discounts cache reads; UCG's is a turn cap, encoded in the `/goal` condition and enforced at the gate. UCG adds a second axis, `--max-stories N`, a per-invocation work bound whose exhaustion still ends the run `complete` with 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, and `story_token_budget` is now a deprecated no-op.
|
|
67
|
+
- `sprint-status.yaml` as 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's `done` row at the `advance` route, and bmad-loop's orchestrator syncs the board itself.
|
|
65
68
|
|
|
66
69
|
## Which to reach for
|
|
67
70
|
|
|
68
|
-
Choose **bmad-
|
|
71
|
+
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.
|
|
69
72
|
|
|
70
|
-
Choose **UCG** if you are on Claude Code
|
|
73
|
+
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).
|
|
71
74
|
|
|
72
|
-
They are not mutually exclusive. Both read the same `sprint-status.yaml` and BMAD artifacts, so
|
|
75
|
+
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.
|
|
73
76
|
|
|
74
77
|
## Verify this yourself
|
|
75
78
|
|
|
76
79
|
Both tools change weekly, so re-check before you rely on anything above:
|
|
77
80
|
|
|
78
|
-
- bmad-
|
|
79
|
-
- UCG: [How It Works](how-it-works.md) and the [Gate Model](gate-model.md).
|
|
81
|
+
- bmad-loop: its [README](https://github.com/bmad-code-org/bmad-loop), [docs/FEATURES.md](https://github.com/bmad-code-org/bmad-loop/blob/main/docs/FEATURES.md), and [docs/ROADMAP.md](https://github.com/bmad-code-org/bmad-loop/blob/main/docs/ROADMAP.md).
|
|
82
|
+
- UCG: [How It Works](./how-it-works.md) and the [Gate Model](./gate-model.md).
|
|
80
83
|
|
|
81
|
-
This snapshot was
|
|
84
|
+
This snapshot was re-cut on 2026-07-28 against bmad-loop v0.9.0 (released 2026-07-21) and UCG v1.0.0 (released 2026-07-28); the previous cut (2026-07-12) read bmad-loop v0.8.1 and UCG v0.5.1, and the one before it (2026-06-28, bmad-auto v0.7.4 and UCG v0.4.0) predates the rename.
|
|
@@ -57,12 +57,12 @@ What the sanitizer **does** before any advisory is surfaced:
|
|
|
57
57
|
What it honestly does **not** do:
|
|
58
58
|
|
|
59
59
|
- It is **not** a complete secret scrubber: redaction is high-precision pattern matching, not a guarantee that nothing sensitive ever survives.
|
|
60
|
-
- It does **not** vote. Advisories carry only a mechanical `recurred` field (`yes`/`no`/`unknown`); there are no LLM self-grades, and nothing recall surfaces is ever an input to `gate_eval.py`. The gate reads TEA's `gate-decision.json` and only that. See the [gate model](gate-model.md).
|
|
60
|
+
- It does **not** vote. Advisories carry only a mechanical `recurred` field (`yes`/`no`/`unknown`); there are no LLM self-grades, and nothing recall surfaces is ever an input to `gate_eval.py`. The gate reads TEA's `gate-decision.json` and only that. See the [gate model](./gate-model.md).
|
|
61
61
|
- It does **not** keep working when claude-mem looks wrong. If the capability contract fails (a missing tool, a malformed probe, a breaking schema change) the latch records recall as absent and the hook denies claude-mem calls for the run. Fail closed, never fail open.
|
|
62
62
|
|
|
63
63
|
## Turning it on
|
|
64
64
|
|
|
65
|
-
Set the knob in your project's `_bmad/custom/ultracode-goal.toml
|
|
65
|
+
Set the knob in your project's `_bmad/custom/ultracode-goal.toml`. **No installer creates that file**, so on most projects you are creating it: `_bmad/custom/` exists already, but the `config.toml` sitting in it belongs to BMAD's own configuration, and putting a UCG knob there does nothing.
|
|
66
66
|
|
|
67
67
|
```toml
|
|
68
68
|
[workflow]
|
package/docs/gate-model.md
CHANGED
|
@@ -3,7 +3,7 @@ title: Gate Model
|
|
|
3
3
|
description: How gate_eval.py turns TEA's gate-decision.json into a fail-closed advance, defer, reloop, or escalate verdict.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
Completion in UltraCode Goal is decided by a deterministic artifact read, not by judgment. `scripts/gate_eval.py` reads TEA's `gate-decision.json` and returns a routing verdict the skill executes. This page documents the verdict mapping, the production AND, the thresholds, the fail-closed contract, and why the `/goal` evaluator alone is insufficient, all traced to [`../skills/ultracode-goal/scripts/gate_eval.py`](
|
|
6
|
+
Completion in UltraCode Goal is decided by a deterministic artifact read, not by judgment. `scripts/gate_eval.py` reads TEA's `gate-decision.json` and returns a routing verdict the skill executes. This page documents the verdict mapping, the production AND, the thresholds, the fail-closed contract, and why the `/goal` evaluator alone is insufficient, all traced to [`../skills/ultracode-goal/scripts/gate_eval.py`](https://github.com/armelhbobdad/bmad-module-ultracode-goal/blob/main/skills/ultracode-goal/scripts/gate_eval.py).
|
|
7
7
|
|
|
8
8
|
## What the gate reads
|
|
9
9
|
|
|
@@ -13,6 +13,8 @@ The script resolves the gate artifact from the trace output directory:
|
|
|
13
13
|
2. If that slim file is absent, it falls back to the always-written `e2e-trace-summary.json` and lifts the gate fields from it. **The slim file's absence is normal, not a failure**: TEA only writes it when the run is gate-eligible and the decision is PASS/CONCERNS/FAIL/WAIVED.
|
|
14
14
|
3. If neither file is present, or the run carries no gate fields, `gate_status` is `NOT_EVALUATED`.
|
|
15
15
|
|
|
16
|
+
**`--story` scopes that resolution, and fails closed when it matches nothing.** Because one run gates many stories, the trace directory usually names its artifacts per story (`trace-2-1.md`, `gate-decision-4.json`). Passing `--story <id>` selects that story's artifacts. If the directory is named per story and the id matches none of them, the script does **not** fall back to an unscoped read: it returns `NOT_EVALUATED` with a reason naming the absent story, which routes to `escalate`. That matters because the fallback used to fire, so a story that produced no trace artifacts at all silently resolved a *neighbouring* story's decision and could report `PASS` / `advance` having been evaluated by nothing. The documented single-story fallback is untouched: a directory whose candidates are all generically named (`trace.md`, `gate-decision.json`) still resolves unscoped, so a single-story trace directory behaves exactly as it always did. The Epic-level gate is not that case: it passes the epic's own id via `--story` and matches it against trailing name components, so epic `4` resolves `gate-decision-4.json` and never its child story `4-1`, and an epic with no artifact of its own escalates rather than borrowing one.
|
|
17
|
+
|
|
16
18
|
The script never re-derives TEA's thresholds; it reads `gate_status` as given by the trace workflow.
|
|
17
19
|
|
|
18
20
|
How the script resolves an artifact into a `gate_status`:
|
|
@@ -148,4 +150,4 @@ The same `PASS` gate, but with a test review scoring 74, downgrades to `reloop`;
|
|
|
148
150
|
|
|
149
151
|
## Why the `/goal` evaluator alone is insufficient
|
|
150
152
|
|
|
151
|
-
The `/goal` loop that drives Execute ends with an evaluator confirming the success condition, but that evaluator only sees the transcript. It cannot open `gate-decision.json`. So it can confirm "the tests I was shown printed green" but not "TEA's deterministic gate read PASS against the traceability matrix and the NFR thresholds." Letting it be the completion authority would let the run grade itself from its own notes. `gate_eval.py` reads the file the model cannot author, which is exactly why it, and not the transcript evaluator, decides. See [why](why-ultracode-goal.md) and the routing detail in [`references/gate.md`](
|
|
153
|
+
The `/goal` loop that drives Execute ends with an evaluator confirming the success condition, but that evaluator only sees the transcript. It cannot open `gate-decision.json`. So it can confirm "the tests I was shown printed green" but not "TEA's deterministic gate read PASS against the traceability matrix and the NFR thresholds." Letting it be the completion authority would let the run grade itself from its own notes. `gate_eval.py` reads the file the model cannot author, which is exactly why it, and not the transcript evaluator, decides. See [why](./why-ultracode-goal.md) and the routing detail in [`references/gate.md`](https://github.com/armelhbobdad/bmad-module-ultracode-goal/blob/main/skills/ultracode-goal/references/gate.md).
|
package/docs/getting-started.md
CHANGED
|
@@ -11,15 +11,16 @@ UltraCode Goal conducts BMAD and TEA skills and runs deterministic Python under
|
|
|
11
11
|
|
|
12
12
|
| Tool | Required for | Install |
|
|
13
13
|
|------|--------------|---------|
|
|
14
|
-
| Claude Code | **The runtime: non-negotiable.** UCG composes `/goal`, Auto Mode, Auto Memory, and runtime hooks, which only exist in Claude Code; the autonomous run cannot execute anywhere else | <https://
|
|
14
|
+
| Claude Code | **The runtime: non-negotiable.** UCG composes `/goal`, Auto Mode, Auto Memory, and runtime hooks, which only exist in Claude Code; the autonomous run cannot execute anywhere else | <https://claude.com/product/claude-code> |
|
|
15
15
|
| Node.js >= 22 | Installation, `npx` commands | <https://nodejs.org> |
|
|
16
|
-
| Python >= 3.
|
|
16
|
+
| Python >= 3.11 | The deterministic gate, preflight, and hook scripts (run via `uv`) | <https://www.python.org> |
|
|
17
17
|
| `uv` | Running the module's Python scripts with automatic dependency management | <https://docs.astral.sh/uv/> |
|
|
18
18
|
| `git` | Epic-branch isolation and per-story commits (the real rollback) | <https://git-scm.com> |
|
|
19
|
-
| `gh` (GitHub CLI) | Submitting or queuing [health-check](health-check.md) findings | <https://cli.github.com> |
|
|
20
|
-
| A BMAD project with an Epic | The unit of delivery: a `_bmad/` install, a `sprint-status.yaml`, and at least one Epic with stories | see [bmad-method.org](https://docs.bmad-method.org) |
|
|
19
|
+
| `gh` (GitHub CLI) | Submitting or queuing [health-check](./health-check.md) findings | <https://cli.github.com> |
|
|
20
|
+
| A BMAD project with an Epic | The unit of delivery: a `_bmad/` install, a `sprint-status.yaml`, and at least one Epic with stories | see [docs.bmad-method.org](https://docs.bmad-method.org) |
|
|
21
|
+
| TEA (Test Architect) | **The gate: non-negotiable.** UCG invokes the `bmad-testarch-*` skills to produce the `gate-decision.json` that `gate_eval.py` reads. Required in both profiles: `--light` still runs test-design and trace | <https://github.com/bmad-code-org/bmad-method-test-architecture-enterprise> |
|
|
21
22
|
|
|
22
|
-
The run also depends on recent Claude Code primitives: `/goal`, dynamic workflows, and Auto Memory. The preflight script version-gates these and reports a mechanical blocker if the installed Claude Code is below the minimum any of them needs (see [troubleshooting](troubleshooting.md)).
|
|
23
|
+
The run also depends on recent Claude Code primitives: `/goal`, dynamic workflows, and Auto Memory. The preflight script version-gates these and reports a mechanical blocker if the installed Claude Code is below the minimum any of them needs (see [troubleshooting](./troubleshooting.md)).
|
|
23
24
|
|
|
24
25
|
## Install
|
|
25
26
|
|
|
@@ -37,18 +38,37 @@ Invoke the skill with one of its trigger phrases ("run an epic autonomously", "e
|
|
|
37
38
|
2. **Preflight runs.** Stage 2 is the autonomy gate. It runs a mechanical check (`preflight_check.py`), auto-remediates the fixable ambers (scaffolding the test framework, generating missing acceptance criteria, pre-creating TEA output dirs, and so on), then adds a semantic scan for undecided product or architecture decisions the script cannot see. The run launches **only** when the post-remediation intervention budget is zero and the semantic scan found no red blocker. A single undecided architecture decision stops the run here rather than letting an unattended run guess it.
|
|
38
39
|
3. **The launch briefing.** On an attended run, before the first unattended action the skill prints a one-screen briefing: what is about to run, the worst-case turn envelope, the autonomy line ("from here I will not ask you anything"), the kill switch (Ctrl-C, or delete the Epic branch; `/rewind` will not help), and where to watch (the run's `.decision-log.md` and `run-status.json`). One soft confirm crosses the line.
|
|
39
40
|
|
|
40
|
-
From there the run is autonomous: it defines done with TEA, executes each story to a green commit, gates each one deterministically, and finalizes with a run report and the deferred-work ledger. See [how it works](how-it-works.md) for the full stage-by-stage narration and the routing diagram.
|
|
41
|
+
From there the run is autonomous: it defines done with TEA, executes each story to a green commit, gates each one deterministically, and finalizes with a run report and the deferred-work ledger. See [how it works](./how-it-works.md) for the full stage-by-stage narration and the routing diagram.
|
|
41
42
|
|
|
42
43
|
## Run-mode flags
|
|
43
44
|
|
|
44
45
|
| Flag | Effect |
|
|
45
46
|
|------|--------|
|
|
46
47
|
| `--light` | Trace-only gate. Downscopes from the full TEA chain to `bmad-testarch-trace` plus `gate_eval.py --profile light`: no NFR/test-review AND. |
|
|
47
|
-
| `--parallel` | Experimental worktree fan-out. Each story runs isolated in its own worktree; no mid-run input. The sequential `/goal` spine is the default and recommended path; see [parallel mode](parallel-mode.md). |
|
|
48
|
+
| `--parallel` | Experimental worktree fan-out. Each story runs isolated in its own worktree; no mid-run input. The sequential `/goal` spine is the default and recommended path; see [parallel mode](./parallel-mode.md). |
|
|
48
49
|
| `--yes` | Skips Stage 1's open-floor invite and the launch confirm. The launch briefing still prints. **Never** skips the hard preflight gate. |
|
|
49
50
|
| `-H` | Headless. Runs non-interactively, never prompts (an unresolvable secret becomes a red blocker, not a question), and emits one JSON object at every exit point. |
|
|
50
51
|
| `--retro` | Runs the close-out retrospective (`bmad-retrospective`). Interactive runs offer it at Epic close anyway; headless runs it only when `--retro` is passed. |
|
|
52
|
+
| `--max-stories N` | Bounds this **invocation** to N stories, then finalizes normally (report, ledger, terminal JSON). It is a work bound, not a scope narrowing: in-scope stays every not-`done` story, so the next invocation resumes at the story this one stopped before. No Epic-level gate is authored while stories remain. See [one story per process](#one-story-per-process). |
|
|
53
|
+
|
|
54
|
+
## One story per process
|
|
55
|
+
|
|
56
|
+
A headless run drives every remaining story in one Claude Code session, and that session's context only grows: by the fifth story it carries four stories of transcript it will never need again. `scripts/drive_epic.py` moves that boundary into the process table. It spawns one `claude -p` per story under `--max-stories 1`, so each story's context dies with the process that held it:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
uv run .claude/skills/ultracode-goal/scripts/drive_epic.py \
|
|
60
|
+
--epic 7 \
|
|
61
|
+
--impl-artifacts _bmad-output/implementation-artifacts \
|
|
62
|
+
--profile light \
|
|
63
|
+
--dry-run
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Run it from your project root. The path above is the Claude Code skill copy the installer writes; the module copy under your resolved UCG folder (`_bmad/ucg/ultracode-goal/scripts/drive_epic.py` by default) is the same file, and in a clone of this repository it is `skills/ultracode-goal/scripts/drive_epic.py`.
|
|
67
|
+
|
|
68
|
+
Drop `--dry-run` to actually spawn. Point `--impl-artifacts` at the directory holding your `sprint-status.yaml`; the driver refuses to start if it is not there, since that is the sprint plan it reads. That directory also has to be the one your config resolves `implementation_artifacts` to, because the spawned session writes its terminal `run-result.json` where the config says, not where the driver was pointed. The driver cannot check that half for you: it would have to re-implement the skill's own config resolution to do it.
|
|
69
|
+
|
|
70
|
+
The driver is read-only on your tree with exactly one exception: it deletes the pinned `run-result.json` before each spawn, so the file's presence means *that* spawn reached a terminal. It stops on anything it cannot verify, and says why: no readable terminal, a `blocked` envelope (with the reason), a status it does not recognize, a `complete` whose story did not reach `done`, or a session that outran `--session-timeout` (2 hours by default; `0` disables it). Useful flags: `--limit N` caps how many sessions it spawns, `--permission-mode` defaults to `acceptEdits` and refuses `bypassPermissions` unless you also pass `--allow-full-autonomy`, and `--skill-command` overrides the invocation string for a plugin-marketplace install (`/bmad-module-ultracode-goal:ultracode-goal`).
|
|
51
71
|
|
|
52
72
|
## Hook security
|
|
53
73
|
|
|
54
|
-
At preflight the skill auto-merges its **PreToolUse** guard and **Stop** budget hook into `.claude/settings.local.json`, a machine-local, gitignored file, honored after the workspace trust dialog. These hooks are the enforcement layer that blocks a commit on a protected branch and bounds a runaway story; they are not shared into the repo. Because they execute on your machine, review what gets merged: see [SECURITY.md](
|
|
74
|
+
At preflight the skill auto-merges its **PreToolUse** guard and **Stop** budget hook into `.claude/settings.local.json`, a machine-local, gitignored file, honored after the workspace trust dialog. These hooks are the enforcement layer that blocks a commit on a protected branch and bounds a runaway story; they are not shared into the repo. Because they execute on your machine, review what gets merged: see [SECURITY.md](https://github.com/armelhbobdad/bmad-module-ultracode-goal/blob/main/SECURITY.md) for the hook-security model and what to check before granting trust.
|