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
@@ -1,24 +1,29 @@
1
1
  #!/usr/bin/env python3
2
2
  # /// script
3
- # requires-python = ">=3.10"
3
+ # requires-python = ">=3.11"
4
4
  # dependencies = []
5
5
  # ///
6
6
  """Deterministic numerator ground-truth verifier.
7
7
 
8
- Grep-and-count helper for the SKF test-skill workflow (coverage-check.md §4b
9
- "Numerator ground-truth"). It fires only on the inflation signature
10
- (`stats.exports_documented == effective_denominator` exactly): the numerator
11
- equals the denominator, the tell of a documented count padded to force 100%
12
- coverage. On that signature the declared count is not trusted — every declared
13
- export name is greped against the skill's documentation surface and only the
14
- names that actually appear count toward coverage.
15
-
16
- Distinct from reconcile-coverage.py (whose scalar/stack branches grep the §1
17
- inventory names and return only a residual missing *count*): this script greps
18
- the full declared metadata/provenance set and enumerates the *absent* names so
19
- §4b can list them in a High-severity gap. Both scripts share the same grep
20
- semantics (SKILL.md ∪ sorted references/*.md, UTF-8, case-sensitive substring
21
- containment — mirroring `grep "{name}"`) so their numerators agree.
8
+ Lookup-and-count helper for the SKF test-skill workflow (coverage-check.md
9
+ §2b, its "Numerator ground truth" paragraph; §4b records the gap). It fires
10
+ only on the inflation signature
11
+ (`stats.exports_documented == effective_denominator` exactly, or, for a
12
+ provenance map with no `::` entry, its distinct entry names number
13
+ `effective_denominator`): the numerator equals the denominator, the tell of a
14
+ documented count padded to force 100% coverage. On that signature the declared
15
+ count is not trusted: every declared export name is looked up in the skill's
16
+ documentation surface and only the names that actually appear count toward
17
+ coverage.
18
+
19
+ Distinct from reconcile-coverage.py (whose scalar/stack branches look up the §1
20
+ inventory names and return only a residual missing *count*): this script looks
21
+ up the full declared metadata/provenance set and enumerates the *absent* names so
22
+ §4b can list them in a High-severity gap. Both scripts read the same text and
23
+ match names the same way, through validate-inventory.py beside them (SKILL.md ∪
24
+ sorted references/*.md, UTF-8; the name as a fixed string, case-sensitive, never
25
+ inside a longer identifier, so `get` is not found in `target` or `getAll`), so
26
+ their numerators agree.
22
27
 
23
28
  Input schema (one JSON object):
24
29
  {
@@ -26,59 +31,71 @@ Input schema (one JSON object):
26
31
  "skillPackagePath": "/path/to/skill" # SKILL.md ∪ references/*.md
27
32
  }
28
33
 
34
+ or the files: --inputs <coverage-inputs.json> --skill-dir <skill package>.
35
+ --inputs reads load-coverage-inputs.py metadata's output: its `declaredNames`
36
+ and `inflationSignature`. Without the signature there is nothing to verify,
37
+ so the result is `skipped` and `inflated` is false; a caller can run the
38
+ command on every skill.
39
+
29
40
  Output (stdout, one object):
30
41
  {
42
+ "skipped": <bool>, # --inputs only: true when there is no inflation signature
31
43
  "declared": <int>, # de-duplicated declared name count
32
44
  "verified": <int>, # declared names present in the doc surface
33
45
  "present": [names], # sorted
34
- "absent": [names], # sorted (declared − verified) — the gap list
46
+ "absent": [names], # sorted (declared − verified): the gap list
35
47
  "inflated": <bool> # verified < declared (numerator was padded)
36
48
  }
37
49
  or {"error": ..., "code": "INVALID_INPUT"} on a schema violation.
38
50
 
39
- `verified` is the numerator §4b uses for Export Coverage (it overrides the
40
- declared count when `inflated` is true).
51
+ `verified` is the numerator §2c's reconcile-coverage.py call uses (it
52
+ overrides the declared count when `inflated` is true): reconcile-coverage.py
53
+ --verified reads this result. --output also writes it to a file.
41
54
 
42
55
  CLI usage (mirrors reconcile-coverage.py):
56
+ uv run verify-declared-numerator.py --inputs <file> --skill-dir <dir> [--output <file>]
43
57
  uv run verify-declared-numerator.py '<JSON>' # positional
44
58
  uv run verify-declared-numerator.py --json-input '<JSON>' # explicit flag
45
59
  cat input.json | uv run verify-declared-numerator.py --stdin # piped input
46
60
 
47
61
  Exit codes:
48
- 0 — verification emitted successfully
49
- 1 — no input / input could not be parsed as JSON
50
- 2 — input parsed but schema/semantics invalid (error object emitted as JSON)
62
+ 0 verification emitted successfully
63
+ 1 no input, input that does not parse as JSON, or an --inputs file that cannot be read
64
+ 2 input parsed but schema/semantics invalid (error object emitted as JSON)
51
65
  """
52
66
 
53
67
  from __future__ import annotations
54
68
 
55
69
  import argparse
70
+ import importlib.util
56
71
  import json
57
72
  import sys
58
73
  from pathlib import Path
59
74
 
75
+ _INVENTORY_MODULE = None
76
+
77
+
78
+ def _inventory():
79
+ """validate-inventory.py beside this script: the name match lives there."""
80
+ global _INVENTORY_MODULE
81
+ if _INVENTORY_MODULE is None:
82
+ sibling = Path(__file__).resolve().parent / "validate-inventory.py"
83
+ spec = importlib.util.spec_from_file_location("skf_validate_inventory", sibling)
84
+ if spec is None or spec.loader is None or not sibling.is_file():
85
+ raise ImportError(f"validate-inventory.py not found beside {Path(__file__).name}")
86
+ module = importlib.util.module_from_spec(spec)
87
+ spec.loader.exec_module(module)
88
+ _INVENTORY_MODULE = module
89
+ return _INVENTORY_MODULE
90
+
60
91
 
61
92
  def make_error(message):
62
93
  return {"error": message, "code": "INVALID_INPUT"}
63
94
 
64
95
 
65
96
  def load_doc_text(skill_package_path):
66
- """Concatenate SKILL.md ∪ references/*.md text for name-presence grepping.
67
-
68
- Deterministic: references are read in sorted order. Reads as UTF-8 so
69
- non-ASCII exports do not mojibake on Windows (cp1252 default). Mirrors
70
- reconcile-coverage.py.load_doc_text so the two numerators agree.
71
- """
72
- root = Path(skill_package_path)
73
- parts = []
74
- skill_md = root / "SKILL.md"
75
- if skill_md.is_file():
76
- parts.append(skill_md.read_text(encoding="utf-8"))
77
- refs_dir = root / "references"
78
- if refs_dir.is_dir():
79
- for ref in sorted(refs_dir.glob("*.md")):
80
- parts.append(ref.read_text(encoding="utf-8"))
81
- return "\n".join(parts)
97
+ """SKILL.md ∪ references/*.md text, as validate-inventory.py reads it."""
98
+ return _inventory().load_doc_text(skill_package_path)
82
99
 
83
100
 
84
101
  def _validate(inp):
@@ -102,8 +119,8 @@ def verify(inp, doc_text=None):
102
119
  if doc_text is None:
103
120
  doc_text = load_doc_text(inp["skillPackagePath"])
104
121
 
105
- present = sorted(n for n in declared_set if n in doc_text)
106
- absent = sorted(n for n in declared_set if n not in doc_text)
122
+ present = _inventory().names_present(declared_set, doc_text)
123
+ absent = sorted(set(declared_set) - set(present))
107
124
 
108
125
  return {
109
126
  "declared": len(declared_set),
@@ -122,7 +139,7 @@ def _build_parser():
122
139
  prog="verify-declared-numerator",
123
140
  description=(
124
141
  "Deterministic numerator ground-truth verifier (coverage-check.md "
125
- "§4b). Greps the full declared export set against SKILL.md ∪ "
142
+ "§2b). Greps the full declared export set against SKILL.md ∪ "
126
143
  "references/*.md and enumerates the present/absent names so a padded "
127
144
  "numerator is caught and the verified count replaces it."
128
145
  ),
@@ -150,9 +167,32 @@ def _build_parser():
150
167
  action="store_true",
151
168
  help="Read the JSON object from stdin.",
152
169
  )
170
+ src.add_argument(
171
+ "--inputs",
172
+ metavar="PATH",
173
+ help="load-coverage-inputs.py metadata output: declaredNames and inflationSignature.",
174
+ )
175
+ parser.add_argument("--skill-dir", metavar="DIR",
176
+ help="the skill package (with --inputs): SKILL.md and references/")
177
+ parser.add_argument("--output", metavar="PATH", help="also write the result to this file")
153
178
  return parser
154
179
 
155
180
 
181
+ def verify_from_inputs(inputs, skill_dir, doc_text=None):
182
+ """Verify the declared set of a load-coverage-inputs.py metadata result."""
183
+ if not isinstance(inputs, dict):
184
+ return make_error("--inputs must hold a JSON object")
185
+ names = inputs.get("declaredNames")
186
+ if inputs.get("inflationSignature") is not True:
187
+ declared = len({n for n in names if isinstance(n, str) and n}) if isinstance(names, list) else 0
188
+ return {"skipped": True, "declared": declared, "verified": None, "present": [], "absent": [],
189
+ "inflated": False}
190
+ result = verify({"declaredNames": names, "skillPackagePath": skill_dir}, doc_text=doc_text)
191
+ if result.get("code") != "INVALID_INPUT":
192
+ result = {"skipped": False, **result}
193
+ return result
194
+
195
+
156
196
  def _resolve_input(args):
157
197
  if args.stdin:
158
198
  return sys.stdin.read()
@@ -163,30 +203,67 @@ def _resolve_input(args):
163
203
  return ""
164
204
 
165
205
 
206
+ def _write_output(path, result):
207
+ target = Path(path)
208
+ if result.get("code") == "INVALID_INPUT":
209
+ target.unlink(missing_ok=True)
210
+ return
211
+ target.parent.mkdir(parents=True, exist_ok=True)
212
+ target.write_bytes((json.dumps(result, indent=2, ensure_ascii=False) + "\n").encode("utf-8"))
213
+
214
+
166
215
  def main(argv=None):
167
216
  parser = _build_parser()
168
217
  args = parser.parse_args(argv)
169
- raw = _resolve_input(args)
170
- if not raw.strip():
171
- parser.print_usage(file=sys.stderr)
172
- print(
173
- "error: no input provided (positional arg, --json-input, or --stdin)",
174
- file=sys.stderr,
175
- )
176
- return 1
177
-
178
- try:
179
- data = json.loads(raw)
180
- except json.JSONDecodeError as exc:
181
- print(json.dumps(make_error(f"Invalid JSON: {exc.msg}"), indent=2))
182
- return 1
183
-
184
- result = verify(data)
218
+ if args.inputs is not None:
219
+ if not args.skill_dir:
220
+ parser.error("--inputs needs --skill-dir")
221
+ try:
222
+ inputs = json.loads(Path(args.inputs).read_bytes().decode("utf-8-sig"))
223
+ except (OSError, UnicodeDecodeError, json.JSONDecodeError) as exc:
224
+ print(f"error: cannot read --inputs {args.inputs}: {exc}", file=sys.stderr)
225
+ return 1
226
+ result = verify_from_inputs(inputs, args.skill_dir)
227
+ else:
228
+ raw = _resolve_input(args)
229
+ if not raw.strip():
230
+ parser.print_usage(file=sys.stderr)
231
+ print(
232
+ "error: no input provided (positional arg, --json-input, --stdin or --inputs)",
233
+ file=sys.stderr,
234
+ )
235
+ return 1
236
+
237
+ try:
238
+ data = json.loads(raw)
239
+ except json.JSONDecodeError as exc:
240
+ print(json.dumps(make_error(f"Invalid JSON: {exc.msg}"), indent=2))
241
+ return 1
242
+
243
+ result = verify(data)
244
+ if args.output:
245
+ _write_output(args.output, result)
185
246
  print(json.dumps(result, indent=2))
186
247
  if isinstance(result, dict) and result.get("code") == "INVALID_INPUT":
187
248
  return 2
188
249
  return 0
189
250
 
190
251
 
252
+ def _force_utf8(*streams) -> None:
253
+ """Reconfigure stdout and stderr to UTF-8, keeping each stream's error handler.
254
+
255
+ A Windows console pipes them as cp1252, which cannot print every character
256
+ of the --help text, so --help would stop with UnicodeEncodeError.
257
+ """
258
+ for stream in streams:
259
+ if hasattr(stream, "reconfigure"):
260
+ errors = getattr(stream, "errors", None)
261
+ if errors is None:
262
+ stream.reconfigure(encoding="utf-8")
263
+ else:
264
+ stream.reconfigure(encoding="utf-8", errors=errors)
265
+
266
+
191
267
  if __name__ == "__main__":
268
+ _force_utf8(sys.stdout, sys.stderr)
192
269
  raise SystemExit(main())
@@ -5,6 +5,7 @@ skillDir: ''
5
5
  runId: ''
6
6
  testMode: ''
7
7
  forgeTier: ''
8
+ hardGate: ''
8
9
  testResult: ''
9
10
  score: ''
10
11
  threshold: ''
@@ -20,22 +21,28 @@ nextWorkflow: ''
20
21
  # Test Report: {{skillName}}
21
22
 
22
23
  <!--
23
- Section order is LOAD-BEARING: step 5 §5 enforces it, step 6 §5 verifies
24
- stepsCompleted against the canonical chain. Do not reorder or delete anchors.
25
-
26
- Anchor / Step mapping:
27
- Test Summary → detect-mode
28
- Coverage Analysis → coverage-check
29
- Coherence Analysis → coherence-check
30
- External Validation→ external-validators
31
- (hard gate) → step-hard-gate (reads findings, blocks or passes; no report section)
32
- Completeness Score → score
33
- Gap Report → report (includes Discovery Quality subsection)
24
+ Each stage writes its section in place of the heading below that it owns and
25
+ the placeholder comment under that heading, so every heading occurs once.
26
+ Before the result files are written, report.md §4c checks that each heading
27
+ occurs exactly once and that no placeholder comment is left: a stage that
28
+ skipped its section stops the run there. Do not reorder or delete the
29
+ headings or their placeholder comments.
30
+
31
+ Heading / owning step:
32
+ Test Summary → detect-mode §2
33
+ Coverage Analysis → coverage-check §5
34
+ Coherence Analysis → coherence-check §6
35
+ External Validation → external-validators §5
36
+ (hard gate) → step-hard-gate reads the gap ledger; it writes the
37
+ Completeness Score section only when it blocks the run
38
+ Completeness Score → score §6, or step-hard-gate §3 on a blocked run
39
+ Gap Report → report §4c, rendered from the gap ledger (with the
40
+ Discovery Quality subsection)
34
41
  -->
35
42
 
36
43
  ## Test Summary
37
44
 
38
- <!-- Populated by detect-mode §3 -->
45
+ <!-- Populated by detect-mode §2 -->
39
46
 
40
47
  ## Coverage Analysis
41
48
 
@@ -51,9 +58,8 @@ Anchor / Step mapping:
51
58
 
52
59
  ## Completeness Score
53
60
 
54
- <!-- Populated by score §6 -->
61
+ <!-- Populated by score §6, or by step-hard-gate §3 when the hard gate blocks the run -->
55
62
 
56
63
  ## Gap Report
57
64
 
58
- <!-- Populated by report §3-§4b (includes Discovery Quality subsection) -->
59
-
65
+ <!-- Populated by report §4c from the gap ledger (includes the Discovery Quality subsection) -->
@@ -7,17 +7,18 @@ description: Smart regeneration preserving [MANUAL] sections after source change
7
7
 
8
8
  ## Overview
9
9
 
10
- Surgically updates existing skills when source code changes, preserving all [MANUAL] developer content while re-extracting only affected exports with full provenance tracking. Only changed exports are re-extracted — unchanged content is never touched. Every regenerated instruction must trace to code with file:line citations. Stack skills (`skill_type: "stack"` in metadata.json) are not supported by surgical update — use `skf-create-stack-skill` to re-compose from updated constituents. If a stack skill is provided, this workflow exits with a redirect message.
10
+ Surgically updates existing skills when source code changes, preserving all [MANUAL] developer content while re-extracting only affected exports with full provenance tracking; unchanged content is never touched, and each regenerated instruction cites code by file:line. Stack skills (`skill_type: "stack"` in metadata.json) are not updated here: this workflow redirects them to `skf-create-stack-skill`, which re-composes them from updated constituents.
11
11
 
12
12
  ## Conventions
13
13
 
14
14
  - Bare paths (e.g. `references/<name>.md`) resolve from the skill root.
15
- - **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 — stage files reference `knowledge/version-paths.md` and `knowledge/tool-resolution.md`, and the terminal step chains to `shared/health-check.md`.
16
- - `references/` holds prompt content carved out of SKILL.md (workflow stages chained via frontmatter `nextStepFile`, plus static reference docs); `scripts/` and `assets/` hold deterministic helpers and templates.
15
+ - **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; stage files reference `knowledge/version-paths.md` and `knowledge/tool-resolution.md`, and the terminal step chains to `shared/health-check.md`.
16
+ - **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.
17
+ - `references/` holds the workflow stages, chained by each file's frontmatter `nextStepFile` (init.md §8 loads `gap-driven.md` through `gapDrivenStepFile` instead when `update_mode` is `gap-driven`), the [MANUAL] rules file merge.md loads, and the invocation contract; `scripts/` holds this skill's own helper.
17
18
  - `{skill-root}` resolves to this skill's installed directory (where `customize.toml` lives, if present).
18
19
  - `{project-root}`-prefixed paths resolve from the project working directory.
19
20
  - `{skill-name}` resolves to the skill directory's basename.
20
- - **Cross-skill data coupling:** stages in this workflow load four shared assets from `skf-create-skill` to keep extraction semantics aligned between create and update — `re-extract.md` pulls `extraction-patterns.md`, `extraction-patterns-tracing.md`, and `tier-degradation-rules.md` from `skf-create-skill/references/`; `remote-source-resolution.md` references `source-resolution-protocols.md`; `write.md` reads `skill-sections.md` from `skf-create-skill/assets/`. Update-skill assumes these files are present at install time and that their semantics are stable across the two skills' versions.
21
+ - **Cross-skill data coupling:** stages load shared assets from `skf-create-skill`, so create and update extract alike: `re-extract.md` pulls `extraction-patterns.md`, `extraction-patterns-tracing.md` and `tier-degradation-rules.md` from `skf-create-skill/references/`, `detect-changes.md` pulls `extraction-patterns.md`, and `gap-driven.md` pulls `extraction-patterns.md` and `tier-degradation-rules.md`; `init.md` §6c reads the version files the Version Reconciliation section of `skf-create-skill/references/source-resolution-protocols.md` lists, and `skf-source-tree.py` (init.md §6b) computes a remote skill's clone path with its workspace rule; `write.md` reads `skill-sections.md` from `skf-create-skill/assets/`, and `extraction-patterns.md` and, for §2's by-hand public API count, `entry-points-by-hand.md` from `skf-create-skill/references/`.
21
22
 
22
23
  ## Role
23
24
 
@@ -32,30 +33,26 @@ These rules apply to every step in this workflow:
32
33
  - Only load one step file at a time — never preload future steps
33
34
  - Always communicate in `{communication_language}`
34
35
  - If `{headless_mode}` is true, auto-proceed through confirmation gates with their default action and log each auto-decision
36
+ - Every HALT, ABORT or other exit before step 7 runs the **Halt procedure** of the step file it fires in: one `{runStateHelper}` `halt` call that undoes this run's writes, removes the private source tree, releases the run lock and, headless, prints the halt's line. A halt never falls through to step 6.
37
+ - While `{source_tree}` is bound, a step that finds `{source_root}` missing HALTs with status `blocked` (`error.phase` `<step>:source-tree-missing`) instead of reading its files as deleted.
38
+ - **Run log.** Warnings and gate decisions live in the run folder, never only in context: a step records each warning the moment it raises it, and each gate its decision, with the `record` call that step names.
35
39
 
36
40
  ## Stages
37
41
 
38
42
  | # | Step | File | Auto-proceed |
39
43
  |---|------|------|--------------|
40
44
  | 1 | Initialize & Load | references/init.md | No (confirm) |
41
- | 2 | Detect Changes | references/detect-changes.md | Yes |
45
+ | 2 | Detect Changes | references/detect-changes.md | Conditional (§1b, §1c and §2.2 ask when triggered) |
46
+ | 2g | Gap-Driven Repair (only when `update_mode` is gap-driven: in place of steps 2 and 3) | references/gap-driven.md | Conditional (§1 rule R1 asks [D]/[R] when a gap's remediation names removal) |
42
47
  | 3 | Re-Extract | references/re-extract.md | Yes |
43
- | 4 | Merge | references/merge.md | Yes |
44
- | 5 | Validate | references/validate.md | Yes |
45
- | 6 | Write | references/write.md | Yes |
46
- | 7 | Report | references/report.md | Yes |
47
- | 8 | Workflow Health Check | references/health-check.md | Yes |
48
+ | 4 | Merge | references/merge.md | Conditional ([C] after resolved [MANUAL] conflicts) |
49
+ | 5 | Write | references/write.md | Yes |
50
+ | 6 | Report | references/report.md | Yes |
51
+ | 7 | Workflow Health Check | references/health-check.md | Yes |
48
52
 
49
53
  ## Invocation Contract
50
54
 
51
- | Aspect | Detail |
52
- |--------|--------|
53
- | **Inputs** | skill_name [required] |
54
- | **Flags** | `--headless` / `-H` (auto-resolve all gates); `--from-test-report` (gap-driven mode); `--allow-workspace-drift` (gap-driven only — bypass §0.a pinning guard); `--allow-degraded` (headless only — pre-authorize the lossy degraded full re-extraction when the provenance map is missing, instead of halting `blocked`; init.md §4); `--detect-only` (run detect-changes only, exit before re-extract; envelope `status="detect-only"`); `--dry-run` (run detect-changes + re-extract, exit before merge/write; envelope `status="dry-run"` describes what would change). If both `--detect-only` and `--dry-run` are passed, `--detect-only` wins. |
55
- | **Gates** | step 1: Confirm Gate [C] | step 4: Confirm Gate [C if clean merge, HALT if conflicts] |
56
- | **Outputs** | Updated SKILL.md, metadata.json, provenance-map.json, evidence-report.md (none when `--detect-only` or `--dry-run` is set — those modes are read-only inspection paths) |
57
- | **Concurrency** | Two simultaneous real-update runs against the same skill would corrupt provenance. init.md §1b acquires a PID-file lock at `{forge_data_folder}/{skill_name}/.skf-update.lock` before any artifact read; live-PID collisions halt with `status: "halted-for-concurrent-run"`. Stale locks (dead PID) are cleared silently with a warning. The lock is released by the terminal health-check step (step 8) on the normal path and by the two init-stage headless halts (§4/§6); mid-workflow halts leave it for the next run's stale-lock self-heal (see init.md §1b Release contract). Read-only modes (`--detect-only`, `--dry-run`) skip the lock entirely — they're safe alongside a concurrent real update. |
58
- | **Headless** | All gates auto-resolve with default action when `{headless_mode}` is true. Each auto-resolved gate appends a `{gate, default_action, taken_action, reason, evidence?}` entry to `headless_decisions[]`, surfaced in step 7's `SKF_UPDATE_RESULT_JSON` envelope so non-interactive runs can be audited post-hoc. A HALT reached in headless mode emits its own `SKF_UPDATE_RESULT_JSON` at the halt site (the site's `status` code plus an `error: {phase, path?, reason}` object) and exits — halts do not fall through to step 7. Pipeline branches on the envelope's top-level `status` field (`success`, `no-changes`, `detect-only`, `dry-run`, or one of the documented `halted-for-*`/`blocked` codes). The first four are successful exits — pipelines treating non-success as failure must include them in the success set. The status enum is defined once in `src/shared/scripts/schemas/skf-update-result-envelope.v1.json`. |
55
+ Headless callers: the inputs, flags, gate map, outputs and the `SKF_UPDATE_RESULT_JSON` line live in `references/invocation-contract.md`. Interactive runs do not need it.
59
56
 
60
57
  ## On Activation
61
58
 
@@ -63,17 +60,33 @@ These rules apply to every step in this workflow:
63
60
  - `project_name`, `output_folder`, `user_name`, `communication_language`, `document_output_language`
64
61
  - `skills_output_folder`, `forge_data_folder`, `sidecar_path`
65
62
 
66
- 2. **Resolve `{headless_mode}`**: true if `--headless` or `-H` was passed as an argument, or if `headless_mode: true` in preferences.yaml. Default: false.
63
+ 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. Bind `{requested_skill}` ← the skill name or folder path the invocation passes (its argument that is neither a flag nor a flag's value), else empty: `references/init.md` §1 takes it as the skill without asking.
67
64
 
68
- 3. **Resolve workflow customization.** Run:
65
+ 3. **Resolve the shared helpers and create the run folder**, before anything can halt. Resolve `{emitEnvelopeHelper}` ← the first that exists of `{project-root}/_bmad/skf/shared/scripts/skf-emit-result-envelope.py` and `{project-root}/src/shared/scripts/skf-emit-result-envelope.py`.
66
+ Resolve `{runStateHelper}` ← the first that exists of `{project-root}/_bmad/skf/shared/scripts/skf-update-run-state.py` and `{project-root}/src/shared/scripts/skf-update-run-state.py`. Then, from `{project-root}`, run:
69
67
 
70
68
  ```bash
71
- python3 {project-root}/_bmad/scripts/resolve_customization.py \
72
- --skill {skill-root} --key workflow
69
+ mkdir -p "{project-root}/_bmad-output/.skf-run" && mktemp -d "{project-root}/_bmad-output/.skf-run/skf-update-skill-XXXXXXXX"
73
70
  ```
74
71
 
75
- This merges the three layers per `bmad-customize` rules (scalars override, arrays append): `{skill-root}/customize.toml` (bundled defaults), `_bmad/custom/<skill-name>.toml` under `{project-root}` (team overrides), and `_bmad/custom/<skill-name>.user.toml` under `{project-root}` (personal overrides). If the script is missing or fails, read `{skill-root}/customize.toml` directly.
72
+ Bind `{run_dir}` ← the path it prints and `{run_id}` ← its folder name less `skf-update-skill-`.
76
73
 
77
- Apply the resolved values so no surface is a silent no-op: execute each entry in `workflow.activation_steps_prepend` in order now; treat every entry in `workflow.persistent_facts` as standing context for the whole run (entries prefixed `file:` are paths or globs whose contents load as facts — the bundled default loads any `project-context.md` under `{project-root}`); resolve `{onCompleteCommand}` ← `workflow.on_complete` if non-empty, else empty string, and stash it in workflow context (`references/report.md` §5b invokes it after the result contract is written; empty string = the hook is a no-op). After activation completes, execute each entry in `workflow.activation_steps_append` in order before `init.md` runs.
74
+ If a helper is missing or the folder cannot be created, HALT: display "**SKF cannot start this update:** {the missing helper (re-install SKF), or the command's first stderr line}. Nothing was changed." Headless, when the emitter resolved, print the halt's line with no run folder, from `{project-root}`:
78
75
 
79
- 4. Load, read the full file, and then execute `references/init.md` to begin the workflow.
76
+ ```bash
77
+ uv run {emitEnvelopeHelper} emit-halt --workflow skf-update-skill <<'SKF_JSON'
78
+ {"status": "blocked", "phase": "on-activation:run-folder", "path": "{project-root}/_bmad-output/.skf-run", "reason": "<which helper is missing, or that stderr line>", "skill_name": "unknown", "version": "unknown", "previous_version": "unknown", "update_mode": "normal"}
79
+ SKF_JSON
80
+ ```
81
+
82
+ 4. **Resolve workflow customization.** Run:
83
+
84
+ ```bash
85
+ uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --project-root {project-root} --key workflow
86
+ ```
87
+
88
+ It merges the bundled `{skill-root}/customize.toml` with `{project-root}/_bmad/custom/skf-update-skill.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. Record the warning in the run log at once: write `customization_resolver_unavailable: <reason>` to `{run_dir}/resolver-warning.txt` with a file write (a resolver error can hold quotes or `$( )`, so never echo it or type it into an argument), then run `uv run {emitEnvelopeHelper} record --run-dir "{run_dir}" --warning "$(cat "{run_dir}/resolver-warning.txt")"` from `{project-root}`.
89
+
90
+ Apply the resolved values so no surface is a silent no-op: execute each entry in `workflow.activation_steps_prepend` in order now; treat every entry in `workflow.persistent_facts` as standing context for the whole run (entries prefixed `file:` are paths or globs whose contents load as facts: 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); resolve `{onCompleteCommand}` ← `workflow.on_complete` if non-empty, else empty string, and stash it in workflow context (`references/report.md` §5b runs it after a finished run's result files, never in `--detect-only`, `--dry-run` or a halt; empty = no-op). After activation completes, execute each entry in `workflow.activation_steps_append` in order before `init.md` runs.
91
+
92
+ 5. Load, read the full file, and then execute `references/init.md` to begin the workflow.
@@ -1,8 +1,8 @@
1
1
  # DO NOT EDIT -- overwritten on every update.
2
2
  #
3
3
  # Workflow customization surface for skf-update-skill.
4
- # Team overrides: _bmad/custom/skf-update-skill.toml (under {project-root})
5
- # Personal overrides: _bmad/custom/skf-update-skill.user.toml (under {project-root})
4
+ # Team overrides: {project-root}/_bmad/custom/skf-update-skill.toml
5
+ # Personal overrides: {project-root}/_bmad/custom/skf-update-skill.user.toml
6
6
 
7
7
  [workflow]
8
8
 
@@ -10,15 +10,17 @@
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 (uv probe, config load).
14
- # Overrides append. Use for org-wide pre-flight checks (auth, network,
15
- # compliance) that must precede any skill update work.
13
+ # Steps SKILL.md On Activation step 4 runs once this file resolves: after
14
+ # the config load, the headless flag and the run folder, before
15
+ # activation_steps_append and references/init.md. Overrides append. Use for
16
+ # org-wide pre-flight checks (auth, network, compliance) that must precede
17
+ # any skill update 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 after activation, before references/init.md (the first
22
+ # stage) runs. Overrides append. Use for context loads or banner
23
+ # customization that should run once activation completes successfully.
22
24
 
23
25
  activation_steps_append = []
24
26
 
@@ -26,23 +28,36 @@ activation_steps_append = []
26
28
  # (drift policies, manual-section preservation rules, compliance
27
29
  # guardrails). Overrides append.
28
30
  #
29
- # Each entry is either:
31
+ # Each entry is one of:
30
32
  # - a literal sentence, e.g. "Updates must preserve [MANUAL] sections verbatim."
31
33
  # - a file reference prefixed with `file:`, e.g.
32
34
  # "file:{project-root}/docs/update-policy.md" (globs supported; file
33
35
  # contents are loaded and treated as facts).
36
+ # - an entry prefixed with `!`, which loads nothing and drops each earlier
37
+ # entry it names.
38
+ #
39
+ # The default below loads every project-context.md under {project-root}.
40
+ # Overrides append, so they cannot delete it; to stop loading those files,
41
+ # set in {project-root}/_bmad/custom/skf-update-skill.toml:
42
+ # persistent_facts = ["!file:{project-root}/**/project-context.md"]
34
43
 
35
44
  persistent_facts = [
36
45
  "file:{project-root}/**/project-context.md",
37
46
  ]
38
47
 
39
48
  # Pipeline-integration hook invoked after report.md §5b writes the result
40
- # contract (the per-run record plus update-skill-result-latest.json). The
49
+ # contract (the per-run record plus update-skill-result-latest.json) of a
50
+ # finished run: an update that wrote a version, or a run that found no
51
+ # change (its result files go in the current version's forge folder). The
41
52
  # command is called as:
42
53
  # <on_complete> --result-path=<{forge_version}/update-skill-result-latest.json>
54
+ # It is not called for --detect-only or --dry-run, which write no result
55
+ # file, nor when a run halts.
43
56
  # Useful for Slack notifications, dashboard ingest, CI hooks, or chaining a
44
- # downstream skill (audit, export, test). Failures are logged to the run's
45
- # warnings[] but never fail the workflow.
57
+ # downstream skill (audit, export, test). A failure is reported to the user
58
+ # in one line and never fails the workflow; it does not reach the result
59
+ # files or the SKF_UPDATE_RESULT_JSON line, which are written before the
60
+ # hook runs.
46
61
  #
47
62
  # Empty string = no-op (default).
48
63