bmad-method-quarkus 1.0.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 (380) hide show
  1. package/.claude-plugin/marketplace.json +53 -0
  2. package/AGENTS.md +12 -0
  3. package/LICENSE +30 -0
  4. package/README.md +94 -0
  5. package/README_CN.md +108 -0
  6. package/README_VN.md +109 -0
  7. package/bmad-modules.yaml +133 -0
  8. package/package.json +123 -0
  9. package/removals.txt +87 -0
  10. package/src/bmm-skills/agents/bmad-agent-analyst/SKILL.md +76 -0
  11. package/src/bmm-skills/agents/bmad-agent-analyst/customize.toml +105 -0
  12. package/src/bmm-skills/agents/bmad-agent-architect/SKILL.md +76 -0
  13. package/src/bmm-skills/agents/bmad-agent-architect/customize.toml +65 -0
  14. package/src/bmm-skills/agents/bmad-agent-dev/SKILL.md +76 -0
  15. package/src/bmm-skills/agents/bmad-agent-dev/customize.toml +83 -0
  16. package/src/bmm-skills/agents/bmad-agent-pm/SKILL.md +76 -0
  17. package/src/bmm-skills/agents/bmad-agent-pm/customize.toml +75 -0
  18. package/src/bmm-skills/agents/bmad-agent-ux-designer/SKILL.md +76 -0
  19. package/src/bmm-skills/agents/bmad-agent-ux-designer/customize.toml +60 -0
  20. package/src/bmm-skills/agents/bmad-quarkus-architect/.memlog.md +12 -0
  21. package/src/bmm-skills/agents/bmad-quarkus-architect/.memlog.md:Zone.Identifier +0 -0
  22. package/src/bmm-skills/agents/bmad-quarkus-architect/SKILL.md +86 -0
  23. package/src/bmm-skills/agents/bmad-quarkus-architect/SKILL.md:Zone.Identifier +0 -0
  24. package/src/bmm-skills/agents/bmad-quarkus-architect/customize.toml +37 -0
  25. package/src/bmm-skills/agents/bmad-quarkus-architect/customize.toml:Zone.Identifier +0 -0
  26. package/src/bmm-skills/agents/bmad-quarkus-architect/references/enrich-stories.md +19 -0
  27. package/src/bmm-skills/agents/bmad-quarkus-architect/references/enrich-stories.md:Zone.Identifier +0 -0
  28. package/src/bmm-skills/agents/bmad-quarkus-architect/references/prompt-quality-canon.md +79 -0
  29. package/src/bmm-skills/agents/bmad-quarkus-architect/references/prompt-quality-canon.md:Zone.Identifier +0 -0
  30. package/src/bmm-skills/agents/bmad-quarkus-architect/skills/bqa-setup/SKILL.md +80 -0
  31. package/src/bmm-skills/agents/bmad-quarkus-architect/skills/bqa-setup/SKILL.md:Zone.Identifier +0 -0
  32. package/src/bmm-skills/agents/bmad-quarkus-architect/skills/bqa-setup/assets/module-help.csv +9 -0
  33. package/src/bmm-skills/agents/bmad-quarkus-architect/skills/bqa-setup/assets/module-help.csv:Zone.Identifier +0 -0
  34. package/src/bmm-skills/agents/bmad-quarkus-architect/skills/bqa-setup/assets/module.yaml +16 -0
  35. package/src/bmm-skills/agents/bmad-quarkus-architect/skills/bqa-setup/assets/module.yaml:Zone.Identifier +0 -0
  36. package/src/bmm-skills/agents/bmad-quarkus-architect/skills/bqa-setup/scripts/cleanup-legacy.py +287 -0
  37. package/src/bmm-skills/agents/bmad-quarkus-architect/skills/bqa-setup/scripts/cleanup-legacy.py:Zone.Identifier +0 -0
  38. package/src/bmm-skills/agents/bmad-quarkus-architect/skills/bqa-setup/scripts/merge-config.py +441 -0
  39. package/src/bmm-skills/agents/bmad-quarkus-architect/skills/bqa-setup/scripts/merge-config.py:Zone.Identifier +0 -0
  40. package/src/bmm-skills/agents/bmad-quarkus-architect/skills/bqa-setup/scripts/merge-help-csv.py +246 -0
  41. package/src/bmm-skills/agents/bmad-quarkus-architect/skills/bqa-setup/scripts/merge-help-csv.py:Zone.Identifier +0 -0
  42. package/src/bmm-skills/agents/bmad-quarkus-architect/skills/quarkus-error-handling-i18n/SKILL.md +181 -0
  43. package/src/bmm-skills/agents/bmad-quarkus-architect/skills/quarkus-error-handling-i18n/SKILL.md:Zone.Identifier +0 -0
  44. package/src/bmm-skills/agents/bmad-quarkus-architect/skills/quarkus-grpc-services/SKILL.md +141 -0
  45. package/src/bmm-skills/agents/bmad-quarkus-architect/skills/quarkus-grpc-services/SKILL.md:Zone.Identifier +0 -0
  46. package/src/bmm-skills/agents/bmad-quarkus-architect/skills/quarkus-hexagonal-core/SKILL.md +392 -0
  47. package/src/bmm-skills/agents/bmad-quarkus-architect/skills/quarkus-hexagonal-core/SKILL.md:Zone.Identifier +0 -0
  48. package/src/bmm-skills/agents/bmad-quarkus-architect/skills/quarkus-kafka-messaging/SKILL.md +148 -0
  49. package/src/bmm-skills/agents/bmad-quarkus-architect/skills/quarkus-kafka-messaging/SKILL.md:Zone.Identifier +0 -0
  50. package/src/bmm-skills/agents/bmad-quarkus-architect/skills/quarkus-observability-otel/SKILL.md +180 -0
  51. package/src/bmm-skills/agents/bmad-quarkus-architect/skills/quarkus-observability-otel/SKILL.md:Zone.Identifier +0 -0
  52. package/src/bmm-skills/agents/bmad-quarkus-architect/skills/quarkus-openapi-tmforum/SKILL.md +128 -0
  53. package/src/bmm-skills/agents/bmad-quarkus-architect/skills/quarkus-openapi-tmforum/SKILL.md:Zone.Identifier +0 -0
  54. package/src/bmm-skills/agents/bmad-quarkus-architect/skills/quarkus-sql-jdbc-agroal/SKILL.md +245 -0
  55. package/src/bmm-skills/agents/bmad-quarkus-architect/skills/quarkus-sql-jdbc-agroal/SKILL.md:Zone.Identifier +0 -0
  56. package/src/bmm-skills/module-help.csv +19 -0
  57. package/src/bmm-skills/module.yaml +92 -0
  58. package/src/bmm-skills/plan/bmad-architecture/SKILL.md +85 -0
  59. package/src/bmm-skills/plan/bmad-architecture/assets/spine-template.md +79 -0
  60. package/src/bmm-skills/plan/bmad-architecture/customize.toml +102 -0
  61. package/src/bmm-skills/plan/bmad-architecture/references/headless.md +26 -0
  62. package/src/bmm-skills/plan/bmad-architecture/references/reviewer-gate.md +13 -0
  63. package/src/bmm-skills/plan/bmad-architecture/scripts/lint_spine.py +257 -0
  64. package/src/bmm-skills/plan/bmad-architecture/scripts/tests/test_lint_spine.py +270 -0
  65. package/src/bmm-skills/plan/bmad-create-epics-and-stories/SKILL.md +93 -0
  66. package/src/bmm-skills/plan/bmad-create-epics-and-stories/customize.toml +41 -0
  67. package/src/bmm-skills/plan/bmad-create-epics-and-stories/steps/step-01-validate-prerequisites.md +263 -0
  68. package/src/bmm-skills/plan/bmad-create-epics-and-stories/steps/step-02-design-epics.md +242 -0
  69. package/src/bmm-skills/plan/bmad-create-epics-and-stories/steps/step-03-create-stories.md +255 -0
  70. package/src/bmm-skills/plan/bmad-create-epics-and-stories/steps/step-04-final-validation.md +143 -0
  71. package/src/bmm-skills/plan/bmad-create-epics-and-stories/templates/epics-template.md +61 -0
  72. package/src/bmm-skills/plan/bmad-generate-project-context/SKILL.md +10 -0
  73. package/src/bmm-skills/plan/bmad-prd/SKILL.md +94 -0
  74. package/src/bmm-skills/plan/bmad-prd/assets/headless-schemas.md +76 -0
  75. package/src/bmm-skills/plan/bmad-prd/assets/prd-template.md +165 -0
  76. package/src/bmm-skills/plan/bmad-prd/assets/prd-validation-checklist.md +135 -0
  77. package/src/bmm-skills/plan/bmad-prd/assets/validation-report-template.html +325 -0
  78. package/src/bmm-skills/plan/bmad-prd/customize.toml +149 -0
  79. package/src/bmm-skills/plan/bmad-prd/references/headless.md +39 -0
  80. package/src/bmm-skills/plan/bmad-prd/references/validate.md +97 -0
  81. package/src/bmm-skills/plan/bmad-prfaq/SKILL.md +135 -0
  82. package/src/bmm-skills/plan/bmad-prfaq/agents/artifact-analyzer.md +60 -0
  83. package/src/bmm-skills/plan/bmad-prfaq/agents/web-researcher.md +49 -0
  84. package/src/bmm-skills/plan/bmad-prfaq/assets/prfaq-template.md +62 -0
  85. package/src/bmm-skills/plan/bmad-prfaq/bmad-manifest.json +16 -0
  86. package/src/bmm-skills/plan/bmad-prfaq/customize.toml +41 -0
  87. package/src/bmm-skills/plan/bmad-prfaq/references/customer-faq.md +55 -0
  88. package/src/bmm-skills/plan/bmad-prfaq/references/internal-faq.md +51 -0
  89. package/src/bmm-skills/plan/bmad-prfaq/references/press-release.md +60 -0
  90. package/src/bmm-skills/plan/bmad-prfaq/references/verdict.md +83 -0
  91. package/src/bmm-skills/plan/bmad-product-brief/SKILL.md +91 -0
  92. package/src/bmm-skills/plan/bmad-product-brief/assets/brief-template.md +41 -0
  93. package/src/bmm-skills/plan/bmad-product-brief/customize.toml +101 -0
  94. package/src/bmm-skills/plan/bmad-project-context/SKILL.md +110 -0
  95. package/src/bmm-skills/plan/bmad-project-context/customize.toml +24 -0
  96. package/src/bmm-skills/plan/bmad-project-context/references/best-practices.md +65 -0
  97. package/src/bmm-skills/plan/bmad-project-context/references/template.md +55 -0
  98. package/src/bmm-skills/plan/bmad-spec/SKILL.md +160 -0
  99. package/src/bmm-skills/plan/bmad-spec/assets/headless-schemas.md +33 -0
  100. package/src/bmm-skills/plan/bmad-spec/assets/spec-template.md +49 -0
  101. package/src/bmm-skills/plan/bmad-spec/assets/stories-schema.md +44 -0
  102. package/src/bmm-skills/plan/bmad-spec/customize.toml +52 -0
  103. package/src/bmm-skills/plan/bmad-sprint-planning/SKILL.md +62 -0
  104. package/src/bmm-skills/plan/bmad-sprint-planning/customize.toml +41 -0
  105. package/src/bmm-skills/plan/bmad-sprint-planning/references/fix-sprint-status.md +30 -0
  106. package/src/bmm-skills/plan/bmad-sprint-planning/references/generate-tracking.md +25 -0
  107. package/src/bmm-skills/plan/bmad-sprint-planning/references/readiness-gate.md +20 -0
  108. package/src/bmm-skills/plan/bmad-sprint-planning/references/status-view.md +14 -0
  109. package/src/bmm-skills/plan/bmad-sprint-planning/references/validate.md +10 -0
  110. package/src/bmm-skills/plan/bmad-sprint-planning/scripts/__pycache__/sprint_plan.cpython-311.pyc +0 -0
  111. package/src/bmm-skills/plan/bmad-sprint-planning/scripts/sprint_plan.py +697 -0
  112. package/src/bmm-skills/plan/bmad-sprint-planning/scripts/tests/__pycache__/test_sprint_plan.cpython-311-pytest-9.1.1.pyc +0 -0
  113. package/src/bmm-skills/plan/bmad-sprint-planning/scripts/tests/test_sprint_plan.py +524 -0
  114. package/src/bmm-skills/plan/bmad-sprint-planning/sprint-status-template.yaml +71 -0
  115. package/src/bmm-skills/plan/bmad-ux/SKILL.md +90 -0
  116. package/src/bmm-skills/plan/bmad-ux/assets/color-themes.md +9 -0
  117. package/src/bmm-skills/plan/bmad-ux/assets/design-directions.md +9 -0
  118. package/src/bmm-skills/plan/bmad-ux/assets/design-example-editorial.md +158 -0
  119. package/src/bmm-skills/plan/bmad-ux/assets/design-example-mobile.md +93 -0
  120. package/src/bmm-skills/plan/bmad-ux/assets/design-example-shadcn.md +109 -0
  121. package/src/bmm-skills/plan/bmad-ux/assets/excalidraw-wireframe.md +19 -0
  122. package/src/bmm-skills/plan/bmad-ux/assets/experience-example-mobile.md +112 -0
  123. package/src/bmm-skills/plan/bmad-ux/assets/experience-example-shadcn.md +133 -0
  124. package/src/bmm-skills/plan/bmad-ux/assets/headless-schemas.md +84 -0
  125. package/src/bmm-skills/plan/bmad-ux/assets/key-screens.md +29 -0
  126. package/src/bmm-skills/plan/bmad-ux/assets/validation-report-template.html +319 -0
  127. package/src/bmm-skills/plan/bmad-ux/customize.toml +102 -0
  128. package/src/bmm-skills/plan/bmad-ux/references/creative-tools.md +19 -0
  129. package/src/bmm-skills/plan/bmad-ux/references/design-md-spec.md +50 -0
  130. package/src/bmm-skills/plan/bmad-ux/references/headless.md +37 -0
  131. package/src/bmm-skills/plan/bmad-ux/references/validate.md +115 -0
  132. package/src/bmm-skills/ship/bmad-build/SKILL.md +13 -0
  133. package/src/bmm-skills/ship/bmad-build/compile-epic-context.md +62 -0
  134. package/src/bmm-skills/ship/bmad-build/customize.toml +164 -0
  135. package/src/bmm-skills/ship/bmad-build/references/deletion-check.md +14 -0
  136. package/src/bmm-skills/ship/bmad-build/review-prompts/edge-case-hunter.md +88 -0
  137. package/src/bmm-skills/ship/bmad-build/review-prompts/verification-gap.md +113 -0
  138. package/src/bmm-skills/ship/bmad-build/spec-template.md +89 -0
  139. package/src/bmm-skills/ship/bmad-build/step-01-clarify-and-route.md +105 -0
  140. package/src/bmm-skills/ship/bmad-build/step-02-plan.md +47 -0
  141. package/src/bmm-skills/ship/bmad-build/step-03-implement.md +49 -0
  142. package/src/bmm-skills/ship/bmad-build/step-04-review.md +55 -0
  143. package/src/bmm-skills/ship/bmad-build/step-05-present.md +75 -0
  144. package/src/bmm-skills/ship/bmad-build/step-oneshot.md +77 -0
  145. package/src/bmm-skills/ship/bmad-build/sync-sprint-status.md +19 -0
  146. package/src/bmm-skills/ship/bmad-build/workflow.md +84 -0
  147. package/src/bmm-skills/ship/bmad-build-auto/SKILL.md +13 -0
  148. package/src/bmm-skills/ship/bmad-build-auto/compile-epic-context.md +62 -0
  149. package/src/bmm-skills/ship/bmad-build-auto/customize.toml +121 -0
  150. package/src/bmm-skills/ship/bmad-build-auto/references/deletion-check.md +14 -0
  151. package/src/bmm-skills/ship/bmad-build-auto/review-prompts/edge-case-hunter.md +88 -0
  152. package/src/bmm-skills/ship/bmad-build-auto/review-prompts/verification-gap.md +113 -0
  153. package/src/bmm-skills/ship/bmad-build-auto/spec-template.md +99 -0
  154. package/src/bmm-skills/ship/bmad-build-auto/step-01-clarify-and-route.md +83 -0
  155. package/src/bmm-skills/ship/bmad-build-auto/step-02-plan.md +27 -0
  156. package/src/bmm-skills/ship/bmad-build-auto/step-03-implement.md +44 -0
  157. package/src/bmm-skills/ship/bmad-build-auto/step-04-review.md +96 -0
  158. package/src/bmm-skills/ship/bmad-build-auto/workflow.md +104 -0
  159. package/src/bmm-skills/ship/bmad-checkpoint-preview/SKILL.md +68 -0
  160. package/src/bmm-skills/ship/bmad-checkpoint-preview/customize.toml +41 -0
  161. package/src/bmm-skills/ship/bmad-checkpoint-preview/generate-trail.md +38 -0
  162. package/src/bmm-skills/ship/bmad-checkpoint-preview/step-01-orientation.md +105 -0
  163. package/src/bmm-skills/ship/bmad-checkpoint-preview/step-02-walkthrough.md +89 -0
  164. package/src/bmm-skills/ship/bmad-checkpoint-preview/step-03-detail-pass.md +106 -0
  165. package/src/bmm-skills/ship/bmad-checkpoint-preview/step-04-testing.md +74 -0
  166. package/src/bmm-skills/ship/bmad-checkpoint-preview/step-05-wrapup.md +30 -0
  167. package/src/bmm-skills/ship/bmad-code-review/SKILL.md +90 -0
  168. package/src/bmm-skills/ship/bmad-code-review/customize.toml +113 -0
  169. package/src/bmm-skills/ship/bmad-code-review/references/deletion-check.md +14 -0
  170. package/src/bmm-skills/ship/bmad-code-review/review-prompts/edge-case-hunter.md +88 -0
  171. package/src/bmm-skills/ship/bmad-code-review/review-prompts/verification-gap.md +113 -0
  172. package/src/bmm-skills/ship/bmad-code-review/steps/step-01-gather-context.md +87 -0
  173. package/src/bmm-skills/ship/bmad-code-review/steps/step-02-review.md +32 -0
  174. package/src/bmm-skills/ship/bmad-code-review/steps/step-03-triage.md +50 -0
  175. package/src/bmm-skills/ship/bmad-code-review/steps/step-04-present.md +132 -0
  176. package/src/bmm-skills/ship/bmad-correct-course/SKILL.md +300 -0
  177. package/src/bmm-skills/ship/bmad-correct-course/checklist.md +288 -0
  178. package/src/bmm-skills/ship/bmad-correct-course/customize.toml +41 -0
  179. package/src/bmm-skills/ship/bmad-qa-generate-e2e-tests/SKILL.md +176 -0
  180. package/src/bmm-skills/ship/bmad-qa-generate-e2e-tests/checklist.md +33 -0
  181. package/src/bmm-skills/ship/bmad-qa-generate-e2e-tests/customize.toml +41 -0
  182. package/src/bmm-skills/ship/bmad-retrospective/SKILL.md +94 -0
  183. package/src/bmm-skills/ship/bmad-retrospective/customize.toml +41 -0
  184. package/src/bmm-skills/ship/bmad-retrospective/references/acceptance-verdict.md +55 -0
  185. package/src/bmm-skills/ship/bmad-retrospective/references/aggregate-views.md +17 -0
  186. package/src/bmm-skills/ship/bmad-retrospective/references/evidence-gathering.md +30 -0
  187. package/src/bmm-skills/ship/bmad-retrospective/references/retro-document.md +84 -0
  188. package/src/bmm-skills/ship/bmad-retrospective/references/team-discussion.md +22 -0
  189. package/src/bmm-skills/ship/bmad-retrospective/scripts/__pycache__/sprint_status.cpython-311.pyc +0 -0
  190. package/src/bmm-skills/ship/bmad-retrospective/scripts/git_evidence.py +304 -0
  191. package/src/bmm-skills/ship/bmad-retrospective/scripts/sprint_status.py +746 -0
  192. package/src/bmm-skills/ship/bmad-retrospective/scripts/tests/__pycache__/test_git_evidence.cpython-311-pytest-9.1.1.pyc +0 -0
  193. package/src/bmm-skills/ship/bmad-retrospective/scripts/tests/__pycache__/test_sprint_status.cpython-311-pytest-9.1.1.pyc +0 -0
  194. package/src/bmm-skills/ship/bmad-retrospective/scripts/tests/fixtures/sprint-status-template.yaml +71 -0
  195. package/src/bmm-skills/ship/bmad-retrospective/scripts/tests/test_git_evidence.py +750 -0
  196. package/src/bmm-skills/ship/bmad-retrospective/scripts/tests/test_sprint_status.py +1579 -0
  197. package/src/bmm-skills/v6-shims/README.md +28 -0
  198. package/src/bmm-skills/v6-shims/bmad-create-architecture/SKILL.md +30 -0
  199. package/src/bmm-skills/v6-shims/bmad-create-architecture/customize.toml +41 -0
  200. package/src/bmm-skills/v6-shims/bmad-create-prd/SKILL.md +30 -0
  201. package/src/bmm-skills/v6-shims/bmad-create-prd/customize.toml +41 -0
  202. package/src/bmm-skills/v6-shims/bmad-create-story/SKILL.md +434 -0
  203. package/src/bmm-skills/v6-shims/bmad-create-story/checklist.md +357 -0
  204. package/src/bmm-skills/v6-shims/bmad-create-story/customize.toml +41 -0
  205. package/src/bmm-skills/v6-shims/bmad-create-story/discover-inputs.md +88 -0
  206. package/src/bmm-skills/v6-shims/bmad-create-story/template.md +49 -0
  207. package/src/bmm-skills/v6-shims/bmad-dev-auto/SKILL.md +19 -0
  208. package/src/bmm-skills/v6-shims/bmad-dev-story/SKILL.md +502 -0
  209. package/src/bmm-skills/v6-shims/bmad-dev-story/checklist.md +80 -0
  210. package/src/bmm-skills/v6-shims/bmad-dev-story/customize.toml +44 -0
  211. package/src/bmm-skills/v6-shims/bmad-document-project/SKILL.md +14 -0
  212. package/src/bmm-skills/v6-shims/bmad-domain-research/SKILL.md +14 -0
  213. package/src/bmm-skills/v6-shims/bmad-edit-prd/SKILL.md +30 -0
  214. package/src/bmm-skills/v6-shims/bmad-edit-prd/customize.toml +42 -0
  215. package/src/bmm-skills/v6-shims/bmad-market-research/SKILL.md +14 -0
  216. package/src/bmm-skills/v6-shims/bmad-quick-dev/SKILL.md +19 -0
  217. package/src/bmm-skills/v6-shims/bmad-sprint-status/SKILL.md +26 -0
  218. package/src/bmm-skills/v6-shims/bmad-sprint-status/customize.toml +41 -0
  219. package/src/bmm-skills/v6-shims/bmad-technical-research/SKILL.md +14 -0
  220. package/src/bmm-skills/v6-shims/bmad-validate-prd/SKILL.md +30 -0
  221. package/src/bmm-skills/v6-shims/bmad-validate-prd/customize.toml +42 -0
  222. package/src/core-skills/bmad-advanced-elicitation/SKILL.md +65 -0
  223. package/src/core-skills/bmad-advanced-elicitation/assets/methods.csv +72 -0
  224. package/src/core-skills/bmad-advanced-elicitation/customize.toml +54 -0
  225. package/src/core-skills/bmad-advanced-elicitation/scripts/pick_methods.py +233 -0
  226. package/src/core-skills/bmad-advanced-elicitation/scripts/tests/test_pick_methods.py +228 -0
  227. package/src/core-skills/bmad-brainstorming/SKILL.md +80 -0
  228. package/src/core-skills/bmad-brainstorming/assets/brain-icons.json +166 -0
  229. package/src/core-skills/bmad-brainstorming/assets/brain-methods.csv +109 -0
  230. package/src/core-skills/bmad-brainstorming/assets/brain-selector.html +328 -0
  231. package/src/core-skills/bmad-brainstorming/customize.toml +84 -0
  232. package/src/core-skills/bmad-brainstorming/references/converge.md +24 -0
  233. package/src/core-skills/bmad-brainstorming/references/finalize.md +26 -0
  234. package/src/core-skills/bmad-brainstorming/references/headless.md +54 -0
  235. package/src/core-skills/bmad-brainstorming/references/in-chat-techniques.md +18 -0
  236. package/src/core-skills/bmad-brainstorming/references/mode-autonomous.md +10 -0
  237. package/src/core-skills/bmad-brainstorming/references/mode-facilitator.md +11 -0
  238. package/src/core-skills/bmad-brainstorming/references/mode-partner.md +16 -0
  239. package/src/core-skills/bmad-brainstorming/references/resume.md +5 -0
  240. package/src/core-skills/bmad-brainstorming/scripts/brain.py +770 -0
  241. package/src/core-skills/bmad-brainstorming/scripts/tests/test_brain.py +239 -0
  242. package/src/core-skills/bmad-customize/SKILL.md +111 -0
  243. package/src/core-skills/bmad-customize/scripts/list_customizable_skills.py +231 -0
  244. package/src/core-skills/bmad-customize/scripts/tests/test_list_customizable_skills.py +249 -0
  245. package/src/core-skills/bmad-deep-recon/SKILL.md +82 -0
  246. package/src/core-skills/bmad-deep-recon/assets/research.template.md +18 -0
  247. package/src/core-skills/bmad-deep-recon/customize.toml +212 -0
  248. package/src/core-skills/bmad-deep-recon/references/draft.md +8 -0
  249. package/src/core-skills/bmad-deep-recon/references/finalize.md +11 -0
  250. package/src/core-skills/bmad-deep-recon/references/html-briefing.md +16 -0
  251. package/src/core-skills/bmad-deep-recon/references/lifecycle.md +11 -0
  252. package/src/core-skills/bmad-deep-recon/references/process.md +10 -0
  253. package/src/core-skills/bmad-deep-recon/references/run.md +73 -0
  254. package/src/core-skills/bmad-deep-recon/references/selection.md +13 -0
  255. package/src/core-skills/bmad-deep-recon/references/synthesis.md +16 -0
  256. package/src/core-skills/bmad-deep-recon/references/verification.md +29 -0
  257. package/src/core-skills/bmad-deep-recon/scripts/recon_kit.py +322 -0
  258. package/src/core-skills/bmad-deep-recon/scripts/tests/test_recon_kit.py +144 -0
  259. package/src/core-skills/bmad-deep-recon/types/academic-lit.md +19 -0
  260. package/src/core-skills/bmad-deep-recon/types/competitive.md +19 -0
  261. package/src/core-skills/bmad-deep-recon/types/domain.md +19 -0
  262. package/src/core-skills/bmad-deep-recon/types/market.md +19 -0
  263. package/src/core-skills/bmad-deep-recon/types/technical.md +19 -0
  264. package/src/core-skills/bmad-deep-recon/types/user-voice.md +19 -0
  265. package/src/core-skills/bmad-forge-idea/SKILL.md +107 -0
  266. package/src/core-skills/bmad-forge-idea/customize.toml +42 -0
  267. package/src/core-skills/bmad-forge-idea/scripts/resolve_personas.py +275 -0
  268. package/src/core-skills/bmad-forge-idea/scripts/tests/test_resolve_personas.py +138 -0
  269. package/src/core-skills/bmad-help/SKILL.md +75 -0
  270. package/src/core-skills/bmad-party-mode/SKILL.md +60 -0
  271. package/src/core-skills/bmad-party-mode/customize.toml +211 -0
  272. package/src/core-skills/bmad-party-mode/references/create-party.md +70 -0
  273. package/src/core-skills/bmad-party-mode/references/mode-agent-team.md +13 -0
  274. package/src/core-skills/bmad-party-mode/references/mode-auto.md +13 -0
  275. package/src/core-skills/bmad-party-mode/references/mode-subagent.md +31 -0
  276. package/src/core-skills/bmad-party-mode/references/party-memory.md +51 -0
  277. package/src/core-skills/bmad-party-mode/scripts/resolve_party.py +282 -0
  278. package/src/core-skills/bmad-party-mode/scripts/tests/test_resolve_party.py +146 -0
  279. package/src/core-skills/bmad-review/SKILL.md +49 -0
  280. package/src/core-skills/bmad-review/customize.toml +141 -0
  281. package/src/core-skills/bmad-review/references/editorial-common.md +56 -0
  282. package/src/core-skills/bmad-review/references/lens-adversarial.md +19 -0
  283. package/src/core-skills/bmad-review/references/lens-edge-case-hunter.md +54 -0
  284. package/src/core-skills/bmad-review/references/lens-prose.md +7 -0
  285. package/src/core-skills/bmad-review/references/lens-structure.md +9 -0
  286. package/src/core-skills/bmad-review/references/lens-verification-gap.md +92 -0
  287. package/src/core-skills/bmad-review/references/structure-models.md +44 -0
  288. package/src/core-skills/bmad-review/scripts/tests/test_word_metrics.py +62 -0
  289. package/src/core-skills/bmad-review/scripts/word_metrics.py +102 -0
  290. package/src/core-skills/module-help.csv +10 -0
  291. package/src/core-skills/module.yaml +38 -0
  292. package/src/core-skills/v6-shims/README.md +25 -0
  293. package/src/core-skills/v6-shims/bmad-editorial-review/SKILL.md +6 -0
  294. package/src/core-skills/v6-shims/bmad-editorial-review/customize.toml +31 -0
  295. package/src/core-skills/v6-shims/bmad-editorial-review-prose/SKILL.md +6 -0
  296. package/src/core-skills/v6-shims/bmad-editorial-review-structure/SKILL.md +6 -0
  297. package/src/core-skills/v6-shims/bmad-review-adversarial-general/SKILL.md +6 -0
  298. package/src/core-skills/v6-shims/bmad-review-edge-case-hunter/SKILL.md +6 -0
  299. package/src/core-skills/v6-shims/bmad-review-verification-gap/SKILL.md +6 -0
  300. package/src/scripts/__pycache__/config_utils.cpython-311.pyc +0 -0
  301. package/src/scripts/config_utils.py +119 -0
  302. package/src/scripts/memlog.py +224 -0
  303. package/src/scripts/render_skill.py +401 -0
  304. package/src/scripts/resolve_config.py +74 -0
  305. package/src/scripts/resolve_customization.py +99 -0
  306. package/src/scripts/tests/__pycache__/test_config_utils.cpython-311.pyc +0 -0
  307. package/src/scripts/tests/__pycache__/test_resolve_config.cpython-311.pyc +0 -0
  308. package/src/scripts/tests/__pycache__/test_resolve_customization.cpython-311.pyc +0 -0
  309. package/src/scripts/tests/test_config_utils.py +85 -0
  310. package/src/scripts/tests/test_memlog.py +306 -0
  311. package/src/scripts/tests/test_resolve_config.py +89 -0
  312. package/src/scripts/tests/test_resolve_customization.py +77 -0
  313. package/tools/bundle-web-bundles.js +117 -0
  314. package/tools/format-workflow-md.js +263 -0
  315. package/tools/installer/README.md +60 -0
  316. package/tools/installer/bmad-cli.js +105 -0
  317. package/tools/installer/cli-utils.js +57 -0
  318. package/tools/installer/commands/install.js +149 -0
  319. package/tools/installer/commands/status.js +65 -0
  320. package/tools/installer/commands/uninstall.js +167 -0
  321. package/tools/installer/core/config.js +73 -0
  322. package/tools/installer/core/existing-install.js +121 -0
  323. package/tools/installer/core/install-paths.js +132 -0
  324. package/tools/installer/core/installer.js +1767 -0
  325. package/tools/installer/core/legacy-warnings.js +151 -0
  326. package/tools/installer/core/manifest-generator.js +859 -0
  327. package/tools/installer/core/manifest.js +433 -0
  328. package/tools/installer/core/uv-check.js +195 -0
  329. package/tools/installer/core/wsl-node-check.js +109 -0
  330. package/tools/installer/file-ops.js +204 -0
  331. package/tools/installer/fs-native.js +116 -0
  332. package/tools/installer/ide/_config-driven.js +972 -0
  333. package/tools/installer/ide/manager.js +324 -0
  334. package/tools/installer/ide/platform-codes.js +80 -0
  335. package/tools/installer/ide/platform-codes.yaml +343 -0
  336. package/tools/installer/ide/shared/installed-skills.js +50 -0
  337. package/tools/installer/ide/shared/path-utils.js +219 -0
  338. package/tools/installer/ide/shared/skill-manifest.js +57 -0
  339. package/tools/installer/install-messages.yaml +37 -0
  340. package/tools/installer/list-options.js +210 -0
  341. package/tools/installer/message-loader.js +83 -0
  342. package/tools/installer/modules/channel-plan.js +203 -0
  343. package/tools/installer/modules/channel-resolver.js +241 -0
  344. package/tools/installer/modules/custom-module-manager.js +924 -0
  345. package/tools/installer/modules/external-manager.js +671 -0
  346. package/tools/installer/modules/git-env.js +47 -0
  347. package/tools/installer/modules/module-help-schema.js +13 -0
  348. package/tools/installer/modules/official-modules.js +2257 -0
  349. package/tools/installer/modules/plugin-resolver.js +398 -0
  350. package/tools/installer/modules/version-resolver.js +336 -0
  351. package/tools/installer/project-root.js +224 -0
  352. package/tools/installer/prompts.js +791 -0
  353. package/tools/installer/set-overrides.js +330 -0
  354. package/tools/installer/ui.js +2167 -0
  355. package/tools/installer/yaml-format.js +245 -0
  356. package/tools/javascript-conventions.md +5 -0
  357. package/tools/migrate-custom-module-paths.js +124 -0
  358. package/tools/skill-validator.md +378 -0
  359. package/tools/validate-published-implementation-model.mjs +68 -0
  360. package/tools/validate-sidebar-order.js +388 -0
  361. package/tools/validate-skills.js +735 -0
  362. package/tools/validate-svg-changes.sh +356 -0
  363. package/web-bundles/README.md +46 -0
  364. package/web-bundles/brainstorming-coach/INSTRUCTIONS.md +86 -0
  365. package/web-bundles/brainstorming-coach/SKILL.md +83 -0
  366. package/web-bundles/brainstorming-coach/brain-methods.csv +62 -0
  367. package/web-bundles/bundles.json +139 -0
  368. package/web-bundles/market-and-industry-research/INSTRUCTIONS.md +88 -0
  369. package/web-bundles/market-and-industry-research/SKILL.md +59 -0
  370. package/web-bundles/prd-coach/INSTRUCTIONS.md +86 -0
  371. package/web-bundles/prd-coach/SKILL.md +101 -0
  372. package/web-bundles/prd-coach/prd-template.md +165 -0
  373. package/web-bundles/prd-coach/prd-validation-checklist.md +135 -0
  374. package/web-bundles/prfaq-coach/INSTRUCTIONS.md +86 -0
  375. package/web-bundles/prfaq-coach/SKILL.md +139 -0
  376. package/web-bundles/product-brief-coach/INSTRUCTIONS.md +86 -0
  377. package/web-bundles/product-brief-coach/SKILL.md +113 -0
  378. package/web-bundles/ux-coach/INSTRUCTIONS.md +92 -0
  379. package/web-bundles/ux-coach/SKILL.md +187 -0
  380. package/web-bundles/ux-coach/ux-validation.md +100 -0
@@ -0,0 +1,257 @@
1
+ #!/usr/bin/env python3
2
+ # /// script
3
+ # requires-python = ">=3.10"
4
+ # ///
5
+ """lint-spine β€” the mechanical half of spine decision-integrity, done deterministically.
6
+
7
+ LLMs miscount IDs and miss literal placeholders; a grep does not. This linter owns the
8
+ checks a script does better than a prompt, and leaves the semantic half (is each Rule
9
+ actually enforceable? does the boundary make sense?) to the rubric walker.
10
+
11
+ It reads ARCHITECTURE-SPINE.md from a workspace and reports, as compact JSON on stdout:
12
+
13
+ - placeholder literal TBD / TODO / "similar to AD-n" / unfilled {template-token}
14
+ - ad_id duplicate or non-monotonic AD-n identifiers
15
+ - ad_fields an AD-n block missing Binds / Prevents / Rule
16
+ - version_pin a ## Stack table row with no version
17
+
18
+ Fenced code blocks are blanked (replaced with equal-count blank lines) before scanning, so
19
+ mermaid and source trees don't trip false positives AND reported line numbers still line up
20
+ with the real file. Reported lines are absolute file lines (frontmatter offset added). Exit
21
+ code is always 0 β€” findings travel in the JSON; the caller (Reviewer Gate / rubric walker)
22
+ decides what to do with them.
23
+ """
24
+ from __future__ import annotations
25
+
26
+ import argparse
27
+ import json
28
+ import re
29
+ import sys
30
+ from pathlib import Path
31
+
32
+ SPINE = "ARCHITECTURE-SPINE.md"
33
+
34
+ AD_HEADING = re.compile(r"^#{2,4}\s*AD-(\d+)\b(.*)$", re.MULTILINE)
35
+ HEADING = re.compile(r"^#{1,6}\s", re.MULTILINE)
36
+ FENCE = re.compile(r"```.*?```", re.DOTALL)
37
+ PLACEHOLDER_WORD = re.compile(r"\b(TBD|TODO|FIXME|XXX)\b")
38
+ SIMILAR_TO = re.compile(r"similar to AD-\d+", re.IGNORECASE)
39
+ TEMPLATE_TOKEN = re.compile(r"\{[a-z_][a-z0-9_ /.-]*\}")
40
+
41
+
42
+ def split_frontmatter(text: str) -> tuple[str, str, int]:
43
+ """Return (frontmatter, body, body_line_offset).
44
+
45
+ Frontmatter is the content between the first two lines that are *exactly* `---`
46
+ (line-exact, like memlog.split β€” a `---` inside a value or a body thematic break never
47
+ truncates it). body_line_offset is the number of file lines before the body begins, so a
48
+ body-relative line number plus the offset gives the absolute file line. Absent frontmatter
49
+ β†’ ('', text, 0)."""
50
+ lines = text.split("\n")
51
+ if lines and lines[0] == "---":
52
+ for i in range(1, len(lines)):
53
+ if lines[i] == "---":
54
+ fm = "\n".join(lines[1:i])
55
+ body = "\n".join(lines[i + 1:])
56
+ return fm, body, i + 1
57
+ return "", text, 0
58
+
59
+
60
+ def blank_fences(text: str) -> str:
61
+ """Replace each fenced block with the same number of newlines, so scanning skips fenced
62
+ content while every line number outside the fence stays put."""
63
+ return FENCE.sub(lambda m: "\n" * m.group(0).count("\n"), text)
64
+
65
+
66
+ def line_of(text: str, idx: int) -> int:
67
+ return text.count("\n", 0, idx) + 1
68
+
69
+
70
+ def find_placeholders(body: str, offset: int) -> list[dict]:
71
+ findings: list[dict] = []
72
+ scan = blank_fences(body)
73
+ # (regex, label, severity) β€” TBD/TODO and dangling cross-refs are unambiguous; a bare
74
+ # {template-token} can be legitimate brace prose, so it is flagged low ("possible") to keep
75
+ # the mechanical pass near-zero false-positive rather than train reviewers to ignore it.
76
+ for rx, label, severity in (
77
+ (PLACEHOLDER_WORD, "placeholder marker", "high"),
78
+ (SIMILAR_TO, "unresolved cross-reference", "high"),
79
+ (TEMPLATE_TOKEN, "possible unfilled template token (verify)", "low"),
80
+ ):
81
+ for m in rx.finditer(scan):
82
+ findings.append({
83
+ "category": "placeholder",
84
+ "severity": severity,
85
+ "detail": f"{label}: {m.group(0)!r}",
86
+ "location": f"{SPINE} (line {offset + line_of(scan, m.start())})",
87
+ })
88
+ return findings
89
+
90
+
91
+ def find_frontmatter_placeholders(frontmatter: str) -> list[dict]:
92
+ """Catch unfilled tokens left in frontmatter (e.g. paradigm/scope/date) β€” part of the
93
+ spine contract, but outside the body that find_placeholders scans."""
94
+ findings: list[dict] = []
95
+ for rx, label, severity in (
96
+ (PLACEHOLDER_WORD, "placeholder marker", "high"),
97
+ (TEMPLATE_TOKEN, "possible unfilled template token (verify)", "low"),
98
+ ):
99
+ for m in rx.finditer(frontmatter):
100
+ findings.append({
101
+ "category": "placeholder",
102
+ "severity": severity,
103
+ "detail": f"frontmatter {label}: {m.group(0)!r}",
104
+ "location": f"{SPINE} frontmatter (line {1 + line_of(frontmatter, m.start())})",
105
+ })
106
+ return findings
107
+
108
+
109
+ def find_ad_issues(body: str, offset: int) -> list[dict]:
110
+ findings: list[dict] = []
111
+ scan = blank_fences(body) # AD headings shown inside a code fence are not live ADs
112
+ matches = list(AD_HEADING.finditer(scan))
113
+ seen: dict[int, int] = {}
114
+ prev: int | None = None
115
+ for m in matches:
116
+ num = int(m.group(1))
117
+ file_line = offset + line_of(scan, m.start())
118
+ loc = f"{SPINE} AD-{num} (line {file_line})"
119
+ if num in seen:
120
+ findings.append({
121
+ "category": "ad_id",
122
+ "severity": "high",
123
+ "detail": f"AD-{num} id reused (also at line {seen[num]})",
124
+ "location": loc,
125
+ })
126
+ else:
127
+ seen[num] = file_line
128
+ if prev is not None and num <= prev:
129
+ findings.append({
130
+ "category": "ad_id",
131
+ "severity": "high",
132
+ "detail": f"AD-{num} is non-monotonic (follows AD-{prev}); ids must ascend and never renumber",
133
+ "location": loc,
134
+ })
135
+ prev = num if prev is None else max(prev, num)
136
+
137
+ # block text = from this heading to the next heading of any level
138
+ start = m.end()
139
+ nxt = HEADING.search(scan, start)
140
+ block = scan[start:nxt.start()] if nxt else scan[start:]
141
+ low = block.lower()
142
+ missing = [f for f in ("binds", "prevents", "rule") if f not in low]
143
+ if missing:
144
+ findings.append({
145
+ "category": "ad_fields",
146
+ "severity": "high",
147
+ "detail": f"AD-{num} missing required field(s): {', '.join(missing)}",
148
+ "location": loc,
149
+ })
150
+ return findings
151
+
152
+
153
+ def find_unpinned_stack(body: str, offset: int) -> list[dict]:
154
+ """Flag a `## Stack` table row that names something but leaves its version blank or a
155
+ placeholder. Pinning lives in the body table now, not frontmatter. A row whose name is
156
+ still a `{token}` skeleton is left to the placeholder pass, not double-reported here.
157
+
158
+ Fences are blanked first (like find_placeholders / find_ad_issues), so a pipe-row or
159
+ heading inside a code block is never read as live Stack content. The heading match is
160
+ `## Stack` with a word boundary, so a renamed heading (`## Stack & Versions`) still
161
+ counts. Name and Version columns are located from the header row, so a reordered table
162
+ pairs name to version correctly; both default to the canonical positions (0, 1)."""
163
+ findings: list[dict] = []
164
+ in_stack = False
165
+ header_seen = False
166
+ name_idx, ver_idx = 0, 1
167
+ scan = blank_fences(body)
168
+ for i, raw in enumerate(scan.splitlines()):
169
+ if HEADING.match(raw):
170
+ in_stack = re.match(r"^##\s+Stack\b", raw) is not None
171
+ header_seen = False
172
+ name_idx, ver_idx = 0, 1
173
+ continue
174
+ if not in_stack or not raw.lstrip().startswith("|"):
175
+ continue
176
+ if set(raw.strip()) <= set("|-: "):
177
+ continue # separator row
178
+ cells = _table_cells(raw)
179
+ if not header_seen:
180
+ header_seen = True
181
+ for j, c in enumerate(cells):
182
+ if c.lower() == "name":
183
+ name_idx = j
184
+ elif c.lower() == "version":
185
+ ver_idx = j
186
+ continue
187
+ name = cells[name_idx] if len(cells) > name_idx else ""
188
+ version = cells[ver_idx] if len(cells) > ver_idx else ""
189
+ if not name or TEMPLATE_TOKEN.search(name):
190
+ continue
191
+ if not version or TEMPLATE_TOKEN.search(version):
192
+ findings.append({
193
+ "category": "version_pin",
194
+ "severity": "medium",
195
+ "detail": f"Stack entry {name!r} has no version",
196
+ "location": f"{SPINE} (line {offset + i + 1})",
197
+ })
198
+ return findings
199
+
200
+
201
+ def _table_cells(row: str) -> list[str]:
202
+ """Split a markdown table row into trimmed cells, dropping the leading/trailing pipe."""
203
+ s = row.strip()
204
+ if s.startswith("|"):
205
+ s = s[1:]
206
+ if s.endswith("|"):
207
+ s = s[:-1]
208
+ return [c.strip() for c in s.split("|")]
209
+
210
+
211
+ def lint(text: str) -> dict:
212
+ frontmatter, body, offset = split_frontmatter(text)
213
+ findings: list[dict] = []
214
+ findings += find_frontmatter_placeholders(frontmatter)
215
+ findings += find_placeholders(body, offset)
216
+ findings += find_ad_issues(body, offset)
217
+ findings += find_unpinned_stack(body, offset)
218
+ counts: dict[str, int] = {}
219
+ for f in findings:
220
+ counts[f["severity"]] = counts.get(f["severity"], 0) + 1
221
+ return {
222
+ "ok": len(findings) == 0,
223
+ "spine": SPINE,
224
+ "total_findings": len(findings),
225
+ "by_severity": counts,
226
+ "findings": findings,
227
+ }
228
+
229
+
230
+ def main(argv: list[str] | None = None) -> int:
231
+ ap = argparse.ArgumentParser(description="Lint an architecture spine for mechanical integrity.")
232
+ ap.add_argument("--workspace", required=True, help="run folder containing ARCHITECTURE-SPINE.md")
233
+ ap.add_argument("-o", "--output", help="write JSON here instead of stdout")
234
+ args = ap.parse_args(argv)
235
+
236
+ spine_path = Path(args.workspace) / SPINE
237
+ if not spine_path.exists():
238
+ result = {"ok": False, "error": f"{spine_path} not found", "findings": [], "total_findings": 0}
239
+ else:
240
+ try:
241
+ text = spine_path.read_text(encoding="utf-8")
242
+ except (OSError, UnicodeDecodeError) as e:
243
+ # honor the "exit code is always 0" contract: a read/decode failure travels in JSON
244
+ result = {"ok": False, "error": f"could not read {spine_path}: {e}", "findings": [], "total_findings": 0}
245
+ else:
246
+ result = lint(text)
247
+
248
+ out = json.dumps(result, indent=2)
249
+ if args.output:
250
+ Path(args.output).write_text(out + "\n", encoding="utf-8")
251
+ else:
252
+ print(out)
253
+ return 0
254
+
255
+
256
+ if __name__ == "__main__":
257
+ sys.exit(main())
@@ -0,0 +1,270 @@
1
+ # /// script
2
+ # requires-python = ">=3.10"
3
+ # dependencies = ["pytest>=8.0"]
4
+ # ///
5
+ """Tests for lint_spine.py. Run: uv run --with pytest pytest scripts/tests/test_lint_spine.py
6
+
7
+ The spine under test: a clean spine lints empty; the linter catches exactly the
8
+ mechanical defects a prompt is unreliable at β€” literal placeholders, AD-n id breakage,
9
+ AD-n blocks missing required fields, and unpinned Stack versions.
10
+ """
11
+ import importlib.util
12
+ import json
13
+ import re
14
+ import sys
15
+ from pathlib import Path
16
+
17
+ import pytest
18
+
19
+ _SPEC = importlib.util.spec_from_file_location(
20
+ "lint_spine", Path(__file__).resolve().parent.parent / "lint_spine.py"
21
+ )
22
+ lint_spine = importlib.util.module_from_spec(_SPEC)
23
+ sys.modules["lint_spine"] = lint_spine
24
+ _SPEC.loader.exec_module(lint_spine)
25
+
26
+
27
+ CLEAN = """---
28
+ name: 'Demo'
29
+ ---
30
+
31
+ ## Invariants & Rules
32
+
33
+ ### AD-1 β€” single write path
34
+
35
+ - **Binds:** all
36
+ - **Prevents:** divergent mutation
37
+ - **Rule:** state changes only through the command bus
38
+
39
+ ### AD-2 β€” layered deps `[ADOPTED]`
40
+
41
+ - **Binds:** all
42
+ - **Prevents:** import cycles
43
+ - **Rule:** ui -> app -> domain, never backward
44
+
45
+ ```mermaid
46
+ flowchart LR
47
+ A --> B{decision}
48
+ ```
49
+
50
+ ## Stack
51
+
52
+ | Name | Version |
53
+ | --- | --- |
54
+ | fastapi | 0.115 |
55
+ | pydantic | 2.9 |
56
+ """
57
+
58
+
59
+ def cats(result):
60
+ return sorted(f["category"] for f in result["findings"])
61
+
62
+
63
+ def test_clean_spine_passes():
64
+ result = lint_spine.lint(CLEAN)
65
+ assert result["ok"] is True
66
+ assert result["total_findings"] == 0
67
+
68
+
69
+ def test_mermaid_braces_not_flagged():
70
+ # the {decision} node lives in a fenced block and must not read as a template token
71
+ result = lint_spine.lint(CLEAN)
72
+ assert "placeholder" not in cats(result)
73
+
74
+
75
+ def test_placeholder_markers_caught():
76
+ text = CLEAN.replace("the command bus", "TBD")
77
+ result = lint_spine.lint(text)
78
+ assert "placeholder" in cats(result)
79
+
80
+
81
+ def test_similar_to_caught():
82
+ text = CLEAN.replace("import cycles", "similar to AD-1")
83
+ result = lint_spine.lint(text)
84
+ assert any("cross-reference" in f["detail"] for f in result["findings"])
85
+
86
+
87
+ def test_unfilled_template_token_caught():
88
+ text = CLEAN.replace("single write path", "{decision}")
89
+ result = lint_spine.lint(text)
90
+ assert any(f["category"] == "placeholder" for f in result["findings"])
91
+
92
+
93
+ def test_duplicate_ad_id_caught():
94
+ text = CLEAN.replace("### AD-2 β€” layered deps `[ADOPTED]`", "### AD-1 β€” layered deps")
95
+ result = lint_spine.lint(text)
96
+ assert "ad_id" in cats(result)
97
+
98
+
99
+ def test_non_monotonic_ad_id_caught():
100
+ text = CLEAN.replace("### AD-2 β€” layered deps `[ADOPTED]`", "### AD-5 β€” layered deps").replace(
101
+ "### AD-1 β€” single write path", "### AD-9 β€” single write path"
102
+ )
103
+ result = lint_spine.lint(text)
104
+ assert any("non-monotonic" in f["detail"] for f in result["findings"])
105
+
106
+
107
+ def test_missing_field_caught():
108
+ text = CLEAN.replace("- **Rule:** state changes only through the command bus\n", "")
109
+ result = lint_spine.lint(text)
110
+ assert any(f["category"] == "ad_fields" and "rule" in f["detail"] for f in result["findings"])
111
+
112
+
113
+ def test_unpinned_dep_caught():
114
+ text = CLEAN.replace("| fastapi | 0.115 |", "| fastapi | |")
115
+ result = lint_spine.lint(text)
116
+ assert "version_pin" in cats(result)
117
+
118
+
119
+ def test_placeholder_version_caught():
120
+ text = CLEAN.replace("| fastapi | 0.115 |", "| fastapi | {pin} |")
121
+ result = lint_spine.lint(text)
122
+ assert any(f["category"] == "version_pin" and "fastapi" in f["detail"] for f in result["findings"])
123
+
124
+
125
+ def test_no_stack_section_ok():
126
+ text = CLEAN.split("## Stack")[0]
127
+ result = lint_spine.lint(text)
128
+ assert "version_pin" not in cats(result)
129
+
130
+
131
+ def test_stack_skeleton_row_not_version_pinned():
132
+ # a leftover {token} name is the placeholder pass's job, not a double-reported version_pin
133
+ text = CLEAN.replace("| fastapi | 0.115 |", "| {language / framework} | {pinned version} |")
134
+ result = lint_spine.lint(text)
135
+ assert "version_pin" not in cats(result)
136
+
137
+
138
+ def test_stack_html_comment_not_parsed_as_row():
139
+ text = CLEAN.replace("## Stack\n", "## Stack\n\n<!-- SEED β€” verified current 2026-06 -->\n")
140
+ result = lint_spine.lint(text)
141
+ assert "version_pin" not in cats(result)
142
+
143
+
144
+ def test_template_token_is_low_severity():
145
+ # a bare {token} can be legitimate brace prose; it is flagged, but low (not high) so the
146
+ # mechanical pass stays near-zero false-positive
147
+ text = CLEAN.replace("single write path", "{decision}")
148
+ result = lint_spine.lint(text)
149
+ toks = [f for f in result["findings"] if f["category"] == "placeholder" and "template token" in f["detail"]]
150
+ assert toks and all(f["severity"] == "low" for f in toks)
151
+
152
+
153
+ def test_no_frontmatter_body_still_scanned():
154
+ text = "## Invariants\n\n### AD-1 β€” x\n\n- **Binds:** all\n- **Prevents:** drift\n- **Rule:** TBD\n"
155
+ result = lint_spine.lint(text)
156
+ assert "placeholder" in cats(result) # TBD caught even with no frontmatter
157
+
158
+
159
+ def test_frontmatter_value_with_dashes_not_truncated():
160
+ # a value containing '---' must not be read as the closing fence (line-exact close)
161
+ text = ("---\nname: 'x'\nscope: 'phase 1 --- phase 2'\n---\n\n"
162
+ "## Stack\n\n| Name | Version |\n| --- | --- |\n| fastapi | |\n")
163
+ result = lint_spine.lint(text)
164
+ assert any(f["category"] == "version_pin" for f in result["findings"]) # read past the inline ---
165
+
166
+
167
+ def test_ad_heading_in_fence_not_counted():
168
+ text = (
169
+ "---\nname: 'x'\n---\n\n"
170
+ "### AD-1 β€” real\n\n- **Binds:** all\n- **Prevents:** drift\n- **Rule:** do x\n\n"
171
+ "## Docs\n\n```text\n### AD-2 β€” illustrative only, no fields\n```\n"
172
+ )
173
+ result = lint_spine.lint(text)
174
+ assert result["ok"] is True # the fenced AD-2 is not a live AD β†’ no ad_fields/ad_id finding
175
+
176
+
177
+ def test_stack_table_flags_only_the_unpinned_row():
178
+ text = ("---\nname: 'x'\n---\n\n## Stack\n\n| Name | Version |\n| --- | --- |\n"
179
+ "| fastapi | 0.115 |\n| redis | |\n")
180
+ result = lint_spine.lint(text)
181
+ pins = [f for f in result["findings"] if f["category"] == "version_pin"]
182
+ assert len(pins) == 1 and "redis" in pins[0]["detail"]
183
+
184
+
185
+ def test_stack_table_all_pinned_ok():
186
+ text = ("---\nname: 'x'\n---\n\n## Stack\n\n| Name | Version |\n| --- | --- |\n"
187
+ "| fastapi | 0.115 |\n")
188
+ result = lint_spine.lint(text)
189
+ assert "version_pin" not in cats(result)
190
+
191
+
192
+ def test_fenced_stack_rows_not_parsed():
193
+ # an illustrative fenced table under ## Stack must not be read as live rows (fences are
194
+ # blanked first, like every other pass) β€” a blank-version row inside a fence is not a finding
195
+ text = ("---\nname: 'x'\n---\n\n## Stack\n\n| Name | Version |\n| --- | --- |\n"
196
+ "| fastapi | 0.115 |\n\n```text\n| example | |\n```\n")
197
+ result = lint_spine.lint(text)
198
+ assert "version_pin" not in cats(result)
199
+
200
+
201
+ def test_fenced_stack_heading_not_live():
202
+ # a `## Stack` heading shown inside a code fence is not the live Stack section
203
+ text = ("---\nname: 'x'\n---\n\n## Docs\n\n```md\n## Stack\n\n| foo | |\n```\n")
204
+ result = lint_spine.lint(text)
205
+ assert "version_pin" not in cats(result)
206
+
207
+
208
+ def test_renamed_stack_heading_still_scanned():
209
+ # the heading match is word-boundary, so a varied `## Stack` heading still counts
210
+ text = ("---\nname: 'x'\n---\n\n## Stack & Versions\n\n| Name | Version |\n| --- | --- |\n"
211
+ "| redis | |\n")
212
+ result = lint_spine.lint(text)
213
+ pins = [f for f in result["findings"] if f["category"] == "version_pin"]
214
+ assert len(pins) == 1 and "redis" in pins[0]["detail"]
215
+
216
+
217
+ def test_reordered_columns_pair_name_to_version():
218
+ # Version-then-Name header: the unpinned row must still be flagged by its real name
219
+ text = ("---\nname: 'x'\n---\n\n## Stack\n\n| Version | Name |\n| --- | --- |\n"
220
+ "| 0.115 | fastapi |\n| | redis |\n")
221
+ result = lint_spine.lint(text)
222
+ pins = [f for f in result["findings"] if f["category"] == "version_pin"]
223
+ assert len(pins) == 1 and "redis" in pins[0]["detail"]
224
+
225
+
226
+ def test_placeholder_line_number_is_absolute():
227
+ # a TBD after a multi-line fence reports its real file line (fence blanked, not collapsed)
228
+ text = (
229
+ "---\nname: 'x'\n---\n\n"
230
+ "## A\n\n"
231
+ "```text\nf1\nf2\nf3\n```\n\n"
232
+ "TBD here\n"
233
+ )
234
+ result = lint_spine.lint(text)
235
+ ph = next(f for f in result["findings"] if "TBD" in f["detail"])
236
+ n = int(re.search(r"line (\d+)", ph["location"]).group(1))
237
+ assert n == 13
238
+
239
+
240
+ def test_missing_spine_file_reports_error(tmp_path, capsys):
241
+ rc = lint_spine.main(["--workspace", str(tmp_path)])
242
+ out = json.loads(capsys.readouterr().out)
243
+ assert rc == 0 and out["ok"] is False and "not found" in out["error"]
244
+
245
+
246
+ def test_frontmatter_unfilled_token_caught():
247
+ # an unfilled {scope}/{paradigm}/{date} in frontmatter is part of the contract and must lint
248
+ text = "---\nname: 'x'\nscope: '{what this spine governs}'\n---\n\n## Invariants\n"
249
+ result = lint_spine.lint(text)
250
+ fm = [f for f in result["findings"] if f["category"] == "placeholder" and "frontmatter" in f["detail"]]
251
+ assert fm and any("template token" in f["detail"] for f in fm)
252
+
253
+
254
+ def test_frontmatter_tbd_caught():
255
+ text = "---\nname: 'x'\nstatus: TBD\n---\n\n## Invariants\n"
256
+ result = lint_spine.lint(text)
257
+ assert any(f["category"] == "placeholder" and "frontmatter" in f["detail"] and "TBD" in f["detail"]
258
+ for f in result["findings"])
259
+
260
+
261
+ def test_unreadable_spine_returns_error_not_crash(tmp_path, capsys):
262
+ # a spine that exists but can't be UTF-8 decoded must yield error JSON + exit 0, not a traceback
263
+ (tmp_path / lint_spine.SPINE).write_bytes(b"\xff\xfe bad bytes not utf-8")
264
+ rc = lint_spine.main(["--workspace", str(tmp_path)])
265
+ out = json.loads(capsys.readouterr().out)
266
+ assert rc == 0 and out["ok"] is False and "could not read" in out["error"]
267
+
268
+
269
+ if __name__ == "__main__":
270
+ sys.exit(pytest.main([__file__, "-q"]))
@@ -0,0 +1,93 @@
1
+ ---
2
+ name: bmad-create-epics-and-stories
3
+ description: 'Break requirements into epics and user stories. Use when the user says "create the epics and stories list"'
4
+ ---
5
+
6
+ # Create Epics and Stories
7
+
8
+ **Goal:** Transform PRD requirements and Architecture decisions into comprehensive stories organized by user value, creating detailed, actionable stories with complete acceptance criteria for the Developer agent.
9
+
10
+ **Your Role:** In addition to your name, communication_style, and persona, you are also a product strategist and technical specifications writer collaborating with a product owner. This is a partnership, not a client-vendor relationship. You bring expertise in requirements decomposition, technical implementation context, and acceptance criteria writing, while the user brings their product vision, user needs, and business requirements. Work together as equals.
11
+
12
+ ## Conventions
13
+
14
+ - Bare paths (e.g. `steps/step-01-validate-prerequisites.md`) resolve from the skill root.
15
+ - `{skill-root}` resolves to this skill's installed directory (where `customize.toml` lives).
16
+ - `{project-root}`-prefixed paths resolve from the project working directory.
17
+ - `{skill-name}` resolves to the skill directory's basename.
18
+
19
+ ## WORKFLOW ARCHITECTURE
20
+
21
+ This uses **step-file architecture** for disciplined execution:
22
+
23
+ ### Core Principles
24
+
25
+ - **Micro-file Design**: Each step toward the overall goal is a self-contained instruction file; adhere to one file at a time, as directed
26
+ - **Just-In-Time Loading**: Only 1 current step file will be loaded and followed to completion - never load future step files until told to do so
27
+ - **Sequential Enforcement**: Sequence within the step files must be completed in order, no skipping or optimization allowed
28
+ - **State Tracking**: Document progress in output file frontmatter using `stepsCompleted` array when a workflow produces a document
29
+ - **Append-Only Building**: Build documents by appending content as directed to the output file
30
+
31
+ ### Step Processing Rules
32
+
33
+ 1. **READ COMPLETELY**: Always read the entire step file before taking any action
34
+ 2. **FOLLOW SEQUENCE**: Execute all numbered sections in order, never deviate
35
+ 3. **WAIT FOR INPUT**: If a menu is presented, halt and wait for user selection
36
+ 4. **CHECK CONTINUATION**: If the step has a menu with Continue as an option, only proceed to next step when user selects 'C' (Continue)
37
+ 5. **SAVE STATE**: Update `stepsCompleted` in frontmatter before loading next step
38
+ 6. **LOAD NEXT**: When directed, read fully and follow the next step file
39
+
40
+ ### Critical Rules (NO EXCEPTIONS)
41
+
42
+ - πŸ›‘ **NEVER** load multiple step files simultaneously
43
+ - πŸ“– **ALWAYS** read entire step file before execution
44
+ - 🚫 **NEVER** skip steps or optimize the sequence
45
+ - πŸ’Ύ **ALWAYS** update frontmatter of output files when writing the final output for a specific step
46
+ - 🎯 **ALWAYS** follow the exact instructions in the step file
47
+ - ⏸️ **ALWAYS** halt at menus and wait for user input
48
+ - πŸ“‹ **NEVER** create mental todo lists from future steps
49
+
50
+ ## On Activation
51
+
52
+ ### Step 1: Resolve the Workflow Block
53
+
54
+ Run: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key workflow`
55
+
56
+ **If the script fails**, resolve the `workflow` block yourself by reading these three files in base β†’ team β†’ user order and applying the same structural merge rules as the resolver:
57
+
58
+ 1. `{skill-root}/customize.toml` β€” defaults
59
+ 2. `{project-root}/_bmad/custom/{skill-name}.toml` β€” team overrides
60
+ 3. `{project-root}/_bmad/custom/{skill-name}.user.toml` β€” personal overrides
61
+
62
+ Any missing file is skipped. Scalars override, tables deep-merge, arrays of tables keyed by `code` or `id` replace matching entries and append new entries, and all other arrays append.
63
+
64
+ ### Step 2: Execute Prepend Steps
65
+
66
+ Execute each entry in `{workflow.activation_steps_prepend}` in order before proceeding.
67
+
68
+ ### Step 3: Load Persistent Facts
69
+
70
+ Treat every entry in `{workflow.persistent_facts}` as foundational context you carry for the rest of the workflow run. Entries prefixed `file:` are paths or globs under `{project-root}` β€” load the referenced contents as facts. All other entries are facts verbatim.
71
+
72
+ ### Step 4: Load Config
73
+
74
+ Load config from `{project-root}/_bmad/bmm/config.yaml` and resolve:
75
+ - Use `{user_name}` for greeting
76
+ - Use `{communication_language}` for all communications
77
+ - Use `{document_output_language}` for output documents
78
+ - Use `{planning_artifacts}` for output location and artifact scanning
79
+ - Use `{project_knowledge}` for additional context scanning
80
+
81
+ ### Step 5: Greet the User
82
+
83
+ Greet `{user_name}`, speaking in `{communication_language}`.
84
+
85
+ ### Step 6: Execute Append Steps
86
+
87
+ Execute each entry in `{workflow.activation_steps_append}` in order.
88
+
89
+ Activation is complete. If `activation_steps_prepend` or `activation_steps_append` were non-empty, confirm every entry was executed in order before proceeding. Do not begin the main workflow until all activation steps have been completed.
90
+
91
+ ## Execution
92
+
93
+ Read fully and follow: `./steps/step-01-validate-prerequisites.md` to begin the workflow.
@@ -0,0 +1,41 @@
1
+ # DO NOT EDIT -- overwritten on every update.
2
+ #
3
+ # Workflow customization surface for bmad-create-epics-and-stories. Mirrors the
4
+ # agent customization shape under the [workflow] namespace.
5
+
6
+ [workflow]
7
+
8
+ # --- Configurable below. Overrides merge per BMad structural rules: ---
9
+ # scalars: override wins β€’ arrays (persistent_facts, activation_steps_*): append
10
+ # arrays-of-tables with `code`/`id`: replace matching items, append new ones.
11
+
12
+ # Steps to run before the standard activation (config load, greet).
13
+ # Overrides append. Use for pre-flight loads, compliance checks, etc.
14
+
15
+ activation_steps_prepend = []
16
+
17
+ # Steps to run after greet but before the workflow begins.
18
+ # Overrides append. Use for context-heavy setup that should happen
19
+ # once the user has been acknowledged.
20
+
21
+ activation_steps_append = []
22
+
23
+ # Persistent facts the workflow keeps in mind for the whole run
24
+ # (standards, compliance constraints, stylistic guardrails).
25
+ # Distinct from the runtime memory sidecar β€” these are static context
26
+ # loaded on activation. Overrides append.
27
+ #
28
+ # Each entry is either:
29
+ # - a literal sentence, e.g. "All epics must deliver complete end-to-end user value."
30
+ # - a file reference prefixed with `file:`, e.g. "file:{project-root}/docs/standards.md"
31
+ # (glob patterns are supported; the file's contents are loaded and treated as facts).
32
+
33
+ persistent_facts = [
34
+ "file:{project-root}/**/project-context.md",
35
+ ]
36
+
37
+ # Scalar: executed when the workflow reaches Step 4 (Final Validation) and the
38
+ # user confirms [C] Complete β€” after the epics.md is saved and bmad-help is invoked.
39
+ # Override wins. Leave empty for no custom post-completion behavior.
40
+
41
+ on_complete = ""