bmad-module-ultracode-goal 0.4.0 → 0.5.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 +3 -3
- package/docs/architecture.md +1 -1
- package/docs/comparison.md +81 -0
- package/docs/getting-started.md +1 -1
- package/docs/how-it-works.md +0 -4
- package/docs/index.md +1 -0
- package/package.json +2 -2
- package/skills/ultracode-goal/assets/execute-epic.workflow.js +4 -5
- package/skills/ultracode-goal/customize.toml +1 -1
- package/skills/ultracode-goal/references/execute.md +4 -2
- package/skills/ultracode-goal/references/gate.md +24 -3
- package/skills/ultracode-goal/references/ingest-and-scope.md +3 -0
- package/skills/ultracode-goal/references/preflight.md +6 -1
- package/tools/cli/lib/ide-skills.js +4 -30
- package/tools/cli/lib/installer.js +8 -27
- package/tools/cli/lib/platform-codes.yaml +9 -206
- package/tools/cli/lib/ui.js +9 -54
- package/website/astro.config.mjs +1 -0
|
@@ -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": "0.5.1",
|
|
23
23
|
"author": {
|
|
24
24
|
"name": "Armel"
|
|
25
25
|
},
|
package/README.md
CHANGED
|
@@ -18,8 +18,6 @@
|
|
|
18
18
|
|
|
19
19
|
**Built for [Claude Code](https://www.anthropic.com/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
|
-
**What still ships everywhere, and what doesn't.** The shift-left planning customization and the standalone `/ucg-formalize` readiness gate are provider-portable BMAD content that installs on any editor; the install never refuses. What Claude Code adds is the preflight enforcement that fires `/ucg-formalize` automatically at run start. Off Claude Code, `/ucg-formalize` stays a manual, on-demand verdict you invoke yourself, and its readiness verdict plus five-key headless envelope are byte-identical across providers; only the automatic invocation is Claude-Code-only. ([How portability works →](./docs/how-it-works.md#portability-what-installs-everywhere-and-what-claude-code-adds))
|
|
22
|
-
|
|
23
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._
|
|
24
22
|
|
|
25
23
|
</div>
|
|
@@ -69,7 +67,7 @@ Requires [Claude Code](https://www.anthropic.com/claude-code) (the runtime UCG c
|
|
|
69
67
|
npx bmad-module-ultracode-goal install
|
|
70
68
|
```
|
|
71
69
|
|
|
72
|
-
You'll be prompted for a project name
|
|
70
|
+
You'll be prompted for a project name and whether to install the learning material; the skill installs for Claude Code. UCG is also available through the Claude plugin marketplace. See [Getting Started](./docs/getting-started.md) for that path.
|
|
73
71
|
|
|
74
72
|
> **Hook security:** UCG installs `PreToolUse`/`Stop` hooks into your machine-local, gitignored `.claude/settings.local.json` at preflight, never into a committed file. They run zero-dependency Python scripts shipped in the skill. See [SECURITY.md](SECURITY.md) for exactly what they execute and how to remove them.
|
|
75
73
|
|
|
@@ -99,6 +97,8 @@ A skeptical reader is probably already running one of these. Here is the honest
|
|
|
99
97
|
|
|
100
98
|
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.**
|
|
101
99
|
|
|
100
|
+
UCG's closest peer is [bmad-auto](https://github.com/bmad-code-org/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 an honest, side-by-side look at where each one wins, see [UCG vs bmad-auto](https://armelhbobdad.github.io/bmad-module-ultracode-goal/comparison/).
|
|
101
|
+
|
|
102
102
|
## Verifying
|
|
103
103
|
|
|
104
104
|
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.
|
package/docs/architecture.md
CHANGED
|
@@ -69,7 +69,7 @@ skills/ultracode-goal/
|
|
|
69
69
|
│ ├── guard_pretooluse.py # commit invariants (PreToolUse)
|
|
70
70
|
│ └── budget_stop.py # turn/token budget (Stop)
|
|
71
71
|
├── skills/
|
|
72
|
-
│ └── ucg-formalize/ # Standalone readiness gate
|
|
72
|
+
│ └── ucg-formalize/ # Standalone readiness gate
|
|
73
73
|
└── assets/
|
|
74
74
|
├── execute-epic.workflow.js # EXPERIMENTAL --parallel worktree fan-out
|
|
75
75
|
├── module.yaml · module-setup.md · module-help.csv # install metadata
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: UCG vs bmad-auto
|
|
3
|
+
description: An honest, side-by-side comparison of UltraCode Goal and bmad-code-org's bmad-auto orchestrator, including where bmad-auto is the better choice and which to reach for when.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Both UltraCode Goal (UCG) and [bmad-auto](https://github.com/bmad-code-org/bmad-auto) 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-auto is the better tool.
|
|
7
|
+
|
|
8
|
+
Snapshot: UCG v0.4.0 and bmad-auto v0.7.4, both as of 2026-06-28. Both projects are young and moving fast, so treat every line below as a point-in-time reading and verify the current state for yourself (links at the bottom).
|
|
9
|
+
|
|
10
|
+
## The one difference everything else follows from
|
|
11
|
+
|
|
12
|
+
bmad-auto 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) 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
|
+
|
|
14
|
+
UCG puts the control loop **inside Claude Code**. The run is a Claude Code skill that composes `/goal`, Auto Mode, runtime hooks, and dynamic workflows. 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 gate artifact.
|
|
15
|
+
|
|
16
|
+
The consequence cascades: bmad-auto is a tool you run beside any supported agent; UCG is a capability that lives within one specific agent.
|
|
17
|
+
|
|
18
|
+
## At a glance
|
|
19
|
+
|
|
20
|
+
| Dimension | bmad-auto | UltraCode Goal (UCG) |
|
|
21
|
+
|---|---|---|
|
|
22
|
+
| Runtime | External Python process plus tmux; Linux, macOS, or WSL | A skill inside Claude Code; no external process, no tmux |
|
|
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 | On-disk artifact checks plus your test and lint commands | TEA quality gate (`gate-decision.json`: P0/P1/overall, NFR, test-review) read by `gate_eval.py` |
|
|
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` (config, git, tmux, CLI, hooks) | `validate` plus a semantic scan that refuses to launch on an undecided product or architecture decision |
|
|
29
|
+
| Observability | Rich Textual TUI: dashboard, attach to live sessions, journal, token totals | Files: `.decision-log.md`, a `run-status.json` heartbeat, a transcript ticker, the `/workflows` view |
|
|
30
|
+
| Deferred work | A triage-and-execute **sweep** engine plus a decisions workflow | An append-only ledger surfaced at finalize; no execute engine |
|
|
31
|
+
| Escalation | Typed (CRITICAL / PREFERENCE) plus an interactive resolve agent | An escalate verdict and a blocked headless envelope; resume from the decision log |
|
|
32
|
+
| Isolation | Opt-in git worktree per story or bundle, merged back locally | Sequential by default; an experimental `--parallel` worktree fan-out |
|
|
33
|
+
| Extensibility | A plugin system plus a Unity game-engine plugin | `customize.toml` knobs and planning-shaping fragments |
|
|
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.7.4; rich docs; CI + test suite | Community module; v0.4.0; docs site; CI + test suite |
|
|
36
|
+
| License | MIT | MIT |
|
|
37
|
+
|
|
38
|
+
## Where bmad-auto is stronger
|
|
39
|
+
|
|
40
|
+
This is a genuinely strong tool; pretending otherwise would make this page useless.
|
|
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 and only its final completion gate is deterministic. If you want zero LLM judgment in the orchestration itself, bmad-auto is the cleaner model.
|
|
43
|
+
2. **Agent portability.** It drives claude, codex, gemini, or GitHub Copilot CLI, 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 Textual TUI 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 into a run is files and the transcript.
|
|
45
|
+
4. **A deferred-work engine, not just a ledger.** `bmad-auto 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 and surfaces it at the end; acting on it is manual.
|
|
46
|
+
5. **Extensibility and reach.** A real plugin system (observe, veto, mutate the cycle) and a Unity game-engine integration. UCG exposes configuration knobs, not a plugin API.
|
|
47
|
+
6. **Operational maturity.** Disk reclamation (clean and archive, retention windows, worktree teardown), cost-weighted token budgets that discount cache reads, an adapter-authoring path for new CLIs, and the backing of the bmad-code-org org.
|
|
48
|
+
|
|
49
|
+
## Where UCG is stronger
|
|
50
|
+
|
|
51
|
+
1. **Completion gated on formal traceability, not on build-and-review alone.** UCG's completion authority is the Test Architect's gate: a traceability matrix that holds acceptance criteria to hard thresholds (P0 = 100%, P1 >= 90%, overall >= 80%), ANDed in production with an NFR assessment and a test-review score. bmad-auto's gate is strict but differently shaped: your test and lint commands, a non-empty diff, an independent baseline-commit check, the spec marked done, and two adversarial review hunters. What UCG adds is the requirement that every acceptance criterion is demonstrably traced to a passing test at those thresholds, which bmad-auto does not compute.
|
|
52
|
+
2. **ATDD-first.** UCG turns each story's acceptance criteria into executable, red-phase (`test.skip`) tests before any code is written, then drives them to green. The acceptance tests are a first-class generated artifact, not a by-product. bmad-auto relies on the dev skill's own implementation plus the test commands you supply.
|
|
53
|
+
3. **A planning-readiness gate that can refuse to launch.** UCG's preflight hands a read of the PRD, architecture, and stories to a throwaway subagent that hunts undecided product or architecture decisions, PRD-versus-architecture contradictions, and an undefinable "done". Any such RED stops the run rather than letting an unattended agent guess. bmad-auto's preflight is mechanical (config, git, tmux, CLI, hooks); it assumes the sprint's stories are already ready to build.
|
|
54
|
+
4. **No moving parts outside the agent.** UCG is a skill: no external daemon, no tmux, no separate process 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.
|
|
55
|
+
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
|
+
|
|
57
|
+
## What they share
|
|
58
|
+
|
|
59
|
+
- A deterministic completion authority the model cannot talk its way past: bmad-auto's on-disk artifact and command checks plus its baseline-commit "lie detector"; UCG's TEA gate read.
|
|
60
|
+
- Fresh-context review separated from implementation, to kill self-review anchoring bias.
|
|
61
|
+
- Adversarial review passes, bounded so they cannot oscillate forever.
|
|
62
|
+
- Optional git worktree isolation.
|
|
63
|
+
- Resumable runs and per-story token budgets.
|
|
64
|
+
- `sprint-status.yaml` as planning truth, owned by the BMAD skills; both build on BMAD-METHOD.
|
|
65
|
+
|
|
66
|
+
## Which to reach for
|
|
67
|
+
|
|
68
|
+
Choose **bmad-auto** 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 want the tool published under the bmad-code-org org.
|
|
69
|
+
|
|
70
|
+
Choose **UCG** if you are on Claude Code, you want completion judged by the Test Architect's traceability thresholds (every acceptance criterion traced to a passing test) rather than by build-and-review checks, 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 a single skill with no external process to operate.
|
|
71
|
+
|
|
72
|
+
They are not mutually exclusive. Both read the same `sprint-status.yaml` and BMAD artifacts, so you can plan and gate an Epic UCG's way and grind a deferred-work backlog bmad-auto's way in the same project.
|
|
73
|
+
|
|
74
|
+
## Verify this yourself
|
|
75
|
+
|
|
76
|
+
Both tools change weekly, so re-check before you rely on anything above:
|
|
77
|
+
|
|
78
|
+
- bmad-auto: its [README](https://github.com/bmad-code-org/bmad-auto), [docs/FEATURES.md](https://github.com/bmad-code-org/bmad-auto/blob/main/docs/FEATURES.md), and [docs/ROADMAP.md](https://github.com/bmad-code-org/bmad-auto/blob/main/docs/ROADMAP.md).
|
|
79
|
+
- UCG: [How It Works](how-it-works.md) and the [Gate Model](gate-model.md).
|
|
80
|
+
|
|
81
|
+
This snapshot was taken on 2026-06-28 against bmad-auto v0.7.4 and UCG v0.4.0.
|
package/docs/getting-started.md
CHANGED
|
@@ -27,7 +27,7 @@ The run also depends on recent Claude Code primitives: `/goal`, dynamic workflow
|
|
|
27
27
|
npx bmad-module-ultracode-goal install
|
|
28
28
|
```
|
|
29
29
|
|
|
30
|
-
The installer is interactive: it prompts for the project name and
|
|
30
|
+
The installer is interactive: it prompts for the project name and whether to install the learning material, then installs the skill for Claude Code. As an alternative, the module can be installed from the plugin marketplace entry (`.claude-plugin/marketplace.json`) the same way as other BMAD plugins.
|
|
31
31
|
|
|
32
32
|
## First run
|
|
33
33
|
|
package/docs/how-it-works.md
CHANGED
|
@@ -137,7 +137,3 @@ With `-H`, the run is non-interactive: infer scope, default to production (unles
|
|
|
137
137
|
```
|
|
138
138
|
|
|
139
139
|
An automator parses one schema regardless of where the run stopped; a blocked-before-report exit returns `report` and `deferred_work` as `null` rather than omitting them.
|
|
140
|
-
|
|
141
|
-
## Portability: what installs everywhere, and what Claude Code adds
|
|
142
|
-
|
|
143
|
-
UCG installs on any editor and never refuses. The shift-left planning customization is provider-portable BMAD content; it shapes your planning workflows wherever it lands. The standalone `/ucg-formalize` readiness gate installs everywhere too. The one thing Claude Code adds is the preflight enforcement that runs that gate automatically at run start: that automatic invocation is a Claude Code-only capability. Off Claude Code, `/ucg-formalize` remains a manual, on-demand verdict you invoke yourself; the readiness check still exists, it is simply no longer fired for you by preflight. The readiness verdict definition and the five-key headless envelope above are byte-identical across providers; only the automatic invocation changes. UCG documents this gap plainly rather than implying a readiness check runs by itself where the runtime cannot run it.
|
package/docs/index.md
CHANGED
|
@@ -64,3 +64,4 @@ The docs split into three buckets: **Why** (start here), **Try** (do stuff), and
|
|
|
64
64
|
- [Health Check](./health-check.md): the terminal self-improvement reflection: what it sends, the privacy model, and how to disable it.
|
|
65
65
|
- [Cross-Session Recall](./cross-session-recall.md): the optional claude-mem integration and its trust model.
|
|
66
66
|
- [Troubleshooting](./troubleshooting.md): real failure modes and their remediations.
|
|
67
|
+
- [UCG vs bmad-auto](./comparison.md): an honest, side-by-side comparison with bmad-code-org's bmad-auto orchestrator.
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json.schemastore.org/package.json",
|
|
3
3
|
"name": "bmad-module-ultracode-goal",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.5.1",
|
|
5
5
|
"description": "BMAD module — Run a BMAD Epic autonomously to a machine-checked, TEA-gated Definition-of-Done.",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"bmad",
|
|
@@ -73,7 +73,7 @@
|
|
|
73
73
|
"@clack/prompts": "^1.1.0",
|
|
74
74
|
"chalk": "^4.1.2",
|
|
75
75
|
"commander": "^14.0.0",
|
|
76
|
-
"figlet": "
|
|
76
|
+
"figlet": "1.11.0",
|
|
77
77
|
"fs-extra": "^11.3.0",
|
|
78
78
|
"js-yaml": "^4.1.0"
|
|
79
79
|
},
|
|
@@ -137,7 +137,7 @@ function runStory(s, i) {
|
|
|
137
137
|
`Execute these steps IN ORDER, printing real evidence at each step (the printed evidence keeps the run auditable, but the GATE is gate_eval.py, not your judgment):\n` +
|
|
138
138
|
`1. bmad-create-story (Create mode only — never Resume) to fully context the story file if it is not already complete.\n` +
|
|
139
139
|
`2. bmad-dev-story to implement it, UN-SKIPPING the red-phase ATDD acceptance tests for this story (remove the test.skip markers that define the Definition-of-Done) so they actually run.\n` +
|
|
140
|
-
`3. Run and PRINT the project's test, lint, and build commands. Once all three are green, write the tests-ran marker file ${implArtifacts}/.tests-ran-${id} (exact name the PreToolUse hook checks, with ULTRACODE_STORY_ID=${id} for this worktree) so the hook permits the commit. Do NOT proceed to commit unless all three are green.\n` +
|
|
140
|
+
`3. Run and PRINT the project's test, lint, and build commands. In a monorepo, scope the test run wide enough to catch cross-package regressions — run the full suite, or the changed package(s) plus their dependents (e.g. --affected and downstream), not just this story's own package: a story's change can regress a sibling package's conformance gate within this worktree, and a package-scoped run reports green while that sibling gate is red. Once all three are green, write the tests-ran marker file ${implArtifacts}/.tests-ran-${id} (exact name the PreToolUse hook checks, with ULTRACODE_STORY_ID=${id} for this worktree) so the hook permits the commit. Do NOT proceed to commit unless all three are green.\n` +
|
|
141
141
|
reviewStep +
|
|
142
142
|
`5. COMMIT AT GREEN: make exactly ONE commit on this worktree's branch capturing the story. The PreToolUse hook will deny the commit on a protected branch or without the tests-ran marker — that is expected enforcement, satisfy it rather than bypass it. Set committed=true only if the commit succeeded on green.\n` +
|
|
143
143
|
`6. GATE THIS STORY — run EXACTLY:\n` +
|
|
@@ -188,11 +188,10 @@ for (const r of perStory) {
|
|
|
188
188
|
phase('EpicGate')
|
|
189
189
|
const epicGate = await agent(
|
|
190
190
|
`All stories of BMAD Epic "${epic}" have been delivered on their worktree branches. ` +
|
|
191
|
-
`Run the EPIC-LEVEL
|
|
192
|
-
(isProduction ? ` (run bmad-testarch-automate -> bmad-testarch-trace
|
|
191
|
+
`Run the EPIC-LEVEL TRACE gate over the consolidated epic — a trace-only read of the epic's gate_status, passing NO --nfr/--test-review (the per-story production NFR/test-review ANDs already ran at each story gate, and TEA writes no epic-level aggregate; a placeholder epic-level --test-review path would fail-closed and spuriously downgrade an epic PASS to reloop)` +
|
|
192
|
+
(isProduction ? ` (run bmad-testarch-automate -> bmad-testarch-trace first to build the epic trace decision)` : ` (run bmad-testarch-trace first)`) +
|
|
193
193
|
`, then run EXACTLY:\n` +
|
|
194
|
-
` uv run ${skillRoot}/scripts/gate_eval.py --trace-output ${traceOutput} --story ${epic} --profile ${profile}` +
|
|
195
|
-
(isProduction ? ` --nfr <nfr-assessment.md> --test-review <test-review.md>` : ``) + `\n` +
|
|
194
|
+
` uv run ${skillRoot}/scripts/gate_eval.py --trace-output ${traceOutput} --story ${epic} --profile ${profile}\n` +
|
|
196
195
|
`Return the script's verdict, gate_status, and reasons VERBATIM. Do not recompute thresholds or override the verdict.\n` +
|
|
197
196
|
`Per-story outcomes for context: ${JSON.stringify(perStory.map((r) => ({ story: r.story, verdict: r.verdict, gate_status: r.gate_status })))}\n\n` +
|
|
198
197
|
`Return ONLY the JSON object matching the schema.`,
|
|
@@ -28,7 +28,7 @@ story_token_budget = 1500000
|
|
|
28
28
|
parallel_max_concurrency = 8
|
|
29
29
|
|
|
30
30
|
# --- Commands pre-populated to the allowlist before an unattended run ---
|
|
31
|
-
allowlist_commands = ["git status", "git add
|
|
31
|
+
allowlist_commands = ["git status", "git add", "git commit", "npm test", "npm run lint", "npm run build", "pytest", "uv run"]
|
|
32
32
|
|
|
33
33
|
# --- Hook fired at epic completion (prompt or shell command); empty = none ---
|
|
34
34
|
on_epic_complete = ""
|
|
@@ -14,9 +14,10 @@ For each in-scope story, in sprint order, run this loop:
|
|
|
14
14
|
|
|
15
15
|
0. **Set the current story** so the PreToolUse hook can locate this story's marker: write the story id to `{workflow.implementation_artifacts}/.current-story` (or export `ULTRACODE_STORY_ID=<story_id>` for the run). The guard reads the story id from `ULTRACODE_STORY_ID`, falling back to that `.current-story` file — without one set, it cannot find the marker and denies every commit.
|
|
16
16
|
1. `bmad-create-story` (if not already current) → `bmad-dev-story` implementing the feature and **un-skipping** the story's ATDD acceptance tests (remove `test.skip()`) — **production only**; under `--light` there are no ATDD tests to un-skip, so the DoD is the story's acceptance criteria satisfied with lint and build green. Before delegating, check the run's `.decision-log.md` for an **Operator notes** entry naming this story (a pre-launch hint like "watch the auth flow in story 3") and surface that note into the `bmad-dev-story` / review context for this story so the operator's last words actually reach the work.
|
|
17
|
-
2. Run the tests, lint, and build, and **PRINT the raw output** (pass/fail counts, lint result, build result) into the transcript. This printed evidence is what keeps the run judgeable mid-flight and what the `/goal` driver reads to pace itself — but it is *evidence*, not the gate. **Once all three go green, write the tests-ran marker** `{workflow.implementation_artifacts}/.tests-ran-<story_id>` (mirroring `assets/execute-epic.workflow.js` step 3) — the PreToolUse guard denies the step-4 commit unless this marker exists for the current story, so write it only after a real green run.
|
|
17
|
+
2. Run the tests, lint, and build, and **PRINT the raw output** (pass/fail counts, lint result, build result) into the transcript. **In a monorepo, scope that test run wide enough to catch cross-package regressions** — run the full suite, or the changed package(s) plus everything downstream of them (e.g. an `--affected` set *and its dependents*), not just this story's own package. A story's change can regress a *sibling* package's conformance gate (a cross-package RBAC, ownership, or architecture-boundary check), and a run scoped to only this story's package reports green while that sibling gate is red — deferring the red (and its fix) to a later story or the Epic gate instead of catching it at the story that caused it. This printed evidence is what keeps the run judgeable mid-flight and what the `/goal` driver reads to pace itself — but it is *evidence*, not the gate. **Once all three go green, write the tests-ran marker** `{workflow.implementation_artifacts}/.tests-ran-<story_id>` (mirroring `assets/execute-epic.workflow.js` step 3) — the PreToolUse guard denies the step-4 commit unless this marker exists for the current story, so write it only after a real green run.
|
|
18
18
|
3. **Production profile only:** `bmad-testarch-test-review`, then `bmad-code-review`. A `CONCERNS`-grade or non-critical finding appends to `{workflow.deferred_work_path}` and the story proceeds. A **P0 / critical FAIL never defers** — re-loop within the turn budget or escalate.
|
|
19
|
-
4. **Commit at green** (one commit per green story). The PreToolUse hook blocks a commit on a protected branch and blocks a commit when no "tests-ran" marker exists for the current story, so step 0 must have set the current story and step 2 must have actually run and written `{workflow.implementation_artifacts}/.tests-ran-<story_id>` **in a prior, SEPARATE command**. The guard pre-evaluates the command *string* before it runs, so a marker written by a `printf`/`echo` in the SAME compound command as the commit (e.g. `printf … > .tests-ran-<id> && git commit …`) does not yet exist at hook-eval time and the commit is denied. Write the marker, then commit — two distinct tool calls.
|
|
19
|
+
4. **Commit at green** (one commit per green story). The PreToolUse hook blocks a commit on a protected branch and blocks a commit when no "tests-ran" marker exists for the current story, so step 0 must have set the current story and step 2 must have actually run and written `{workflow.implementation_artifacts}/.tests-ran-<story_id>` **in a prior, SEPARATE command**. The guard pre-evaluates the command *string* before it runs, so a marker written by a `printf`/`echo` in the SAME compound command as the commit (e.g. `printf … > .tests-ran-<id> && git commit …`) does not yet exist at hook-eval time and the commit is denied. Write the marker, then commit — two distinct tool calls. **Stage only the current story's paths.** In production, Stage 3 generated *every* in-scope story's red-phase tests up front, so a sibling story's still-skipped tests can co-reside in the same shared dirs as this story's (one `test/` package may hold two stories' acceptance specs before either commits). A blanket `git add -A` here sweeps those uncommitted sibling tests into this story's commit and pollutes the per-story boundary — stage this story's source + test paths explicitly (`git add <this story's paths>`) instead. The allowlist ships plain `git add` (a prefix covering both `-A` and a scoped `git add <paths>`) so the targeted add needs no extra approval. (Under `--light` no ATDD tests are generated, so the collision cannot arise; under `--parallel` each story owns its worktree, so it does not arise there either.)
|
|
20
|
+
5. **Re-verify on the committed HEAD.** Re-run the authoritative full suite (tests + lint + build, the same wide scope as step 2) on the just-committed, clean tree and **PRINT** the result before advancing. Step 2's pre-commit run cannot see a **conformance gate scoped to *tracked* files** — a `git ls-files`-based ref/ownership/architecture-boundary check: a story's **new** files are still untracked at step 2, so the gate skips them and reports green, then reds the instant the commit tracks them (generated or `.gitignore`d files hide the same way). This committed tree is the exact fileset CI and the Stage-5 gate will see, so a story that is green pre-commit but red here is a **false green** the pre-commit run and the `/goal` transcript evaluator both miss. A red means the story is **not** done: remediate, write a fresh `.tests-ran-<story_id>` marker, and re-commit (amend or a follow-up within the story boundary) until the committed HEAD is green — only then advance.
|
|
20
21
|
|
|
21
22
|
**Sub-skill halt catch-all.** If any orchestrated sub-skill blocks on interactive input mid-run, treat it as escalate for that story — write the escalation marker and stop; do not answer its prompt blind.
|
|
22
23
|
|
|
@@ -63,6 +64,7 @@ Each story runs isolated in its own worktree: `bmad-dev-story` (un-skip ATDD —
|
|
|
63
64
|
- **Shared Auto Memory.** Concurrent worktrees write to **one** Auto Memory directory — there is no per-worktree isolation of learned facts; expect interleaving.
|
|
64
65
|
- **Under-documented interplay.** The workflow↔skill handoff (how args bind, how subagents inherit the allowlist and hooks) is not fully specified by the platform docs; treat its behavior as empirically validated, not guaranteed.
|
|
65
66
|
- **No `run-status.json` heartbeat.** Worktree agents cannot reliably write one shared snapshot (each worktree sees its own copy of `{workflow.implementation_artifacts}`), so this path does not write it — progress is watched via the workflow progress view (`/workflows`) and its run log, and the launch briefing says so.
|
|
67
|
+
- **No post-commit re-verify.** Unlike the sequential spine's step 5, the fan-out commits at green and goes straight to per-story `gate_eval` without re-running the suite on the committed tree — so a **tracked-files-scoped conformance gate** (a `git ls-files`-based ref/ownership/boundary check) that only reds once a worktree's new files are committed can slip a per-worktree green through to the merge. Until this path re-verifies on the committed HEAD, treat the epic-level gate over the merged result as the backstop for that class, and prefer the sequential spine for repos that carry such a gate.
|
|
66
68
|
|
|
67
69
|
### Graceful degradation
|
|
68
70
|
|
|
@@ -13,7 +13,7 @@ The gate reads artifacts TEA produces. In **production**, before running the gat
|
|
|
13
13
|
|
|
14
14
|
`bmad-testarch-nfr` (produces `nfr-assessment.md`) and `bmad-testarch-test-review` are independent — of each other *and* of the automate→trace chain — so run them in any order, or concurrently with it; `gate_eval.py` consumes all three artifacts without caring how they were produced. (`bmad-testarch-test-review` normally runs in Execute per story — run it here only if you lack a current `test-review.md` for the story.) In **`--light`**, skip all of the above and run only `bmad-testarch-trace`, then the gate with `--profile light` (trace gate only — no NFR/review AND).
|
|
15
15
|
|
|
16
|
-
## Non-web
|
|
16
|
+
## Non-web stack (web-only TEA chain): author the deterministic trace artifacts
|
|
17
17
|
|
|
18
18
|
When the module's TEA chain is web-only, `bmad-testarch-trace` cannot run on a non-web stack and so cannot emit the binding gate decision. Do **not** reverse-engineer a prior run's leftover artifacts — author the two files to the exact shape `scripts/gate_eval.py` reads; every other field in real TEA output (`target`, `links`/`trace_report_path`, `rationale`, `schema_version`) is decoration the reader never touches. Name both for the story (`trace-<id>.md`, `gate-decision-<id>.json`) so `--story <id>` scoping resolves them in a shared `--trace-output` dir.
|
|
19
19
|
|
|
@@ -32,7 +32,28 @@ gateDecisionFile: gate-decision-<id>.json # the slim file to read; relative to -
|
|
|
32
32
|
{ "gate_status": "PASS", "p0_status": "MET", "p1_status": "MET", "overall_status": "MET" }
|
|
33
33
|
```
|
|
34
34
|
|
|
35
|
-
Write a PASS only when the story's acceptance criteria
|
|
35
|
+
Write a PASS only when the story is demonstrably done to its profile's Definition-of-Done (under `--light`: acceptance criteria satisfied with lint and build green; under production the bar is higher — also un-skipped passing acceptance tests plus test-review/code-review, per the profile note below — see `references/define-done.md`); a non-green story is `reloop`/`escalate`, never a hand-authored PASS (see the INVARIANT in "Route on the verdict"). `p0_status`/`p1_status`/`overall_status` are passthrough-only here — they do not drive the `--light` verdict, so write them to reflect reality, never to dress up a non-green story. If you instead write the always-present `e2e-trace-summary.json`, the reader takes its top-level `gate_status` and the nested `gate_criteria.{p0_status,p1_status,overall_status}` — the same fields one level down.
|
|
36
|
+
|
|
37
|
+
**Which profile's gate you then run.** The hand-authored trace decision above is the same file for either profile; only what you AND onto it differs. Under **`--light`** it *is* the whole gate — run `gate_eval.py --profile light` (below) and stop. Under **production** — the legitimate case when an operator scopes foundational, non-web packages to the full chain — the production ANDs still apply. TEA's *browser* generators are what a non-web stack cannot run as-is: ATDD in Stage 3 and the automate→trace pair here. So the story's acceptance tests are authored and driven in the stack's own harness (the Vitest case) and reach the production Definition-of-Done un-skipped and passing, and you hand-author the trace decision above in place of automate→trace. `bmad-testarch-nfr` and `bmad-testarch-test-review` are independent of that browser pair (see "Backfill the gate evidence" above), so still produce `nfr-assessment.md` and `test-review.md` the normal way and run `gate_eval.py --profile production --story <story_id> --nfr … --test-review …`. Pass **both** flags: `gate_eval.py` fail-closes a `--nfr`/`--test-review` path that is given-but-missing, but a flag you simply *omit* is silently skipped and its AND quietly dropped — so omitting them on a production run inflates the gate by losing a signal, the same dishonesty the hand-authored-PASS rule forbids. If a signal genuinely cannot be produced on the stack either, that is a CONCERNS/`defer` or a `reloop`, never a dropped flag. A stack that cannot meet the production acceptance-test bar at all belongs under `--light` (see the framework fitness caveat in `references/preflight.md`), not a hand-waved production PASS. The honesty bar is unchanged: a PASS requires full AC coverage by passing tests, never to dodge an AND.
|
|
38
|
+
|
|
39
|
+
**Hand-authored `nfr-assessment.md` and `test-review.md` shapes (production path only).** `gate_eval.py` scans these two files with the *same* parser it uses on real TEA output, so a hand- or agent-authored file must carry the exact fields below — otherwise the scanner reads the signal as *not found* and, under the fail-closed contract, treats it as **failing**, spuriously downgrading an `advance` to `reloop`. (Under `--light` neither file is read, so this whole block is production-only.) Only the named field is parsed; everything else is human prose.
|
|
40
|
+
|
|
41
|
+
`nfr-assessment.md` — the reader needs one field:
|
|
42
|
+
|
|
43
|
+
```markdown
|
|
44
|
+
**Overall Status:** PASS
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
`PASS` | `CONCERNS` | `FAIL` (the key may also be written `overallStatus:`). A `FAIL` — or a status the scanner cannot find — downgrades `advance`→`reloop`.
|
|
48
|
+
|
|
49
|
+
`test-review.md` — the reader needs two fields:
|
|
50
|
+
|
|
51
|
+
```markdown
|
|
52
|
+
**Quality Score**: 89/100
|
|
53
|
+
**Recommendation**: Approve
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
The score **must** carry the `/100` denominator: a bare `score: 89` matches nothing, is read as *not found*, and fail-closes to `reloop` — always write it as `N/100` (a `Quality Score` label or a bare `score` both parse, but only with `/100`). `Recommendation` ∈ `Approve` | `Approve with Comments` | `Request Changes` | `Block`; a `Block`, or a score `< 80`, downgrades `advance`→`reloop`.
|
|
36
57
|
|
|
37
58
|
## Run the gate
|
|
38
59
|
|
|
@@ -63,7 +84,7 @@ Do not recompute TEA thresholds or re-judge `gate_status` — read it as given.
|
|
|
63
84
|
|
|
64
85
|
## Route on the verdict
|
|
65
86
|
|
|
66
|
-
- **`advance`** (gate_status PASS or WAIVED) → the story passes. Move to the next story. When **every story of the Epic is `done`**, run the Epic-level trace gate the
|
|
87
|
+
- **`advance`** (gate_status PASS or WAIVED) → the story passes. Move to the next story. When **every story of the Epic is `done`**, run the Epic-level **trace** gate: pass the epic's own id via `--story` (scoped per the `--story` note above) and read its `gate_status` **only** — do **not** pass `--nfr`/`--test-review` at the epic level. TEA produces NFR and test-review **per story, not per epic**, so there is no epic-level aggregate to AND, and every story's own production gate already ANDed its signals before reaching `done`; the epic roll-up is a pure trace read (`--profile production` with neither flag and `--profile light` are identical here — the test suite exercises the epic-level resolution under `--profile light`). Omitting the flags at the epic level is therefore *correct*, not the signal-dropping the per-story production gate forbids in "Run the gate" (that rule governs a per-story gate, where TEA did produce the artifacts). Passing an epic-level `--test-review`/`--nfr` path that no aggregate writes is exactly the mistake that gets "test-review file … not found; treated as failing" and spuriously downgrades an epic PASS to `reloop`. Then proceed to Stage 6 (`references/finalize.md`). **Partial-by-design exception:** if this run delivered only a deliberate *strict subset* of the Epic's stories (in-scope ⊊ Epic — e.g. a conditional / evidence-gated Epic where the operator scoped a subset; this is distinct from ingest-and-scope.md's already-`done`-skipping, which still ends with every story `done`) — do **not** author an Epic-level gate: a PASS would misrepresent an incomplete Epic as complete. Record the per-story advance(s) and proceed to Stage 6 with the Epic left in its partial / conditional state (the `partial-complete` terminal outcome — see `references/finalize.md`).
|
|
67
88
|
|
|
68
89
|
- **`defer`** (gate_status CONCERNS, or non-critical code-review / NFR findings that did not flip the gate) → append the open items to the ledger at `{workflow.deferred_work_path}` using the schema below, then **advance** anyway. The Epic keeps moving; the parked work is visible.
|
|
69
90
|
|
|
@@ -25,10 +25,13 @@ Resolution order:
|
|
|
25
25
|
```
|
|
26
26
|
|
|
27
27
|
It emits one line per Epic — id, story count, per-status counts, and `all_done` — and the story list per Epic. If the operator named an Epic, take it. Otherwise pick the obvious in-flight Epic from the rollup (single `in-progress`, or the next `backlog` after the last `done`). If genuinely ambiguous, list the candidates with their status and ask. Headless: pick the lowest-numbered not-`done` Epic and log the choice plus the rejected candidates. The pick stays judgment; the rollup only replaces the YAML parse.
|
|
28
|
+
|
|
29
|
+
**Numeric-key caveat.** The rollup groups stories by their numeric epic prefix (`^\d+`), so a track whose epic keys are non-numeric — e.g. an isolated `epic-st-5` / `st-5-1` starter track — returns `sprint_status_present: true` with an **empty `epics` array** (not an error; the helper still exits 0). Do not read that empty-but-present result as "the track has no epics" — it is the signal the track was not numerically disambiguated per rule 6. Reading the isolated `sprint-status.yaml` directly recovers Stage-1 scope selection, but treat that as a **diagnostic only**: the same numeric-prefix limit binds Stage 2's `formalize_check.py --epic` reader, so an alpha-keyed track still formalizes to zero in-scope stories downstream. A track meant to run the pipeline must be **re-keyed to a free epic number** (rule 6); do not carry an alpha-keyed track past Stage 1 on the strength of a direct read alone.
|
|
28
30
|
2. Confirm the Epic has a body (acceptance-bearing stories or an Epic file). A title-only Epic with no stories is not blocking here — Stage 2 generates missing stories/ACs via `bmad-create-story`. Note it so Stage 2 expects remediation.
|
|
29
31
|
3. **In-scope = not-yet-`done`.** The run's in-scope stories are the resolved Epic's stories whose rollup status is not `done`. A partially-done Epic — say stories 1–3 hand-finished before this run was ever invoked — carries only its remaining stories into preflight; log the done ones as `skipped-already-done` so Execute never re-drives them (the resume cursor only covers re-invocations that have a prior run folder; this rule covers the fresh invocation that doesn't). **Operator-scoped subset:** if the operator deliberately names a *strict subset* of the not-`done` stories (a conditional or evidence-gated Epic where only some stories are in play this run), honor it — in-scope ⊊ Epic. Such a run ends in the **`partial-complete`** terminal state with no Epic-level gate authored (gate.md / finalize.md), distinct from the already-done skip above, which still ends with every story `done`. Headless never narrows this way: its in-scope is every not-`done` story, so a successful headless run always finishes the Epic.
|
|
30
32
|
4. **Already-done short-circuit.** If *every* story for the resolved Epic is already `done`, do not carry a no-op Epic into preflight: surface "this Epic is already complete — re-run anyway?" and proceed only on a yes (an explicit yes re-scopes all stories deliberately). Headless: emit the same five-key blocked JSON (`report`/`deferred_work` `null`) with `reason` "epic already complete".
|
|
31
33
|
5. If `sprint-status.yaml` is absent (the rollup says so and emits no Epics) or `{planning_artifacts}` has no PRD/ADR for this Epic, that is not a hard stop at this stage — record the gap; Stage 2 preflight reports it mechanically and the semantic scan judges whether the missing planning artifact is a true RED (undecided product/architecture) or a benign absence.
|
|
34
|
+
6. **Cross-file or colliding-epic initiative.** The resolution chain keys on the epic *number*: the rollup and `formalize_check.py --epic` both read it against one `sprint-status.yaml` inside `{workflow.implementation_artifacts}`, and the Stage-5 gate (`gate_eval.py`) resolves per-story trace artifacts *by id* inside `{workflow.trace_output_dir}`. So an initiative that is **not** tracked in that sprint-status (its epic/stories live in a separate planning file, e.g. a starter-template track brought in alongside the product's own epics) — **or** whose epic number **collides** with an epic already in it — cannot be resolved by number without silently hitting the wrong, unrelated epic. Run it as an **isolated track**: point `--impl-artifacts` (and the matching `{workflow.trace_output_dir}` / test-artifacts root) at a dedicated dir that holds *only* this initiative's own `sprint-status.yaml` and stories, and give its stories **disambiguated ids that keep a numeric epic prefix** — a free, high epic *number* no shared-track epic uses (e.g. `epic-90` with stories `90-1`, `90-2`), never an alpha prefix like `st-5`. Keep the disambiguation numeric because the number-keyed readers named above group by the `^\d+` prefix: an alpha-keyed track (`epic-st-5` / `st-5-1`) silently rolls up to an empty `epics` array and formalizes to zero in-scope stories. Pass that isolated `--impl-artifacts` to the sprint-status readers (`preflight_check.py --rollup`, `formalize_check.py`); scope the gate to the isolated track by pointing `gate_eval.py --trace-output` at that dedicated trace dir with `--story <disambiguated id>` (it keys on the story id against trace-report filenames, never on the epic number against a sprint-status, so it takes no `--impl-artifacts`). Record the isolated `--impl-artifacts` and trace-output paths in `.decision-log.md` so Stage 2 and the gate inherit them verbatim; never let a number-keyed read fall through to the shared `sprint-status.yaml`.
|
|
32
35
|
|
|
33
36
|
Do not open story or planning files for deep reading here — note their paths so Stage 2 and the TEA stages scan them. Reading them now bloats context ahead of delegation.
|
|
34
37
|
|
|
@@ -47,11 +47,13 @@ Clear each remediable blocker, then **re-run the check** so the budget reflects
|
|
|
47
47
|
- **Missing acceptance criteria / story** for an in-scope story: generate via `bmad-create-story` so each story carries clear, testable ACs. TEA atdd and trace both need them; a story without ACs has nothing to trace and will stall.
|
|
48
48
|
- **Test-artifacts dirs absent** (`test_artifacts_dirs` incomplete): pre-create the trace/test-design/test-review output dirs (`{workflow.trace_output_dir}` and its siblings under the TEA `test_artifacts` root) so TEA writes land deterministically and `gate_eval.py` finds them in Stage 5.
|
|
49
49
|
- **`project-context.md` count != 1** (`project_context_count`) — advisory only: `preflight_check.py` reports it as a **check** and never appends it to `blockers[]`, so a count of `0` or `> 1` never moves `budget` and never blocks launch. Resolve to exactly **one** anyway (generate via `bmad-generate-project-context` if zero; de-dup if multiple): `{workflow.persistent_facts}` globs this file and duplicates poison Auto-Memory grounding — that is why to fix it, not the gate.
|
|
50
|
-
- **`sprint-status.yaml` absent** (`sprint_status_present: false`): ensure it is present (via `bmad-sprint-planning`). Its presence makes TEA test-design **auto-select Epic-Level** and skip its interactive System/Epic mode prompt — without it, Stage 3 stalls on a question no one is there to answer.
|
|
50
|
+
- **`sprint-status.yaml` absent** (`sprint_status_present: false`): ensure it is present (via `bmad-sprint-planning`). Its presence makes TEA test-design **auto-select Epic-Level** and skip its interactive System/Epic mode prompt — without it, Stage 3 stalls on a question no one is there to answer. **Non-default-track caveat:** `preflight_check.py`'s `sprint_status_present` falls back to a repo-wide `_bmad-output/**` glob, so on a run scoped to a non-default `--impl-artifacts` dir (an isolated track, per ingest-and-scope.md's cross-file/colliding-epic rule) it can read `true` off a *foreign* track's `sprint-status.yaml` while this run's own track has none — this `sprint_status_present: false` trigger then never fires. On any non-default `--impl-artifacts` run, take `formalize_check.py`'s strict per-impl-artifacts read (the §1b `sprint_status_absent` mechanical gap) as the authoritative sprint-status signal and remediate off *that*, not the glob-backed flag.
|
|
51
51
|
- **TEA mode**: force **Create** mode for every TEA workflow this run. Resume/Validate/Edit are interactive and will halt an unattended run. Set/confirm whatever the TEA config exposes (`tea_execution_mode`) so no workflow resumes a prior session.
|
|
52
52
|
- **Secrets / credentials** a story needs (test env keys, API tokens): **interactive** — prompt **once**, now, and capture them out of git. **Headless** — do not prompt; an unresolvable secret becomes a RED blocker (step 4), never a deferred question.
|
|
53
53
|
- **Formalize mechanical gaps** (`formalize_check.py`'s `mechanical_gaps[]` from step 1b): fold these machine-derivable, meaning-preserving fixes into *this same* pass — never a second remediation pass and never a new step heading. The genuinely-new one is the leaked-TEA-artifact **MOVE-and-re-point**: move a TEA artifact that leaked into a source/impl dir out to the `{workflow.trace_output_dir}` / test_artifacts root, then re-point every in-repo reference to the new path (content is only relocated, never rewritten) — the MOVE targets a *genuine* TEA artifact only; the kernel now excludes UCG's own story notes / run sentinels whose filename merely carries a marker token because the story slug does (`formalize_check.py:_is_ucg_impl_artifact`), so they no longer reach this remediation. Should any *other* non-TEA false positive ever surface, **verify identity before moving** and archive it *out of the impl-artifacts scan tree* — never into the trace dir (that misfiles it) and never leave it in place (it stays counted and deadlocks the `budget == 0` gate, since a remediable gap that is never cleared keeps the formalize verdict off `ready`) — recording in `.decision-log.md` what it actually is. The orphaned-index and missing-AC gaps reuse the `bmad-create-story` scaffold this step already runs. Auto-clear **only** a `mechanical_gaps[]` entry whose `remediable == true` (the kernel's human-authored `remediable` literal, never re-decided in this prose); a leaked-artifact finding the kernel emitted as a `judgment_candidates[]` entry or with `remediable: false` is **not** moved here — that residual content-soundness judgment routes to the step-3 scan / step-4 hard gate. These remediations reuse the existing remediate-then-re-run loop below ("run the script from step 1 again"), so the budget re-reflects the formalize fixes on re-run with no extra invocation.
|
|
54
54
|
|
|
55
|
+
**Stale-hook pre-arming (before any remediation commit).** A prior UCG run may have left its PreToolUse guard (`scripts/hooks/guard_pretooluse.py`) and Stop budget hook (`scripts/hooks/budget_stop.py`) armed in `{project-root}/.claude/settings.local.json` — still live *now*, because step 5 has not yet re-armed this run's hooks. That stale guard mis-governs any remediation that commits (the dirty-tree `git_clean: false` clear especially): its marker-gate keys on `.current-story` plus a `.tests-ran-<story_id>` marker in the impl-artifacts, and on a fresh run `.current-story` is either unset — so no marker resolves and the commit is **denied**, dead-ending the remediation — or still points at the prior run's last story, whose persisted marker (Finalize removes only `.mem-state.json`, never the tests-ran markers) it then **rides to a spurious green**, waving the commit through under stale, wrong-run enforcement. Both failure modes are wrong for this run. Do **not** forge a marker and do **not** wait on the gate: **disarm the prior-run hooks first** — remove the UCG `guard_pretooluse.py` / `budget_stop.py` entries from `settings.local.json` — then make the remediation commit, and let step 5 re-merge both hooks freshly with *this* run's injected env. Log the disarm and the step-5 re-arm to `.decision-log.md`.
|
|
56
|
+
|
|
55
57
|
**Ordering: only framework → ci is load-bearing** (the CI scaffold halts without a framework, as its bullet states). Every other remediation above is mutually independent — run them in any order, or concurrently; do not serialize them defensively.
|
|
56
58
|
|
|
57
59
|
**Remediation halt catch-all.** If a remediation sub-skill itself fails or blocks on interactive input, do not re-invoke it blind and do not answer its prompt — record a **RED** blocker naming the sub-skill and the exact input or decision it needed, and let the hard gate (step 4) stop the run. This mirrors Execute's sub-skill halt catch-all; a bare re-report of "budget still N" with no cause is not an account.
|
|
@@ -82,6 +84,8 @@ The subagent must return **ONLY this object — no prose, no document quotes bey
|
|
|
82
84
|
"advisories_checked": [{"sig": "<advisory id>", "status": "recurred|not-observed|unknown"}]}
|
|
83
85
|
```
|
|
84
86
|
|
|
87
|
+
**Retrieving the result on an async-spawn platform.** The contract above assumes a *synchronous* spawn whose return text reaches you directly. If this run spawns the subagent as a **background teammate** instead, its plain-text return is **not** routed back to the conductor — so additionally instruct it to persist this *same* object to a **run-scoped** file — `{workflow.implementation_artifacts}/.preflight-scan-<run-id>.json`, using the `<run-id>` minted in Stage 1 (`epic-<id>-<UTC yyyymmddThhmmssZ>`) so a **prior** run's scan sitting at a shared path can never be misread as this one's — and read *that* file back, or message you the object explicitly. Because the async write may not have landed yet, wait for **this** run's file to appear and never fall back to an older or differently-named one; before feeding the object into the step-4 hard gate, confirm it is this run's scan (its findings reference this Epic, not a prior one). The discarded-context discipline is unchanged: you ingest only the object, never the corpus, which stays discarded in the subagent's context. (The same retrieval rule applies to any subagent this run spawns asynchronously — e.g. a background-delegated Execute `bmad-dev-story` or a gate TEA sub-skill: route its structured result through a file or an explicit message, never an unrouted plain-text return.)
|
|
88
|
+
|
|
85
89
|
Every `reds` entry is **RED** — it cannot be auto-remediated, because the fix is a human decision, and an unattended run guessing it produces confidently wrong work. A purely cosmetic gap belongs in `concerns`, never RED; recall-derived hypotheses are attributed under `advisories_checked` and are never themselves RED and never block launch. Record each RED finding with its source and the exact decision needed in `.decision-log.md`.
|
|
86
90
|
|
|
87
91
|
## 4. Hard gate
|
|
@@ -119,6 +123,7 @@ Do these in order; each must be asserted, not assumed:
|
|
|
119
123
|
- `ULTRACODE_TOKEN_BUDGET={workflow.story_token_budget}`
|
|
120
124
|
- `ULTRACODE_EPIC_BRANCH_PREFIX={workflow.epic_branch_prefix}`
|
|
121
125
|
- The same PreToolUse guard now also enforces the Cross-Session Recall latch from `{workflow.implementation_artifacts}/.mem-state.json` — the merged hook reads it automatically, fail-closed; no new env var to inject.
|
|
126
|
+
- **The commit/push guard string-matches the verb; it does not parse the command.** The guard scans each shell segment and flags any segment where `git` is followed by the literal `commit`/`push` verb — including the verb sitting inside an `echo`, a log line, or a here-string in a verification command, not only a real commit. So on a `{workflow.protected_branches}` branch a benign command that merely *mentions* `git commit` or `git push` is denied; and on the epic branch, before the story's `.tests-ran-<story_id>` marker exists, a command that merely mentions `git commit` is denied (the marker gate is commit-only — a `git push` mention is never marker-gated). Either way the tool call is wasted, so keep those literals out of echoes and status/verification commands during the run. (execute.md step 4 covers the narrower marker-written-in-the-same-compound-command trap.)
|
|
122
127
|
- **Allowlist.** Pre-populate the tool allowlist with `{workflow.allowlist_commands}` so the unattended run (and any fan-out subagents, which inherit the allowlist) can run tests/lint/build/commit without a permission prompt that no one is there to approve.
|
|
123
128
|
|
|
124
129
|
### Launch briefing (interactive only)
|
|
@@ -5,7 +5,8 @@
|
|
|
5
5
|
* supporting files) are copied directly to each IDE's skills/ directory.
|
|
6
6
|
* IDEs read SKILL.md natively.
|
|
7
7
|
*
|
|
8
|
-
*
|
|
8
|
+
* UCG is Claude-Code-only; platform-codes.yaml carries the single Claude Code
|
|
9
|
+
* target (config-driven, no IDE-specific code).
|
|
9
10
|
*/
|
|
10
11
|
|
|
11
12
|
const path = require('node:path');
|
|
@@ -51,39 +52,12 @@ function getAvailablePlatforms() {
|
|
|
51
52
|
});
|
|
52
53
|
}
|
|
53
54
|
|
|
54
|
-
/**
|
|
55
|
-
* Get IDE auto-detection markers.
|
|
56
|
-
* Returns { 'claude-code': ['.claude'], 'cursor': ['.cursor'], ... }
|
|
57
|
-
*
|
|
58
|
-
* Uses explicit detection_marker from platform config when available,
|
|
59
|
-
* otherwise derives from the top-level directory of target_dir.
|
|
60
|
-
* The derived marker only works when the IDE's config directory exists
|
|
61
|
-
* independently of the installer (e.g. .claude/ exists before UCG install).
|
|
62
|
-
*/
|
|
63
|
-
function getDetectionMarkers() {
|
|
64
|
-
const config = loadPlatforms();
|
|
65
|
-
const markers = {};
|
|
66
|
-
for (const [code, p] of Object.entries(config.platforms)) {
|
|
67
|
-
if (p.suspended) continue;
|
|
68
|
-
const targetDir = p.installer?.target_dir;
|
|
69
|
-
if (!targetDir) continue;
|
|
70
|
-
if (p.installer.detection_marker) {
|
|
71
|
-
markers[code] = [p.installer.detection_marker];
|
|
72
|
-
} else {
|
|
73
|
-
// Derive from target_dir — works when top-level dir is the IDE's own config dir
|
|
74
|
-
const topDir = '.' + targetDir.split('/')[0].replace(/^\./, '');
|
|
75
|
-
markers[code] = [topDir];
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
return markers;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
55
|
/**
|
|
82
56
|
* Install skill directories to all selected IDEs.
|
|
83
57
|
*
|
|
84
58
|
* @param {string} projectDir - Project root directory
|
|
85
59
|
* @param {string} ucgDir - Path to installed UCG module (e.g., {projectDir}/_bmad/ucg)
|
|
86
|
-
* @param {string[]} ideCodes - Array of IDE codes (
|
|
60
|
+
* @param {string[]} ideCodes - Array of IDE codes (always ['claude-code'])
|
|
87
61
|
* @returns {{ installed: number, ides: string[], directories: string[] }}
|
|
88
62
|
*/
|
|
89
63
|
async function installSkillsToIdes(projectDir, ucgDir, ideCodes) {
|
|
@@ -215,4 +189,4 @@ async function removeAllUcgSkills(projectDir) {
|
|
|
215
189
|
return removed;
|
|
216
190
|
}
|
|
217
191
|
|
|
218
|
-
module.exports = { installSkillsToIdes, getAvailablePlatforms,
|
|
192
|
+
module.exports = { installSkillsToIdes, getAvailablePlatforms, removeAllUcgSkills, loadPlatforms };
|
|
@@ -22,16 +22,6 @@ const DEV_ARTIFACTS = new Set(['.analysis', '.decision-log.md', '__pycache__', '
|
|
|
22
22
|
// deliberately NOT enrolled here.
|
|
23
23
|
const STEP6B_PLANNING_FRAGMENTS = ['bmad-prd', 'bmad-architecture', 'bmad-create-epics-and-stories', 'bmad-create-story'];
|
|
24
24
|
|
|
25
|
-
// Single canonical cross-provider portability gap line.
|
|
26
|
-
// Exported so the integration test asserts against this exact string — keep it a clean,
|
|
27
|
-
// honest sentence that matches /Claude.?Code.*only/i and contains NONE of the
|
|
28
|
-
// forbidden cross-provider auto-enforcement phrases. The note is non-blocking:
|
|
29
|
-
// the portable fragments + the standalone /ucg-formalize gate install on every
|
|
30
|
-
// provider; only the preflight HOOK auto-runs on Claude Code, and elsewhere
|
|
31
|
-
// /ucg-formalize is a manual on-demand verdict.
|
|
32
|
-
const PORTABILITY_GAP_LINE =
|
|
33
|
-
'Automatic preflight gating at run start is a Claude Code-only capability; on other providers /ucg-formalize stays available as a manual, on-demand verdict you invoke yourself, while the portable shaping fragments and the standalone gate still install everywhere.';
|
|
34
|
-
|
|
35
25
|
class Installer {
|
|
36
26
|
constructor() {
|
|
37
27
|
// Resolve directories relative to this file (tools/cli/lib/ -> up 3 levels)
|
|
@@ -57,13 +47,18 @@ class Installer {
|
|
|
57
47
|
if (config._savedConfigYaml) {
|
|
58
48
|
try {
|
|
59
49
|
const savedData = yaml.load(config._savedConfigYaml);
|
|
60
|
-
if (!config.ides && savedData.ides) config.ides = savedData.ides;
|
|
61
50
|
if (config.install_learning == null && savedData.install_learning != null) config.install_learning = savedData.install_learning;
|
|
62
51
|
} catch {
|
|
63
52
|
/* ignore parse errors, defaults will apply */
|
|
64
53
|
}
|
|
65
54
|
}
|
|
66
55
|
|
|
56
|
+
// UCG is Claude-Code-only, so an update always refreshes the Claude Code
|
|
57
|
+
// skill copy. Older installs did not persist `ides`; without this the IDE
|
|
58
|
+
// copy is never re-copied (Step 5 skips on an empty list) and silently
|
|
59
|
+
// stays on the previous version even though _bmad/ucg/ updated.
|
|
60
|
+
config.ides = ['claude-code'];
|
|
61
|
+
|
|
67
62
|
s.start('Updating UCG files...');
|
|
68
63
|
await fs.remove(ucgDir);
|
|
69
64
|
s.stop('Old files cleared');
|
|
@@ -157,14 +152,6 @@ class Installer {
|
|
|
157
152
|
log.warn(msg);
|
|
158
153
|
};
|
|
159
154
|
try {
|
|
160
|
-
// Cross-provider honesty: emit the single
|
|
161
|
-
// portability gap line when the target IDE set excludes Claude Code.
|
|
162
|
-
// Never a refusal, never a duplicate — exactly one print.
|
|
163
|
-
const ides = Array.isArray(config.ides) ? config.ides : [];
|
|
164
|
-
if (!ides.includes('claude-code')) {
|
|
165
|
-
warn(PORTABILITY_GAP_LINE);
|
|
166
|
-
}
|
|
167
|
-
|
|
168
155
|
// The merge engine deep_merge is imported by
|
|
169
156
|
// merge_customization.py from {projectDir}/_bmad/scripts/resolve_customization.py.
|
|
170
157
|
// If it is absent/older, no-op Step 6b entirely (verify-only degrade):
|
|
@@ -253,13 +240,7 @@ class Installer {
|
|
|
253
240
|
* @returns {Promise<boolean>}
|
|
254
241
|
*/
|
|
255
242
|
async isSkillPresent(projectDir, skill) {
|
|
256
|
-
const roots = [
|
|
257
|
-
path.join(projectDir, '.claude', 'skills'),
|
|
258
|
-
path.join(projectDir, '.cursor', 'skills'),
|
|
259
|
-
path.join(projectDir, '.opencode', 'skills'),
|
|
260
|
-
path.join(projectDir, 'bmad', 'skills'),
|
|
261
|
-
path.join(projectDir, '_bmad', 'skills'),
|
|
262
|
-
];
|
|
243
|
+
const roots = [path.join(projectDir, '.claude', 'skills'), path.join(projectDir, '_bmad', 'skills')];
|
|
263
244
|
for (const root of roots) {
|
|
264
245
|
if (await fs.pathExists(path.join(root, skill))) return true;
|
|
265
246
|
}
|
|
@@ -416,4 +397,4 @@ class Installer {
|
|
|
416
397
|
}
|
|
417
398
|
}
|
|
418
399
|
|
|
419
|
-
module.exports = { Installer,
|
|
400
|
+
module.exports = { Installer, STEP6B_PLANNING_FRAGMENTS };
|
|
@@ -1,39 +1,21 @@
|
|
|
1
1
|
# BMAD Platform Codes Configuration
|
|
2
2
|
#
|
|
3
|
+
# UltraCode Goal is Claude-Code-only: its autonomous run composes Claude Code
|
|
4
|
+
# primitives (/goal, Auto Mode, Auto Memory, PreToolUse/Stop hooks, dynamic
|
|
5
|
+
# workflows) that no other editor provides, so the installer targets Claude Code
|
|
6
|
+
# and only Claude Code. This file stays config-driven (one entry) so the install
|
|
7
|
+
# machinery has a single source of truth.
|
|
8
|
+
#
|
|
3
9
|
# Each platform entry has:
|
|
4
10
|
# name: Display name shown to users
|
|
5
11
|
# preferred: Whether shown as a recommended option on install
|
|
6
|
-
#
|
|
7
|
-
#
|
|
8
|
-
# skill in this IDE's chat. Examples:
|
|
9
|
-
# "/" — slash command, e.g. /ultracode-goal (most IDEs)
|
|
10
|
-
# "$" — dollar mention, e.g. $ultracode-goal (Codex)
|
|
11
|
-
# "/skill:" — namespaced slash, e.g. /skill:ultracode-goal (Pi)
|
|
12
|
-
# Omit when the IDE only auto-invokes skills from descriptions and has
|
|
13
|
-
# no manual invocation form (Cline, GitHub Copilot, Junie, etc.).
|
|
12
|
+
# skill_invocation_prefix: Prefix users type to invoke a named skill in this
|
|
13
|
+
# IDE's chat (e.g. "/" -> /ultracode-goal).
|
|
14
14
|
# installer:
|
|
15
|
+
# detection_marker: (optional) Path that signals the IDE is present
|
|
15
16
|
# target_dir: Directory where skill directories are installed
|
|
16
17
|
# legacy_targets: (optional) Old target dirs to clean up on reinstall
|
|
17
18
|
platforms:
|
|
18
|
-
antigravity:
|
|
19
|
-
name: "Google Antigravity"
|
|
20
|
-
preferred: false
|
|
21
|
-
skill_invocation_prefix: "/"
|
|
22
|
-
installer:
|
|
23
|
-
detection_marker: .agent/antigravity
|
|
24
|
-
legacy_targets:
|
|
25
|
-
- .agent/workflows
|
|
26
|
-
target_dir: .agent/skills
|
|
27
|
-
|
|
28
|
-
auggie:
|
|
29
|
-
name: "Auggie"
|
|
30
|
-
preferred: false
|
|
31
|
-
skill_invocation_prefix: "/"
|
|
32
|
-
installer:
|
|
33
|
-
legacy_targets:
|
|
34
|
-
- .augment/commands
|
|
35
|
-
target_dir: .augment/skills
|
|
36
|
-
|
|
37
19
|
claude-code:
|
|
38
20
|
name: "Claude Code"
|
|
39
21
|
preferred: true
|
|
@@ -42,182 +24,3 @@ platforms:
|
|
|
42
24
|
legacy_targets:
|
|
43
25
|
- .claude/commands
|
|
44
26
|
target_dir: .claude/skills
|
|
45
|
-
|
|
46
|
-
cline:
|
|
47
|
-
name: "Cline"
|
|
48
|
-
preferred: false
|
|
49
|
-
# Auto-invoked from descriptions; no manual prefix
|
|
50
|
-
installer:
|
|
51
|
-
detection_marker: .clinerules
|
|
52
|
-
legacy_targets:
|
|
53
|
-
- .clinerules/workflows
|
|
54
|
-
target_dir: .cline/skills
|
|
55
|
-
|
|
56
|
-
codex:
|
|
57
|
-
name: "Codex"
|
|
58
|
-
preferred: false
|
|
59
|
-
skill_invocation_prefix: "$"
|
|
60
|
-
installer:
|
|
61
|
-
detection_marker: .codex
|
|
62
|
-
legacy_targets:
|
|
63
|
-
- .codex/prompts
|
|
64
|
-
target_dir: .agents/skills
|
|
65
|
-
|
|
66
|
-
codebuddy:
|
|
67
|
-
name: "CodeBuddy"
|
|
68
|
-
preferred: false
|
|
69
|
-
skill_invocation_prefix: "/"
|
|
70
|
-
installer:
|
|
71
|
-
legacy_targets:
|
|
72
|
-
- .codebuddy/commands
|
|
73
|
-
target_dir: .codebuddy/skills
|
|
74
|
-
|
|
75
|
-
crush:
|
|
76
|
-
name: "Crush"
|
|
77
|
-
preferred: false
|
|
78
|
-
# Auto-invoked from descriptions; no manual prefix
|
|
79
|
-
installer:
|
|
80
|
-
legacy_targets:
|
|
81
|
-
- .crush/commands
|
|
82
|
-
target_dir: .crush/skills
|
|
83
|
-
|
|
84
|
-
cursor:
|
|
85
|
-
name: "Cursor"
|
|
86
|
-
preferred: true
|
|
87
|
-
skill_invocation_prefix: "/"
|
|
88
|
-
installer:
|
|
89
|
-
legacy_targets:
|
|
90
|
-
- .cursor/commands
|
|
91
|
-
target_dir: .cursor/skills
|
|
92
|
-
|
|
93
|
-
gemini:
|
|
94
|
-
name: "Gemini CLI"
|
|
95
|
-
preferred: false
|
|
96
|
-
skill_invocation_prefix: "/"
|
|
97
|
-
installer:
|
|
98
|
-
legacy_targets:
|
|
99
|
-
- .gemini/commands
|
|
100
|
-
target_dir: .gemini/skills
|
|
101
|
-
|
|
102
|
-
github-copilot:
|
|
103
|
-
name: "GitHub Copilot"
|
|
104
|
-
preferred: false
|
|
105
|
-
# Auto-invoked from descriptions; no manual prefix
|
|
106
|
-
installer:
|
|
107
|
-
detection_marker: .github/copilot-instructions.md
|
|
108
|
-
legacy_targets:
|
|
109
|
-
- .github/agents
|
|
110
|
-
- .github/prompts
|
|
111
|
-
target_dir: .github/skills
|
|
112
|
-
|
|
113
|
-
iflow:
|
|
114
|
-
name: "iFlow"
|
|
115
|
-
preferred: false
|
|
116
|
-
skill_invocation_prefix: "/"
|
|
117
|
-
installer:
|
|
118
|
-
legacy_targets:
|
|
119
|
-
- .iflow/commands
|
|
120
|
-
target_dir: .iflow/skills
|
|
121
|
-
|
|
122
|
-
junie:
|
|
123
|
-
name: "Junie"
|
|
124
|
-
preferred: false
|
|
125
|
-
# Auto-invoked from descriptions; no manual prefix
|
|
126
|
-
installer:
|
|
127
|
-
target_dir: .junie/skills
|
|
128
|
-
|
|
129
|
-
kilo:
|
|
130
|
-
name: "KiloCoder"
|
|
131
|
-
preferred: false
|
|
132
|
-
# Auto-invoked from descriptions; no manual prefix
|
|
133
|
-
installer:
|
|
134
|
-
legacy_targets:
|
|
135
|
-
- .kilocode/workflows
|
|
136
|
-
target_dir: .kilocode/skills
|
|
137
|
-
|
|
138
|
-
kiro:
|
|
139
|
-
name: "Kiro"
|
|
140
|
-
preferred: false
|
|
141
|
-
# Auto-invoked from descriptions; no manual prefix
|
|
142
|
-
installer:
|
|
143
|
-
legacy_targets:
|
|
144
|
-
- .kiro/steering
|
|
145
|
-
target_dir: .kiro/skills
|
|
146
|
-
|
|
147
|
-
ona:
|
|
148
|
-
name: "Ona"
|
|
149
|
-
preferred: false
|
|
150
|
-
skill_invocation_prefix: "/"
|
|
151
|
-
installer:
|
|
152
|
-
target_dir: .ona/skills
|
|
153
|
-
|
|
154
|
-
opencode:
|
|
155
|
-
name: "OpenCode"
|
|
156
|
-
preferred: false
|
|
157
|
-
skill_invocation_prefix: "/"
|
|
158
|
-
installer:
|
|
159
|
-
legacy_targets:
|
|
160
|
-
- .opencode/agents
|
|
161
|
-
- .opencode/commands
|
|
162
|
-
- .opencode/agent
|
|
163
|
-
- .opencode/command
|
|
164
|
-
target_dir: .opencode/skills
|
|
165
|
-
|
|
166
|
-
pi:
|
|
167
|
-
name: "Pi"
|
|
168
|
-
preferred: false
|
|
169
|
-
skill_invocation_prefix: "/skill:"
|
|
170
|
-
installer:
|
|
171
|
-
target_dir: .pi/skills
|
|
172
|
-
|
|
173
|
-
qoder:
|
|
174
|
-
name: "Qoder"
|
|
175
|
-
preferred: false
|
|
176
|
-
skill_invocation_prefix: "/"
|
|
177
|
-
installer:
|
|
178
|
-
target_dir: .qoder/skills
|
|
179
|
-
|
|
180
|
-
qwen:
|
|
181
|
-
name: "QwenCoder"
|
|
182
|
-
preferred: false
|
|
183
|
-
skill_invocation_prefix: "/"
|
|
184
|
-
installer:
|
|
185
|
-
legacy_targets:
|
|
186
|
-
- .qwen/commands
|
|
187
|
-
target_dir: .qwen/skills
|
|
188
|
-
|
|
189
|
-
roo:
|
|
190
|
-
name: "Roo Code"
|
|
191
|
-
preferred: false
|
|
192
|
-
skill_invocation_prefix: "/"
|
|
193
|
-
installer:
|
|
194
|
-
legacy_targets:
|
|
195
|
-
- .roo/commands
|
|
196
|
-
target_dir: .roo/skills
|
|
197
|
-
|
|
198
|
-
rovo-dev:
|
|
199
|
-
name: "Rovo Dev"
|
|
200
|
-
preferred: false
|
|
201
|
-
# Auto-invoked from descriptions; no manual prefix
|
|
202
|
-
installer:
|
|
203
|
-
legacy_targets:
|
|
204
|
-
- .rovodev/workflows
|
|
205
|
-
target_dir: .rovodev/skills
|
|
206
|
-
|
|
207
|
-
trae:
|
|
208
|
-
name: "Trae"
|
|
209
|
-
preferred: false
|
|
210
|
-
# Auto-invoked from descriptions; no manual prefix
|
|
211
|
-
installer:
|
|
212
|
-
legacy_targets:
|
|
213
|
-
- .trae/rules
|
|
214
|
-
target_dir: .trae/skills
|
|
215
|
-
|
|
216
|
-
windsurf:
|
|
217
|
-
name: "Windsurf"
|
|
218
|
-
preferred: false
|
|
219
|
-
skill_invocation_prefix: "/"
|
|
220
|
-
installer:
|
|
221
|
-
legacy_targets:
|
|
222
|
-
- .windsurf/workflows
|
|
223
|
-
target_dir: .windsurf/skills
|
package/tools/cli/lib/ui.js
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* spark #A5B4FC — icons
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
-
const { intro, outro, text,
|
|
12
|
+
const { intro, outro, text, confirm, note, isCancel, cancel, log, select } = require('@clack/prompts');
|
|
13
13
|
const chalk = require('chalk');
|
|
14
14
|
const figlet = require('figlet');
|
|
15
15
|
const path = require('node:path');
|
|
@@ -17,7 +17,7 @@ const fs = require('fs-extra');
|
|
|
17
17
|
const yaml = require('js-yaml');
|
|
18
18
|
const { readManifest } = require('./manifest');
|
|
19
19
|
const { compareVersions } = require('./version-check');
|
|
20
|
-
const { getAvailablePlatforms
|
|
20
|
+
const { getAvailablePlatforms } = require('./ide-skills');
|
|
21
21
|
|
|
22
22
|
const UCG_FOLDER = '_bmad/ucg';
|
|
23
23
|
|
|
@@ -210,31 +210,6 @@ class UI {
|
|
|
210
210
|
log.info('Previous configuration detected — defaults pre-populated.');
|
|
211
211
|
}
|
|
212
212
|
|
|
213
|
-
// Build IDE options from platform-codes.yaml
|
|
214
|
-
const platforms = getAvailablePlatforms();
|
|
215
|
-
const ideOptions = platforms.map((p) => ({
|
|
216
|
-
label: p.preferred ? `${p.label} (Recommended)` : p.label,
|
|
217
|
-
value: p.value,
|
|
218
|
-
}));
|
|
219
|
-
|
|
220
|
-
// Pre-check IDEs: saved config takes priority, then auto-detect from directories
|
|
221
|
-
const savedIdes = savedConfig?.ides || [];
|
|
222
|
-
let initialIdes = [];
|
|
223
|
-
if (savedIdes.length > 0) {
|
|
224
|
-
initialIdes = savedIdes;
|
|
225
|
-
} else {
|
|
226
|
-
const detectedIdes = await this.detectIdes(projectDir);
|
|
227
|
-
if (detectedIdes.length > 0) {
|
|
228
|
-
initialIdes = detectedIdes;
|
|
229
|
-
log.info(`Auto-detected IDEs: ${brand.light(detectedIdes.join(', '))}`);
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
// Mark initially selected IDEs
|
|
234
|
-
for (const opt of ideOptions) {
|
|
235
|
-
opt.initialSelected = initialIdes.includes(opt.value);
|
|
236
|
-
}
|
|
237
|
-
|
|
238
213
|
// Project name
|
|
239
214
|
const project_name = await text({
|
|
240
215
|
message: 'Project name:',
|
|
@@ -245,17 +220,11 @@ class UI {
|
|
|
245
220
|
return { cancelled: true };
|
|
246
221
|
}
|
|
247
222
|
|
|
248
|
-
//
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
required: true,
|
|
254
|
-
});
|
|
255
|
-
if (isCancel(ides)) {
|
|
256
|
-
cancel('Installation cancelled.');
|
|
257
|
-
return { cancelled: true };
|
|
258
|
-
}
|
|
223
|
+
// UCG is Claude-Code-only: its autonomous run composes Claude Code
|
|
224
|
+
// primitives (/goal, Auto Mode, hooks, dynamic workflows) no other editor
|
|
225
|
+
// provides, so the skill installs to Claude Code with no IDE prompt.
|
|
226
|
+
const ides = ['claude-code'];
|
|
227
|
+
log.info(`The skill installs for ${brand.light('Claude Code')}.`);
|
|
259
228
|
|
|
260
229
|
// Learning material
|
|
261
230
|
const install_learning = await confirm({
|
|
@@ -291,20 +260,6 @@ class UI {
|
|
|
291
260
|
};
|
|
292
261
|
}
|
|
293
262
|
|
|
294
|
-
async detectIdes(projectDir) {
|
|
295
|
-
const markers = getDetectionMarkers();
|
|
296
|
-
const detected = [];
|
|
297
|
-
for (const [ide, paths] of Object.entries(markers)) {
|
|
298
|
-
for (const p of paths) {
|
|
299
|
-
if (await fs.pathExists(path.join(projectDir, p))) {
|
|
300
|
-
detected.push(ide);
|
|
301
|
-
break;
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
|
-
return detected;
|
|
306
|
-
}
|
|
307
|
-
|
|
308
263
|
async loadSavedConfig(projectDir, ucgFolder) {
|
|
309
264
|
const configPath = path.join(projectDir, ucgFolder, 'config.yaml');
|
|
310
265
|
try {
|
|
@@ -352,8 +307,8 @@ class UI {
|
|
|
352
307
|
// Compose the activate line shown in steps and outro.
|
|
353
308
|
let activateLine;
|
|
354
309
|
if (invocations.length === 0) {
|
|
355
|
-
//
|
|
356
|
-
activateLine = `${brand.light('/ultracode-goal')} ${chalk.dim('(Claude Code)')}
|
|
310
|
+
// Defensive: no IDE list resolved. UCG installs for Claude Code only.
|
|
311
|
+
activateLine = `${brand.light('/ultracode-goal')} ${chalk.dim('(Claude Code)')}`;
|
|
357
312
|
} else if (invocations.length === 1) {
|
|
358
313
|
const inv = invocations[0];
|
|
359
314
|
activateLine = inv.auto ? chalk.dim(`${inv.ide} auto-loads ultracode-goal`) : brand.light(inv.command);
|
package/website/astro.config.mjs
CHANGED
|
@@ -122,6 +122,7 @@ export default defineConfig({
|
|
|
122
122
|
{ label: 'Health Check', slug: 'health-check' },
|
|
123
123
|
{ label: 'Cross-Session Recall', slug: 'cross-session-recall' },
|
|
124
124
|
{ label: 'Troubleshooting', slug: 'troubleshooting' },
|
|
125
|
+
{ label: 'UCG vs bmad-auto', slug: 'comparison' },
|
|
125
126
|
],
|
|
126
127
|
},
|
|
127
128
|
],
|