ma-agents 3.8.0 → 3.11.0

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.
Files changed (98) hide show
  1. package/README.md +13 -5
  2. package/bin/cli.js +140 -63
  3. package/lib/agents.js +12 -20
  4. package/lib/bmad-cache/cache-manifest.json +8 -8
  5. package/lib/bmad-cache/cis/_git_preserved/index +0 -0
  6. package/lib/bmad-cache/cis/_git_preserved/logs/HEAD +1 -1
  7. package/lib/bmad-cache/cis/_git_preserved/logs/refs/heads/main +1 -1
  8. package/lib/bmad-cache/cis/_git_preserved/logs/refs/remotes/origin/HEAD +1 -1
  9. package/lib/bmad-cache/cis/_git_preserved/objects/pack/pack-42ffc048f54e58ce94c6331bc6be97ebbb7936f2.idx +0 -0
  10. package/lib/bmad-cache/cis/_git_preserved/objects/pack/{pack-cad8ff313ea5db860ddcc7780f03917dcba1da8d.pack → pack-42ffc048f54e58ce94c6331bc6be97ebbb7936f2.pack} +0 -0
  11. package/lib/bmad-cache/cis/_git_preserved/objects/pack/pack-42ffc048f54e58ce94c6331bc6be97ebbb7936f2.rev +0 -0
  12. package/lib/bmad-cache/cis/_git_preserved/packed-refs +1 -1
  13. package/lib/bmad-cache/cis/_git_preserved/refs/heads/main +1 -1
  14. package/lib/bmad-cache/cis/_git_preserved/shallow +1 -1
  15. package/lib/bmad-cache/cis/src/module-help.csv +5 -5
  16. package/lib/bmad-cache/gds/_git_preserved/index +0 -0
  17. package/lib/bmad-cache/gds/_git_preserved/logs/HEAD +1 -1
  18. package/lib/bmad-cache/gds/_git_preserved/logs/refs/heads/main +1 -1
  19. package/lib/bmad-cache/gds/_git_preserved/logs/refs/remotes/origin/HEAD +1 -1
  20. package/lib/bmad-cache/gds/_git_preserved/objects/pack/pack-9427a146a90c00bb542cba038874bf9671ba4dc0.idx +0 -0
  21. package/lib/bmad-cache/gds/_git_preserved/objects/pack/{pack-c1322f7c8531a89dc4f3f34c4955d194f286c1e6.pack → pack-9427a146a90c00bb542cba038874bf9671ba4dc0.pack} +0 -0
  22. package/lib/bmad-cache/gds/_git_preserved/objects/pack/pack-9427a146a90c00bb542cba038874bf9671ba4dc0.rev +0 -0
  23. package/lib/bmad-cache/gds/_git_preserved/packed-refs +1 -1
  24. package/lib/bmad-cache/gds/_git_preserved/refs/heads/main +1 -1
  25. package/lib/bmad-cache/gds/_git_preserved/shallow +1 -1
  26. package/lib/bmad-cache/gds/src/module-help.csv +34 -34
  27. package/lib/bmad-cache/tea/.claude-plugin/marketplace.json +1 -1
  28. package/lib/bmad-cache/tea/.github/workflows/publish.yaml +168 -0
  29. package/lib/bmad-cache/tea/README.md +67 -57
  30. package/lib/bmad-cache/tea/_git_preserved/index +0 -0
  31. package/lib/bmad-cache/tea/_git_preserved/objects/pack/pack-f0df537f2649464ff6c5aee241165eb9c8664227.idx +0 -0
  32. package/lib/bmad-cache/tea/_git_preserved/objects/pack/{pack-9b16db8eb5022c18cef1f0a27d63b6e0f4bc2b2a.pack → pack-f0df537f2649464ff6c5aee241165eb9c8664227.pack} +0 -0
  33. package/lib/bmad-cache/tea/_git_preserved/objects/pack/pack-f0df537f2649464ff6c5aee241165eb9c8664227.rev +0 -0
  34. package/lib/bmad-cache/tea/_git_preserved/packed-refs +1 -1
  35. package/lib/bmad-cache/tea/_git_preserved/refs/heads/main +1 -1
  36. package/lib/bmad-cache/tea/_git_preserved/shallow +1 -1
  37. package/lib/bmad-cache/tea/package-lock.json +2 -2
  38. package/lib/bmad-cache/tea/package.json +5 -6
  39. package/lib/bmad-cache/tea/src/agents/bmad-tea/resources/knowledge/contract-testing.md +2 -3
  40. package/lib/bmad-cache/tea/src/agents/bmad-tea/resources/knowledge/pact-consumer-framework-setup.md +42 -95
  41. package/lib/bmad-cache/tea/src/agents/bmad-tea/resources/knowledge/pactjs-utils-consumer-helpers.md +5 -6
  42. package/lib/bmad-cache/tea/src/agents/bmad-tea/resources/knowledge/pactjs-utils-provider-verifier.md +1 -1
  43. package/lib/bmad-cache/tea/src/agents/bmad-tea/resources/tea-index.csv +1 -1
  44. package/lib/bmad-cache/tea/src/module-help.csv +9 -9
  45. package/lib/bmad-extension/.claude-plugin/marketplace.json.template +2 -2
  46. package/lib/bmad-extension/skills/add-sprint/SKILL.md +39 -0
  47. package/lib/bmad-extension/skills/add-to-sprint/SKILL.md +39 -0
  48. package/lib/bmad-extension/skills/bmad-dev-story/workflow.md +39 -0
  49. package/lib/bmad-extension/skills/bmad-sprint-planning/workflow.md +41 -0
  50. package/lib/bmad-extension/skills/bmad-sprint-status/workflow.md +39 -0
  51. package/lib/bmad-extension/skills/cleanup-done/SKILL.md +39 -0
  52. package/lib/bmad-extension/skills/close-sprint/SKILL.md +39 -0
  53. package/lib/bmad-extension/skills/generate-backlog/SKILL.md +41 -0
  54. package/lib/bmad-extension/skills/modify-sprint/SKILL.md +39 -0
  55. package/lib/bmad-extension/skills/module.yaml +1 -1
  56. package/lib/bmad-extension/skills/prioritize-backlog/SKILL.md +39 -0
  57. package/lib/bmad-extension/skills/remove-from-sprint/SKILL.md +39 -0
  58. package/lib/bmad-extension/skills/sprint-status-view/SKILL.md +39 -0
  59. package/lib/bmad-extension/workflows/add-sprint/workflow.md +39 -0
  60. package/lib/bmad-extension/workflows/add-to-sprint/workflow.md +39 -0
  61. package/lib/bmad-extension/workflows/modify-sprint/workflow.md +39 -0
  62. package/lib/bmad-extension/workflows/sprint-status-view/workflow.md +39 -0
  63. package/lib/bmad-extension-plugin/.claude-plugin/marketplace.json +2 -2
  64. package/lib/bmad-extension-plugin/skills/add-sprint/SKILL.md +39 -0
  65. package/lib/bmad-extension-plugin/skills/add-to-sprint/SKILL.md +39 -0
  66. package/lib/bmad-extension-plugin/skills/bmad-dev-story/workflow.md +39 -0
  67. package/lib/bmad-extension-plugin/skills/bmad-sprint-planning/workflow.md +41 -0
  68. package/lib/bmad-extension-plugin/skills/bmad-sprint-status/workflow.md +39 -0
  69. package/lib/bmad-extension-plugin/skills/cleanup-done/SKILL.md +39 -0
  70. package/lib/bmad-extension-plugin/skills/close-sprint/SKILL.md +39 -0
  71. package/lib/bmad-extension-plugin/skills/generate-backlog/SKILL.md +41 -0
  72. package/lib/bmad-extension-plugin/skills/modify-sprint/SKILL.md +39 -0
  73. package/lib/bmad-extension-plugin/skills/module.yaml +1 -1
  74. package/lib/bmad-extension-plugin/skills/prioritize-backlog/SKILL.md +39 -0
  75. package/lib/bmad-extension-plugin/skills/remove-from-sprint/SKILL.md +39 -0
  76. package/lib/bmad-extension-plugin/skills/sprint-status-view/SKILL.md +39 -0
  77. package/lib/bmad.js +76 -8
  78. package/lib/installer.js +6 -1
  79. package/package.json +4 -4
  80. package/skills/add-sprint/SKILL.md +39 -0
  81. package/skills/add-to-sprint/SKILL.md +39 -0
  82. package/skills/bmad-sprint-planning/SKILL.md +41 -0
  83. package/skills/bmad-sprint-status/SKILL.md +39 -0
  84. package/skills/cleanup-done/SKILL.md +39 -0
  85. package/skills/close-sprint/SKILL.md +39 -0
  86. package/skills/generate-backlog/SKILL.md +41 -0
  87. package/skills/modify-sprint/SKILL.md +39 -0
  88. package/skills/prioritize-backlog/SKILL.md +39 -0
  89. package/skills/remove-from-sprint/SKILL.md +39 -0
  90. package/skills/sprint-status-view/SKILL.md +39 -0
  91. package/skills/story-status-lookup/SKILL.md +38 -21
  92. package/lib/bmad-cache/cis/_git_preserved/objects/pack/pack-cad8ff313ea5db860ddcc7780f03917dcba1da8d.idx +0 -0
  93. package/lib/bmad-cache/cis/_git_preserved/objects/pack/pack-cad8ff313ea5db860ddcc7780f03917dcba1da8d.rev +0 -0
  94. package/lib/bmad-cache/gds/_git_preserved/objects/pack/pack-c1322f7c8531a89dc4f3f34c4955d194f286c1e6.idx +0 -0
  95. package/lib/bmad-cache/gds/_git_preserved/objects/pack/pack-c1322f7c8531a89dc4f3f34c4955d194f286c1e6.rev +0 -0
  96. package/lib/bmad-cache/tea/.github/workflows/manual-release.yaml +0 -216
  97. package/lib/bmad-cache/tea/_git_preserved/objects/pack/pack-9b16db8eb5022c18cef1f0a27d63b6e0f4bc2b2a.idx +0 -0
  98. package/lib/bmad-cache/tea/_git_preserved/objects/pack/pack-9b16db8eb5022c18cef1f0a27d63b6e0f4bc2b2a.rev +0 -0
@@ -76,9 +76,9 @@ export default defineConfig({
76
76
 
77
77
  **Key Points**:
78
78
 
79
- - **`fileParallelism: false` is required** — primary defense against non-deterministic pact generation. Without it, parallel workers race on the shared pact JSON file and corrupt interactions. Symptom: local runs pass, CI randomly fails with `Cannot change pact content for already published pact`. See Example 10 for the determinism gate that enforces byte-stability across re-runs.
79
+ - **`fileParallelism: false` is required** — primary defense against non-deterministic pact generation. Without it, parallel workers race on the shared pact JSON file and corrupt interactions. Symptom: local runs pass, CI randomly fails with `Cannot change pact content for already published pact`. The `publish-pact.sh` `jq` sort (Example 4) provides byte-stability at publish time.
80
80
  - **`pool: 'forks'` + `singleFork: true` is required for multi-file consumer suites** — same config the provider side uses (`pactjs-utils-provider-verifier.md` Example 7). Best current understanding: the `@pact-foundation/pact` napi-rs binding is not robust across Vitest worker threads sharing a process; with the default threads pool (Vitest v1) and multiple `.pacttest.ts` files on the same consumer+provider pair, we observed reproducible "request was expected but not received" flakes on Linux CI only. `singleFork: true` serializes every pact file into one forked subprocess and eliminated the flake on two repos (`pactjs-utils`, `seon-mcp-server`). Vitest v2+ defaults to `forks`, but set the pool explicitly so the contract does not drift with Vitest version bumps.
81
- - **Single-file consumer suites** (one `.pacttest.ts` per consumer+provider pair) have not been observed to flake under default threads pool, because FFI state is not shared across files when there is only one file. Adding `pool: 'forks'` is still recommended it future-proofs you the moment a second file is added but a suite passing today with only `fileParallelism: false` is not broken.
81
+ - **One `.pacttest.ts` per consumer+provider pair is the canonical pattern** — not just an observation. Two files for the same pair in one process (which `singleFork: true` guarantees) cause an FFI handle collision: the second file's `new PactV4(...)` call re-enters the FFI handle still holding stale state from the first file → "request was expected but not received" sporadically on Linux CI. The fix is structural merge the files, not the config. `pool: 'forks'` is still required for pact JSON write safety but does NOT prevent same-pair file splits from colliding. Multiple files for **different** pairs (different consumer or provider name) are correct and safe. See Example 10 for the ✅/❌ pattern.
82
82
  - **Interacting settings**: leave `isolate` at its default (`true`). Do NOT set `sequence.concurrent: true`, `maxConcurrency > 1`, or `maxWorkers > 1` in this config — they defeat the serialization this rule relies on. `hookTimeout` may be raised if mock-server startup is slow, but keep `testTimeout` ≥ `hookTimeout`.
83
83
  - Do NOT add `setupFiles`, `coverage`, or other settings from the unit test config
84
84
  - Keep it minimal — Pact tests run in Node environment with extended timeout
@@ -96,8 +96,7 @@ export default defineConfig({
96
96
  ```json
97
97
  {
98
98
  "scripts": {
99
- "test:pact:consumer": "./scripts/check-pact-determinism.sh 'npm run test:pact:consumer:run' 3 ./pacts",
100
- "test:pact:consumer:run": "vitest run --config vitest.config.pact.ts",
99
+ "test:pact:consumer": "vitest run --config vitest.config.pact.ts",
101
100
  "publish:pact": ". ./scripts/env-setup.sh && ./scripts/publish-pact.sh",
102
101
  "can:i:deploy:consumer": ". ./scripts/env-setup.sh && PACTICIPANT=<service-name> ./scripts/can-i-deploy.sh",
103
102
  "record:consumer:deployment": ". ./scripts/env-setup.sh && PACTICIPANT=<service-name> ./scripts/record-deployment.sh"
@@ -109,8 +108,6 @@ Replace `<service-name>` with the consumer's pacticipant name (e.g., `my-fronten
109
108
 
110
109
  **Key Points**:
111
110
 
112
- - **`test:pact:consumer` IS the determinism gate** — it runs the inner command 3× and fails if pact output is not byte-stable. This is the command CI and developers run before pushing. See Example 10 for the `check-pact-determinism.sh` script itself.
113
- - **`test:pact:consumer:run` is the fast inner command** for TDD loops (a single pass of the suite, no gate). Developers can iterate with this; CI always goes through the outer gated script.
114
111
  - Use colon-separated naming: `test:pact:consumer`, NOT `test:contract` or `test:contract:consumer`
115
112
  - Broker scripts source `env-setup.sh` inline in package.json (`. ./scripts/env-setup.sh && ...`)
116
113
  - `PACTICIPANT` is set per-script invocation, not globally
@@ -139,7 +136,7 @@ export GITHUB_SHA="${GITHUB_SHA:-$(git rev-parse --short HEAD)}"
139
136
  export GITHUB_BRANCH="${GITHUB_BRANCH:-$(git rev-parse --abbrev-ref HEAD)}"
140
137
  ```
141
138
 
142
- #### `scripts/publish-pact.sh` — Publish Pacts to Broker (with defense-in-depth normalization)
139
+ #### `scripts/publish-pact.sh` — Publish Pacts to Broker
143
140
 
144
141
  ```bash
145
142
  #!/bin/bash
@@ -147,9 +144,8 @@ export GITHUB_BRANCH="${GITHUB_BRANCH:-$(git rev-parse --abbrev-ref HEAD)}"
147
144
  #
148
145
  # Before publish, normalize each pact JSON: sort interactions by (description, provider state name,
149
146
  # method, path) and sort object keys via `jq -S`. This gives byte-stable output to the broker even
150
- # if the PactV4 generator produces ordering drift between runs. Paired with scripts/check-pact-determinism.sh
151
- # as defense-in-depth the gate catches drift pre-publish; normalization ensures "Cannot change pact
152
- # content" from PactFlow never fires on ordering-only changes that slip past the gate.
147
+ # if the PactV4 generator produces ordering drift between runs. Ensures "Cannot change pact content"
148
+ # from PactFlow never fires on ordering-only changes.
153
149
  #
154
150
  # Requires: PACT_BROKER_BASE_URL, PACT_BROKER_TOKEN, GITHUB_SHA, GITHUB_BRANCH, jq
155
151
  # -e: exit on error -u: error on undefined vars -o pipefail: fail if any pipe segment fails
@@ -229,7 +225,7 @@ fi
229
225
  - Use `PACTICIPANT` env var (required via `${PACTICIPANT:?...}`), not hardcoded service names
230
226
  - `can-i-deploy` includes `--retry-while-unknown=10 --retry-interval=30` (waits for provider verification)
231
227
  - `record-deployment` has branch guard (only records on main/master)
232
- - **`publish-pact.sh` normalizes interactions with `jq -S` + `sort_by(...)` before publishing** — defense-in-depth alongside the determinism gate (Example 10). The gate catches drift; normalization ensures byte-stable payload to the broker regardless of generator quirks. Keep both; they protect against different failure modes.
228
+ - **`publish-pact.sh` normalizes interactions with `jq -S` + `sort_by(...)` before publishing** — ensures byte-stable payload to the broker regardless of generator ordering quirks.
233
229
  - Do NOT invent custom env vars like `PACT_CONSUMER_VERSION` or `PACT_BREAKING_CHANGE` in scripts — those are handled by `env-setup.sh` and the CI detect-breaking-change action respectively
234
230
 
235
231
  ---
@@ -276,8 +272,8 @@ jobs:
276
272
  - name: Install dependencies
277
273
  run: npm ci
278
274
 
279
- # (1) Generate pact files — runs the determinism gate (3 runs + byte-stable check via jq)
280
- - name: Consumer pact tests (determinism gate)
275
+ # (1) Generate pact files
276
+ - name: Run consumer contract tests
281
277
  run: npm run test:pact:consumer
282
278
 
283
279
  # (2) Publish pacts to broker (publish-pact.sh also normalizes interaction order as defense-in-depth)
@@ -301,8 +297,7 @@ jobs:
301
297
 
302
298
  **Key Points**:
303
299
 
304
- - **1:1 local/CI parity is a hard rule**: every CI step is `npm run <same-name-a-dev-uses>`. Never let CI invoke `vitest` or `pact-broker` directly — that divergence is how "works on my machine" slips in. The determinism gate, publish, can-i-deploy, and record-deployment are all the same commands a developer runs locally.
305
- - **The determinism gate is its own visible step, not a side-effect of publish.** A failing gate must be debuggable from the CI log without re-running. Do not fold it into a `prepublish:pact` hook — folding hides the failure inside a publish log and makes attribution harder.
300
+ - **1:1 local/CI parity is a hard rule**: every CI step is `npm run <same-name-a-dev-uses>`. Never let CI invoke `vitest` or `pact-broker` directly — that divergence is how "works on my machine" slips in. Consumer tests, publish, can-i-deploy, and record-deployment are all the same commands a developer runs locally.
306
301
  - **Workflow-level `env` block** for broker secrets and git vars — not per-step
307
302
  - **`detect-breaking-change` step** runs before install to set `PACT_BREAKING_CHANGE` env var
308
303
  - **Step numbering skips (3)** — step 3 is the webhook-triggered provider verification (happens externally)
@@ -625,89 +620,42 @@ pact-logs/
625
620
 
626
621
  ---
627
622
 
628
- ### Example 10: Determinism Gate Script (Primary Defense)
623
+ ### Example 10: Test File Organization One File Per Consumer+Provider Pair
629
624
 
630
- **Context**: Even with `fileParallelism: false` (Example 2) and one-interaction-per-`it()` (see `pactjs-utils-consumer-helpers.md`), the PactV4 Rust FFI layer can occasionally produce byte-different pact JSON between runs — interaction ordering drift, nested matcher serialization quirks, or `Date` / random-value matchers that weren't locked down. This causes PactFlow to reject re-publishes of the same consumer SHA with `Cannot change pact content for already published pact`. The determinism gate runs the consumer suite N times locally and in CI, hashes the normalized pact files, and fails fast if drift is detected — before any publish is attempted.
625
+ **Context**: Avoiding Pact Rust FFI handle collisions when structuring consumer test files.
631
626
 
632
- **Implementation**:
633
-
634
- #### `scripts/check-pact-determinism.sh`
635
-
636
- ```bash
637
- #!/bin/bash
638
- # Run a pact consumer command N times and fail if the generated pact files are not byte-stable.
639
- # Primary defense against PactV4 non-deterministic output.
640
- #
641
- # Usage: ./scripts/check-pact-determinism.sh "<cmd>" [runs] [pact-dir]
642
- # Example: ./scripts/check-pact-determinism.sh 'npm run test:pact:consumer:run' 3 ./pacts
643
- #
644
- # Requires: jq installed on the runner (ubuntu-latest has it; macOS users need `brew install jq`).
645
- set -euo pipefail
646
-
647
- CMD="${1:?usage: ./scripts/check-pact-determinism.sh \"<cmd>\" [runs] [pact-dir]}"
648
- RUNS="${PACT_DETERMINISM_RUNS:-${2:-3}}"
649
- PACT_DIR="${3:-./pacts}"
627
+ **Rule**: Every consumer+provider pair maps to exactly one `.pacttest.ts` file. Never split interactions for the same pair across multiple files.
650
628
 
651
- TMP_DIR="$(mktemp -d)"
652
- trap 'rm -rf "$TMP_DIR"' EXIT
629
+ **Root cause**: The Pact Rust FFI maintains one handle per consumer+provider pair per process. With `singleFork: true` (all files run sequentially in one forked process), two files for the same pair access the same FFI handle back-to-back. The second file's `new PactV4({ consumer, provider })` call re-enters the handle still holding stale interaction state from the first file. The first test in the second file starts the mock server in this corrupted state — "request was expected but not received" results, sporadic and Linux-CI-only (execution order differs between environments).
653
630
 
654
- hash_pact_file() {
655
- # Sort interactions by (description, first provider state name, method, path), sort keys with -S.
656
- # The sorted output is what we hash — so ordering-only drift does NOT count as non-determinism here.
657
- # (The gate catches deeper drift; ordering drift is handled by publish-pact.sh normalization.)
658
- jq -S '.interactions |= sort_by(.description, (.providerStates[0].name // ""), .request.method, .request.path)' "$1" \
659
- | shasum -a 256 | awk '{print $1}'
660
- }
631
+ **Evidence**: In `pactjs-utils`, `movies-read.pacttest.ts` and `movies-write.pacttest.ts` both used `consumer: 'SampleAppConsumer', provider: 'SampleMoviesAPI'`. The vitest config and CI workflow were correct throughout. The fix was merging the two files into `movies.pacttest.ts`. The config was not changed.
661
632
 
662
- for run in $(seq 1 "$RUNS"); do
663
- echo "→ determinism run $run/$RUNS"
664
- rm -f "$PACT_DIR"/*.json 2>/dev/null || true
665
- eval "$CMD" >"$TMP_DIR/run-$run.log" 2>&1 || {
666
- echo "❌ run $run failed dumping log:"
667
- cat "$TMP_DIR/run-$run.log"
668
- exit 1
669
- }
670
- : > "$TMP_DIR/run-$run.hashes"
671
- for f in "$PACT_DIR"/*.json; do
672
- [ -f "$f" ] || continue
673
- printf '%s %s\n' "$(hash_pact_file "$f")" "$(basename "$f")" >> "$TMP_DIR/run-$run.hashes"
674
- done
675
- sort -o "$TMP_DIR/run-$run.hashes" "$TMP_DIR/run-$run.hashes"
676
- done
677
-
678
- # Compare every subsequent run against run 1.
679
- FAIL=0
680
- for run in $(seq 2 "$RUNS"); do
681
- if ! diff -q "$TMP_DIR/run-1.hashes" "$TMP_DIR/run-$run.hashes" >/dev/null; then
682
- FAIL=1
683
- echo ""
684
- echo "❌ Pact output differs between run 1 and run $run:"
685
- diff "$TMP_DIR/run-1.hashes" "$TMP_DIR/run-$run.hashes" || true
686
- fi
687
- done
688
-
689
- if [ "$FAIL" -ne 0 ]; then
690
- echo ""
691
- echo "Pact output is non-deterministic across $RUNS runs. Likely causes:"
692
- echo " • multiple .addInteraction() chained in a single it() block (PactV4 FFI drops one non-deterministically)"
693
- echo " • fileParallelism: true in vitest.config.pact.ts (workers race on shared pact JSON)"
694
- echo " • missing pool: 'forks' + singleFork: true (threads pool shares FFI state across files on Linux CI)"
695
- echo " • Date / random matchers that don't lock a stable example value"
696
- echo " • provider state params mutating between runs (e.g. Date.now())"
697
- exit 1
698
- fi
699
-
700
- echo "✅ Pact output is byte-stable across $RUNS runs."
633
+ ```typescript
634
+ // WRONG same consumer+provider pair split across two files
635
+ // movies-read.pacttest.ts
636
+ const pact = new PactV4({ consumer: 'SampleAppConsumer', provider: 'SampleMoviesAPI', ... })
637
+ describe('Read Operations', () => { /* 4 tests: GET /movies, GET /movies/:id */ })
638
+
639
+ // movies-write.pacttest.ts ← second PactV4 for the SAME pair = FFI handle collision
640
+ const pact = new PactV4({ consumer: 'SampleAppConsumer', provider: 'SampleMoviesAPI', ... })
641
+ describe('Write Operations', () => { /* 5 tests: POST, PUT, DELETE */ })
642
+
643
+ // RIGHT one file per consumer+provider pair, describe blocks for organization
644
+ // movies.pacttest.ts
645
+ const pact = new PactV4({ consumer: 'SampleAppConsumer', provider: 'SampleMoviesAPI', ... })
646
+ describe('Movies API', () => {
647
+ describe('Read Operations', () => { /* 4 tests */ })
648
+ describe('Write Operations', () => { /* 5 tests */ })
649
+ })
701
650
  ```
702
651
 
703
652
  **Key Points**:
704
653
 
705
- - **Wire this script into `test:pact:consumer`** (see Example 3). The outer script IS the gate; the inner `test:pact:consumer:run` is the single-pass command for TDD loops.
706
- - **Default 3 runs** is the sweet spot 2 runs miss intermittent drops, >3 slows CI without catching more. Override with an env var or the positional arg if you're actively debugging a flake.
707
- - **Treat gate failures as a P0 bug, not a "retry until green" condition.** Find the source of non-determinism (chained `addInteraction`, unsorted interactions, Date-dependent matchers). Do not raise `RUNS` to 10 to mask the symptom.
708
- - **Requires `jq`** installed by default on `ubuntu-latest`. For macOS local dev, document `brew install jq` in the project README.
709
- - **In CI, make this its own visible step** (see Example 5 step (1) naming). Do not fold into a `prepublish:pact` hook that hides the failure inside a publish log.
710
- - **Defense-in-depth with `publish-pact.sh` normalization** (Example 4): the gate catches pre-publish drift; the publish-time `jq` sort ensures any ordering-only drift that slipped past the gate still produces a byte-stable payload to PactFlow.
654
+ - **File = contract**: A `.pacttest.ts` file represents one consumer+provider contract. One contract = one file.
655
+ - **Describe blocks, not files**: Organize by operation type (`Read Operations`, `Write Operations`), resource, or feature always within one file per pair.
656
+ - **Different pairs = different files**: `ServiceA / BackendAPI` and `ServiceA / AuthAPI` are two contracts and correctly use two separate files. This rule only forbids splitting ONE pair.
657
+ - **`singleFork: true` is not a fix for this**: It ensures correct pact JSON write semantics across files, but when two files share a pair it actually guarantees the FFI collision (both land in the same process). Without it you'd get file-write races instead. Neither is safe. The fix is one file per pair.
658
+ - **Naming convention**: `{domain}.pacttest.ts` when one domain maps to one pair. `{consumer-kebab}-{provider-kebab}.pacttest.ts` when the filename must be self-describing about which pair it covers.
711
659
 
712
660
  ---
713
661
 
@@ -715,12 +663,11 @@ echo "✅ Pact output is byte-stable across $RUNS runs."
715
663
 
716
664
  Before presenting the consumer CDC framework to the user, verify:
717
665
 
718
- - [ ] `vitest.config.pact.ts` is minimal **and sets `fileParallelism: false` AND `pool: 'forks'` with `poolOptions.forks.singleFork: true`** (`fileParallelism: false` prevents shared pact JSON corruption from parallel workers; forks + `singleFork: true` eliminates the Linux-CI "request was expected but not received" flake observed once a second `.pacttest.ts` is added — see Example 2 Key Points for evidence, mechanism qualifier, and single-file exception)
666
+ - [ ] `vitest.config.pact.ts` is minimal **and sets `fileParallelism: false` AND `pool: 'forks'` with `poolOptions.forks.singleFork: true`** (`fileParallelism: false` prevents shared pact JSON corruption from parallel workers; forks + `singleFork: true` is required for pact JSON write safety across files — see Example 2 Key Points for mechanism and evidence)
667
+ - [ ] Each consumer+provider pair is covered by exactly ONE `.pacttest.ts` file — never split interactions for the same pair across multiple files (two `PactV4` instances for the same pair in one process cause FFI handle collision → "request was expected but not received" on Linux CI; `singleFork: true` does NOT prevent this — it ensures both files share one process, which guarantees the collision; see Example 10)
719
668
  - [ ] `vitest.config.pact.ts` does NOT set `sequence.concurrent: true`, `maxConcurrency > 1`, `maxWorkers > 1`, or `isolate: false` — all four defeat the serialization the rule relies on
720
- - [ ] `package.json` splits `test:pact:consumer` (gated determinism runner) and `test:pact:consumer:run` (inner single-pass command)
721
- - [ ] `scripts/check-pact-determinism.sh` is present, hashes via `jq -S` + `sort_by`, defaults to 3 runs, and is the body of the `test:pact:consumer` script
722
- - [ ] `scripts/publish-pact.sh` normalizes interactions with `jq -S '.interactions |= sort_by(.description, (.providerStates[0].name // ""), .request.method, .request.path)'` before the `pact-broker publish` call (defense-in-depth alongside the gate)
723
- - [ ] Script names match pactjs-utils (`test:pact:consumer`, `test:pact:consumer:run`, `publish:pact`, `can:i:deploy:consumer`, `record:consumer:deployment`)
669
+ - [ ] `scripts/publish-pact.sh` normalizes interactions with `jq -S '.interactions |= sort_by(.description, (.providerStates[0].name // ""), .request.method, .request.path)'` before the `pact-broker publish` call (ensures byte-stable payload to PactFlow regardless of generator ordering)
670
+ - [ ] Script names match pactjs-utils (`test:pact:consumer`, `publish:pact`, `can:i:deploy:consumer`, `record:consumer:deployment`)
724
671
  - [ ] Scripts source `env-setup.sh` inline in package.json
725
672
  - [ ] Shell scripts use `pact-broker` not `npx pact-broker`
726
673
  - [ ] Shell scripts use `PACTICIPANT` env var pattern
@@ -730,7 +677,7 @@ Before presenting the consumer CDC framework to the user, verify:
730
677
  - [ ] CI workflow named `contract-test-consumer.yml`
731
678
  - [ ] CI has workflow-level env block (not per-step)
732
679
  - [ ] CI has `detect-breaking-change` step before install
733
- - [ ] CI step (1) is the determinism gate (calls `npm run test:pact:consumer`) — its own visible step, not folded into publish
680
+ - [ ] CI step (1) generates pact files (calls `npm run test:pact:consumer`) — its own visible step, not folded into publish
734
681
  - [ ] CI steps are 1:1 with developer commands — every CI step calls `npm run <same-name>` a dev would run locally (no direct `vitest` or `pact-broker` invocation)
735
682
  - [ ] CI step numbering skips (3) — webhook-triggered provider verification
736
683
  - [ ] CI can-i-deploy has `PACT_BREAKING_CHANGE != 'true'` condition
@@ -260,10 +260,9 @@ it.each([
260
260
 
261
261
  **Key Points**:
262
262
 
263
- - **This rule stacks with two other MANDATORY vitest settings**: `fileParallelism: false` AND `pool: 'forks'` with `poolOptions.forks.singleFork: true`. All three are required and address different failure modes `fileParallelism: false` prevents parallel workers from racing on the shared pact JSON; `pool: 'forks'` + `singleFork: true` prevents the Pact Rust FFI from leaking state across files (manifests as "request was expected but not received" flakes on Linux CI only); one-interaction-per-`it()` prevents the FFI from dropping interactions within a single test body.
264
- - Symptom of violating this rule: the pact file is byte-different between otherwise-identical runs; `scripts/check-pact-determinism.sh` flags drift; PactFlow rejects a republish with `Cannot change pact content`.
263
+ - **This rule stacks with two MANDATORY vitest settings and one file-organization rule. All four address different failure modes; none substitutes for the others**: (1) `fileParallelism: false` prevents parallel workers racing on the shared pact JSON file; (2) `pool: 'forks'` with `singleFork: true` required for pact JSON write safety across multiple files; (3) **one `.pacttest.ts` per consumer+provider pair** — `singleFork: true` keeps all files in one process, so two files for the same pair produce an FFI handle collision ("request was expected but not received" on Linux CI, sporadic); (4) one-interaction-per-`it()` (this rule) — prevents the FFI from dropping interactions within a single test body. See `pact-consumer-framework-setup.md` Example 10 for the file-organization ✅/❌ pattern.
264
+ - Symptom of violating this rule: the pact file is byte-different between otherwise-identical runs; PactFlow rejects a republish with `Cannot change pact content`.
265
265
  - The rule applies to both HTTP consumer pacts (`PactV4`) and message consumer pacts (`MessageConsumerPact`).
266
- - See `pact-consumer-framework-setup.md` Example 10 for the determinism gate that automatically catches violations of this rule.
267
266
 
268
267
  ## Key Points
269
268
 
@@ -278,13 +277,13 @@ it.each([
278
277
  - **Body shorthand**: `setJsonBody` keeps body-only responses concise and readable
279
278
  - **Matchers check type, not value**: `string('My movie')` means "any string", `integer(1)` means "any integer". The example values are arbitrary — the provider can return different values and verification still passes as long as the type matches. Use matchers only in `.willRespondWith()` (responses), never in `.withRequest()` (requests) — Postel's Law applies.
280
279
  - **Reuse test values across files**: Interactions are uniquely identified by `uponReceiving` + `.given()`, not by placeholder values. Two test files can both use `testId: 100` without conflicting. On the provider side, shared values simplify state handlers — idempotent handlers (check if exists, create if not) only need to ensure one record exists. Use different values only when testing different states of the same entity type (e.g., `movieExists(100)` for happy paths vs. `movieNotFound(999)` for error paths).
281
- - **One `addInteraction()` per `it()` block (MANDATORY for PactV4)**: Multiple interactions inside one `it()` cause the Rust FFI to non-deterministically drop interactions. Use one `it()` per interaction or `it.each(...)` for parameterized cases. See Example 6 and the determinism gate in `pact-consumer-framework-setup.md` Example 10.
280
+ - **One `addInteraction()` per `it()` block (MANDATORY for PactV4)**: Multiple interactions inside one `it()` cause the Rust FFI to non-deterministically drop interactions. Use one `it()` per interaction or `it.each(...)` for parameterized cases. See Example 6.
282
281
 
283
282
  ## Related Fragments
284
283
 
285
284
  - `pactjs-utils-overview.md` — installation, decision tree, design philosophy
286
285
  - `pactjs-utils-provider-verifier.md` — provider-side state handler implementation; same `pool: 'forks'` + `singleFork: true` rule as consumer
287
- - `pact-consumer-framework-setup.md` — Vitest `fileParallelism: false` + `pool: 'forks'` + `singleFork: true` config, determinism gate (Example 10), and CI wiring
286
+ - `pact-consumer-framework-setup.md` — Vitest `fileParallelism: false` + `pool: 'forks'` + `singleFork: true` config and CI wiring
288
287
  - `contract-testing.md` — foundational patterns with raw Pact.js
289
288
 
290
289
  ## Anti-Patterns
@@ -375,6 +374,6 @@ it('returns empty list', async () => {
375
374
  });
376
375
  ```
377
376
 
378
- See Example 6 above for the full rationale and the determinism gate that enforces this rule.
377
+ See Example 6 above for the full rationale.
379
378
 
380
379
  _Source: @seontechnologies/pactjs-utils consumer-helpers module, pactjs-utils sample-app consumer tests_
@@ -296,7 +296,7 @@ export default defineConfig({
296
296
  - `pactjs-utils-overview.md` — installation, decision tree, design philosophy
297
297
  - `pactjs-utils-consumer-helpers.md` — consumer-side state parameter creation, **one-interaction-per-`it()` rule**
298
298
  - `pactjs-utils-request-filter.md` — auth injection for provider verification
299
- - `pact-consumer-framework-setup.md` — consumer-side framework setup, Vitest `fileParallelism: false`, determinism gate
299
+ - `pact-consumer-framework-setup.md` — consumer-side framework setup, Vitest `fileParallelism: false`, CI wiring
300
300
  - `pact-broker-webhooks.md` — PactFlow → GitHub webhook auth/staleness for webhook-triggered provider verification (`contract_requiring_verification_published`)
301
301
  - `contract-testing.md` — foundational patterns with raw Pact.js
302
302
 
@@ -38,7 +38,7 @@ pactjs-utils-consumer-helpers,Pact.js Utils Consumer Helpers,"createProviderStat
38
38
  pactjs-utils-provider-verifier,Pact.js Utils Provider Verifier,"buildVerifierOptions, buildMessageVerifierOptions; vitest pool:forks + singleFork for FFI safety (same rule applies to consumer and provider)","pactjs-utils,provider,consumer,contract-testing,pact,api,backend,ci,vitest,ffi",specialized,knowledge/pactjs-utils-provider-verifier.md
39
39
  pactjs-utils-request-filter,Pact.js Utils Request Filter,"createRequestFilter, noOpRequestFilter for auth injection","pactjs-utils,auth,contract-testing,pact",specialized,knowledge/pactjs-utils-request-filter.md
40
40
  pact-mcp,Pact MCP Server,"SmartBear MCP for PactFlow: generate tests, review, can-i-deploy, provider states","pact,mcp,pactflow,contract-testing,broker",specialized,knowledge/pact-mcp.md
41
- pact-consumer-framework-setup,Pact Consumer CDC Framework Setup,"Directory structure, vitest config with fileParallelism:false + pool:forks + singleFork:true (FFI safety), determinism gate (check-pact-determinism.sh), jq-normalized publishing, 1:1 local/CI parity, PactV4 patterns","pactjs-utils,consumer,contract-testing,pact,ci,framework,setup,vitest,shell-scripts,determinism,jq,pactv4,ffi",specialized,knowledge/pact-consumer-framework-setup.md
41
+ pact-consumer-framework-setup,Pact Consumer CDC Framework Setup,"Directory structure, vitest config with fileParallelism:false + pool:forks + singleFork:true (FFI safety), one-file-per-consumer+provider-pair rule (FFI handle collision prevention), jq-normalized publishing, 1:1 local/CI parity, PactV4 patterns","pactjs-utils,consumer,contract-testing,pact,ci,framework,setup,vitest,shell-scripts,jq,pactv4,ffi,file-organization,one-file-per-pair",specialized,knowledge/pact-consumer-framework-setup.md
42
42
  pact-broker-webhooks,Pact Broker Webhooks,"PactFlow → GitHub repository_dispatch auth via dedicated machine user + classic PAT (repo scope, no expiration) + PactFlow secret; staleness monitoring and PAT rotation runbook","pact,pactflow,broker,webhooks,github,auth,pat,ci,operations,security",specialized,knowledge/pact-broker-webhooks.md
43
43
  adr-quality-readiness-checklist,ADR Quality Readiness Checklist,"8-category 29-criteria framework for ADR testability and NFR assessment","nfr,testability,adr,quality,assessment,checklist",extended,knowledge/adr-quality-readiness-checklist.md
44
44
  playwright-cli,Playwright CLI,"Token-efficient CLI for AI coding agents: element refs, sessions, snapshots, trace analysis, debug=cli autonomous investigation","cli,browser,agent,automation,snapshot,trace,debug",core,knowledge/playwright-cli.md
@@ -1,11 +1,11 @@
1
1
  module,skill,display-name,menu-code,description,action,args,phase,after,before,required,output-location,outputs
2
2
  Test Architecture Enterprise,_meta,,,,,,,,,false,https://bmad-code-org.github.io/bmad-method-test-architecture-enterprise/llms.txt,
3
- Test Architecture Enterprise,bmad-teach-me-testing,Teach Me Testing,TMT,Teach testing fundamentals through 7 sessions (TEA Academy).,,0-learning,,,false,test_artifacts,"progress file|session notes|certificate"
4
- Test Architecture Enterprise,bmad-testarch-test-design,Test Design,TD,Risk-based test planning.,,3-solutioning,,bmad-testarch-framework,false,test_artifacts,test design document
5
- Test Architecture Enterprise,bmad-testarch-framework,Test Framework,TF,Initialize production-ready test framework.,,3-solutioning,bmad-testarch-test-design,bmad-testarch-ci,false,test_artifacts,framework scaffold
6
- Test Architecture Enterprise,bmad-testarch-ci,CI Setup,CI,Configure CI/CD quality pipeline.,,3-solutioning,bmad-testarch-framework,,false,test_artifacts,ci config
7
- Test Architecture Enterprise,bmad-testarch-atdd,ATDD,AT,Generate red-phase acceptance test scaffolds before implementation.,,4-implementation,bmad-create-story:create,bmad-dev-story,false,test_artifacts,"atdd-checklist|red-phase acceptance tests"
8
- Test Architecture Enterprise,bmad-testarch-automate,Test Automation,TA,Expand test coverage.,,4-implementation,bmad-testarch-atdd,,false,test_artifacts,test suite
9
- Test Architecture Enterprise,bmad-testarch-test-review,Test Review,RV,Quality audit (0-100 scoring).,,4-implementation,bmad-testarch-automate,,false,test_artifacts,review report
10
- Test Architecture Enterprise,bmad-testarch-nfr,NFR Assessment,NR,Non-functional requirements assessment.,,4-implementation,bmad-testarch-automate,,false,test_artifacts,nfr report
11
- Test Architecture Enterprise,bmad-testarch-trace,Traceability,TR,Coverage traceability and gate.,,4-implementation,bmad-testarch-test-review,,false,test_artifacts,"traceability matrix|gate decision"
3
+ Test Architecture Enterprise,bmad-teach-me-testing,Teach Me Testing,TMT,Teach testing fundamentals through 7 sessions (TEA Academy).,,,0-learning,,,false,test_artifacts,progress file|session notes|certificate
4
+ Test Architecture Enterprise,bmad-testarch-test-design,Test Design,TD,Risk-based test planning.,,,3-solutioning,,bmad-testarch-framework,false,test_artifacts,test design document
5
+ Test Architecture Enterprise,bmad-testarch-framework,Test Framework,TF,Initialize production-ready test framework.,,,3-solutioning,bmad-testarch-test-design,bmad-testarch-ci,false,test_artifacts,framework scaffold
6
+ Test Architecture Enterprise,bmad-testarch-ci,CI Setup,CI,Configure CI/CD quality pipeline.,,,3-solutioning,bmad-testarch-framework,,false,test_artifacts,ci config
7
+ Test Architecture Enterprise,bmad-testarch-atdd,ATDD,AT,Generate red-phase acceptance test scaffolds before implementation.,,,4-implementation,bmad-create-story:create,bmad-dev-story,false,test_artifacts,atdd-checklist|red-phase acceptance tests
8
+ Test Architecture Enterprise,bmad-testarch-automate,Test Automation,TA,Expand test coverage.,,,4-implementation,bmad-testarch-atdd,,false,test_artifacts,test suite
9
+ Test Architecture Enterprise,bmad-testarch-test-review,Test Review,RV,Quality audit (0-100 scoring).,,,4-implementation,bmad-testarch-automate,,false,test_artifacts,review report
10
+ Test Architecture Enterprise,bmad-testarch-nfr,NFR Assessment,NR,Non-functional requirements assessment.,,,4-implementation,bmad-testarch-automate,,false,test_artifacts,nfr report
11
+ Test Architecture Enterprise,bmad-testarch-trace,Traceability,TR,Coverage traceability and gate.,,,4-implementation,bmad-testarch-test-review,,false,test_artifacts,traceability matrix|gate decision
@@ -2,7 +2,7 @@
2
2
  "_comment": [
3
3
  "BMAD Builder convention: the wrapper directory '.claude-plugin/' is a SHARED convention used by skills-capable platforms — it is NOT a Claude-only binding. BMAD adopted Anthropic's published plugin layout because it was the closest thing to an open standard at the time; multi-tool routing (claude-code, copilot, cline, roo-code, kilocode, cursor) is handled by BMAD's own installer based on the --tools flag. See https://bmad-builder-docs.bmad-method.org/how-to/distribute-your-module/ and https://bmad-builder-docs.bmad-method.org/explanation/.",
4
4
  "This is a TEMPLATE file consumed by scripts/build-plugin.js (Story 22.4). Tokens of the form ${var} are replaced at build time; the resolved manifest lands at lib/bmad-extension-plugin/.claude-plugin/marketplace.json. Do NOT hand-edit the generated file.",
5
- "Fields follow the v6.5.0 schema read by tools/installer/modules/custom-module-manager.js (top-level: name, owner, description, license, homepage, repository, keywords; per-plugin: name, source, description, version, author, skills[]).",
5
+ "Fields follow the v6.6.0 schema read by tools/installer/modules/custom-module-manager.js (top-level: name, owner, description, license, homepage, repository, keywords; per-plugin: name, source, description, version, author, skills[]).",
6
6
  "plugins[].source interpretation: a value of \"./\" means 'the directory containing .claude-plugin/' — i.e. the plugin output root (lib/bmad-extension-plugin/). Skill paths (\"./skills/<name>\") are resolved relative to that same root. Story 22.4's build script MUST honor this convention.",
7
7
  "compatible_tools is an informational, BMAD-wide convention (not read by the installer) used to signal multi-tool parity with downstream consumers. The authoritative list of supported tools is the --tools flag accepted by the BMAD installer.",
8
8
  "bmad_min_version forward-compat policy: this floor assumes upstream bmad-method changes remain additive (new fields / new optional schema). Any breaking upstream change requires bumping bmad_min_version in lockstep with the pinned bmad-method dependency in package.json."
@@ -39,7 +39,7 @@
39
39
  "roo-code",
40
40
  "kilocode"
41
41
  ],
42
- "bmad_min_version": "6.5.0",
42
+ "bmad_min_version": "6.6.0",
43
43
  "plugins": [
44
44
  {
45
45
  "name": "ma-skills",
@@ -11,6 +11,45 @@ triggers:
11
11
 
12
12
  Guided workflow to create a new sprint entry in the `sprints` section of `sprint-status.yaml` with capacity limits, optional ISO dates, and auto-incremented sprint ID.
13
13
 
14
+ ## Backend Routing
15
+
16
+ Before executing any file-system operations, determine and route to the correct backend:
17
+
18
+ 1. Read `_bmad-output/implementation-artifacts/sprint-status.yaml` and extract the `tracking_system` field.
19
+ If the field is absent or the file does not exist, read `sprint_backend` from `_bmad/bmm/config.yaml`. Use that value if present, otherwise default to `file-system`.
20
+
21
+ 2. If `tracking_system` is `file-system`:
22
+ Proceed with the **File-System Backend** instructions below.
23
+
24
+ 3. If `tracking_system` is `jira`:
25
+ a. Perform the Jira operation: Create a new sprint in the board for project `{jira_project_key}` at `{jira_url}` using the sprint create API. Set the sprint name, goal (if provided), start date, and end date from the provided sprint data. The new sprint starts in "future/planning" state.
26
+ Use whatever Jira-capable tool is available in your current tool context.
27
+ Map Jira entities to the canonical schema (Sprint → sprints[], Backlog → backlog[],
28
+ Epic → epics[], Jira status → canonical vocabulary per Section 6.3 of the routing spec).
29
+ b. If the Jira operation SUCCEEDS: continue with the Jira data returned. Jira is the source of truth.
30
+ c. If the Jira operation FAILS for any reason:
31
+ - If no Jira-capable tool is available in your current context:
32
+ Pause and present the user with:
33
+ > "No Jira-capable tool is available. To use Jira tracking, configure a Jira integration
34
+ > in your agent (an MCP server, plugin, or native integration connected to the Jira
35
+ > instance at `{jira_url}`). How would you like to proceed?
36
+ > (a) Retry — attempt the Jira operation again once a Jira tool is configured
37
+ > (b) Switch to file management — update sprint-status.yaml and config to use
38
+ > file-system backend, then complete this operation locally. This change is permanent."
39
+ - If a Jira tool attempted the operation but returned an error:
40
+ Pause and present the user with:
41
+ > "The Jira operation failed: {actual Jira error details}. How would you like to proceed?
42
+ > (a) Retry — attempt the Jira operation again
43
+ > (b) Switch to file management — update sprint-status.yaml and config to use
44
+ > file-system backend, then complete this operation locally. This change is permanent."
45
+ If user chooses (b) in either case: write `tracking_system: file-system` to `sprint-status.yaml`,
46
+ update `sprint_backend: file-system` in `_bmad/bmm/config.yaml`,
47
+ then proceed with **File-System Backend** instructions below.
48
+
49
+ 4. **File-System Backend** — execute the workflow steps below.
50
+
51
+ ---
52
+
14
53
  <workflow>
15
54
 
16
55
  <step n="0" goal="Load configuration and validate file existence">
@@ -13,6 +13,45 @@ Guided workflow to move backlog items to a sprint in the unified `sprint-status.
13
13
 
14
14
  **Movement semantics:** Each item exists in exactly one location — either the `backlog` array OR a sprint's `items` array, never both. This skill atomically removes items from `backlog` and appends them to the target sprint's `items` array in a single file write.
15
15
 
16
+ ## Backend Routing
17
+
18
+ Before executing any file-system operations, determine and route to the correct backend:
19
+
20
+ 1. Read `_bmad-output/implementation-artifacts/sprint-status.yaml` and extract the `tracking_system` field.
21
+ If the field is absent or the file does not exist, read `sprint_backend` from `_bmad/bmm/config.yaml`. Use that value if present, otherwise default to `file-system`.
22
+
23
+ 2. If `tracking_system` is `file-system`:
24
+ Proceed with the **File-System Backend** instructions below.
25
+
26
+ 3. If `tracking_system` is `jira`:
27
+ a. Perform the Jira operation: Find the Jira issue matching the item ID in project `{jira_project_key}` at `{jira_url}` (search by issue key or summary). Find the active sprint on the board for project `{jira_project_key}`. Move the issue to the active sprint using the "add issue to sprint" operation.
28
+ Use whatever Jira-capable tool is available in your current tool context.
29
+ Map Jira entities to the canonical schema (Sprint → sprints[], Backlog → backlog[],
30
+ Epic → epics[], Jira status → canonical vocabulary per Section 6.3 of the routing spec).
31
+ b. If the Jira operation SUCCEEDS: continue with the Jira data returned. Jira is the source of truth.
32
+ c. If the Jira operation FAILS for any reason:
33
+ - If no Jira-capable tool is available in your current context:
34
+ Pause and present the user with:
35
+ > "No Jira-capable tool is available. To use Jira tracking, configure a Jira integration
36
+ > in your agent (an MCP server, plugin, or native integration connected to the Jira
37
+ > instance at `{jira_url}`). How would you like to proceed?
38
+ > (a) Retry — attempt the Jira operation again once a Jira tool is configured
39
+ > (b) Switch to file management — update sprint-status.yaml and config to use
40
+ > file-system backend, then complete this operation locally. This change is permanent."
41
+ - If a Jira tool attempted the operation but returned an error:
42
+ Pause and present the user with:
43
+ > "The Jira operation failed: {actual Jira error details}. How would you like to proceed?
44
+ > (a) Retry — attempt the Jira operation again
45
+ > (b) Switch to file management — update sprint-status.yaml and config to use
46
+ > file-system backend, then complete this operation locally. This change is permanent."
47
+ If user chooses (b) in either case: write `tracking_system: file-system` to `sprint-status.yaml`,
48
+ update `sprint_backend: file-system` in `_bmad/bmm/config.yaml`,
49
+ then proceed with **File-System Backend** instructions below.
50
+
51
+ 4. **File-System Backend** — execute the workflow steps below.
52
+
53
+ ---
54
+
16
55
  <workflow>
17
56
 
18
57
  <step n="0" goal="Load configuration and validate file existence">
@@ -36,6 +36,45 @@ Load config from `{project-root}/_bmad/bmm/config.yaml` and resolve:
36
36
 
37
37
  ---
38
38
 
39
+ ## Backend Routing
40
+
41
+ Before executing any status-update operations, determine and route to the correct backend:
42
+
43
+ 1. Read `_bmad-output/implementation-artifacts/sprint-status.yaml` and extract the `tracking_system` field.
44
+ If the field is absent or the file does not exist, read `sprint_backend` from `_bmad/bmm/config.yaml`. Use that value if present, otherwise default to `file-system`.
45
+
46
+ 2. If `tracking_system` is `file-system`:
47
+ Proceed with the **File-System Backend** instructions below.
48
+
49
+ 3. If `tracking_system` is `jira`:
50
+ a. Perform the Jira operation: Find the Jira issue matching the item ID in project `{jira_project_key}` at `{jira_url}` (search by issue key or summary). Transition the issue to the new status using the Jira issue transition API. Map canonical status to Jira workflow status: backlog → Backlog/Open, ready-for-dev → To Do/Selected for Development, in-progress → In Progress, review → In Review/Code Review, done → Done/Resolved, on-hold → On Hold/Blocked, cancelled → Won't Do/Cancelled.
51
+ Use whatever Jira-capable tool is available in your current tool context.
52
+ Map Jira entities to the canonical schema (Sprint → sprints[], Backlog → backlog[],
53
+ Epic → epics[], Jira status → canonical vocabulary per Section 6.3 of the routing spec).
54
+ b. If the Jira operation SUCCEEDS: continue with the Jira data returned. Jira is the source of truth.
55
+ c. If the Jira operation FAILS for any reason:
56
+ - If no Jira-capable tool is available in your current context:
57
+ Pause and present the user with:
58
+ > "No Jira-capable tool is available. To use Jira tracking, configure a Jira integration
59
+ > in your agent (an MCP server, plugin, or native integration connected to the Jira
60
+ > instance at `{jira_url}`). How would you like to proceed?
61
+ > (a) Retry — attempt the Jira operation again once a Jira tool is configured
62
+ > (b) Switch to file management — update sprint-status.yaml and config to use
63
+ > file-system backend, then complete this operation locally. This change is permanent."
64
+ - If a Jira tool attempted the operation but returned an error:
65
+ Pause and present the user with:
66
+ > "The Jira operation failed: {actual Jira error details}. How would you like to proceed?
67
+ > (a) Retry — attempt the Jira operation again
68
+ > (b) Switch to file management — update sprint-status.yaml and config to use
69
+ > file-system backend, then complete this operation locally. This change is permanent."
70
+ If user chooses (b) in either case: write `tracking_system: file-system` to `sprint-status.yaml`,
71
+ update `sprint_backend: file-system` in `_bmad/bmm/config.yaml`,
72
+ then proceed with **File-System Backend** instructions below.
73
+
74
+ 4. **File-System Backend** — execute the workflow steps below.
75
+
76
+ ---
77
+
39
78
  ## EXECUTION
40
79
 
41
80
  <workflow>
@@ -42,6 +42,47 @@ Load config from `{project-root}/_bmad/bmm/config.yaml` and resolve:
42
42
 
43
43
  ---
44
44
 
45
+ ## Backend Routing
46
+
47
+ Before executing any file-system operations, determine and route to the correct backend:
48
+
49
+ 1. Read `_bmad-output/implementation-artifacts/sprint-status.yaml` and extract the `tracking_system` field.
50
+ If the field is absent or the file does not exist, read `sprint_backend` from `_bmad/bmm/config.yaml`. Use that value if present, otherwise default to `file-system`.
51
+
52
+ 2. If `tracking_system` is `file-system`:
53
+ Proceed with the **File-System Backend** instructions below.
54
+
55
+ 3. If `tracking_system` is `jira`:
56
+ > "This operation will create/update Jira sprints and items in bulk. If it fails mid-way, Jira may be in partial state. The Jira server URL is `{jira_url}` and project key is `{jira_project_key}` (from `_bmad/bmm/config.yaml`). Proceed?"
57
+
58
+ a. Perform the Jira operation: Query all epics, backlog issues, sprint definitions, and sprint items for project `{jira_project_key}` at `{jira_url}` (multiple sequential read calls). For the write phase: create new Jira sprints for each sprint definition not already in Jira (one API call per sprint). Create or update Jira issues for each item in the plan (one API call per item). Map item fields as follows: title → issue summary, type → issue type (story → Story, bug → Bug), status → Jira workflow status (see status mapping below), priority → issue priority/rank. Map sprint fields: name → sprint name, start_date → sprint start date, end_date → sprint end date. Status mapping: backlog → Backlog/Open, ready-for-dev → To Do/Selected for Development, in-progress → In Progress, review → In Review/Code Review, done → Done/Resolved, on-hold → On Hold/Blocked, cancelled → Won't Do/Cancelled.
59
+ Use whatever Jira-capable tool is available in your current tool context.
60
+ Map Jira entities to the canonical schema (Sprint → sprints[], Backlog → backlog[],
61
+ Epic → epics[], Jira status → canonical vocabulary per Section 6.3 of the routing spec).
62
+ b. If the Jira operation SUCCEEDS: continue with the Jira data returned. Jira is the source of truth.
63
+ c. If the Jira operation FAILS for any reason:
64
+ - If no Jira-capable tool is available in your current context:
65
+ Pause and present the user with:
66
+ > "No Jira-capable tool is available. To use Jira tracking, configure a Jira integration
67
+ > in your agent (an MCP server, plugin, or native integration connected to the Jira
68
+ > instance at `{jira_url}`). How would you like to proceed?
69
+ > (a) Retry — attempt the Jira operation again once a Jira tool is configured
70
+ > (b) Switch to file management — update sprint-status.yaml and config to use
71
+ > file-system backend, then complete this operation locally. This change is permanent."
72
+ - If a Jira tool attempted the operation but returned an error:
73
+ Pause and present the user with:
74
+ > "The Jira operation failed: {actual Jira error details}. How would you like to proceed?
75
+ > (a) Retry — attempt the Jira operation again
76
+ > (b) Switch to file management — update sprint-status.yaml and config to use
77
+ > file-system backend, then complete this operation locally. This change is permanent."
78
+ If user chooses (b) in either case: write `tracking_system: file-system` to `sprint-status.yaml`,
79
+ update `sprint_backend: file-system` in `_bmad/bmm/config.yaml`,
80
+ then proceed with **File-System Backend** instructions below.
81
+
82
+ 4. **File-System Backend** — execute the workflow steps below.
83
+
84
+ ---
85
+
45
86
  ## EXECUTION
46
87
 
47
88
  <workflow>
@@ -37,6 +37,45 @@ Load config from `{project-root}/_bmad/bmm/config.yaml` and resolve:
37
37
 
38
38
  ---
39
39
 
40
+ ## Backend Routing
41
+
42
+ Before executing any file-system operations, determine and route to the correct backend:
43
+
44
+ 1. Read `_bmad-output/implementation-artifacts/sprint-status.yaml` and extract the `tracking_system` field.
45
+ If the field is absent or the file does not exist, read `sprint_backend` from `_bmad/bmm/config.yaml`. Use that value if present, otherwise default to `file-system`.
46
+
47
+ 2. If `tracking_system` is `file-system`:
48
+ Proceed with the **File-System Backend** instructions below.
49
+
50
+ 3. If `tracking_system` is `jira`:
51
+ a. Perform the Jira operation: Query the active sprint for project `{jira_project_key}` at `{jira_url}` and retrieve all sprint issues with their statuses. Query backlog issue count. Query epic progress (completed stories per epic). Map Jira sprint states and issue statuses to canonical vocabulary per the status mapping below. Use this data for health analysis — no writes. Status mapping: Backlog/Open → backlog, To Do/Selected for Development → ready-for-dev, In Progress → in-progress, In Review/Code Review → review, Done/Resolved → done, On Hold/Blocked → on-hold, Won't Do/Cancelled → cancelled.
52
+ Use whatever Jira-capable tool is available in your current tool context.
53
+ Map Jira entities to the canonical schema (Sprint → sprints[], Backlog → backlog[],
54
+ Epic → epics[], Jira status → canonical vocabulary per Section 6.3 of the routing spec).
55
+ b. If the Jira operation SUCCEEDS: continue with the Jira data returned. Jira is the source of truth.
56
+ c. If the Jira operation FAILS for any reason:
57
+ - If no Jira-capable tool is available in your current context:
58
+ Pause and present the user with:
59
+ > "No Jira-capable tool is available. To use Jira tracking, configure a Jira integration
60
+ > in your agent (an MCP server, plugin, or native integration connected to the Jira
61
+ > instance at `{jira_url}`). How would you like to proceed?
62
+ > (a) Retry — attempt the Jira operation again once a Jira tool is configured
63
+ > (b) Switch to file management — update sprint-status.yaml and config to use
64
+ > file-system backend, then complete this operation locally. This change is permanent."
65
+ - If a Jira tool attempted the operation but returned an error:
66
+ Pause and present the user with:
67
+ > "The Jira operation failed: {actual Jira error details}. How would you like to proceed?
68
+ > (a) Retry — attempt the Jira operation again
69
+ > (b) Switch to file management — update sprint-status.yaml and config to use
70
+ > file-system backend, then complete this operation locally. This change is permanent."
71
+ If user chooses (b) in either case: write `tracking_system: file-system` to `sprint-status.yaml`,
72
+ update `sprint_backend: file-system` in `_bmad/bmm/config.yaml`,
73
+ then proceed with **File-System Backend** instructions below.
74
+
75
+ 4. **File-System Backend** — execute the steps below.
76
+
77
+ ---
78
+
40
79
  ## EXECUTION
41
80
 
42
81
  <workflow>