bmad-module-skill-forge 2.2.0 → 4.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 (437) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/README.md +49 -49
  3. package/docs/404.md +10 -8
  4. package/docs/_data/pinned.yaml +22 -13
  5. package/docs/_internal/STABILITY.md +58 -35
  6. package/docs/agents.md +39 -53
  7. package/docs/architecture.md +65 -51
  8. package/docs/bmad-synergy.md +53 -51
  9. package/docs/campaign.md +127 -75
  10. package/docs/concepts.md +34 -28
  11. package/docs/examples.md +70 -68
  12. package/docs/forge-auto.md +34 -31
  13. package/docs/getting-started.md +118 -57
  14. package/docs/how-it-works.md +25 -21
  15. package/docs/index.md +15 -15
  16. package/docs/skill-model.md +70 -59
  17. package/docs/troubleshooting.md +143 -18
  18. package/docs/verifying-a-skill.md +87 -57
  19. package/docs/why-skf.md +24 -22
  20. package/docs/workflows.md +274 -110
  21. package/package.json +18 -10
  22. package/src/forger/preferences.yaml +8 -1
  23. package/src/knowledge/agentskills-spec.md +2 -0
  24. package/src/knowledge/ccc-bridge.md +40 -24
  25. package/src/knowledge/confidence-tiers.md +9 -5
  26. package/src/knowledge/overview.md +3 -3
  27. package/src/knowledge/progressive-capability.md +8 -8
  28. package/src/knowledge/provenance-tracking.md +9 -5
  29. package/src/knowledge/qmd-registry.md +3 -3
  30. package/src/knowledge/skf-knowledge-index.csv +2 -2
  31. package/src/knowledge/skill-lifecycle.md +18 -11
  32. package/src/knowledge/split-body-strategy.md +0 -3
  33. package/src/knowledge/tool-resolution.md +4 -2
  34. package/src/knowledge/version-paths.md +101 -15
  35. package/src/module-help.csv +3 -3
  36. package/src/module.yaml +10 -0
  37. package/src/shared/data/ast-grep-recipes.yaml +608 -0
  38. package/src/shared/data/ide-context-files.json +30 -0
  39. package/src/shared/health-check.md +31 -59
  40. package/src/shared/references/description-guard-protocol.md +12 -9
  41. package/src/shared/references/feasibility-report-schema.md +19 -13
  42. package/src/shared/references/headless-gate-convention.md +55 -3
  43. package/src/shared/references/output-contract-schema.md +19 -8
  44. package/src/shared/references/pipeline-contracts.md +94 -29
  45. package/src/shared/references/tessl-review.md +77 -0
  46. package/src/shared/scripts/schemas/skf-analyze-result-envelope.v1.json +194 -0
  47. package/src/shared/scripts/schemas/skf-audit-result-envelope.v1.json +192 -0
  48. package/src/shared/scripts/schemas/skf-brief-result-envelope.v1.json +32 -4
  49. package/src/shared/scripts/schemas/skf-campaign-result-envelope.v1.json +174 -0
  50. package/src/shared/scripts/schemas/skf-create-skill-result-envelope.v1.json +284 -0
  51. package/src/shared/scripts/schemas/skf-drop-skill-result-envelope.v1.json +164 -0
  52. package/src/shared/scripts/schemas/skf-export-result-envelope.v1.json +160 -0
  53. package/src/shared/scripts/schemas/skf-quick-skill-result-envelope.v1.json +261 -0
  54. package/src/shared/scripts/schemas/skf-refine-architecture-result-envelope.v1.json +192 -0
  55. package/src/shared/scripts/schemas/skf-rename-skill-result-envelope.v1.json +179 -0
  56. package/src/shared/scripts/schemas/skf-setup-result-envelope.v1.json +27 -11
  57. package/src/shared/scripts/schemas/skf-stack-result-envelope.v1.json +176 -0
  58. package/src/shared/scripts/schemas/skf-test-result-envelope.v1.json +173 -0
  59. package/src/shared/scripts/schemas/skf-update-result-envelope.v1.json +19 -5
  60. package/src/shared/scripts/schemas/skf-verify-stack-result-envelope.v1.json +180 -0
  61. package/src/shared/scripts/schemas/skill-brief.v1.json +34 -0
  62. package/src/shared/scripts/schemas/workspace-detection.v1.json +1 -1
  63. package/src/shared/scripts/skf-atomic-write.py +233 -64
  64. package/src/shared/scripts/skf-build-change-manifest.py +2753 -28
  65. package/src/shared/scripts/skf-ccc-git-hygiene.py +532 -0
  66. package/src/shared/scripts/skf-check-unit-records.py +184 -0
  67. package/src/shared/scripts/skf-check-workspace-drift.py +538 -9
  68. package/src/shared/scripts/skf-classify-changed-files.py +772 -0
  69. package/src/shared/scripts/skf-comention-pairs.py +1333 -123
  70. package/src/shared/scripts/skf-compare-file-hashes.py +267 -105
  71. package/src/shared/scripts/skf-count-imports.py +1867 -0
  72. package/src/shared/scripts/skf-count-tokens.py +1 -1
  73. package/src/shared/scripts/skf-derive-assembly-shape.py +21 -3
  74. package/src/shared/scripts/skf-description-guard.py +99 -11
  75. package/src/shared/scripts/skf-detect-docs.py +694 -2
  76. package/src/shared/scripts/skf-detect-language.py +486 -107
  77. package/src/shared/scripts/skf-detect-registry.py +887 -0
  78. package/src/shared/scripts/skf-detect-scripts-assets.py +197 -55
  79. package/src/shared/scripts/skf-detect-tools.py +209 -27
  80. package/src/shared/scripts/skf-detect-workspaces.py +506 -30
  81. package/src/shared/scripts/skf-disqualify-candidates.py +821 -182
  82. package/src/shared/scripts/skf-emit-brief-result-envelope.py +69 -191
  83. package/src/shared/scripts/skf-emit-result-envelope.py +1604 -106
  84. package/src/shared/scripts/skf-enumerate-stack-skills.py +986 -117
  85. package/src/shared/scripts/skf-extract-public-api.py +5247 -96
  86. package/src/shared/scripts/skf-extraction-inventory.py +1280 -0
  87. package/src/shared/scripts/skf-extraction-snapshot.py +664 -0
  88. package/src/shared/scripts/skf-fetch-temporal.py +674 -0
  89. package/src/shared/scripts/skf-find-cycles.py +97 -29
  90. package/src/shared/scripts/skf-find-test-report.py +476 -0
  91. package/src/shared/scripts/skf-forge-tier-rw.py +469 -205
  92. package/src/shared/scripts/skf-github-fetch.py +365 -0
  93. package/src/shared/scripts/skf-github-probe.py +700 -0
  94. package/src/shared/scripts/skf-hash-content.py +180 -20
  95. package/src/shared/scripts/skf-language-corpora.py +1 -1
  96. package/src/shared/scripts/skf-load-provenance.py +161 -27
  97. package/src/shared/scripts/skf-manifest-ops.py +1 -1
  98. package/src/shared/scripts/skf-merge-ccc-exclusions.py +2307 -223
  99. package/src/shared/scripts/skf-merge-doc-urls.py +143 -20
  100. package/src/shared/scripts/skf-names-present.py +221 -0
  101. package/src/shared/scripts/skf-pair-intersect.py +119 -28
  102. package/src/shared/scripts/skf-parse-gaps.py +1384 -0
  103. package/src/shared/scripts/skf-preapply.py +1 -1
  104. package/src/shared/scripts/skf-preflight.py +176 -28
  105. package/src/shared/scripts/skf-promote-staged.py +430 -0
  106. package/src/shared/scripts/skf-provenance-gap-dispatch.py +64 -8
  107. package/src/shared/scripts/skf-qmd-classify-collections.py +229 -45
  108. package/src/shared/scripts/skf-quick-batch.py +774 -0
  109. package/src/shared/scripts/skf-rebuild-managed-sections.py +972 -88
  110. package/src/shared/scripts/skf-recommend-scope-type.py +323 -156
  111. package/src/shared/scripts/skf-render-metadata-stats.py +156 -12
  112. package/src/shared/scripts/skf-render-quick-metadata.py +132 -28
  113. package/src/shared/scripts/skf-render-stack-metadata.py +976 -0
  114. package/src/shared/scripts/skf-resolve-authoritative-files.py +155 -14
  115. package/src/shared/scripts/skf-resolve-package.py +523 -106
  116. package/src/shared/scripts/skf-rewrite-skill-name.py +433 -47
  117. package/src/shared/scripts/skf-run-lock.py +577 -0
  118. package/src/shared/scripts/skf-scan-manifests.py +998 -57
  119. package/src/shared/scripts/skf-scan-skill-md-structure.py +1341 -37
  120. package/src/shared/scripts/skf-severity-classify.py +712 -108
  121. package/src/shared/scripts/skf-shape-detect.py +298 -204
  122. package/src/shared/scripts/skf-shard-body.py +9 -8
  123. package/src/shared/scripts/skf-skill-inventory.py +2412 -89
  124. package/src/shared/scripts/skf-skills-module.py +472 -0
  125. package/src/shared/scripts/skf-source-tree.py +1796 -0
  126. package/src/shared/scripts/skf-structural-diff.py +787 -121
  127. package/src/shared/scripts/skf-tessl-review.py +706 -0
  128. package/src/shared/scripts/skf-update-active-symlink.py +120 -67
  129. package/src/shared/scripts/skf-update-run-state.py +624 -0
  130. package/src/shared/scripts/skf-validate-brief-inputs.py +92 -29
  131. package/src/shared/scripts/skf-validate-brief-schema.py +23 -2
  132. package/src/shared/scripts/skf-validate-feasibility-report.py +577 -66
  133. package/src/shared/scripts/skf-validate-frontmatter.py +103 -26
  134. package/src/shared/scripts/skf-validate-output.py +712 -64
  135. package/src/shared/scripts/skf-validate-pins.py +1 -1
  136. package/src/shared/scripts/skf-verify-no-trace.py +116 -10
  137. package/src/shared/scripts/skf-verify-provenance-completeness.py +3945 -152
  138. package/src/shared/scripts/skf-write-skill-brief.py +406 -25
  139. package/src/shared/tool-requirements.yaml +201 -0
  140. package/src/skf-analyze-source/SKILL.md +41 -36
  141. package/src/skf-analyze-source/assets/skill-brief-schema.md +7 -8
  142. package/src/skf-analyze-source/customize.toml +36 -24
  143. package/src/skf-analyze-source/references/auto-docs-only.md +58 -20
  144. package/src/skf-analyze-source/references/continue.md +2 -13
  145. package/src/skf-analyze-source/references/discover-additional-source.md +147 -0
  146. package/src/skf-analyze-source/references/generate-briefs.md +121 -55
  147. package/src/skf-analyze-source/references/headless-contract.md +42 -15
  148. package/src/skf-analyze-source/references/identify-units.md +96 -110
  149. package/src/skf-analyze-source/references/init.md +73 -71
  150. package/src/skf-analyze-source/references/map-and-detect.md +123 -105
  151. package/src/skf-analyze-source/references/map-unit-exports.md +68 -0
  152. package/src/skf-analyze-source/references/recommend.md +51 -70
  153. package/src/skf-analyze-source/references/scan-project.md +60 -84
  154. package/src/skf-analyze-source/references/scan-root.md +39 -0
  155. package/src/skf-analyze-source/references/step-auto-scope-coexistence.md +47 -0
  156. package/src/skf-analyze-source/references/step-auto-scope-corpora.md +53 -0
  157. package/src/skf-analyze-source/references/step-auto-scope-split.md +91 -0
  158. package/src/skf-analyze-source/references/step-auto-scope.md +208 -293
  159. package/src/skf-analyze-source/references/step-shape-detect.md +14 -12
  160. package/src/skf-analyze-source/references/unit-detection-heuristics.md +37 -42
  161. package/src/skf-audit-skill/SKILL.md +43 -51
  162. package/src/skf-audit-skill/assets/drift-report-template.md +28 -3
  163. package/src/skf-audit-skill/customize.toml +41 -20
  164. package/src/skf-audit-skill/references/constituent-freshness.md +91 -0
  165. package/src/skf-audit-skill/references/doc-drift.md +141 -0
  166. package/src/skf-audit-skill/references/headless-contract.md +29 -0
  167. package/src/skf-audit-skill/references/health-check.md +2 -0
  168. package/src/skf-audit-skill/references/init.md +149 -210
  169. package/src/skf-audit-skill/references/re-index.md +103 -110
  170. package/src/skf-audit-skill/references/report.md +96 -33
  171. package/src/skf-audit-skill/references/semantic-diff.md +34 -25
  172. package/src/skf-audit-skill/references/severity-classify.md +79 -65
  173. package/src/skf-audit-skill/references/severity-rules.md +15 -6
  174. package/src/skf-audit-skill/references/structural-diff.md +80 -90
  175. package/src/skf-audit-skill/references/upstream-checkout.md +77 -0
  176. package/src/skf-audit-skill/scripts/render-drift-tables.py +712 -0
  177. package/src/skf-brief-skill/SKILL.md +37 -26
  178. package/src/skf-brief-skill/assets/description-voice-examples.md +1 -1
  179. package/src/skf-brief-skill/assets/scope-templates.md +18 -25
  180. package/src/skf-brief-skill/assets/skill-brief-schema.md +30 -23
  181. package/src/skf-brief-skill/customize.toml +48 -20
  182. package/src/skf-brief-skill/references/analyze-target.md +144 -127
  183. package/src/skf-brief-skill/references/confirm-brief.md +11 -9
  184. package/src/skf-brief-skill/references/draft-checkpoint.md +36 -17
  185. package/src/skf-brief-skill/references/gather-intent-ratify.md +68 -0
  186. package/src/skf-brief-skill/references/gather-intent.md +87 -182
  187. package/src/skf-brief-skill/references/headless-args.md +84 -16
  188. package/src/skf-brief-skill/references/health-check.md +1 -1
  189. package/src/skf-brief-skill/references/invocation-contract.md +18 -13
  190. package/src/skf-brief-skill/references/portfolio-similarity-check.md +1 -1
  191. package/src/skf-brief-skill/references/qmd-collection-registration.md +7 -10
  192. package/src/skf-brief-skill/references/scope-definition.md +123 -47
  193. package/src/skf-brief-skill/references/step-auto-brief.md +26 -100
  194. package/src/skf-brief-skill/references/step-auto-validate.md +20 -121
  195. package/src/skf-brief-skill/references/version-resolution.md +7 -10
  196. package/src/skf-brief-skill/references/write-brief.md +66 -57
  197. package/src/skf-campaign/SKILL.md +31 -34
  198. package/src/skf-campaign/assets/campaign-state-schema.json +25 -4
  199. package/src/skf-campaign/customize.toml +47 -16
  200. package/src/skf-campaign/references/campaign-contracts.md +39 -29
  201. package/src/skf-campaign/references/campaign-directive-spec.md +4 -2
  202. package/src/skf-campaign/references/health-check.md +7 -16
  203. package/src/skf-campaign/references/step-01-setup.md +46 -84
  204. package/src/skf-campaign/references/step-02-strategy.md +31 -30
  205. package/src/skf-campaign/references/step-03-pins.md +26 -18
  206. package/src/skf-campaign/references/step-04-provenance.md +24 -23
  207. package/src/skf-campaign/references/step-05-skill-loop.md +67 -48
  208. package/src/skf-campaign/references/step-06-batch.md +41 -34
  209. package/src/skf-campaign/references/step-07-capstone.md +40 -25
  210. package/src/skf-campaign/references/step-08-verify.md +28 -29
  211. package/src/skf-campaign/references/step-09-refine.md +29 -30
  212. package/src/skf-campaign/references/step-10-export.md +48 -36
  213. package/src/skf-campaign/references/step-11-maintenance.md +31 -34
  214. package/src/skf-campaign/references/step-resume.md +37 -68
  215. package/src/skf-campaign/scripts/campaign-deps.py +57 -18
  216. package/src/skf-campaign/scripts/campaign-parse-manifest.py +361 -54
  217. package/src/skf-campaign/scripts/campaign-provenance.py +96 -53
  218. package/src/skf-campaign/scripts/campaign-quality-gate.py +592 -0
  219. package/src/skf-campaign/scripts/campaign-render-batch.py +257 -49
  220. package/src/skf-campaign/scripts/campaign-render-kickoff.py +343 -50
  221. package/src/skf-campaign/scripts/campaign-report.py +204 -37
  222. package/src/skf-campaign/scripts/campaign-state.py +1128 -0
  223. package/src/skf-campaign/scripts/campaign-status.py +10 -74
  224. package/src/skf-campaign/scripts/campaign-validate-pins.py +30 -3
  225. package/src/skf-campaign/scripts/campaign-validate-state.py +34 -4
  226. package/src/skf-campaign/templates/campaign-brief-template.yaml +4 -5
  227. package/src/skf-campaign/templates/campaign-report-template.md +5 -1
  228. package/src/skf-campaign/templates/kickoff-template.md +0 -14
  229. package/src/skf-create-skill/SKILL.md +27 -20
  230. package/src/skf-create-skill/assets/compile-assembly-rules.md +11 -8
  231. package/src/skf-create-skill/assets/skill-sections.md +21 -11
  232. package/src/skf-create-skill/customize.toml +20 -8
  233. package/src/skf-create-skill/references/authoritative-files-protocol.md +36 -58
  234. package/src/skf-create-skill/references/batch-mode.md +81 -0
  235. package/src/skf-create-skill/references/ccc-index-check.md +27 -0
  236. package/src/skf-create-skill/references/compile.md +119 -70
  237. package/src/skf-create-skill/references/component-extraction.md +113 -91
  238. package/src/skf-create-skill/references/enrich.md +41 -23
  239. package/src/skf-create-skill/references/entry-points-by-hand.md +37 -0
  240. package/src/skf-create-skill/references/extract.md +204 -162
  241. package/src/skf-create-skill/references/extraction-patterns-by-hand.md +141 -0
  242. package/src/skf-create-skill/references/extraction-patterns-tracing.md +11 -11
  243. package/src/skf-create-skill/references/extraction-patterns.md +588 -201
  244. package/src/skf-create-skill/references/generate-artifacts.md +145 -93
  245. package/src/skf-create-skill/references/health-check.md +1 -1
  246. package/src/skf-create-skill/references/load-brief.md +53 -36
  247. package/src/skf-create-skill/references/relabel-rule.md +12 -0
  248. package/src/skf-create-skill/references/report.md +37 -57
  249. package/src/skf-create-skill/references/source-resolution-protocols.md +58 -169
  250. package/src/skf-create-skill/references/step-auto-shard.md +20 -93
  251. package/src/skf-create-skill/references/step-doc-rot.md +44 -60
  252. package/src/skf-create-skill/references/step-doc-sources.md +28 -19
  253. package/src/skf-create-skill/references/sub/ccc-discover.md +18 -7
  254. package/src/skf-create-skill/references/sub/fetch-docs.md +106 -59
  255. package/src/skf-create-skill/references/sub/fetch-temporal.md +53 -166
  256. package/src/skf-create-skill/references/tier-degradation-rules.md +18 -9
  257. package/src/skf-create-skill/references/validate.md +173 -99
  258. package/src/skf-create-skill/scripts/scan-doc-rot.py +232 -99
  259. package/src/skf-create-stack-skill/SKILL.md +29 -56
  260. package/src/skf-create-stack-skill/assets/metadata-contract.md +51 -0
  261. package/src/skf-create-stack-skill/assets/provenance-map-schema.md +15 -15
  262. package/src/skf-create-stack-skill/assets/stack-skill-template.md +23 -57
  263. package/src/skf-create-stack-skill/customize.toml +23 -12
  264. package/src/skf-create-stack-skill/references/compile-stack.md +57 -66
  265. package/src/skf-create-stack-skill/references/compose-mode-rules.md +24 -44
  266. package/src/skf-create-stack-skill/references/detect-integrations.md +92 -95
  267. package/src/skf-create-stack-skill/references/detect-manifests.md +46 -71
  268. package/src/skf-create-stack-skill/references/generate-output.md +138 -128
  269. package/src/skf-create-stack-skill/references/init.md +90 -32
  270. package/src/skf-create-stack-skill/references/integration-patterns.md +1 -17
  271. package/src/skf-create-stack-skill/references/invocation-contract.md +34 -0
  272. package/src/skf-create-stack-skill/references/manifest-patterns.md +32 -20
  273. package/src/skf-create-stack-skill/references/parallel-extract.md +112 -38
  274. package/src/skf-create-stack-skill/references/rank-and-confirm.md +57 -75
  275. package/src/skf-create-stack-skill/references/report.md +39 -33
  276. package/src/skf-create-stack-skill/references/validate.md +20 -39
  277. package/src/skf-drop-skill/SKILL.md +28 -51
  278. package/src/skf-drop-skill/customize.toml +44 -30
  279. package/src/skf-drop-skill/references/execute.md +83 -146
  280. package/src/skf-drop-skill/references/health-check.md +2 -0
  281. package/src/skf-drop-skill/references/invocation-contract.md +64 -0
  282. package/src/skf-drop-skill/references/report.md +46 -30
  283. package/src/skf-drop-skill/references/select.md +122 -124
  284. package/src/skf-drop-skill/scripts/dir-sizes.py +54 -26
  285. package/src/skf-drop-skill/scripts/drop-roster.py +322 -0
  286. package/src/skf-export-skill/SKILL.md +40 -62
  287. package/src/skf-export-skill/assets/managed-section-format.md +14 -50
  288. package/src/skf-export-skill/assets/snippet-format.md +3 -1
  289. package/src/skf-export-skill/customize.toml +42 -13
  290. package/src/skf-export-skill/references/generate-snippet.md +54 -46
  291. package/src/skf-export-skill/references/health-check.md +2 -0
  292. package/src/skf-export-skill/references/invocation-contract.md +15 -0
  293. package/src/skf-export-skill/references/load-skill.md +88 -62
  294. package/src/skf-export-skill/references/manifest-rebuild.md +9 -10
  295. package/src/skf-export-skill/references/multi-skill-mode.md +4 -4
  296. package/src/skf-export-skill/references/orphan-context-detection.md +13 -5
  297. package/src/skf-export-skill/references/orphan-row-detection.md +31 -22
  298. package/src/skf-export-skill/references/package.md +15 -73
  299. package/src/skf-export-skill/references/preflight-snippet-root-probe.md +51 -70
  300. package/src/skf-export-skill/references/result-envelope.md +31 -16
  301. package/src/skf-export-skill/references/summary.md +41 -17
  302. package/src/skf-export-skill/references/token-report.md +4 -12
  303. package/src/skf-export-skill/references/update-context.md +118 -237
  304. package/src/skf-forger/SKILL.md +61 -37
  305. package/src/skf-forger/bmad-skill-manifest.yaml +4 -1
  306. package/src/skf-forger/customize.toml +43 -0
  307. package/src/skf-forger/references/pipeline-mode.md +73 -18
  308. package/src/skf-forger/scripts/forge-status.py +299 -0
  309. package/src/skf-forger/scripts/parse-pipeline.py +322 -54
  310. package/src/skf-forger/scripts/pipeline-gate.py +428 -0
  311. package/src/skf-forger/scripts/pipeline-journal.py +1052 -0
  312. package/src/skf-quick-skill/SKILL.md +54 -53
  313. package/src/skf-quick-skill/assets/skill-template.md +4 -2
  314. package/src/skf-quick-skill/customize.toml +51 -20
  315. package/src/skf-quick-skill/references/batch-mode.md +74 -21
  316. package/src/skf-quick-skill/references/compile.md +30 -31
  317. package/src/skf-quick-skill/references/ecosystem-check.md +7 -57
  318. package/src/skf-quick-skill/references/finalize.md +69 -18
  319. package/src/skf-quick-skill/references/halt-contract.md +41 -29
  320. package/src/skf-quick-skill/references/health-check.md +5 -3
  321. package/src/skf-quick-skill/references/quick-extract.md +114 -45
  322. package/src/skf-quick-skill/references/registry-resolution.md +9 -64
  323. package/src/skf-quick-skill/references/resolve-target.md +116 -66
  324. package/src/skf-quick-skill/references/write-and-validate.md +79 -40
  325. package/src/skf-refine-architecture/SKILL.md +43 -53
  326. package/src/skf-refine-architecture/customize.toml +49 -20
  327. package/src/skf-refine-architecture/references/compile.md +97 -54
  328. package/src/skf-refine-architecture/references/exit-codes.md +30 -0
  329. package/src/skf-refine-architecture/references/finding-storage.md +21 -0
  330. package/src/skf-refine-architecture/references/gap-analysis.md +101 -38
  331. package/src/skf-refine-architecture/references/improvements.md +14 -20
  332. package/src/skf-refine-architecture/references/init.md +98 -57
  333. package/src/skf-refine-architecture/references/issue-detection.md +32 -39
  334. package/src/skf-refine-architecture/references/refinement-rules.md +37 -48
  335. package/src/skf-refine-architecture/references/report.md +65 -54
  336. package/src/skf-refine-architecture/scripts/skf-check-preservation.py +1619 -0
  337. package/src/skf-rename-skill/SKILL.md +19 -54
  338. package/src/skf-rename-skill/customize.toml +32 -26
  339. package/src/skf-rename-skill/references/execute.md +230 -184
  340. package/src/skf-rename-skill/references/exit-codes.md +7 -7
  341. package/src/skf-rename-skill/references/health-check.md +1 -7
  342. package/src/skf-rename-skill/references/invocation-contract.md +25 -0
  343. package/src/skf-rename-skill/references/report.md +63 -52
  344. package/src/skf-rename-skill/references/select.md +197 -115
  345. package/src/skf-rename-skill/scripts/skf-validate-rename-name.py +161 -21
  346. package/src/skf-setup/SKILL.md +26 -26
  347. package/src/skf-setup/customize.toml +14 -10
  348. package/src/skf-setup/references/auto-index.md +50 -63
  349. package/src/skf-setup/references/ccc-index.md +29 -90
  350. package/src/skf-setup/references/detect-and-tier.md +58 -67
  351. package/src/skf-setup/references/health-check.md +2 -0
  352. package/src/skf-setup/references/invocation-contract.md +14 -0
  353. package/src/skf-setup/references/report.md +43 -166
  354. package/src/skf-setup/references/tier-rules.md +5 -5
  355. package/src/skf-setup/references/write-config.md +34 -57
  356. package/src/skf-test-skill/SKILL.md +17 -57
  357. package/src/skf-test-skill/assets/output-section-formats.md +33 -34
  358. package/src/skf-test-skill/customize.toml +27 -13
  359. package/src/skf-test-skill/references/coherence-check.md +134 -62
  360. package/src/skf-test-skill/references/coverage-check-tiers.md +35 -0
  361. package/src/skf-test-skill/references/coverage-check.md +209 -264
  362. package/src/skf-test-skill/references/detect-mode.md +5 -5
  363. package/src/skf-test-skill/references/external-validators.md +94 -82
  364. package/src/skf-test-skill/references/health-check.md +6 -7
  365. package/src/skf-test-skill/references/init.md +164 -91
  366. package/src/skf-test-skill/references/invocation-contract.md +66 -0
  367. package/src/skf-test-skill/references/migration-section-rules.md +5 -2
  368. package/src/skf-test-skill/references/report.md +164 -142
  369. package/src/skf-test-skill/references/score.md +80 -107
  370. package/src/skf-test-skill/references/scoring-rules.md +42 -155
  371. package/src/skf-test-skill/references/source-access-protocol.md +18 -94
  372. package/src/skf-test-skill/references/step-hard-gate.md +51 -33
  373. package/src/skf-test-skill/scripts/aggregate-coherence.py +218 -30
  374. package/src/skf-test-skill/scripts/build-result-context.py +380 -0
  375. package/src/skf-test-skill/scripts/check-metadata-coherence.py +37 -4
  376. package/src/skf-test-skill/scripts/combine-external-scores.py +23 -6
  377. package/src/skf-test-skill/scripts/compute-score.py +223 -45
  378. package/src/skf-test-skill/scripts/gap-ledger.py +1666 -0
  379. package/src/skf-test-skill/scripts/hard-gate.py +203 -0
  380. package/src/skf-test-skill/scripts/load-coverage-inputs.py +1198 -0
  381. package/src/skf-test-skill/scripts/locate-export-segments.py +835 -0
  382. package/src/skf-test-skill/scripts/reconcile-coverage.py +547 -79
  383. package/src/skf-test-skill/scripts/score-signatures.py +479 -0
  384. package/src/skf-test-skill/scripts/stage-helper-payload.py +148 -0
  385. package/src/skf-test-skill/scripts/validate-inventory.py +311 -16
  386. package/src/skf-test-skill/scripts/verify-declared-numerator.py +133 -56
  387. package/src/skf-test-skill/templates/test-report-template.md +21 -15
  388. package/src/skf-update-skill/SKILL.md +38 -25
  389. package/src/skf-update-skill/customize.toml +27 -12
  390. package/src/skf-update-skill/references/detect-changes.md +253 -223
  391. package/src/skf-update-skill/references/gap-driven.md +336 -0
  392. package/src/skf-update-skill/references/health-check.md +31 -5
  393. package/src/skf-update-skill/references/init.md +254 -84
  394. package/src/skf-update-skill/references/invocation-contract.md +12 -0
  395. package/src/skf-update-skill/references/manual-section-rules.md +6 -23
  396. package/src/skf-update-skill/references/merge.md +182 -49
  397. package/src/skf-update-skill/references/re-extract.md +53 -262
  398. package/src/skf-update-skill/references/report.md +102 -35
  399. package/src/skf-update-skill/references/write.md +357 -155
  400. package/src/skf-update-skill/scripts/skf-new-file-diff.py +183 -46
  401. package/src/skf-verify-stack/SKILL.md +23 -42
  402. package/src/skf-verify-stack/assets/feasibility-report-template.md +11 -5
  403. package/src/skf-verify-stack/customize.toml +55 -22
  404. package/src/skf-verify-stack/references/coverage-patterns.md +17 -8
  405. package/src/skf-verify-stack/references/coverage.md +67 -64
  406. package/src/skf-verify-stack/references/exit-codes.md +21 -8
  407. package/src/skf-verify-stack/references/init.md +107 -62
  408. package/src/skf-verify-stack/references/integration-verification-rules.md +12 -13
  409. package/src/skf-verify-stack/references/integrations.md +106 -65
  410. package/src/skf-verify-stack/references/report.md +59 -42
  411. package/src/skf-verify-stack/references/requirements.md +32 -9
  412. package/src/skf-verify-stack/references/synthesize.md +53 -39
  413. package/src/skf-verify-stack/scripts/skf-coverage-tally.py +398 -52
  414. package/src/skf-verify-stack/scripts/skf-previous-report.py +330 -0
  415. package/src/skf-verify-stack/scripts/skf-report-delta.py +453 -49
  416. package/src/skf-verify-stack/scripts/skf-verdict-rollup.py +240 -27
  417. package/tools/cli/commands/install.js +11 -4
  418. package/tools/cli/commands/status.js +15 -3
  419. package/tools/cli/commands/update.js +11 -4
  420. package/tools/cli/lib/tool-check.js +320 -0
  421. package/tools/cli/lib/version-check.js +22 -9
  422. package/tools/cli/skf-cli.js +4 -1
  423. package/.gitattributes +0 -16
  424. package/.nvmrc +0 -1
  425. package/docs/_internal/RELEASING.md +0 -679
  426. package/release-audits/v1.0.0-launch-audit.md +0 -728
  427. package/src/skf-audit-skill/references/step-doc-drift.md +0 -177
  428. package/src/skf-brief-skill/references/headless-source-authority-detection.md +0 -26
  429. package/src/skf-campaign/manifest.yaml +0 -15
  430. package/src/skf-create-skill/assets/tessl-dismissal-rules.md +0 -106
  431. package/src/skf-create-skill/references/ecosystem-check.md +0 -74
  432. package/src/skf-drop-skill/references/headless-contract.md +0 -18
  433. package/src/skf-update-skill/references/merge-conflict-rules.md +0 -15
  434. package/src/skf-update-skill/references/remote-source-resolution.md +0 -98
  435. package/src/skf-update-skill/references/validate.md +0 -124
  436. package/tools/validate-docs-drift.js +0 -233
  437. package/tools/validate-docs-links.js +0 -665
@@ -5,9 +5,6 @@ nextStepFile: 'health-check.md'
5
5
  writeSkillBriefProbeOrder:
6
6
  - '{project-root}/_bmad/skf/shared/scripts/skf-write-skill-brief.py'
7
7
  - '{project-root}/src/shared/scripts/skf-write-skill-brief.py'
8
- emitBriefEnvelopeProbeOrder:
9
- - '{project-root}/_bmad/skf/shared/scripts/skf-emit-brief-result-envelope.py'
10
- - '{project-root}/src/shared/scripts/skf-emit-brief-result-envelope.py'
11
8
  forgeTierRwProbeOrder:
12
9
  - '{project-root}/_bmad/skf/shared/scripts/skf-forge-tier-rw.py'
13
10
  - '{project-root}/src/shared/scripts/skf-forge-tier-rw.py'
@@ -32,7 +29,7 @@ forgeTierFile: '{sidecar_path}/forge-tier.yaml'
32
29
 
33
30
  **Resolve `{writeSkillBriefHelper}`** from `{writeSkillBriefProbeOrder}`; first existing path wins. HALT if no candidate exists.
34
31
 
35
- `{briefSchemaPath}` and `{versionResolutionFile}` document the brief contract for human readers. The deterministic enforcement of that contract lives in `{writeSkillBriefHelper}` and its JSON Schema artifact at `src/shared/scripts/schemas/skill-brief.v1.json`. Load `{briefSchemaPath}` only if you need to explain a specific field to the user during inline adjustments — otherwise skip the read; the script is the source of truth.
32
+ `assets/skill-brief-schema.md` and `{versionResolutionFile}` document the brief contract for human readers. The deterministic enforcement of that contract lives in `{writeSkillBriefHelper}` and its JSON Schema artifact at `src/shared/scripts/schemas/skill-brief.v1.json`. Load `assets/skill-brief-schema.md` only if you need to explain a specific field to the user during inline adjustments; otherwise skip the read: the script is the source of truth.
36
33
 
37
34
  ### 2. Resolve Output Path
38
35
 
@@ -46,11 +43,19 @@ The script's atomic-write helper creates parent directories as needed (`mkdir -p
46
43
 
47
44
  Before writing, check whether the resolved target path already exists.
48
45
 
49
- **Ratify path (`ratify_mode: true` in workflow context):**
46
+ **Ratify path (`ratify_mode: true` in workflow context):** step 1 (`references/gather-intent-ratify.md`) authorized overwriting only the brief it read, `ratify_source_path`: interactively by `[R] Ratify`, then reviewed and approved at step 4, or headlessly by a `from_brief` argument. Check whether the target is that file (the same file through any path or link), each path written as it is on its line between the markers:
50
47
 
51
- The overwrite was already authorized when ratify mode was entered — interactively at step 1 §3.1a (`[R] Ratify` against the same file, then reviewed and approved at step 4), or headlessly at the step 1 §8 GATE `from_brief` route (the operator pointed the run at a brief to ratify). Either way, skip the interactive prompt below; log a single-line `brief-skill: ratify-mode auto-overwriting existing brief at {path}` and proceed to §3. **This ratify branch takes precedence over both the interactive and headless branches below** — when `ratify_mode` is set, neither of those runs. In particular, a headless ratify (`from_brief`) auto-overwrites the brief in place without requiring `force`; `force` governs only the derive route, where overwriting a pre-existing brief is a genuine clobber the operator must opt into.
48
+ ```bash
49
+ uv run python -c 'import os, sys; a, b = sys.stdin.read().splitlines()[:2]; print("same" if os.path.exists(a) and os.path.exists(b) and os.path.samefile(a, b) else "different")' <<'SKF_PATHS'
50
+ {resolved-target-path}
51
+ {ratify_source_path}
52
+ SKF_PATHS
53
+ ```
54
+
55
+ - **`same`:** skip both gates below, with no `force` needed: log a single-line `brief-skill: ratify-mode auto-overwriting existing brief at {path}` and proceed to §3.
56
+ - **`different`** (the brief lives outside `{forge_data_folder}/<name>/`, or step 4 renamed it): an existing file at the target is another brief, so the gates below apply as on the derive route.
52
57
 
53
- **Interactive (`{headless_mode}` is false, `ratify_mode` not set):**
58
+ **Interactive (`{headless_mode}` is false), unless the ratify check printed `same`:**
54
59
 
55
60
  If the file exists, present:
56
61
 
@@ -60,18 +65,18 @@ Overwrite it with the brief you just approved? [Y/N]"
60
65
  - **[Y]** Overwrite — proceed to §3.
61
66
  - **[N]** Cancel — emit a single-line stderr log `brief-skill: overwrite-cancelled at {path}` and HALT with exit code 5 (do not chain to step 6; the run produced no new artifact).
62
67
 
63
- **Headless (`{headless_mode}` is true):**
68
+ **GATE [default: HALT unless `force` was supplied]**: headless (`{headless_mode}` is true), unless the ratify check printed `same`:
64
69
 
65
70
  If the file exists:
66
71
 
67
72
  - If `force` was supplied as a headless argument: log `"headless: force-overwriting existing brief at {path}"` and proceed to §3.
68
- - Otherwise: emit the error envelope per §4b with `halt_reason: "overwrite-cancelled"`, then HALT with exit code 5.
73
+ - Otherwise: emit the halt envelope first, `uv run {emitBriefEnvelopeHelper} emit --target stderr` with `halt_reason: "overwrite-cancelled"` (SKILL.md Halt Contract), then HALT with exit code 5.
69
74
 
70
75
  If the file does not exist, proceed normally.
71
76
 
72
77
  ### 3. Write the Brief
73
78
 
74
- Assemble the brief context as a **flat** JSON object — every approved value is a top-level key, scope is split across four `scope_*` keys instead of nested, and every optional field is passed as `null` when not set rather than conditionally omitted. This eliminates the "decide what to omit" cognitive load that previously made this the most expensive HALT-typo site in the workflow:
79
+ **Derive run** (any run but a ratify run): assemble the brief context as a **flat** JSON object: every approved value is a top-level key, scope is split across the `scope_*` keys instead of nested, and every optional field is passed as `null` when not set rather than conditionally omitted:
75
80
 
76
81
  ```json
77
82
  {
@@ -90,28 +95,41 @@ Assemble the brief context as a **flat** JSON object — every approved value is
90
95
  "scope_exclude": ["{approved exclude patterns}"],
91
96
  "scope_notes": "{approved scope notes or empty string}",
92
97
  "scope_rationale": null | {"recommended":"...","chosen":"...","accepted_recommendation":true|false,"heuristic":"...","reason":"...","recorded":"YYYY-MM-DD"},
93
- "scope_tier_a_include": null | ["{tier-A authoring-surface patterns — from step 03 §3c capture, or hydrated on a ratify run}"],
94
- "scope_amendments": null | [{"path":"...","action":"...","reason":"...","date":"YYYY-MM-DD","workflow":"..."}],
98
+ "scope_tier_a_include": null | ["{tier-A authoring-surface patterns, from step 3 §3c}"],
99
+ "scope_registry_path": null | "{a component library's registry file; this key and the next two from step 3's component-library flow or its headless default}",
100
+ "scope_ui_variants": null | [{"name": "...", "package": "..."}],
101
+ "scope_demo_patterns": null | ["{demo globs}"],
95
102
  "doc_urls": null | [{"url": "...", "label": "...", "source": "{optional: language-registry|readme-detection|homepage|pages-api|docs-folder}"}],
96
103
  "scripts_intent": null | "{detect|none|free-text}",
97
104
  "assets_intent": null | "{detect|none|free-text}",
98
105
  "source_authority": null | "{official|community|internal}",
99
- "target_ref": null | "{explicit git ref — ratify only}",
100
- "source_ref": null | "{resolved git ref — ratify only}"
106
+ "target_ref": null | "{the explicit git ref of step 1's /tree/<ref>/ URL}"
101
107
  }
102
108
  ```
103
109
 
104
- **Ratify mode (`ratify_mode: true`):** this path never ran step 2, so the version was not re-derived — it was hydrated from the upstream brief at step 1 §3.1a (interactive) or the §8 GATE `from_brief` route (headless). Add a `version_resolved` key set to that hydrated `version`; the writer's precedence checks `version_resolved` first, so this pins the output to the brief's authored version. **Without it**, `target_version` and `detected_version` are both null on a ratify run and the writer falls through to the `1.0.0` default, silently discarding the upstream version. Keep `target_version` set to the brief's `target_version` (null if it had none) so the writer's `target_version == version` invariant still holds. Likewise carry `target_ref`/`source_ref` and `scope_tier_a_include`/`scope_amendments` from the hydrated brief (all null on a derive run) so the writer round-trips the monorepo git ref, the stratified tier-A surface, and the amendment audit log instead of dropping them.
105
-
106
- Pipe it into the writer script with the `--from-flat` flag:
110
+ Stage it in the run folder, then run the writer on the file with the `--from-flat` flag:
107
111
 
108
112
  ```bash
109
- echo '<context-json>' | uv run {writeSkillBriefHelper} write --target {resolved-target-path} --from-flat
113
+ cat > "{run_dir}/brief-context.json" <<'SKF_JSON'
114
+ <the brief context above, as one JSON object>
115
+ SKF_JSON
116
+ uv run {writeSkillBriefHelper} write --target {resolved-target-path} --from-flat < "{run_dir}/brief-context.json"
110
117
  ```
111
118
 
112
119
  The script translates flat → nested internally, drops the null optional fields, and runs the same schema validation and atomic write as before — pass every key always, the writer decides what reaches the YAML.
113
120
 
114
- The script:
121
+ **Ratify run (`ratify_mode: true`):** write from the brief step 1 ratified, `{ratify_source_path}`, so nothing it holds is retyped. The writer keeps every field of that brief that it renders and the patch below does not name, such as its version, which step 2 never re-derives on a ratify run (an [R] pass analyzes the brief's ref but keeps the hydrated version), its git refs and its `scope.amendments` log. The patch holds the fields step 4 or a step 3 `[R]` pass can change: write each `<field>` as its current value in JSON, `null` when it is unset, which removes the key (an `[R]` pass that moved `scope.type` off `component-library` unsets the three component-library fields). Add any other field the user changed at step 4 under its brief key; a changed `version` sets `target_version` too when the brief holds one, because the writer keeps the two equal:
122
+
123
+ ```bash
124
+ cat > "{run_dir}/ratify-patch.json" <<'SKF_JSON'
125
+ {"name": <name>, "description": <description>, "language": <language>,
126
+ "scope": {"type": <scope.type>, "include": <scope.include>, "exclude": <scope.exclude>, "notes": <scope.notes>, "rationale": <scope.rationale>, "tier_a_include": <scope.tier_a_include>, "registry_path": <scope.registry_path>, "ui_variants": <scope.ui_variants>, "demo_patterns": <scope.demo_patterns>},
127
+ "scripts_intent": <scripts_intent>, "assets_intent": <assets_intent>, "doc_urls": <doc_urls>}
128
+ SKF_JSON
129
+ uv run {writeSkillBriefHelper} write --target {resolved-target-path} --base-brief "{ratify_source_path}" --patch-file "{run_dir}/ratify-patch.json"
130
+ ```
131
+
132
+ Either way, the script:
115
133
  - Validates the context against `src/shared/scripts/schemas/skill-brief.v1.json`
116
134
  - Applies the version-precedence rule from `{versionResolutionFile}`
117
135
  - Enforces the `target_version == version` invariant (refuses to write a brief that violates it)
@@ -122,55 +140,41 @@ The script:
122
140
  **On script failure (non-zero exit):**
123
141
  - Exit 1 (validation/invariant): The error JSON on stderr names the offending field. This indicates a context-assembly bug, not a user error — surface the message to the user, log it, then HALT.
124
142
  - Interactive: **HALT** — display the error JSON's `message` field.
125
- - Headless: emit the error envelope per §4b with `halt_reason: "input-invalid"`, then `exit 2`.
126
- - Exit 2 (I/O failure): The atomic write failed (target unwritable, disk full, etc.).
143
+ - Headless: emit the halt envelope first, `uv run {emitBriefEnvelopeHelper} emit --target stderr` with `halt_reason: "input-invalid"` (SKILL.md Halt Contract), then HALT (exit code 2).
144
+ - Exit 2 (I/O failure): The atomic write failed (target unwritable, disk full, etc.). On a ratify run it can also mean the brief at `{ratify_source_path}` could not be read: show the error JSON's `message` field.
127
145
  - Interactive: **HALT** — "**Error:** Failed to write skill-brief.yaml. Check that the directory is writable and try again."
128
- - Headless: emit the error envelope per §4b with `halt_reason: "write-failed"`, then `exit 4`.
129
-
130
- **On success:** capture `brief_path` and `version` from the response envelope — both are needed for §4b and §6.
146
+ - Headless: emit the halt envelope first, `uv run {emitBriefEnvelopeHelper} emit --target stderr` with `halt_reason: "write-failed"` (SKILL.md Halt Contract), then HALT (exit code 4).
131
147
 
132
- **Draft cleanup.** After a successful write, remove `{forge_data_folder}/{skill-name}/.brief-draft.json` if it exists (`rm -f` — silent on absent). The draft was a step 1 §7 checkpoint covering the in-flight workflow window; once the brief is written it is no longer meaningful. In headless mode this rm is a no-op (drafts are only written interactively).
148
+ **On success:** capture `brief_path` and `version` from the response envelope (§4b, §6 and §6b need them), and add each entry of its `warnings[]` to `workflow_warnings[]`.
133
149
 
134
- ### 4b. Headless Result Envelope (Canonical)
150
+ **Draft cleanup.** After a successful write, remove `{forge_data_folder}/{skill-name}/.brief-draft.json` if it exists (`rm -f`, silent on absent). The draft was the checkpoint step 1 §8 and step 3 §5c wrote for the in-flight workflow window; once the brief is written it is no longer meaningful. In headless mode this rm is a no-op (drafts are only written interactively).
135
151
 
136
- **Resolve `{emitBriefEnvelopeHelper}`** from `{emitBriefEnvelopeProbeOrder}`; first existing path wins. HALT if no candidate exists.
152
+ ### 3b. QMD Collection Registration (Deep Tier Only)
137
153
 
138
- This section is the canonical envelope-emission reference for the workflow. Every headless emission — the success terminal here and every HARD HALT in step 1/02/05 — uses this contract. Remote sites point here instead of restating it.
154
+ **IF forge tier is Deep AND QMD tool is available:** resolve `{forgeTierRwHelper}` from `{forgeTierRwProbeOrder}` (first existing path wins), then load `{qmdRegistrationFile}` and follow the procedure there to index the brief into a QMD collection and update the forge-tier registry. If neither path exists, do not HALT: the brief is already written, and a QMD problem never fails the run. Index the brief all the same, skip the procedure's registry update, and add `QMD registry not updated: skf-forge-tier-rw.py not found` to `workflow_warnings[]`. A warning the procedure logs goes on `workflow_warnings[]` too, which is why this runs before §4b builds the envelope.
139
155
 
140
- **Success (this call site only — emitted from §3 directly):**
156
+ **IF forge tier is NOT Deep OR QMD is not available:** skip this section silently: do not load `{qmdRegistrationFile}`. No messaging.
141
157
 
142
- ```bash
143
- echo '{"status":"success","brief_path":"<from §3 response>","skill_name":"<name>","version":"<from §3 response>","language":"<language>","scope_type":"<scope.type>","halt_reason":null}' | \
144
- uv run {emitBriefEnvelopeHelper} emit
145
- ```
158
+ ### 4b. Result Envelope (Headless)
146
159
 
147
- **Error (used by every HARD HALT site):**
160
+ When `{headless_mode}` is true, build the run's `SKF_BRIEF_RESULT_JSON` line now, after the write (§3) and the QMD registration (§3b), so `workflow_warnings[]` holds every warning the run raised. `{emitBriefEnvelopeHelper}` was resolved at SKILL.md On Activation step 4, and `references/invocation-contract.md` defines each field. Bind `{result_envelope_line}` to the line it prints, and do not display it here: the shared health check displays it verbatim as the run's last line, the final message a `claude -p` caller reads:
148
161
 
149
162
  ```bash
150
- echo '{"status":"error","skill_name":"<name>","halt_reason":"<reason>"}' | \
151
- uv run {emitBriefEnvelopeHelper} emit --target stderr
163
+ uv run {emitBriefEnvelopeHelper} emit <<'SKF_BRIEF_RESULT'
164
+ {"status":"success","brief_path":"<brief_path from §3>","skill_name":"<name>","version":"<version from §3>","language":"<language>","scope_type":"<scope.type>","halt_reason":null,"mode":null,"warnings":[<workflow_warnings[] as JSON strings>]}
165
+ SKF_BRIEF_RESULT
152
166
  ```
153
167
 
154
- When the HALT fires before `skill_name` has been resolved (step 1 §1 pre-flight write probe, step 1 §8 input-missing on a malformed args bundle), pass the partially-gathered value or the literal `"unknown"` — the script accepts any non-empty string at this position.
168
+ The helper derives `exit_code`, checks the line against the envelope schema and prints it on stdout. If `{emitBriefEnvelopeHelper}` has no path, or the helper exits non-zero or prints no line, leave `{result_envelope_line}` empty and display its error: the brief is already written, so the run goes on.
155
169
 
156
- The script derives `exit_code` deterministically from `halt_reason` (null→0, input-missing/input-invalid→2, forge-tier-missing/target-inaccessible/gh-auth-failed→3, write-failed→4, overwrite-cancelled→5, user-cancelled→6 [interactive-only — headless never raises this]), validates against `src/shared/scripts/schemas/skf-brief-result-envelope.v1.json`, and prints the prefixed `SKF_BRIEF_RESULT_JSON: {…}` line.
170
+ A HALT in this step, or in steps 1 and 2, does not use this section: it emits the error envelope through the SKILL.md Halt Contract, which also gives the `unknown` placeholder for a halt before the skill name is resolved.
157
171
 
158
- The script enforces the success/error halt_reason invariant (success requires null halt_reason; error requires non-null). The `user-cancelled` halt_reason is accepted for completeness (interactive `[X]` Cancel sites in step 1/03/04) but never appears on the headless code path.
159
-
160
- Invocation sites (each pointed at this block, not duplicated): step 1 §1 (write-failed pre-resolution; forge-tier-missing), step 1 §8 (input-missing/input-invalid GATE), step 2 §1 (target-inaccessible/gh-auth-failed), step 5 §2b (overwrite-cancelled), step 5 §3 (input-invalid/write-failed from script). The step 1 §1 forge-tier-missing and step 2 §1 target-inaccessible/gh-auth-failed sites emit through this block too, so every headless HALT class surfaces a `SKF_BRIEF_RESULT_JSON` envelope — there are no envelope-silent failure classes.
161
-
162
- When `{headless_mode}` is false, skip this section silently — no envelope is emitted.
163
-
164
- ### 5. QMD Collection Registration (Deep Tier Only)
165
-
166
- **Resolve `{forgeTierRwHelper}`** from `{forgeTierRwProbeOrder}`; first existing path wins. HALT if no candidate exists.
167
-
168
- **IF forge tier is Deep AND QMD tool is available:** load `{qmdRegistrationFile}` and follow the procedure there to index the brief into a QMD collection and update the forge-tier registry.
169
-
170
- **IF forge tier is NOT Deep OR QMD is not available:** skip this section silently — do not load `{qmdRegistrationFile}`. No messaging.
172
+ When `{headless_mode}` is false, skip this section silently: no envelope is emitted.
171
173
 
172
174
  ### 6. Display Success Summary
173
175
 
176
+ When `{headless_mode}` is true, skip this section: the envelope §4b bound is the run's result.
177
+
174
178
  "**Skill brief written successfully.**
175
179
 
176
180
  ---
@@ -199,7 +203,7 @@ After compilation, you can:
199
203
 
200
204
  ### 6b. On-Complete Hook (pipeline integration)
201
205
 
202
- If `{onCompleteCommand}` is non-empty (resolved at SKILL.md On Activation §3 from `workflow.on_complete`), invoke it now — after the brief has been written (§3) and the result contract finalized (§4b) — as:
206
+ If `{onCompleteCommand}` is non-empty (resolved at SKILL.md On Activation §3 from `workflow.on_complete`), invoke it now, after the brief has been written (§3) and, in a headless run, the result envelope built and bound to `{result_envelope_line}` (§4b):
203
207
 
204
208
  ```bash
205
209
  {onCompleteCommand} --result-path={brief_path}
@@ -207,12 +211,17 @@ If `{onCompleteCommand}` is non-empty (resolved at SKILL.md On Activation §3 fr
207
211
 
208
212
  where `{brief_path}` is the absolute path captured from the §3 response envelope (the freshly written `skill-brief.yaml`, the stable artifact a downstream consumer chains from).
209
213
 
210
- - On success: log to `workflow_warnings[]` as informational only if the hook emitted stderr (`on_complete hook stderr: …`); otherwise no entry.
211
- - On non-zero exit / process error: log to `workflow_warnings[]` (`on_complete hook failed (exit {code}): {stderr_snippet}`).
212
- - **Never fail the workflow on hook errors** — the hook is for pipeline integration (chaining into create-skill, Slack, dashboards, CI), not for gating brief production.
214
+ - **Never fail the workflow on hook errors:** the hook is for pipeline integration (chaining into create-skill, Slack, dashboards, CI), not for gating brief production. On a non-zero exit or a process error, display one line, `on_complete hook failed (exit {code}): {first line of its stderr}`, and continue. A headless run bound its envelope at §4b, so the envelope does not carry this line.
215
+ - On success, add nothing: the hook's own output is its report.
213
216
 
214
- When `{onCompleteCommand}` is empty (bundled default), skip this section entirely — no hook is invoked.
217
+ When `{onCompleteCommand}` is empty (bundled default), skip this section entirely: no hook is invoked. An `[auto]` run runs only §3b of this file: step-auto-validate.md §3 runs the same hook right after its envelope.
215
218
 
216
219
  ### 7. Chain to Health Check
217
220
 
218
- Once the brief file has been written and the success summary displayed, load, read the full file, and execute `{nextStepFile}`. The health-check step is the true terminal step — do not stop here even though the summary reads as final.
221
+ Once the brief file has been written (and, outside headless mode, the success summary displayed), remove the run folder step 1 §1 created, with what the run staged in it (the guard keeps the command to that folder):
222
+
223
+ ```bash
224
+ case "{run_dir}" in "{project-root}/_bmad-output/.skf-run/skf-brief-skill-"*) rm -rf "{run_dir}" ;; esac
225
+ ```
226
+
227
+ Then load, read the full file, and execute `{nextStepFile}`. The health-check step is the true terminal step: do not stop here even though the summary reads as final.
@@ -7,7 +7,7 @@ description: Campaign orchestration — multi-library skill production with depe
7
7
 
8
8
  ## Overview
9
9
 
10
- Orchestrates the production of 15+ skills across multiple sessions by driving them through the full SKF pipeline (brief, generate, compile, test, export) in dependency order. Campaign sits atop the pipeline ladder: it sequences the workflows that produce skills rather than producing artifacts itself. File-based state (`_campaign-state.yaml`) survives context death, enabling resume from any point.
10
+ Orchestrates the production of 15+ skills across multiple sessions by driving them through the full SKF pipeline (brief, generate, compile, test, export) in dependency order. File-based state (`_campaign-state.yaml`) survives context death, enabling resume from any point.
11
11
 
12
12
  ## Conventions
13
13
 
@@ -16,41 +16,40 @@ Orchestrates the production of 15+ skills across multiple sessions by driving th
16
16
  - `{skill-root}` resolves to this skill's installed directory (where `customize.toml` lives).
17
17
  - `{project-root}`-prefixed paths resolve from the project working directory.
18
18
  - `{skill-name}` resolves to the skill directory's basename.
19
+ - **Module-level path exception:** bare paths beginning with `knowledge/` or `shared/` resolve from the SKF module root (`{project-root}/_bmad/skf/` installed, `src/` in dev), not the skill root; e.g. `shared/health-check.md` and the envelope schemas under `shared/scripts/schemas/`.
20
+ - **Sibling skills:** a path that names another SKF skill's folder (`skf-<name>/...`) resolves from the SKF module root, and that skill must be installed with this one.
19
21
 
20
22
  ## Role
21
23
 
22
- You are a campaign orchestrator operating in Ferris's Management mode. You sequence workflows, track per-skill state, enforce quality gates, and ensure every skill reaches its target tier — while the individual pipeline workflows handle the actual artifact production.
24
+ You are a campaign orchestrator operating in Ferris's Management mode. You sequence workflows, track per-skill state, enforce quality gates, and ensure every skill reaches its target tier, while the individual pipeline workflows handle the actual artifact production.
23
25
 
24
26
  ## On Activation
25
27
 
26
28
  Run these steps once, in order, before dispatching to Mode Routing.
27
29
 
28
- 1. **Load config.** Read `{project-root}/_bmad/skf/config.yaml` and `{sidecar_path}/preferences.yaml` in one batched message (independent files). From config resolve `project_name`, `user_name`, `communication_language`, `document_output_language`, `skills_output_folder`, `forge_data_folder`, `sidecar_path`. From preferences resolve `headless_mode` (default false). If the config file is missing, fall back to `forge_data_folder = forge-data`.
30
+ 1. **Load config.** Read `{project-root}/_bmad/skf/config.yaml` and `{sidecar_path}/preferences.yaml` in one batched message (independent files). From config resolve `project_name`, `user_name`, `communication_language`, `document_output_language`, `skills_output_folder`, `forge_data_folder`, `sidecar_path`. If the config file is missing, fall back to `forge_data_folder = forge-data`.
29
31
 
30
- 2. **Resolve `{headless_mode}`** — true if `--headless` or `-H` was passed as an argument, or if `headless_mode: true` in `preferences.yaml`. Default: false.
32
+ 2. **Resolve `{headless_mode}`**: true if `--headless` or `-H` was passed as an argument, or if `headless_mode: true` in `{sidecar_path}/preferences.yaml`. Default: false.
31
33
 
32
34
  3. **Resolve workflow customization.** Run:
33
35
 
34
36
  ```bash
35
- python3 {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key workflow
37
+ uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --project-root {project-root} --key workflow
36
38
  ```
37
39
 
38
- The script merges three layers (scalars override, arrays append):
40
+ It merges the bundled `{skill-root}/customize.toml` with `{project-root}/_bmad/custom/skf-campaign.toml` (team overrides, committed) and `.user.toml` (personal overrides, gitignored). When it exits non-zero, prints no JSON or is missing, print one line, `[activation/warn] customization_resolver_unavailable: <reason>` (`<reason>`: its first stderr line, `not found` when the script is missing, `no JSON` when it printed none). If the resolver cannot run, read `{skill-root}/customize.toml` alone and use its bundled defaults: the `{project-root}/_bmad/custom/` overrides do not apply to this run. In that case, unless the invocation is `campaign status` (which writes nothing), log `customization_resolver_unavailable: <reason>` as an `event` in the decision log once `{campaignWorkspacePath}` is bound below (`references/campaign-contracts.md`, Decision Log).
39
41
 
40
- - `{skill-root}/customize.toml` — bundled defaults
41
- - `_bmad/custom/<skill-name>.toml` under `{project-root}` — team overrides (committed)
42
- - `_bmad/custom/<skill-name>.user.toml` under `{project-root}` — personal overrides (gitignored)
43
-
44
- If it fails or is missing, fall back to `{skill-root}/customize.toml` directly. Resolve each scalar now (so step files never repeat the conditional) and stash as workflow-context variables:
42
+ Resolve each scalar now (so step files never repeat the conditional) and stash as workflow-context variables:
45
43
 
46
44
  - `{campaignWorkspacePath}` ← `workflow.campaign_workspace_path` if non-empty, else `{forge_data_folder}/_campaign`
47
- - `{qualityGateHard}` / `{qualityGateSoftTarget}` / `{qualityGateSoftFallback}` ← the `quality_gate_*` scalars (defaults `zero-critical-high` / `90` / `80`)
45
+ - `{qualityGateHard}` / `{qualityGateSoftTarget}` / `{qualityGateSoftFallback}` ← the `quality_gate_*` scalars (defaults `zero-critical-high` / `90` / `80`): the base gate, which step-01 §2 and `scripts/campaign-quality-gate.py` adjust with the brief and the directive
48
46
  - `{reportTemplatePath}` ← `workflow.report_template_path` if non-empty, else `templates/campaign-report-template.md`
49
47
  - `{kickoffTemplatePath}` ← `workflow.kickoff_template_path` if non-empty, else `templates/kickoff-template.md`
50
48
  - `{briefTemplatePath}` ← `workflow.brief_template_path` if non-empty, else `templates/campaign-brief-template.yaml`
51
49
  - `{onComplete}` ← `workflow.on_complete` (empty = no-op)
50
+ - `{emitEnvelopeHelper}` ← `{project-root}/_bmad/skf/shared/scripts/skf-emit-result-envelope.py`, else `{project-root}/src/shared/scripts/skf-emit-result-envelope.py` (the first that exists)
52
51
 
53
- Load `workflow.persistent_facts` (literal sentences and `file:` references, globs expanded) and keep them in mind for the whole campaign — they are injected into every per-skill kickoff. Run any `activation_steps_prepend` before step 1 and any `activation_steps_append` after this step.
52
+ Load `workflow.persistent_facts` (literal sentences and `file:` references, globs expanded: the bundled default loads every `project-context.md` under `{project-root}`; an entry prefixed `!` drops each earlier entry it names and loads nothing itself, so an override's `"!file:{project-root}/**/project-context.md"` turns that default off) and keep them in mind for the whole campaign: they are injected into every per-skill kickoff, whose loader drops a `!` entry the same way. Run any `activation_steps_prepend` now, right after the resolve: the config and preferences of steps 1 and 2 are already loaded, so a prepend step can read them but cannot run before them. `activation_steps_append` runs at step 5, once the CLI overrides are parsed.
54
53
 
55
54
  4. **Parse CLI overrides** into the workflow context:
56
55
 
@@ -61,36 +60,34 @@ Run these steps once, in order, before dispatching to Mode Routing.
61
60
  | `--manifest <file>` | Seed step-01 targets from a plain-text `name,repo_url,tier,pin` manifest. Implies `--headless`. |
62
61
  | `--from <skill>` | Resume override — see Mode Routing. |
63
62
 
64
- If `--brief` or `--manifest` is set, force `{headless_mode} = true` (log "headless: coerced by --brief/--manifest" if it was false).
65
-
66
- **`--manifest` format:** one `name,repo_url,tier,pin` target per line (empty `pin` = latest); a trailing `;dep1,dep2` segment sets `depends_on`; blank and `#` lines are skipped. A malformed line HALTs step-01 with the offending line numbers — never a partial target set.
63
+ If `--brief` or `--manifest` is set, force `{headless_mode} = true` (log "headless: coerced by --brief/--manifest" if it was false). This is deliberate: a seeded run is an unattended run (CI), so it takes the default at every gate. To review the plan and the export, give the same file at the Setup question instead, which stays interactive. step-01 §1 documents the manifest format and validates every target.
67
64
 
68
- 5. **Dispatch** per Mode Routing below.
65
+ 5. Run any `activation_steps_append`, then **dispatch** per Mode Routing below.
69
66
 
70
67
  ## Workflow Rules
71
68
 
72
69
  These rules apply to every step in this workflow:
73
70
 
74
- - State-first — write state to disk before chaining to the next step or workflow
75
- - Read-backup-modify-write for all state mutations (State Contract in `references/campaign-contracts.md`)
76
- - Validate `_campaign-state.yaml` on every load by running `uv run scripts/campaign-validate-state.py --state-file {stateFile}` and HALT (exit code 3, `invalid-state`) on non-zero — never hand-validate the schema
77
- - Zero memory dependency — campaign state is 100% recoverable from disk; never rely on conversation context for progress tracking
78
- - Treat a missing or unparseable `SKF_*_RESULT_JSON` envelope from any sub-skill as a sub-skill failure; never write partial state from an unparsed envelope
79
- - Append a one-line entry to the campaign decision log (`{campaignWorkspacePath}/_campaign-decision-log.md`, append-only) at every operator or auto-decision (skip/force, overwrite, export cancel/proceed, `.bak` recovery, user-cancel) so rationale survives compaction and resume
80
- - **Universal cancel affordance** — at any interactive gate between Setup and the Export gate, `cancel`/`exit`/`:q` triggers a HARD HALT with **exit code 12 (`user-cancelled`)**: log it and leave state intact and resumable. Exception: the Export gate's own `[C]ancel` stays exit code 11 (`export-cancelled`) — never also emit 12 there, so an automator's exit-code branch stays deterministic. These keywords count only as a response *to a prompt*; a skill or campaign named `cancel`/`exit` supplied as data is never treated as a cancel.
71
+ - State-first: write state to disk before chaining to the next step or workflow
72
+ - Every state write goes through `scripts/campaign-state.py` (State Contract in `references/campaign-contracts.md`); never edit the state or its `.bak` by hand
73
+ - Validate `_campaign-state.yaml` on every load by running `uv run scripts/campaign-validate-state.py --state-file {stateFile}` and HALT (exit code 3, `invalid-state`) on non-zero; never hand-validate the schema
74
+ - Zero memory dependency: campaign state is 100% recoverable from disk; never rely on conversation context for progress tracking
75
+ - A sub-skill's result is what the step that runs it reads (an `SKF_*_RESULT_JSON` envelope or a verdict): a missing, unparseable or error result is a sub-skill failure, and never write partial state from an unparsed envelope
76
+ - Log every operator decision, headless default and event (skip/force, overwrite, export cancel/proceed, `.bak` recovery, user-cancel, a failed skill) as one typed entry in the append-only `{campaignWorkspacePath}/_campaign-decision-log.md` through `campaign-state.py log` (`references/campaign-contracts.md`), so rationale survives compaction and resume
77
+ - **Universal cancel affordance:** at any interactive gate between Setup and the Export gate, `cancel`/`exit`/`:q` triggers a HARD HALT with **exit code 12 (`user-cancelled`)**: log it and leave state intact and resumable. Exception: the Export gate's own `[C]ancel` stays exit code 11 (`export-cancelled`); never also emit 12 there, so an automator's exit-code branch stays deterministic.
81
78
  - Always communicate in `{communication_language}`
82
79
  - If `{headless_mode}` is true, auto-proceed through confirmation gates with their default action and log each auto-decision
83
- - If `{headless_mode}` is true, emit a single-line JSON progress event to **stderr** at each step's entry, exit, and HARD HALT so schedulers stream live progress — event format in `references/campaign-contracts.md` (Headless Progress Events)
80
+ - If `{headless_mode}` is true, emit a single-line JSON progress event to **stderr** at each step's entry, exit, and HARD HALT, and at every HARD HALT the error envelope (`references/campaign-contracts.md`: Headless Progress Events, Result Contract on HARD HALT)
84
81
 
85
82
  ## Stages
86
83
 
87
84
  | # | Step | File | Auto-proceed |
88
85
  |---|------|------|--------------|
89
86
  | 0 | Setup | references/step-01-setup.md | Yes |
90
- | 1 | Strategy | references/step-02-strategy.md | Yes |
87
+ | 1 | Strategy | references/step-02-strategy.md | No (plan confirmation; headless takes [P]) |
91
88
  | 2 | Pin Validation | references/step-03-pins.md | Yes |
92
89
  | 3 | Provenance | references/step-04-provenance.md | Yes |
93
- | 4 | Skill Loop | references/step-05-skill-loop.md | Yes |
90
+ | 4 | Skill Loop | references/step-05-skill-loop.md | Conditional (a blocked dependency) |
94
91
  | 5 | Tier B Batch | references/step-06-batch.md | Yes |
95
92
  | 6 | Capstone | references/step-07-capstone.md | Yes |
96
93
  | 7 | Verification | references/step-08-verify.md | Yes |
@@ -98,24 +95,24 @@ These rules apply to every step in this workflow:
98
95
  | 9 | Export | references/step-10-export.md | No (write-gate HALT) |
99
96
  | 10 | Maintenance | references/step-11-maintenance.md | Yes |
100
97
 
101
- **Stage numbering:** step files are 1-indexed (`step-01` … `step-11`); `campaign.current_stage` in state is 0-indexed, so step-`NN` runs stage `NN − 1` (step-01 = stage 0, step-11 = stage 10). `references/step-resume.md` §3–§4 own how a resolved stage maps back to its step file on resume (including the `current_stage + 1` advance when no skill is active).
98
+ **Stage numbering:** `campaign.current_stage` is 0-indexed, so step-`NN` runs stage `NN - 1`; `campaign-state.py resume` maps a resumed campaign to its step file.
102
99
 
103
100
  ## Invocation Contract
104
101
 
105
102
  | Aspect | Detail |
106
103
  |--------|--------|
107
104
  | **Inputs** | `campaign` to start a new campaign; `campaign resume [--from=<skill>]` to resume from last active or specified skill; `campaign status` for a read-only progress summary |
108
- | **Outputs** | `_campaign-state.yaml` (state), `campaign-brief.yaml` (machine-generated brief), `campaign-report.md` (post-campaign summary), `_campaign-decision-log.md` (append-only rationale), `SKF_CAMPAIGN_RESULT_JSON` (headless envelope) — all under `{campaignWorkspacePath}` |
105
+ | **Outputs** | `_campaign-state.yaml` (state), `campaign-brief.yaml` (machine-generated brief), `campaign-report.md` (post-campaign summary), `_campaign-decision-log.md` (append-only rationale), all under `{campaignWorkspacePath}`; `SKF_CAMPAIGN_RESULT_JSON` (headless envelope) |
109
106
 
110
107
  ## Contracts
111
108
 
112
- Exit codes, the HARD-HALT error envelope, the read-backup-modify-write **State Contract**, the headless success envelope, and per-step progress events live in `references/campaign-contracts.md` — consult it when you HALT, mutate state, or emit headless output.
109
+ Exit codes, the HARD-HALT error envelope, the **State Contract** (`scripts/campaign-state.py`), the decision log and per-step progress events live in `references/campaign-contracts.md`: consult it when you HALT, write state, or log. The envelope's one definition is `shared/scripts/schemas/skf-campaign-result-envelope.v1.json`; step-11 emits its success line.
113
110
 
114
111
  ## Mode Routing
115
112
 
116
113
  On invocation:
117
114
 
118
- 1. **`campaign resume [--from=<skill>]`** — load `references/step-resume.md` (validates state, recovers from backup, chains to the right stage). `--from=<skill>` overrides the resume point to the named skill.
119
- 2. **`campaign`** (new, no existing state) — run from stage 0 (Setup).
120
- 3. **`campaign`** (state exists) — detect existing `{campaignWorkspacePath}/_campaign-state.yaml` and prompt **resume** (via `references/step-resume.md`) or **overwrite**. On overwrite, first archive the existing `_campaign-state.yaml` and `campaign-brief.yaml` to `{campaignWorkspacePath}/archive/{name}-{timestamp}/` and log it before chaining to step-01. In headless mode, default to **resume** (never silently clobber); archive-and-overwrite only when `--brief`/`--manifest` explicitly seeds a new campaign.
121
- 4. **`campaign status`** (read-only) — load `{campaignWorkspacePath}/_campaign-state.yaml`, validate it via `campaign-validate-state.py`, then run `uv run scripts/campaign-status.py --state-file {campaignWorkspacePath}/_campaign-state.yaml` and display its summary (campaign name, current stage, completed-vs-total, per-status counts) followed by the last ~15 lines of `{campaignWorkspacePath}/_campaign-decision-log.md` for the recent decision trail, then stop. No backup, no mutation, no chaining. Exit 0 (or 9 if the state is unrecoverable).
115
+ 1. **`campaign resume [--from=<skill>]`**: load `references/step-resume.md` (validates state, recovers from backup, chains to the stage `campaign-state.py resume` computes). `--from=<skill>` overrides the resume point to the named skill.
116
+ 2. **`campaign`** (new, no existing state) to run from stage 0 (Setup).
117
+ 3. **`campaign`** (state exists): when `{campaignWorkspacePath}/_campaign-state.yaml` or its `.bak` exists, prompt **resume** (via `references/step-resume.md`) or **overwrite**. On overwrite, first run `uv run scripts/campaign-state.py archive --state-file {campaignWorkspacePath}/_campaign-state.yaml --brief-file {campaignWorkspacePath}/campaign-brief.yaml`, which moves the state, its `.bak` and the brief into a new folder under `{campaignWorkspacePath}/archive/`, and log the `archive_dir` it returns (type `decision`) before chaining to step-01 (its `init` refuses to overwrite a state or backup). A `--brief` that named the workspace's `campaign-brief.yaml` is then read from `archive_dir`. **GATE [default: resume]**: in headless mode, default to **resume** (never silently clobber); archive-and-overwrite only when `--brief`/`--manifest` explicitly seeds a new campaign.
118
+ 4. **`campaign status`** (read-only): load `{campaignWorkspacePath}/_campaign-state.yaml`, validate it via `campaign-validate-state.py`, then run `uv run scripts/campaign-status.py --state-file {campaignWorkspacePath}/_campaign-state.yaml` and display its summary (campaign name, current stage, completed-vs-total, per-status counts) followed by the last ~15 lines of `{campaignWorkspacePath}/_campaign-decision-log.md` for the recent decision trail, then stop. No backup, no mutation, no chaining. Exit 0 (or 9 if the state is unrecoverable).
@@ -8,7 +8,7 @@
8
8
  "properties": {
9
9
  "campaign": {
10
10
  "type": "object",
11
- "required": ["name", "started_at", "last_updated", "current_stage", "quality_gate", "health_findings_queue"],
11
+ "required": ["name", "started_at", "last_updated", "current_stage", "quality_gate"],
12
12
  "additionalProperties": false,
13
13
  "properties": {
14
14
  "name": {
@@ -48,7 +48,8 @@
48
48
  },
49
49
  "health_findings_queue": {
50
50
  "type": "string",
51
- "enum": ["local", "improvement"]
51
+ "enum": ["local", "improvement"],
52
+ "description": "Ignored. Setup asked for it before v3.0.0; the end-of-run health check now decides where findings go. Kept optional so state files that hold it still validate."
52
53
  },
53
54
  "architecture_doc_path": {
54
55
  "type": ["string", "null"],
@@ -80,11 +81,13 @@
80
81
  "description": "Stage 7 verify-stack summary. Detailed findings live in the external report at report_path.",
81
82
  "properties": {
82
83
  "report_path": {
83
- "type": ["string", "null"]
84
+ "type": ["string", "null"],
85
+ "description": "report_path of the skf-verify-stack result envelope: the timestamped report, which no later run rewrites (not the -latest copy)."
84
86
  },
85
87
  "overall_verdict": {
86
88
  "type": ["string", "null"],
87
- "enum": ["Verified", "Plausible", "Risky", "Blocked", null]
89
+ "enum": ["FEASIBLE", "CONDITIONALLY_FEASIBLE", "NOT_FEASIBLE", null],
90
+ "description": "overall_verdict of the skf-verify-stack result envelope."
88
91
  },
89
92
  "coverage_percentage": {
90
93
  "type": ["number", "null"]
@@ -167,6 +170,24 @@
167
170
  },
168
171
  "commit_sha": {
169
172
  "type": ["string", "null"]
173
+ },
174
+ "export": {
175
+ "type": ["object", "null"],
176
+ "additionalProperties": false,
177
+ "required": ["status"],
178
+ "description": "The Export stage's outcome for this skill, recorded by campaign-state.py set-skill --export after its skf-export-skill call: exported, or failed with that call's halt_reason and exit code (null when it gave none). Absent until Export runs the skill; a reset to pending removes it.",
179
+ "properties": {
180
+ "status": {
181
+ "type": "string",
182
+ "enum": ["exported", "failed"]
183
+ },
184
+ "halt_reason": {
185
+ "type": ["string", "null"]
186
+ },
187
+ "exit_code": {
188
+ "type": ["integer", "null"]
189
+ }
190
+ }
170
191
  }
171
192
  }
172
193
  }
@@ -1,8 +1,8 @@
1
1
  # DO NOT EDIT -- overwritten on every update.
2
2
  #
3
3
  # Workflow customization surface for skf-campaign.
4
- # Team overrides: _bmad/custom/skf-campaign.toml (under {project-root})
5
- # Personal overrides: _bmad/custom/skf-campaign.user.toml (under {project-root})
4
+ # Team overrides: {project-root}/_bmad/custom/skf-campaign.toml
5
+ # Personal overrides: {project-root}/_bmad/custom/skf-campaign.user.toml
6
6
 
7
7
  [workflow]
8
8
 
@@ -10,15 +10,18 @@
10
10
  # scalars: override wins • arrays (persistent_facts, activation_steps_*): append
11
11
  # arrays-of-tables with `code`/`id`: replace matching items, append new ones.
12
12
 
13
- # Steps to run before the standard activation (config load, customization
14
- # resolve). Overrides append. Use for org-wide pre-flight checks (auth,
15
- # network, compliance) that must precede any orchestration work.
13
+ # Steps to run right after the customization resolve (On Activation step 3).
14
+ # Config and preferences are already loaded by then, so a step here can read
15
+ # them but cannot run before them. Overrides append. Use for org-wide
16
+ # pre-flight checks (auth, network, compliance) that must precede any
17
+ # orchestration work.
16
18
 
17
19
  activation_steps_prepend = []
18
20
 
19
- # Steps to run after activation but before the first stage executes.
20
- # Overrides append. Use for context loads or banner customization that
21
- # should run once activation completes successfully.
21
+ # Steps to run once activation is complete, the CLI overrides included (so
22
+ # headless mode already reflects --brief and --manifest), just before the
23
+ # first stage executes. Overrides append. Use for context loads or banner
24
+ # customization.
22
25
 
23
26
  activation_steps_append = []
24
27
 
@@ -27,11 +30,21 @@ activation_steps_append = []
27
30
  # into every per-skill kickoff, so project-scoped house facts propagate to
28
31
  # the whole campaign. Overrides append.
29
32
  #
30
- # Each entry is either:
33
+ # Each entry is one of:
31
34
  # - a literal sentence, e.g. "All skills must cite their upstream source."
32
35
  # - a file reference prefixed with `file:`, e.g.
33
36
  # "file:{project-root}/docs/skill-style.md" (globs supported; file
34
37
  # contents are loaded and treated as facts).
38
+ # - an entry prefixed with `!`, which loads nothing and drops each earlier
39
+ # entry it names.
40
+ #
41
+ # The kickoff script expands each `file:` entry when it renders a Tier A
42
+ # kickoff (a `**` glob recursively, so the default below takes every
43
+ # project-context.md under {project-root}) and inlines each matching file in
44
+ # full into every kickoff. Overrides append, and the script drops a `!`
45
+ # entry and each earlier entry it names, so to keep those files out of every
46
+ # Tier A kickoff, set in {project-root}/_bmad/custom/skf-campaign.toml:
47
+ # persistent_facts = ["!file:{project-root}/**/project-context.md"]
35
48
 
36
49
  persistent_facts = [
37
50
  "file:{project-root}/**/project-context.md",
@@ -49,10 +62,25 @@ campaign_workspace_path = ""
49
62
 
50
63
  # --- Quality gate ---
51
64
  #
52
- # Campaign-wide quality bar applied to every skill. Scalars override the
53
- # bundled defaults; the per-campaign brief and any directive `## Quality
54
- # Overrides` still take precedence at runtime. Override here to change the
55
- # org-wide default without forking the skill.
65
+ # Campaign-wide quality bar, enforced on every skill. Precedence, highest
66
+ # first: the directive's `## Quality Overrides` (while the campaign runs),
67
+ # then the `quality_gate` of the campaign-brief.yaml Setup reads (from
68
+ # --brief or its opening question, field by field), then these values.
69
+ # Override here to change the org-wide default without forking the skill.
70
+ #
71
+ # quality_gate_hard: `zero-critical-high` is the only accepted value (Setup
72
+ # halts on any other). It passes a skill only when its test-skill run finds
73
+ # no Critical or High gap. A missing export is a Medium gap: it lowers the
74
+ # coverage score and no longer counts against this gate.
75
+ #
76
+ # quality_gate_soft_target: every Tier A test run gets it as `--threshold`,
77
+ # and a completed skill scoring at or above it exports as `pass`.
78
+ # quality_gate_soft_fallback: a completed skill scoring below the target but
79
+ # at or above this exports as `fallback`; one below it, or with no score, is
80
+ # listed at Export and not exported. test-skill fails a Tier A skill below
81
+ # its threshold unless it scores at least 80 (its threshold fallback), so a
82
+ # soft_fallback below 80 only matters for Tier B skills, checked by their
83
+ # quick-skill (skill-check) score, or for a soft_target below 80.
56
84
 
57
85
  quality_gate_hard = "zero-critical-high"
58
86
  quality_gate_soft_target = 90
@@ -68,8 +96,11 @@ report_template_path = ""
68
96
  kickoff_template_path = ""
69
97
  brief_template_path = ""
70
98
 
71
- # Optional post-completion hook. When non-empty, the workflow invokes:
99
+ # Optional post-completion hook. When non-empty, step-11 invokes it once
100
+ # the campaign is finished: after the report and the final state write
101
+ # (current_stage 10), before the headless result envelope:
72
102
  # <on_complete> --report-path=<path-to-campaign-report.md>
73
- # after the campaign report is finalized (step-11). Failures are logged to
74
- # the decision log but never fail the campaign. Empty = no-op.
103
+ # --report-path is passed only when the report was written; a report that
104
+ # could not be generated leaves the hook called without it. Failures are
105
+ # logged to the decision log but never fail the campaign. Empty = no-op.
75
106
  on_complete = ""