bmad-module-skill-forge 2.2.0 → 3.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 (435) 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 +135 -18
  18. package/docs/verifying-a-skill.md +83 -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 +2 -2
  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 +32 -12
  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 +30 -14
  64. package/src/shared/scripts/skf-build-change-manifest.py +2203 -24
  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 +694 -0
  69. package/src/shared/scripts/skf-comention-pairs.py +1333 -123
  70. package/src/shared/scripts/skf-compare-file-hashes.py +1 -1
  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 +3 -2
  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 +1 -1
  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 +4084 -85
  86. package/src/shared/scripts/skf-extraction-inventory.py +746 -0
  87. package/src/shared/scripts/skf-extraction-snapshot.py +539 -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 +444 -203
  92. package/src/shared/scripts/skf-github-fetch.py +365 -0
  93. package/src/shared/scripts/skf-github-probe.py +661 -0
  94. package/src/shared/scripts/skf-hash-content.py +166 -12
  95. package/src/shared/scripts/skf-language-corpora.py +1 -1
  96. package/src/shared/scripts/skf-load-provenance.py +159 -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 +1 -1
  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 +161 -27
  105. package/src/shared/scripts/skf-promote-staged.py +430 -0
  106. package/src/shared/scripts/skf-provenance-gap-dispatch.py +39 -7
  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 +128 -13
  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 +670 -119
  127. package/src/shared/scripts/skf-tessl-review.py +706 -0
  128. package/src/shared/scripts/skf-update-active-symlink.py +5 -5
  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 +4 -1
  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 +2919 -54
  138. package/src/shared/scripts/skf-write-skill-brief.py +367 -19
  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 +27 -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/init.md +148 -210
  168. package/src/skf-audit-skill/references/re-index.md +96 -108
  169. package/src/skf-audit-skill/references/report.md +96 -33
  170. package/src/skf-audit-skill/references/semantic-diff.md +27 -18
  171. package/src/skf-audit-skill/references/severity-classify.md +79 -65
  172. package/src/skf-audit-skill/references/severity-rules.md +15 -6
  173. package/src/skf-audit-skill/references/structural-diff.md +75 -90
  174. package/src/skf-audit-skill/references/upstream-checkout.md +77 -0
  175. package/src/skf-audit-skill/scripts/render-drift-tables.py +685 -0
  176. package/src/skf-brief-skill/SKILL.md +36 -25
  177. package/src/skf-brief-skill/assets/description-voice-examples.md +1 -1
  178. package/src/skf-brief-skill/assets/scope-templates.md +17 -24
  179. package/src/skf-brief-skill/assets/skill-brief-schema.md +29 -15
  180. package/src/skf-brief-skill/customize.toml +48 -20
  181. package/src/skf-brief-skill/references/analyze-target.md +142 -125
  182. package/src/skf-brief-skill/references/confirm-brief.md +10 -8
  183. package/src/skf-brief-skill/references/draft-checkpoint.md +36 -17
  184. package/src/skf-brief-skill/references/gather-intent-ratify.md +68 -0
  185. package/src/skf-brief-skill/references/gather-intent.md +87 -182
  186. package/src/skf-brief-skill/references/headless-args.md +84 -16
  187. package/src/skf-brief-skill/references/health-check.md +1 -1
  188. package/src/skf-brief-skill/references/invocation-contract.md +18 -13
  189. package/src/skf-brief-skill/references/portfolio-similarity-check.md +1 -1
  190. package/src/skf-brief-skill/references/qmd-collection-registration.md +7 -10
  191. package/src/skf-brief-skill/references/scope-definition.md +123 -47
  192. package/src/skf-brief-skill/references/step-auto-brief.md +24 -80
  193. package/src/skf-brief-skill/references/step-auto-validate.md +20 -121
  194. package/src/skf-brief-skill/references/version-resolution.md +3 -2
  195. package/src/skf-brief-skill/references/write-brief.md +66 -57
  196. package/src/skf-campaign/SKILL.md +31 -34
  197. package/src/skf-campaign/assets/campaign-state-schema.json +25 -4
  198. package/src/skf-campaign/customize.toml +47 -16
  199. package/src/skf-campaign/references/campaign-contracts.md +39 -29
  200. package/src/skf-campaign/references/campaign-directive-spec.md +4 -2
  201. package/src/skf-campaign/references/health-check.md +7 -16
  202. package/src/skf-campaign/references/step-01-setup.md +46 -84
  203. package/src/skf-campaign/references/step-02-strategy.md +31 -30
  204. package/src/skf-campaign/references/step-03-pins.md +26 -18
  205. package/src/skf-campaign/references/step-04-provenance.md +24 -23
  206. package/src/skf-campaign/references/step-05-skill-loop.md +67 -48
  207. package/src/skf-campaign/references/step-06-batch.md +41 -34
  208. package/src/skf-campaign/references/step-07-capstone.md +40 -25
  209. package/src/skf-campaign/references/step-08-verify.md +28 -29
  210. package/src/skf-campaign/references/step-09-refine.md +29 -30
  211. package/src/skf-campaign/references/step-10-export.md +48 -36
  212. package/src/skf-campaign/references/step-11-maintenance.md +31 -34
  213. package/src/skf-campaign/references/step-resume.md +37 -68
  214. package/src/skf-campaign/scripts/campaign-deps.py +57 -18
  215. package/src/skf-campaign/scripts/campaign-parse-manifest.py +361 -54
  216. package/src/skf-campaign/scripts/campaign-provenance.py +96 -53
  217. package/src/skf-campaign/scripts/campaign-quality-gate.py +592 -0
  218. package/src/skf-campaign/scripts/campaign-render-batch.py +257 -49
  219. package/src/skf-campaign/scripts/campaign-render-kickoff.py +343 -50
  220. package/src/skf-campaign/scripts/campaign-report.py +204 -37
  221. package/src/skf-campaign/scripts/campaign-state.py +1128 -0
  222. package/src/skf-campaign/scripts/campaign-status.py +10 -74
  223. package/src/skf-campaign/scripts/campaign-validate-pins.py +30 -3
  224. package/src/skf-campaign/scripts/campaign-validate-state.py +34 -4
  225. package/src/skf-campaign/templates/campaign-brief-template.yaml +4 -5
  226. package/src/skf-campaign/templates/campaign-report-template.md +5 -1
  227. package/src/skf-campaign/templates/kickoff-template.md +0 -14
  228. package/src/skf-create-skill/SKILL.md +27 -20
  229. package/src/skf-create-skill/assets/compile-assembly-rules.md +6 -5
  230. package/src/skf-create-skill/assets/skill-sections.md +15 -5
  231. package/src/skf-create-skill/customize.toml +20 -8
  232. package/src/skf-create-skill/references/authoritative-files-protocol.md +41 -42
  233. package/src/skf-create-skill/references/batch-mode.md +81 -0
  234. package/src/skf-create-skill/references/ccc-index-check.md +27 -0
  235. package/src/skf-create-skill/references/compile.md +107 -29
  236. package/src/skf-create-skill/references/component-extraction.md +113 -91
  237. package/src/skf-create-skill/references/enrich.md +41 -23
  238. package/src/skf-create-skill/references/entry-points-by-hand.md +20 -0
  239. package/src/skf-create-skill/references/extract.md +200 -161
  240. package/src/skf-create-skill/references/extraction-patterns-by-hand.md +141 -0
  241. package/src/skf-create-skill/references/extraction-patterns-tracing.md +2 -2
  242. package/src/skf-create-skill/references/extraction-patterns.md +584 -196
  243. package/src/skf-create-skill/references/generate-artifacts.md +145 -93
  244. package/src/skf-create-skill/references/health-check.md +1 -1
  245. package/src/skf-create-skill/references/load-brief.md +53 -36
  246. package/src/skf-create-skill/references/relabel-rule.md +12 -0
  247. package/src/skf-create-skill/references/report.md +28 -59
  248. package/src/skf-create-skill/references/source-resolution-protocols.md +49 -155
  249. package/src/skf-create-skill/references/step-auto-shard.md +20 -93
  250. package/src/skf-create-skill/references/step-doc-rot.md +44 -60
  251. package/src/skf-create-skill/references/step-doc-sources.md +28 -19
  252. package/src/skf-create-skill/references/sub/ccc-discover.md +18 -7
  253. package/src/skf-create-skill/references/sub/fetch-docs.md +106 -59
  254. package/src/skf-create-skill/references/sub/fetch-temporal.md +53 -166
  255. package/src/skf-create-skill/references/tier-degradation-rules.md +18 -9
  256. package/src/skf-create-skill/references/validate.md +173 -99
  257. package/src/skf-create-skill/scripts/scan-doc-rot.py +232 -99
  258. package/src/skf-create-stack-skill/SKILL.md +29 -56
  259. package/src/skf-create-stack-skill/assets/metadata-contract.md +51 -0
  260. package/src/skf-create-stack-skill/assets/provenance-map-schema.md +15 -15
  261. package/src/skf-create-stack-skill/assets/stack-skill-template.md +23 -57
  262. package/src/skf-create-stack-skill/customize.toml +23 -12
  263. package/src/skf-create-stack-skill/references/compile-stack.md +57 -66
  264. package/src/skf-create-stack-skill/references/compose-mode-rules.md +24 -44
  265. package/src/skf-create-stack-skill/references/detect-integrations.md +92 -95
  266. package/src/skf-create-stack-skill/references/detect-manifests.md +46 -71
  267. package/src/skf-create-stack-skill/references/generate-output.md +138 -128
  268. package/src/skf-create-stack-skill/references/init.md +90 -32
  269. package/src/skf-create-stack-skill/references/integration-patterns.md +1 -17
  270. package/src/skf-create-stack-skill/references/invocation-contract.md +34 -0
  271. package/src/skf-create-stack-skill/references/manifest-patterns.md +32 -20
  272. package/src/skf-create-stack-skill/references/parallel-extract.md +112 -38
  273. package/src/skf-create-stack-skill/references/rank-and-confirm.md +57 -75
  274. package/src/skf-create-stack-skill/references/report.md +39 -33
  275. package/src/skf-create-stack-skill/references/validate.md +20 -39
  276. package/src/skf-drop-skill/SKILL.md +28 -51
  277. package/src/skf-drop-skill/customize.toml +44 -30
  278. package/src/skf-drop-skill/references/execute.md +79 -146
  279. package/src/skf-drop-skill/references/invocation-contract.md +64 -0
  280. package/src/skf-drop-skill/references/report.md +46 -30
  281. package/src/skf-drop-skill/references/select.md +118 -124
  282. package/src/skf-drop-skill/scripts/dir-sizes.py +54 -26
  283. package/src/skf-drop-skill/scripts/drop-roster.py +322 -0
  284. package/src/skf-export-skill/SKILL.md +40 -62
  285. package/src/skf-export-skill/assets/managed-section-format.md +14 -50
  286. package/src/skf-export-skill/assets/snippet-format.md +3 -1
  287. package/src/skf-export-skill/customize.toml +42 -13
  288. package/src/skf-export-skill/references/generate-snippet.md +54 -46
  289. package/src/skf-export-skill/references/health-check.md +2 -0
  290. package/src/skf-export-skill/references/invocation-contract.md +15 -0
  291. package/src/skf-export-skill/references/load-skill.md +88 -62
  292. package/src/skf-export-skill/references/manifest-rebuild.md +9 -10
  293. package/src/skf-export-skill/references/multi-skill-mode.md +4 -4
  294. package/src/skf-export-skill/references/orphan-context-detection.md +13 -5
  295. package/src/skf-export-skill/references/orphan-row-detection.md +31 -22
  296. package/src/skf-export-skill/references/package.md +15 -73
  297. package/src/skf-export-skill/references/preflight-snippet-root-probe.md +51 -70
  298. package/src/skf-export-skill/references/result-envelope.md +31 -16
  299. package/src/skf-export-skill/references/summary.md +41 -17
  300. package/src/skf-export-skill/references/token-report.md +4 -12
  301. package/src/skf-export-skill/references/update-context.md +118 -237
  302. package/src/skf-forger/SKILL.md +61 -37
  303. package/src/skf-forger/bmad-skill-manifest.yaml +4 -1
  304. package/src/skf-forger/customize.toml +43 -0
  305. package/src/skf-forger/references/pipeline-mode.md +73 -18
  306. package/src/skf-forger/scripts/forge-status.py +299 -0
  307. package/src/skf-forger/scripts/parse-pipeline.py +322 -54
  308. package/src/skf-forger/scripts/pipeline-gate.py +428 -0
  309. package/src/skf-forger/scripts/pipeline-journal.py +1052 -0
  310. package/src/skf-quick-skill/SKILL.md +54 -53
  311. package/src/skf-quick-skill/assets/skill-template.md +4 -2
  312. package/src/skf-quick-skill/customize.toml +51 -20
  313. package/src/skf-quick-skill/references/batch-mode.md +74 -21
  314. package/src/skf-quick-skill/references/compile.md +30 -31
  315. package/src/skf-quick-skill/references/ecosystem-check.md +7 -57
  316. package/src/skf-quick-skill/references/finalize.md +69 -18
  317. package/src/skf-quick-skill/references/halt-contract.md +41 -29
  318. package/src/skf-quick-skill/references/health-check.md +5 -3
  319. package/src/skf-quick-skill/references/quick-extract.md +114 -45
  320. package/src/skf-quick-skill/references/registry-resolution.md +9 -64
  321. package/src/skf-quick-skill/references/resolve-target.md +116 -66
  322. package/src/skf-quick-skill/references/write-and-validate.md +79 -40
  323. package/src/skf-refine-architecture/SKILL.md +43 -53
  324. package/src/skf-refine-architecture/customize.toml +49 -20
  325. package/src/skf-refine-architecture/references/compile.md +97 -54
  326. package/src/skf-refine-architecture/references/exit-codes.md +30 -0
  327. package/src/skf-refine-architecture/references/finding-storage.md +21 -0
  328. package/src/skf-refine-architecture/references/gap-analysis.md +101 -38
  329. package/src/skf-refine-architecture/references/improvements.md +14 -20
  330. package/src/skf-refine-architecture/references/init.md +98 -57
  331. package/src/skf-refine-architecture/references/issue-detection.md +32 -39
  332. package/src/skf-refine-architecture/references/refinement-rules.md +37 -48
  333. package/src/skf-refine-architecture/references/report.md +65 -54
  334. package/src/skf-refine-architecture/scripts/skf-check-preservation.py +1619 -0
  335. package/src/skf-rename-skill/SKILL.md +19 -54
  336. package/src/skf-rename-skill/customize.toml +32 -26
  337. package/src/skf-rename-skill/references/execute.md +230 -184
  338. package/src/skf-rename-skill/references/exit-codes.md +7 -7
  339. package/src/skf-rename-skill/references/health-check.md +1 -7
  340. package/src/skf-rename-skill/references/invocation-contract.md +25 -0
  341. package/src/skf-rename-skill/references/report.md +63 -52
  342. package/src/skf-rename-skill/references/select.md +197 -115
  343. package/src/skf-rename-skill/scripts/skf-validate-rename-name.py +161 -21
  344. package/src/skf-setup/SKILL.md +26 -26
  345. package/src/skf-setup/customize.toml +14 -10
  346. package/src/skf-setup/references/auto-index.md +50 -63
  347. package/src/skf-setup/references/ccc-index.md +29 -90
  348. package/src/skf-setup/references/detect-and-tier.md +58 -67
  349. package/src/skf-setup/references/health-check.md +2 -0
  350. package/src/skf-setup/references/invocation-contract.md +14 -0
  351. package/src/skf-setup/references/report.md +43 -166
  352. package/src/skf-setup/references/tier-rules.md +5 -5
  353. package/src/skf-setup/references/write-config.md +34 -57
  354. package/src/skf-test-skill/SKILL.md +17 -57
  355. package/src/skf-test-skill/assets/output-section-formats.md +33 -34
  356. package/src/skf-test-skill/customize.toml +27 -13
  357. package/src/skf-test-skill/references/coherence-check.md +134 -62
  358. package/src/skf-test-skill/references/coverage-check-tiers.md +35 -0
  359. package/src/skf-test-skill/references/coverage-check.md +217 -254
  360. package/src/skf-test-skill/references/detect-mode.md +5 -5
  361. package/src/skf-test-skill/references/external-validators.md +94 -82
  362. package/src/skf-test-skill/references/health-check.md +6 -7
  363. package/src/skf-test-skill/references/init.md +163 -88
  364. package/src/skf-test-skill/references/invocation-contract.md +66 -0
  365. package/src/skf-test-skill/references/migration-section-rules.md +5 -2
  366. package/src/skf-test-skill/references/report.md +162 -142
  367. package/src/skf-test-skill/references/score.md +80 -107
  368. package/src/skf-test-skill/references/scoring-rules.md +41 -155
  369. package/src/skf-test-skill/references/source-access-protocol.md +19 -92
  370. package/src/skf-test-skill/references/step-hard-gate.md +51 -33
  371. package/src/skf-test-skill/scripts/aggregate-coherence.py +218 -30
  372. package/src/skf-test-skill/scripts/build-result-context.py +287 -0
  373. package/src/skf-test-skill/scripts/check-metadata-coherence.py +37 -4
  374. package/src/skf-test-skill/scripts/combine-external-scores.py +23 -6
  375. package/src/skf-test-skill/scripts/compute-score.py +223 -45
  376. package/src/skf-test-skill/scripts/gap-ledger.py +1381 -0
  377. package/src/skf-test-skill/scripts/hard-gate.py +203 -0
  378. package/src/skf-test-skill/scripts/load-coverage-inputs.py +760 -0
  379. package/src/skf-test-skill/scripts/locate-export-segments.py +835 -0
  380. package/src/skf-test-skill/scripts/reconcile-coverage.py +273 -79
  381. package/src/skf-test-skill/scripts/score-signatures.py +459 -0
  382. package/src/skf-test-skill/scripts/stage-helper-payload.py +148 -0
  383. package/src/skf-test-skill/scripts/validate-inventory.py +311 -16
  384. package/src/skf-test-skill/scripts/verify-declared-numerator.py +127 -52
  385. package/src/skf-test-skill/templates/test-report-template.md +21 -15
  386. package/src/skf-update-skill/SKILL.md +38 -25
  387. package/src/skf-update-skill/customize.toml +27 -12
  388. package/src/skf-update-skill/references/detect-changes.md +233 -222
  389. package/src/skf-update-skill/references/gap-driven.md +336 -0
  390. package/src/skf-update-skill/references/health-check.md +31 -5
  391. package/src/skf-update-skill/references/init.md +250 -84
  392. package/src/skf-update-skill/references/invocation-contract.md +12 -0
  393. package/src/skf-update-skill/references/manual-section-rules.md +6 -23
  394. package/src/skf-update-skill/references/merge.md +180 -47
  395. package/src/skf-update-skill/references/re-extract.md +53 -262
  396. package/src/skf-update-skill/references/report.md +100 -35
  397. package/src/skf-update-skill/references/write.md +331 -149
  398. package/src/skf-update-skill/scripts/skf-new-file-diff.py +29 -7
  399. package/src/skf-verify-stack/SKILL.md +23 -42
  400. package/src/skf-verify-stack/assets/feasibility-report-template.md +11 -5
  401. package/src/skf-verify-stack/customize.toml +55 -22
  402. package/src/skf-verify-stack/references/coverage-patterns.md +17 -8
  403. package/src/skf-verify-stack/references/coverage.md +67 -64
  404. package/src/skf-verify-stack/references/exit-codes.md +21 -8
  405. package/src/skf-verify-stack/references/init.md +107 -62
  406. package/src/skf-verify-stack/references/integration-verification-rules.md +12 -13
  407. package/src/skf-verify-stack/references/integrations.md +106 -65
  408. package/src/skf-verify-stack/references/report.md +59 -42
  409. package/src/skf-verify-stack/references/requirements.md +32 -9
  410. package/src/skf-verify-stack/references/synthesize.md +53 -39
  411. package/src/skf-verify-stack/scripts/skf-coverage-tally.py +398 -52
  412. package/src/skf-verify-stack/scripts/skf-previous-report.py +330 -0
  413. package/src/skf-verify-stack/scripts/skf-report-delta.py +453 -49
  414. package/src/skf-verify-stack/scripts/skf-verdict-rollup.py +240 -27
  415. package/tools/cli/commands/install.js +11 -4
  416. package/tools/cli/commands/status.js +15 -3
  417. package/tools/cli/commands/update.js +11 -4
  418. package/tools/cli/lib/tool-check.js +320 -0
  419. package/tools/cli/lib/version-check.js +22 -9
  420. package/tools/cli/skf-cli.js +4 -1
  421. package/.gitattributes +0 -16
  422. package/.nvmrc +0 -1
  423. package/docs/_internal/RELEASING.md +0 -679
  424. package/release-audits/v1.0.0-launch-audit.md +0 -728
  425. package/src/skf-audit-skill/references/step-doc-drift.md +0 -177
  426. package/src/skf-brief-skill/references/headless-source-authority-detection.md +0 -26
  427. package/src/skf-campaign/manifest.yaml +0 -15
  428. package/src/skf-create-skill/assets/tessl-dismissal-rules.md +0 -106
  429. package/src/skf-create-skill/references/ecosystem-check.md +0 -74
  430. package/src/skf-drop-skill/references/headless-contract.md +0 -18
  431. package/src/skf-update-skill/references/merge-conflict-rules.md +0 -15
  432. package/src/skf-update-skill/references/remote-source-resolution.md +0 -98
  433. package/src/skf-update-skill/references/validate.md +0 -124
  434. package/tools/validate-docs-drift.js +0 -233
  435. package/tools/validate-docs-links.js +0 -665
@@ -1,12 +1,18 @@
1
1
  ---
2
2
  nextStepFile: 'ecosystem-check.md'
3
- registryResolutionData: '{registryResolutionPath}'
3
+ registryResolutionData: 'references/registry-resolution.md'
4
4
  packageResolverProbeOrder:
5
5
  - '{project-root}/_bmad/skf/shared/scripts/skf-resolve-package.py'
6
6
  - '{project-root}/src/shared/scripts/skf-resolve-package.py'
7
+ githubProbeProbeOrder:
8
+ - '{project-root}/_bmad/skf/shared/scripts/skf-github-probe.py'
9
+ - '{project-root}/src/shared/scripts/skf-github-probe.py'
7
10
  detectLanguageProbeOrder:
8
11
  - '{project-root}/_bmad/skf/shared/scripts/skf-detect-language.py'
9
12
  - '{project-root}/src/shared/scripts/skf-detect-language.py'
13
+ skillsModuleProbeOrder:
14
+ - '{project-root}/_bmad/skf/shared/scripts/skf-skills-module.py'
15
+ - '{project-root}/src/shared/scripts/skf-skills-module.py'
10
16
  ---
11
17
 
12
18
  <!-- Config: communicate in {communication_language}. -->
@@ -21,22 +27,23 @@ To accept a GitHub URL or package name from the user, resolve it to a GitHub rep
21
27
 
22
28
  - Focus only on resolving the target to a GitHub repository — do not begin extraction or compilation
23
29
  - If resolution fails, hard halt with actionable guidance
30
+ - A HARD HALT prints, after its envelope, this step's `halt` event when `{headless_mode}` is true. Under `--batch` it ends only this target: then return to `references/batch-mode.md` §3, even when the halt reads as the end of the run (`references/halt-contract.md`).
24
31
 
25
32
  ## Steps
26
33
 
27
34
  ### 1. Accept User Input
28
35
 
29
- **Batch mode:** if `--batch` is active (see SKILL.md "Batch Mode"), the current target was already resolved by On Activation step 5 from the next batch line and placed into the workflow context as `target`, with optional `language_hint` and `scope_hint` per-line modifiers. Skip the prompt below — emit `{"batch":<n>,"target":"<target>","status":"start"}` to stderr and proceed directly to §1b with the batch-supplied values.
36
+ **Batch mode:** under `--batch`, `references/batch-mode.md` §2 set `target`, `language_hint` and `scope_hint` from the next pending batch line and printed its `start` event. Skip the prompt below and proceed directly to §1b with those values.
30
37
 
31
- **Single-target mode** (default):
38
+ **Single-target mode** (default): when the invocation carried a target, take it, with `--language-hint` as `language_hint` and `--scope-hint` as `scope_hint` when they were passed (SKILL.md On Activation step 4), and go on to §1b without the prompt below, in either mode. Otherwise ask:
32
39
 
33
40
  "**Quick Skill — fastest path to a skill.**
34
41
 
35
- Provide a **GitHub URL** or **package name** and I'll resolve it to source and compile a best-effort SKILL.md.
42
+ Provide a **GitHub URL**, a **package name** or its **npm, PyPI or crates.io page** and I'll resolve it to source and compile a best-effort SKILL.md.
36
43
 
37
- **Target:** (GitHub URL or package name)
44
+ **Target:** (GitHub URL, package name or registry page URL)
38
45
 
39
- Examples: `cocoindex`, `@tanstack/query`, `https://github.com/tursodatabase/limbo`, `cognee@0.5.0`
46
+ Examples: `cocoindex`, `@tanstack/react-query`, `requests==2.31.0`, `https://github.com/tursodatabase/limbo`, `cognee@0.5.0`
40
47
 
41
48
  **Optional:**
42
49
  - **Language hint:** (if the repo is multi-language)
@@ -44,60 +51,75 @@ Examples: `cocoindex`, `@tanstack/query`, `https://github.com/tursodatabase/limb
44
51
 
45
52
  Or type `cancel` / `exit` / `:q` / `[X]` to leave without writing anything."
46
53
 
47
- Wait for user input. **Cancel branch** — if the user types `cancel`, `exit`, `:q`, `[X]`, or selects `[X] Cancel and exit`, display `"Cancelled — no files were written."` and HARD HALT with **exit code 6 (user-cancelled)** per the exit-code map in `references/halt-contract.md`. Before exiting, emit the error result contract per `references/halt-contract.md` (`phase: "resolve-target"`, `error.code: "user-cancelled"`, `skill_package: null`). Cancellation here is non-destructive — no files have been written yet.
54
+ Wait for user input. **Cancel branch**: if the user types `cancel`, `exit`, `:q`, `[X]`, or selects `[X] Cancel and exit`, display "Cancelled. No files were written." and HARD HALT with **exit code 6 (user-cancelled)**: stage `{"phase": "resolve-target", "halt_reason": "user-cancelled", "reason": "Cancelled. No files were written.", "skill_package": null}` as `{run_dir}/halt.json` and run `uv run {emitEnvelopeHelper} emit-halt --workflow skf-quick-skill --run-dir "{run_dir}" --target stderr < "{run_dir}/halt.json"` (`references/halt-contract.md`). Cancellation here is non-destructive: no files have been written yet.
48
55
 
49
- **GATE [default: use args]** — If `{headless_mode}` and a target (URL or package name) was provided as argument: use it as the target input and auto-proceed, log: "headless: using provided target". If no target provided in headless mode, HALT with: "headless mode requires a target argument."
56
+ **GATE [default: use args]**: if `{headless_mode}` and a target (URL or package name) was provided as argument, use it as the target input, with the hint flags, and auto-proceed, log: "headless: using provided target". If no target was provided in headless mode, HARD HALT with **exit code 2 (input-invalid)**: "Headless mode requires a target argument." Stage `{"phase": "resolve-target", "halt_reason": "input-invalid", "reason": "Headless mode requires a target argument.", "skill_package": null}` as `{run_dir}/halt.json` and run `uv run {emitEnvelopeHelper} emit-halt --workflow skf-quick-skill --run-dir "{run_dir}" --target stderr < "{run_dir}/halt.json"`.
50
57
 
51
- ### 1b. Parse Version Targeting
58
+ ### 1b. Parse the Target
52
59
 
53
- **Version targeting:** If the user input contains `@` followed by a semver-like string (e.g., `cognee@0.5.0`, `https://github.com/org/repo@2.1.0-beta`), parse it as:
54
- - **Package/URL:** everything before the last `@`
55
- - **Target version:** everything after the last `@`
60
+ **Resolve `{packageResolver}`** from `{packageResolverProbeOrder}`; first existing path wins. If no candidate exists, or a call to it prints no JSON on stdout, HARD HALT with **exit code 3 (resolution-failure)**, in interactive mode too: "**The package resolver could not run.** {the call's first stderr line, or with no candidate: SKF's package resolver (`skf-resolve-package.py`) is missing from `{project-root}/_bmad/skf/shared/scripts/`, so re-install SKF.}" Stage `{"phase": "resolve-target", "halt_reason": "resolution-failure", "reason": "The package resolver could not run.", "skill_package": null, "details": {"cause": "<package-resolver-missing, or package-resolver-error after a call that printed no JSON>"}}` as `{run_dir}/halt.json` and run `uv run {emitEnvelopeHelper} emit-halt --workflow skf-quick-skill --run-dir "{run_dir}" --target stderr < "{run_dir}/halt.json"`.
56
61
 
57
- Store the target version as `target_version` in the extraction context. When present, this version overrides auto-detection (same behavior as `target_version` in the skill-brief schema).
62
+ Parse the target. Write it exactly as given on the line between the two markers: the quoted marker hands it to the parser unchanged, quotes, backticks and `$` included.
58
63
 
59
- If no `@version` suffix is present, proceed as today — version will be auto-detected.
60
-
61
- ### 2. Classify Input Type
64
+ ```bash
65
+ uv run {packageResolver} parse-target <<'SKF_TARGET'
66
+ {target}
67
+ SKF_TARGET
68
+ ```
62
69
 
63
- **If input starts with `https://github.com/` or `github.com/`:**
64
- - Extract org/repo from URL
65
- - Set `resolved_url` to the GitHub URL
66
- - Set `repo_name` to the repo name (last path segment)
67
- - Skip to step 3a (Verify Target Version Tag), then step 4 (Detect Language)
70
+ When the parser's `target_version` is not `null`, store it as `target_version` in the extraction context. A `target_version` overrides auto-detection. A `dist_tag` (an npm dist-tag such as `latest` or `canary`) pins no version: log "`{dist_tag}` pins no version; auto-detecting it". Without a `target_version`, the version is auto-detected.
68
71
 
69
- **If input is a package-name-like token** (no whitespace, matches `[@a-zA-Z0-9._/-]+(@<semver>)?`, e.g. `lodash`, `@scope/name`, `requests==2.31`, `cognee@0.5.0`):
70
- - Proceed to step 3 (Registry Resolution)
72
+ ### 2. Route by Kind
71
73
 
72
- **Otherwise — input looks like free-form prose, not a target:**
74
+ - **`github`**: set `resolved_url` ← `url`, `owner` ← `owner`, `repo` ← `repo` and `repo_name` ← `skill_name`, the name the skill is written under. A `/tree/<ref>/<folder>` URL also gives `ref` and `subdir`: set `source_ref` ← `ref`, and `scope_hint` ← `subdir` when no scope hint was given. Skip to §3a (Verify Target Version Tag), then §4 (Detect Language).
75
+ - **`package`** or **`registry-page`**: proceed to §3 (Registry Resolution) with `package_name`, and with `registry` when it is set.
76
+ - **`other-host`**, **`local-path`** or **`unparsed`**: quick-skill cannot resolve the input to a GitHub repository. Instead of a registry lookup that can only fail, show the redirect for its kind, then, in interactive mode, wait for new input and go back to §1b. Two such inputs still name a package that a web search can place, so they try it first: an `other-host` input written with no scheme, such as the Go module path `go.uber.org/zap` (a Go module proxy serves it, not a registry quick-skill asks), and an `unparsed` Maven coordinate `<group>:<artifact>`, such as `com.google.guava:guava`. Take the input as `package_name` and run the web-search step of §3's `fallthrough` branch; show the redirect only when it finds no GitHub URL.
73
77
 
74
- The user typed something like "I want a skill that helps with onboarding" or "build me a brainstorming workflow" — quick-skill cannot resolve that to a GitHub repository. Instead of falling through to a registry-failure HARD HALT, redirect with a sibling-skill suggestion:
78
+ - **`other-host`**: "**Quick Skill reads GitHub repositories only.** `{url}` is on `{host}`. Paste the project's GitHub URL if it has one, or clone it and run `/skf-brief-skill` on the local clone, then `/skf-create-skill`."
79
+ - **`local-path`**: "**Quick Skill reads GitHub repositories, not local folders.** To make a skill from `{path}`, run `/skf-brief-skill` with that path, then `/skf-create-skill`. Or paste the GitHub URL of its repository."
80
+ - **`unparsed`**: the user typed something like "I want a skill that helps with onboarding" or "build me a brainstorming workflow", or text that is no package name or URL. Redirect with a sibling-skill suggestion:
75
81
 
76
- "**This input looks like a description, not a package or URL.** Quick Skill needs a package name (e.g. `lodash`, `@vercel/og`, `requests`) or a GitHub URL (e.g. `https://github.com/lodash/lodash`).
82
+ "**This input looks like a description, not a package or URL.** Quick Skill needs a package name (e.g. `lodash`, `@vercel/og`, `requests==2.31.0`) or a GitHub URL (e.g. `https://github.com/lodash/lodash`).
77
83
 
78
- If you are describing a skill you want to **create from scratch** rather than compile from existing source:
84
+ If you are describing a skill you want to **create from scratch** rather than compile from existing source:
79
85
 
80
- - Run `/skf-create-skill` with a skill brief — full pipeline with provenance tracking and AST-verified exports
81
- - Or use `bmad-agent-builder` for an interactive skill design session
86
+ - Run `/skf-create-skill` with a skill brief: the full pipeline, with provenance tracking and AST-verified exports
87
+ - Or use `bmad-workflow-builder` (a workflow or utility skill) or `bmad-agent-builder` (an agent) for an interactive skill design session
82
88
 
83
- Otherwise, paste the package name or GitHub URL of the library you want to wrap, and quick-skill will resolve it."
89
+ Otherwise, paste the package name or GitHub URL of the library you want to wrap, and quick-skill will resolve it."
84
90
 
85
- **GATE [default: HALT]** — In headless mode, emit the same redirect message and HALT with **exit code 3 (resolution-failure)** per the exit-code map in `references/halt-contract.md`. Before exiting, emit the error result contract per `references/halt-contract.md` (`phase: "resolve-target"`, `error.code: "resolution-failure"`, `skill_package: null`). Do not attempt registry lookups against prose input; that wastes ~3-4 round trips and produces a less actionable error message than the redirect above.
91
+ **GATE [default: HALT]**: in headless mode, after the web search above when the input qualifies for it, emit the redirect for the kind and HARD HALT with **exit code 3 (resolution-failure)**: stage `{"phase": "resolve-target", "halt_reason": "resolution-failure", "reason": "<the redirect's first sentence>", "skill_package": null, "details": {"kind": "<kind>"}}` as `{run_dir}/halt.json` and run `uv run {emitEnvelopeHelper} emit-halt --workflow skf-quick-skill --run-dir "{run_dir}" --target stderr < "{run_dir}/halt.json"`.
86
92
 
87
93
  ### 3. Registry Resolution
88
94
 
89
- Run the shared resolver against the deterministic registries (npm → PyPI → crates.io). The resolver does the HTTP+JSON+GitHub-URL-extraction work; the LLM only handles the web-search fallback below when needed.
90
-
91
- **Resolve `{packageResolver}`** from `{packageResolverProbeOrder}`; first existing path wins. If no candidate exists, fall back to the LLM walk of {registryResolutionData} for the full chain.
95
+ Run the shared resolver (resolved in §1b), which asks every deterministic registry (npm, PyPI, crates.io):
92
96
 
93
97
  ```bash
94
- python3 {packageResolver} {package_name} --timeout 10
98
+ uv run {packageResolver} resolve {package_name} --timeout 10 [--registry {registry}] [--language "{language_hint}"]
95
99
  ```
96
100
 
97
- The resolver emits JSON with `status` (`"ok"` or `"fallthrough"`), `resolved_url`, `repo_owner`, `repo_name`, `registry_used`, `registries_tried`, and a per-registry `registry_outcomes` map. Exit 0 means ok; exit 1 means fallthrough.
101
+ Pass `--registry` when §2 set `registry`, and `--language` when a language hint was given: a JavaScript, TypeScript, Python or Rust hint makes the resolver ask that language's registry alone. It prints JSON whose `status` is `ok`, `ambiguous` or `fallthrough` (exit 0, 3 or 1).
102
+
103
+ - **On `status: "ok"`**: set, from the JSON, `resolved_url`, `owner` ← `repo_owner`, `repo` ← `repo_name`, `repo_name` ← `skill_name` and `registry_used`; when `source_subdir` is set and no scope hint was given, set `scope_hint` ← `source_subdir`. Proceed to §3a.
104
+ - **On `status: "ambiguous"`**: another registry answered for the name too, so it may belong to two projects. `resolved_url`, from `registry_used`, is the chain's pick (the first registry, in the order npm, PyPI, crates.io, that gives a GitHub repository), and `also_found_in` lists every other registry that answered. Run the ambiguous-name gate below.
105
+ - **On `status: "fallthrough"`**: no registry gave a GitHub URL. Load {registryResolutionData} and run its web search for `{package_name}`. If found, take that URL as the target and go back to §1b. If web search also returns nothing, HARD HALT below.
106
+
107
+ **Ambiguous-name gate** (on `status: "ambiguous"` only). Offer every candidate: the pick first, then each `also_found_in` entry that has a `resolved_url`, numbered on from 2. `{others}` names each entry without one: `no-github-link` knows the name but gives no GitHub repository, `error` could not be read.
98
108
 
99
- - **On `status: "ok"`** — capture `resolved_url`, `repo_name`, and `registry_used` from the JSON. Proceed to §3a.
100
- - **On `status: "fallthrough"`** — the deterministic chain returned no GitHub URL (every registry replied with 404 / no-github-link / timeout). Fall back to the web-search step from {registryResolutionData} §4: search `"{package_name} github repository"` with a 15s timeout and look for a GitHub URL in the top results. If found, set `resolved_url` and proceed. If web search also returns nothing, HARD HALT below.
109
+ "**`{package_name}` may name more than one project.**
110
+
111
+ 1. {resolved_url}, from `{registry_used}` (the registry chain's pick)
112
+ 2. {the next candidate's `resolved_url`}, from `{its registry}`
113
+
114
+ {others}
115
+
116
+ Select: [C] Continue with 1 · [2] to [n] Use that candidate · [U] Use another GitHub URL · [X] Cancel and exit"
117
+
118
+ - **IF C**: log "user accepted the `{registry_used}` resolution of `{package_name}`" and continue as on `status: "ok"`.
119
+ - **IF 2 to n**: continue as on `status: "ok"` with that candidate's entry: its `resolved_url`, `owner` ← its `repo_owner`, `repo` ← its `repo_name`, `registry_used` ← its `registry`, and `scope_hint` ← its `source_subdir` when set and no scope hint was given (`repo_name` stays the package's `skill_name`).
120
+ - **IF U**: ask for the GitHub URL of the project the user means, take it as the target and go back to §1b.
121
+ - **IF X**: display "Cancelled. No files were written." and HARD HALT with **exit code 6 (user-cancelled)**: stage `{"phase": "resolve-target", "halt_reason": "user-cancelled", "reason": "Cancelled. No files were written.", "skill_package": null}` as `{run_dir}/halt.json` and run `uv run {emitEnvelopeHelper} emit-halt --workflow skf-quick-skill --run-dir "{run_dir}" --target stderr < "{run_dir}/halt.json"`.
122
+ - **GATE [default: C]**: in headless mode, keep the chain's pick and never halt. Record the resolver's `warning` (`also_found_in: ...`) with `uv run {emitEnvelopeHelper} record --run-dir "{run_dir}" --warning "{warning}"`, and the decision: stage `{"gate": "resolve-target.ambiguous-package", "default_action": "C", "taken_action": "C", "reason": "headless: kept the {registry_used} pick"}` as `{run_dir}/decision.json` and run `uv run {emitEnvelopeHelper} record --workflow skf-quick-skill --run-dir "{run_dir}" --decision < "{run_dir}/decision.json"`. Then continue as on `status: "ok"`. To build another candidate headlessly, pass its GitHub URL or a language hint for its registry (`language=` on a batch line).
101
123
 
102
124
  **If all methods fail — HARD HALT (exit code 3, resolution-failure):**
103
125
 
@@ -110,65 +132,91 @@ Check:
110
132
 
111
133
  **Provide the GitHub URL directly to continue.**"
112
134
 
113
- In interactive mode, wait for corrected input and loop back to step 2. In headless mode, emit the error result contract per `references/halt-contract.md` (`phase: "resolve-target"`, `error.code: "resolution-failure"`, `skill_package: null`) and exit 3.
135
+ In interactive mode, wait for corrected input and loop back to §1b. In headless mode, stage `{"phase": "resolve-target", "halt_reason": "resolution-failure", "reason": "Resolution failed. Could not resolve {package_name} to a GitHub repository.", "skill_package": null}` as `{run_dir}/halt.json` and run `uv run {emitEnvelopeHelper} emit-halt --workflow skf-quick-skill --run-dir "{run_dir}" --target stderr < "{run_dir}/halt.json"`.
114
136
 
115
137
  ### 3a. Verify Target Version Tag (when applicable)
116
138
 
117
- Skip this section if `target_version` is null (auto-detect path — version comes from manifest read in step 3).
139
+ Skip this section if `target_version` is null (auto-detect path: the version comes from the manifest read in step 3).
140
+
141
+ When the target carried a version (§1b), verify the tag exists in the resolved repo before extraction. Otherwise step 3 silently reads from the default branch while metadata records the requested version: a quiet provenance bug where the SKILL.md claims version 0.5.0 but the exports actually came from main.
118
142
 
119
- When the user explicitly supplied `@version` in §1b, verify the tag exists in the resolved repo before extraction. Otherwise step 3 silently reads from the default branch while metadata records the requested version — a quiet provenance bug where the SKILL.md claims version 0.5.0 but the exports actually came from main.
143
+ **Resolve `{githubProbe}`** from `{githubProbeProbeOrder}`; first existing path wins. If no candidate exists, halt as when no probe could read the tags (below).
120
144
 
121
- Probe both with-and-without v-prefix (the v-prefix is conventional but not universal across ecosystems):
145
+ List the repository's tags once, looking for every form a tag gives the version: `0.5.0`, `v0.5.0`, or a monorepo package's `<name>@0.5.0`:
122
146
 
123
147
  ```bash
124
- gh api repos/{owner}/{repo}/git/ref/tags/{target_version} --silent \
125
- || gh api repos/{owner}/{repo}/git/ref/tags/v{target_version} --silent
148
+ uv run {githubProbe} tags --repo {owner}/{repo} --version {target_version} --name {package_name or repo_name} --limit 5
126
149
  ```
127
150
 
128
- **If a matching tag is found** — set `source_ref` to the matching ref (with v-prefix when that variant matched). Step-03's ref-aware source reading uses this value to fetch from the tagged commit. Proceed to §4.
151
+ - **`status: "ok"` with `match` set**: set `source_ref` ← `match`, which replaces a `/tree/` URL's ref. Step 3's ref-aware source reading uses this value to fetch from the tagged commit. Proceed to §4.
152
+ - **`status: "ok"` with `match` null**: the listing lacks the tag. HARD HALT with **exit code 3 (resolution-failure)**:
129
153
 
130
- **If no tag matches** — HARD HALT with **exit code 3 (resolution-failure)**:
154
+ "**Tag `{target_version}` not found in `{owner}/{repo}`.**
131
155
 
132
- "**Tag `{target_version}` not found in `{owner}/{repo}`.**
156
+ The version was parsed from your target but no tag of the resolved repository names it. Quick-skill cannot extract from a version with no commit pointer: the result would be sourced from the default branch but labelled `{target_version}` in metadata.
133
157
 
134
- The version was parsed from your `@version` suffix but does not exist as a tag in the resolved repository. Quick-skill cannot extract from a version with no commit pointer — the result would be sourced from the default branch but labelled `{target_version}` in metadata.
158
+ Tags near this version:
159
+ {the probe's `nearest`, else its `tags`, or "(none: the repo has no tags)"}
135
160
 
136
- Recent tags in this repo:
137
- {list top 5 from `gh api repos/{owner}/{repo}/tags --paginate=false`, or "(none — repo has no tags; omit @version to auto-detect from default branch)"}
161
+ Re-run with one of these tags, or omit the version to auto-detect from the default branch."
138
162
 
139
- Re-run with one of these tags, or omit the `@version` suffix to auto-detect from the default branch."
163
+ Stage `{"phase": "resolve-target", "halt_reason": "resolution-failure", "reason": "Tag {target_version} not found in {owner}/{repo}.", "skill_package": null, "details": {"requested_version": "{target_version}", "available_tags": [<the tags shown>]}}` as `{run_dir}/halt.json` and run `uv run {emitEnvelopeHelper} emit-halt --workflow skf-quick-skill --run-dir "{run_dir}" --target stderr < "{run_dir}/halt.json"`.
164
+ - **`status: "unavailable"`, any other exit, or no `{githubProbe}` candidate**: nothing could read the repository's tags, so the tag may exist. Do not report it missing. HARD HALT with **exit code 3 (resolution-failure)**: "**Could not check tag `{target_version}` in `{owner}/{repo}`.** {the probe's `message` (on stderr after another exit), or with no candidate: SKF's GitHub probe (`skf-github-probe.py`) is missing from `{project-root}/_bmad/skf/shared/scripts/`, so re-install SKF.} Re-run once GitHub can be read, or omit the version to auto-detect from the default branch." Stage `{"phase": "resolve-target", "halt_reason": "resolution-failure", "reason": "Could not check tag {target_version} in {owner}/{repo}.", "skill_package": null, "details": {"requested_version": "{target_version}", "cause": "<the probe's cause, probe-error after another exit, or github-probe-missing>"}}` as `{run_dir}/halt.json` and run `uv run {emitEnvelopeHelper} emit-halt --workflow skf-quick-skill --run-dir "{run_dir}" --target stderr < "{run_dir}/halt.json"`.
140
165
 
141
- Before exiting, emit the error result contract per `references/halt-contract.md` (`phase: "resolve-target"`, `error.code: "resolution-failure"`, `error.details: {requested_version: "{target_version}", available_tags: [...top 5]}`, `skill_package: null`). In headless mode, exit immediately; do not loop.
166
+ In headless mode, halt at once on either; do not re-prompt.
142
167
 
143
168
  ### 4. Detect Language
144
169
 
145
- **Resolve `{detectLanguageHelper}`** from `{detectLanguageProbeOrder}`; first existing path wins. If no candidate exists (e.g. Python/`uv` unavailable), fall back to the manifest-priority walk documented in the helper's `--help` — `package.json` → JavaScript/TypeScript (TypeScript when a `tsconfig.json` is also present), `Cargo.toml` → Rust, `pyproject.toml`/`setup.py`/`setup.cfg` → Python, `go.mod` → Go, `pom.xml` → Java, `build.gradle.kts` → Kotlin, `build.gradle` → Kotlin when `src/main/kotlin/` exists else Java, `*.csproj`/`*.sln` → C#, `Gemfile` → Ruby, then extension frequency — applied by hand.
170
+ **List the repository's files once**, at the ref step 3 reads. Resolve `{githubProbe}` from `{githubProbeProbeOrder}` (§3a may have resolved it already); first existing path wins. Write the listing into the run folder, where the language helper below and step 3 read it, so no step lists the tree again and no path list passes through the model:
171
+
172
+ ```bash
173
+ uv run {githubProbe} tree --repo {owner}/{repo} --ref {source_ref or HEAD} > "{run_dir}/tree.json"
174
+ ```
175
+
176
+ The probe reads the tree through gh, and through GitHub's unauthenticated API when gh is missing or logged out, so a public repository needs no login. A `truncated` listing (GitHub cut a very large tree short) is still read.
177
+
178
+ - **`status: "unavailable"`, any other exit, or no `{githubProbe}` candidate**: nothing could list the repository. HARD HALT with **exit code 3 (resolution-failure)**: "**Could not list the files of `{owner}/{repo}`.** {the probe's `message` (on stderr after another exit), or with no candidate: SKF's GitHub probe (`skf-github-probe.py`) is missing from `{project-root}/_bmad/skf/shared/scripts/`, so re-install SKF.}" Stage `{"phase": "resolve-target", "halt_reason": "resolution-failure", "reason": "Could not list the files of {owner}/{repo}.", "skill_package": null, "details": {"ref": "{source_ref or HEAD}", "cause": "<the probe's cause, probe-error after another exit, or github-probe-missing>"}}` as `{run_dir}/halt.json` and run `uv run {emitEnvelopeHelper} emit-halt --workflow skf-quick-skill --run-dir "{run_dir}" --target stderr < "{run_dir}/halt.json"`.
146
179
 
147
180
  Determine primary language:
148
181
 
149
- 1. **User-provided language hint** (overrides detection) — set `language` to the hint and skip straight to §5. The disambiguation gate below does not run.
182
+ 1. **User-provided language hint** (overrides detection): set `language` to the hint and `language_resolution` to `hint`, and skip straight to §5. The disambiguation gate below does not run.
150
183
 
151
- 2. **Delegate the rule walk to `{detectLanguageHelper}`** — it is the single source of truth for the manifest → language rule table (including the `package.json` JS-vs-TS disambiguation); do not restate or re-derive it here. Fetch the repo file listing once (`gh api repos/{owner}/{repo}/git/trees/{source_ref or default branch}?recursive=1`, reading the `path` values), then hand the flat list to the script:
184
+ 2. **Delegate the rule walk to `{detectLanguageHelper}`**, resolved from `{detectLanguageProbeOrder}` (first existing path wins). If no candidate exists, or its call below prints no JSON on stdout, HARD HALT with **exit code 3 (resolution-failure)**: "**Could not detect the language of `{repo_name}`.** {the call's first stderr line, or with no candidate: SKF's language detector (`skf-detect-language.py`) is missing from `{project-root}/_bmad/skf/shared/scripts/`, so re-install SKF.} Re-run with `--language-hint <lang>` (a batch line's `language=`) to skip detection." Stage `{"phase": "resolve-target", "halt_reason": "resolution-failure", "reason": "Could not detect the language of {repo_name}.", "skill_package": null, "details": {"cause": "<detect-language-missing, or detect-language-error after a call that printed no JSON>"}}` as `{run_dir}/halt.json` and run `uv run {emitEnvelopeHelper} emit-halt --workflow skf-quick-skill --run-dir "{run_dir}" --target stderr < "{run_dir}/halt.json"`. The helper reads the listing from the file:
152
185
 
153
186
  ```bash
154
- echo '{"tree": [<flat list of repo-relative file paths>]}' | uv run {detectLanguageHelper}
187
+ uv run {detectLanguageHelper} --tree-file "{run_dir}/tree.json"
155
188
  ```
156
189
 
157
- The script returns `{language, confidence, detection_source, detected_languages}` after walking the deterministic rule table (manifest presence first, then extension-frequency fallback). `detected_languages` is the ordered, deduplicated set of every manifest-level match in priority order, with `detected_languages[0]` equal to the winning `language`.
190
+ The script returns `{language, confidence, detection_source, source_language, detected_languages}`: the manifests nearest the tree's root decide (folder depth, then rule order), never one in a non-core or hidden folder while another exists, and with no manifest at the root the nearest one decides at `medium` confidence. `detected_languages` lists the deciding manifests' languages in that ranking, then the languages of the manifests that never decide, then `source_language` (the language most source files are in) when no manifest sits at the root, with `detected_languages[0]` equal to the winning `language`.
191
+
192
+ 3. **Auto-pick**: set `language` to the returned `language`. If `detected_languages` is empty (the script recognized no manifest and no source extensions: `language` is `"unknown"`), the repository may still ship agent skills written in Markdown alone, which step 3 documents as a skills module. Resolve `{skillsModuleHelper}` from `{skillsModuleProbeOrder}` and ask it:
193
+
194
+ ```bash
195
+ uv run {skillsModuleHelper} sniff --tree-file "{run_dir}/tree.json" [--scope-hint "{scope_hint}"]
196
+ ```
197
+
198
+ Pass `--scope-hint` when `scope_hint` is set, as step 3 does, so both steps classify the same folder.
199
+
200
+ - **`skills_module` is true**: set `language` to `markdown` and `language_resolution` to `detected`, keep `detected_languages` empty, and go on to §5.
201
+ - **Otherwise** (or no `{skillsModuleHelper}` candidate): treat it as a zero-match resolution: show the §3 resolution-failure guidance so the user can supply a language hint or a different target, and in headless mode HARD HALT with **exit code 3 (resolution-failure)**: stage `{"phase": "resolve-target", "halt_reason": "resolution-failure", "reason": "No language found in {repo_name}.", "skill_package": null}` as `{run_dir}/halt.json` and run `uv run {emitEnvelopeHelper} emit-halt --workflow skf-quick-skill --run-dir "{run_dir}" --target stderr < "{run_dir}/halt.json"`.
202
+
203
+ 4. **Multi-language gate** (`len(detected_languages) > 1`): the helper named more than one language (another manifest's, or the source files' language when no manifest sits at the root). Offer every detected language, the helper's pick first:
158
204
 
159
- 3. **Auto-pick** — set `language` to the returned `language`. If `detected_languages` is empty (the script recognized no manifest and no source extensions — `language` is `"unknown"`), treat it as a zero-match resolution and HALT with the step 1 §3 resolution-failure guidance so the user can supply a language hint or a different target.
205
+ "**`{repo_name}` has manifests for multiple languages.**
160
206
 
161
- 4. **Multi-language gate** (`len(detected_languages) > 1`) — the script found manifests for more than one language. Surface the choice rather than silently keeping the first match. Multi-language repos (Python + JS bindings, or monorepos with mixed manifests) otherwise produce a skill for whichever manifest sorts first in priority order, with no signal that the user might have wanted the other one.
207
+ 1. **{language}** (`detected_languages[0]`, the helper's pick)
208
+ 2. {detected_languages[1]}
162
209
 
163
- "**`{repo_name}` has manifests for multiple languages:** {detected_languages}.
210
+ {and so on, one numbered line per entry of `detected_languages`}
164
211
 
165
- Primary guess: **{language}** (`detected_languages[0]`, manifest-priority order). If you wanted a different language, abort and re-run with `--language-hint <lang>` or with the optional language hint at step 1 §1.
212
+ Select: [C] Continue with 1 · [2] to [n] Use that language · [A] Abort"
166
213
 
167
- Select: [C] Continue with `{language}` · [A] Abort"
214
+ - **IF C**: log "user accepted multi-manifest pick: `{language}`", keep `language` and set `language_resolution: "user-confirmed"`.
215
+ - **IF 2 to n**: set `language` to that entry of `detected_languages`, set `language_resolution: "user-confirmed"` and log "user picked `{language}` of {detected_languages}". `detected_languages` keeps its order.
216
+ - **IF A**: HARD HALT with **exit code 3 (resolution-failure)**: "Aborted to disambiguate language. Re-run with `--language-hint <lang>`." Stage `{"phase": "resolve-target", "halt_reason": "resolution-failure", "reason": "Aborted to disambiguate language.", "skill_package": null, "details": {"detected_languages": [<detected_languages>], "auto_pick": "{language}"}}` as `{run_dir}/halt.json` and run `uv run {emitEnvelopeHelper} emit-halt --workflow skf-quick-skill --run-dir "{run_dir}" --target stderr < "{run_dir}/halt.json"`.
217
+ - **GATE [default: C]**: headless mode auto-proceeds with the helper's pick, sets `language_resolution: "auto-picked-first"`, and records the decision: stage `{"gate": "resolve-target.multi-language", "default_action": "C", "taken_action": "C", "reason": "headless: kept the helper's pick", "evidence": {"detected_languages": [<detected_languages>]}}` as `{run_dir}/decision.json` and run `uv run {emitEnvelopeHelper} record --workflow skf-quick-skill --run-dir "{run_dir}" --decision < "{run_dir}/decision.json"`. To build another of the languages headlessly, pass `--language-hint` (a batch line's `language=`).
168
218
 
169
- - **IF C** — log "user accepted multi-manifest pick: `{language}`" and keep `language`.
170
- - **IF A** — HARD HALT with **exit code 3 (resolution-failure)**: "Aborted to disambiguate language. Re-run with a `language_hint`." Before exiting, emit the error result contract per `references/halt-contract.md` (`phase: "resolve-target"`, `error.code: "resolution-failure"`, `error.details: {detected_languages: [...], auto_pick: "{language}"}`, `skill_package: null`).
171
- - **GATE [default: C]** — Headless mode auto-proceeds with the manifest-priority pick; record `detected_languages` and `language_resolution: "auto-picked-first"` in the extraction context so the result contract surfaces the ambiguity downstream.
219
+ Keep `language_resolution` and `detected_languages` (the helper's list, empty when a hint set the language) for step 6 §3's summary: `language_resolution` is `hint` when a language hint set the language, `detected` when the helper found no second manifest language (or the listing is a skills module with no code), and the gate's `user-confirmed` or `auto-picked-first` otherwise.
172
220
 
173
221
  ### 5. Confirm Resolution
174
222
 
@@ -176,6 +224,8 @@ Determine primary language:
176
224
 
177
225
  - **Repository:** {resolved_url}
178
226
  - **Name:** {repo_name}
227
+ - **Registry:** {registry_used} (omit this line when no registry resolved the target)
228
+ - **Ref:** {source_ref} (omit this line when `source_ref` is not set)
179
229
  - **Language:** {language}
180
230
  - **Scope:** {scope_hint or 'entire repo'}
181
231
 
@@ -183,5 +233,5 @@ Determine primary language:
183
233
 
184
234
  ### 6. Proceed to Next Step
185
235
 
186
- Once the target is resolved to a GitHub repository with confirmed URL, name, and detected language, load and execute {nextStepFile} for the ecosystem check.
236
+ Once the target is resolved to a GitHub repository with confirmed URL, name, and detected language, load and execute {nextStepFile} for the ecosystem check; when `{headless_mode}` is true, print this step's `done` event and step 2's `start` event first (`references/halt-contract.md`).
187
237
 
@@ -6,6 +6,15 @@ frontmatterValidatorProbeOrder:
6
6
  outputValidatorProbeOrder:
7
7
  - '{project-root}/_bmad/skf/shared/scripts/skf-validate-output.py'
8
8
  - '{project-root}/src/shared/scripts/skf-validate-output.py'
9
+ descriptionGuardProbeOrder:
10
+ - '{project-root}/_bmad/skf/shared/scripts/skf-description-guard.py'
11
+ - '{project-root}/src/shared/scripts/skf-description-guard.py'
12
+ skillInventoryProbeOrder:
13
+ - '{project-root}/_bmad/skf/shared/scripts/skf-skill-inventory.py'
14
+ - '{project-root}/src/shared/scripts/skf-skill-inventory.py'
15
+ atomicWriteProbeOrder:
16
+ - '{project-root}/_bmad/skf/shared/scripts/skf-atomic-write.py'
17
+ - '{project-root}/src/shared/scripts/skf-atomic-write.py'
9
18
  ---
10
19
 
11
20
  <!-- Config: communicate in {communication_language}. Generated SKILL.md text in {document_output_language}. -->
@@ -14,44 +23,80 @@ outputValidatorProbeOrder:
14
23
 
15
24
  ## STEP GOAL:
16
25
 
17
- To write the compiled SKILL.md, context-snippet.md, and metadata.json to the versioned skill package, then validate them on disk against the agentskills.io specification at community tier. Writing happens here (before step 6 finalization) because `skill-check` is a file-based CLI — it reads artifacts from disk — so the files must exist before validation runs. Report any gaps or issues. Validation is advisory — issues are reported but do not block the workflow.
26
+ To write the compiled SKILL.md, context-snippet.md, and metadata.json to the versioned skill package, then validate them on disk against the agentskills.io specification at community tier. Validation is advisory: issues are reported but do not block the workflow.
18
27
 
19
28
  ## Rules
20
29
 
21
30
  - Write exactly what was compiled — do not modify content during writing or after validation
22
31
  - Community-tier validation (lighter than official requirements)
32
+ - A HARD HALT prints, after its envelope, this step's `halt` event when `{headless_mode}` is true. Under `--batch` it ends only this target: then return to `references/batch-mode.md` §3, even when the halt reads as the end of the run (`references/halt-contract.md`).
23
33
 
24
34
  ## Steps
25
35
 
26
- ### 1. Create Output Directory
36
+ ### 1. Check Ownership, Then Create Output Directory
27
37
 
28
- Resolve `{version}` from the extraction inventory's detected version, defaulting to `1.0.0` if not detected. Create the skill output directories:
38
+ Resolve `{version}` ← the `version` of `{run_dir}/metadata.json`, which step 4 §4 rendered: the version the target pinned, else the manifest's, else `1.0.0`. The version folder and the file's `version` are then one value.
39
+
40
+ **Ownership check.** Run it before creating any directory and before the overwrite prompt below. Resolve `{skillInventoryHelper}` ← first existing path in `{skillInventoryProbeOrder}` and run:
41
+
42
+ ```bash
43
+ uv run {skillInventoryHelper} {skills_output_folder} --skill {repo_name} --write-check --write-version {version} --forge-data-folder {forge_data_folder}
44
+ ```
45
+
46
+ `--forge-data-folder` only tells the helper whether both settings name one folder.
47
+
48
+ Bind `{write_verdict}` ← `write_check.verdict`, `{write_folder}` ← `write_check.folder`, `{write_detail}` ← `write_check.detail`, and `{existing_generator}` ← `write_check.version_generated_by` and `{existing_tier}` ← `write_check.version_confidence_tier` (the build already at `{version}`, each null when none names it). Continue only when the status is `ok` and `{write_verdict}` is `"ok"`: nothing is at the skill folder yet, it holds only what an interrupted run leaves, or SKF generated it and the version is new or SKF's own. Otherwise create nothing and refuse with the first case that applies:
49
+
50
+ - `{write_verdict}` is `"flat-layout"` → `halt_reason: "flat-layout"`: "**`{repo_name}` still uses the flat layout — nothing was written.** A version written beside its root `SKILL.md` would leave a skill SKF can no longer migrate or rename. Run `@Ferris TS {repo_name}` (or US, AS or EX) once to move it into the versioned layout, then re-run."
51
+ - `{write_verdict}` is `"not-skf-output"` → `halt_reason: "not-skf-output"`: "**`{repo_name}` is not SKF output — nothing was written.** `{write_folder}` {write_detail}, so SKF will not write a version there. A shared `{skills_output_folder}` is supported: SKF leaves the skills it did not generate alone, so manage `{repo_name}` yourself, and Quick Skill names a skill after its target, so to create it under another name, brief it with `@Ferris BS` and compile it with `@Ferris CS`. Only if `{skills_output_folder}` holds a module's own source rather than skills, set `skills_output_folder` in `{project-root}/_bmad/skf/config.yaml` to a folder of its own, move your SKF skills there and re-run `/skf-setup`. A version folder with no `metadata.json` can also be one that an interrupted quick-skill run left behind; delete it yourself in that case."
52
+ - The status is not `ok`, or the output has no `write_check` (an older helper: it has no `--write-check` and reports a new skill as `SKILL_NOT_FOUND`) → `halt_reason: "not-skf-output"`: the same message with "SKF could not check it ({the helper's `error`, if any}; re-install SKF if the installed `skf-skill-inventory.py` is out of date)" in place of "`{write_folder}` {write_detail}".
53
+ - When no helper candidate resolves, continue only when nothing exists at `{skill_group}` (no folder, no file, not even a broken link). Otherwise refuse with `halt_reason: "not-skf-output"` and the same message, giving "SKF cannot check who generated `{skill_group}`: `skf-skill-inventory.py` is missing; re-install SKF" in place of "`{write_folder}` {write_detail}".
54
+
55
+ Each refusal is a HARD HALT with **exit code 9 (state-conflict)**: stage `{"phase": "write-and-validate", "halt_reason": "<the halt reason>", "reason": "<the message's first sentence>", "skill_package": null, "details": {"folder": "<the folder the message names>"}}` as `{run_dir}/halt.json` and run `uv run {emitEnvelopeHelper} emit-halt --workflow skf-quick-skill --run-dir "{run_dir}" --target stderr < "{run_dir}/halt.json"`, with no `--result-dir` (`references/halt-contract.md`). This halt writes no result file on disk: `{skill_package}` would sit in a folder SKF did not generate. It is a HALT, not a gate, so it has no headless default.
56
+
57
+ Then create the skill output directories:
29
58
 
30
59
  ```
31
60
  {skill_group} # {skills_output_folder}/{repo_name}/
32
61
  {skill_package} # {skills_output_folder}/{repo_name}/{version}/{repo_name}/
33
62
  ```
34
63
 
35
- If `{skill_package}` already exists, confirm with user before overwriting:
64
+ If `{skill_package}/metadata.json` exists, confirm with user before overwriting:
65
+
66
+ "**Directory `{skill_package}` already exists.** It holds a `{existing_generator}` build ({existing_tier}); overwriting replaces it whole with a community quick skill, and validation results, result contracts, and any manual tweaks from the previous run will not be preserved. Overwrite existing files? [Y/N]" (say "an SKF build" in place of "a `{existing_generator}` build ({existing_tier})" when `{existing_generator}` is null, and leave out " ({existing_tier})" when only `{existing_tier}` is null).
36
67
 
37
- "**Directory `{skill_package}` already exists.** Overwrite will replace the prior compiled output; validation results, result contracts, and any manual tweaks from the previous run will not be preserved. Overwrite existing files? [Y/N]"
68
+ - **If user selects Y:** when `{existing_generator}` is neither `quick-skill` nor null, remove the old package first, so none of its files (create-skill's `references/` and `extraction-rules.yaml`, for example) stays beside the quick skill, and set `{replaced_build}` ← `{existing_generator}` for step 6's summary. The `case` guard removes nothing unless the path is this skill's version package:
38
69
 
39
- - **If user selects Y:** Proceed to section 2.
40
- - **If user selects N:** HARD HALT with **exit code 5 (overwrite-cancelled)** per the exit-code map in `references/halt-contract.md`: "Overwrite cancelled. Existing skill preserved. Run [QS] with a different skill name or remove the existing directory manually." Before exiting, emit the error result contract per `references/halt-contract.md` (`phase: "write-and-validate"`, `error.code: "overwrite-cancelled"`, `skill_package` set to the existing path that was preserved). Write the `-latest.json` envelope to disk here — `{skill_package}` is known, so consumers that hardcode that path see a deterministic file even on this cancelled run.
70
+ ```bash
71
+ case "{skill_package}" in */{repo_name}/{version}/{repo_name}) rm -rf "{skill_package}" && mkdir -p "{skill_package}" ;; esac
72
+ ```
41
73
 
42
- **GATE [default: Y]** — If `{headless_mode}` is true, auto-proceed with Y and log: "headless: overwriting existing `{skill_package}`".
74
+ Proceed to section 2.
75
+ - **If user selects N:** HARD HALT with **exit code 5 (overwrite-cancelled)**: "Overwrite cancelled. Existing skill preserved. Quick Skill names a skill after its target, so to create it under another name, brief it with `@Ferris BS` and compile it with `@Ferris CS`; or remove the existing directory yourself and re-run." Stage `{"phase": "write-and-validate", "halt_reason": "overwrite-cancelled", "reason": "Overwrite cancelled. Existing skill preserved.", "skill_package": "{skill_package}", "details": {"existing_generator": "{existing_generator}"}}` as `{run_dir}/halt.json` (`existing_generator` null when none names it) and run `uv run {emitEnvelopeHelper} emit-halt --workflow skf-quick-skill --run-dir "{run_dir}" --result-dir "{skill_package}" --target stderr < "{run_dir}/halt.json"`: `{skill_package}` holds `metadata.json`, so the emitter also writes the `-latest.json` envelope there, and consumers that hardcode that path see a deterministic file even on this cancelled run.
76
+
77
+ **GATE [default: Y]** when `{existing_generator}` is `quick-skill` or null: if `{headless_mode}` is true, auto-proceed with Y, log "headless: overwriting existing `{skill_package}`", and record the decision: stage `{"gate": "write-and-validate.overwrite", "default_action": "Y", "taken_action": "Y", "reason": "headless: overwrote the existing package", "evidence": {"skill_package": "{skill_package}"}}` as `{run_dir}/decision.json` and run `uv run {emitEnvelopeHelper} record --workflow skf-quick-skill --run-dir "{run_dir}" --decision < "{run_dir}/decision.json"`.
78
+
79
+ **GATE [default: N]** for any other `{existing_generator}`, so no headless run or batch replaces another workflow's build with a quick skill: if `{headless_mode}` is true, record the decision: stage `{"gate": "write-and-validate.overwrite", "default_action": "N", "taken_action": "N", "reason": "headless: kept the {existing_generator} build", "evidence": {"skill_package": "{skill_package}", "existing_generator": "{existing_generator}"}}` as `{run_dir}/decision.json` and run `uv run {emitEnvelopeHelper} record --workflow skf-quick-skill --run-dir "{run_dir}" --decision < "{run_dir}/decision.json"`, then halt as **If user selects N** does, with the message "**Kept the `{existing_generator}` build at `{skill_package}`.** A headless run never replaces another workflow's build with a quick skill. To replace it, run Quick Skill interactively and answer Y; to keep it, give the quick skill another version (`@Ferris QS <package>@<version>`)." and the `reason` "Kept the {existing_generator} build: a headless run never replaces another workflow's build".
80
+
81
+ A `{skill_package}` without `metadata.json` holds only what an interrupted run leaves (the ownership check refuses anything else), so it is written without asking.
43
82
 
44
83
  ### 2. Write Deliverables
45
84
 
46
- Write the three compiled artifacts to the skill package so that validation in sections 3–7 has files on disk to read:
85
+ Write the three compiled artifacts to the skill package in this order, `metadata.json` first, so a run interrupted mid-write leaves a package that carries the SKF marker, which the next run's ownership check accepts:
86
+
87
+ 1. `{skill_package}/metadata.json`: installed from the file step 4 §4 rendered, never typed again. Resolve `{atomicWriteHelper}` ← first existing path in `{atomicWriteProbeOrder}` and run:
88
+
89
+ ```bash
90
+ uv run {atomicWriteHelper} write --target "{skill_package}/metadata.json" < "{run_dir}/metadata.json"
91
+ ```
47
92
 
48
- **File 1:** `{skill_package}/SKILL.md` — the compiled skill document
49
- **File 2:** `{skill_package}/context-snippet.md` — the compressed context snippet. **Skip this write** if `{overrides.skip_snippet}` was set; the artifact is omitted from `outputs`.
50
- **File 3:** `{skill_package}/metadata.json` — the machine-readable metadata
93
+ It writes the file in place atomically, so an interrupted run never leaves half a `metadata.json`. If no candidate exists, write nothing and HARD HALT with **exit code 3 (resolution-failure)**, in interactive mode too: "**Nothing was written to `{skill_package}`.** SKF's atomic writer (`skf-atomic-write.py`) is missing from `{project-root}/_bmad/skf/shared/scripts/`, so re-install SKF." Stage `{"phase": "write-and-validate", "halt_reason": "resolution-failure", "reason": "Nothing was written: the atomic writer is missing.", "skill_package": "{skill_package}", "details": {"cause": "atomic-writer-missing"}}` as `{run_dir}/halt.json` and run `uv run {emitEnvelopeHelper} emit-halt --workflow skf-quick-skill --run-dir "{run_dir}" --result-dir "{skill_package}" --target stderr < "{run_dir}/halt.json"`, without `--result-dir "{skill_package}"` when no earlier run's `metadata.json` is there (`references/halt-contract.md`).
94
+ 2. `{skill_package}/SKILL.md`: the compiled skill document.
95
+ 3. `{skill_package}/context-snippet.md`: the compressed context snippet. **Skip this write** if `{overrides.skip_snippet}` was set; the artifact is omitted from `outputs`.
51
96
 
52
- Confirm after each write: "Written: SKILL.md" / "Written: context-snippet.md" / "Written: metadata.json". When `--skip-snippet` is active, log "Skipped: context-snippet.md (--skip-snippet)" instead of the snippet write confirmation.
97
+ Confirm after each write: "Written: metadata.json" / "Written: SKILL.md" / "Written: context-snippet.md". When `--skip-snippet` is active, log "Skipped: context-snippet.md (--skip-snippet)" instead of the snippet write confirmation.
53
98
 
54
- **If any write fails — HARD HALT (exit code 4, write-failure):** Before exiting, emit the error result contract per `references/halt-contract.md` (`phase: "write-and-validate"`, `error.code: "write-failure"`, `error.details: {failed_path: <path>, error: <details>}`, `skill_package` set, `outputs` listing any files that did write successfully before the failure).
99
+ **If any write fails, HARD HALT (exit code 4, write-failure):** stage `{"phase": "write-and-validate", "halt_reason": "write-failure", "reason": "Write failed: could not write <path>.", "skill_package": "{skill_package}", "outputs": {<each file that did write before the failure, as "metadata", "skill_md" or "context_snippet" with its path>}, "details": {"failed_path": "<path>", "error": "<details>"}}` as `{run_dir}/halt.json` and run `uv run {emitEnvelopeHelper} emit-halt --workflow skf-quick-skill --run-dir "{run_dir}" --result-dir "{skill_package}" --target stderr < "{run_dir}/halt.json"`. When `metadata.json` itself failed to write, run it without `--result-dir "{skill_package}"`: the contract writes no result file on disk, because a package holding only result files would read as not SKF output to the next run's ownership check.
55
100
 
56
101
  "**Write failed:** Could not write to `{file_path}`.
57
102
 
@@ -67,17 +112,21 @@ Check:
67
112
  Run: `npx skill-check -h`
68
113
 
69
114
  - If succeeds (returns usage information): Continue to automated validation (section 4)
70
- - If fails (command not found or error): Skip to manual fallback in section 4
115
+ - If fails (command not found or error): skip to the frontmatter validator in section 4, and log "security scan skipped: skill-check unavailable" in the validation results
71
116
 
72
117
  ### 4. Validate SKILL.md via skill-check (if available)
73
118
 
74
- **If `npx skill-check` is available**, run automated validation + security scan in one invocation against the skill package written in section 2 (security scan is enabled by default when `--no-security-scan` is omitted, so the same call covers §6 and avoids paying the npx startup cost twice):
119
+ **If `npx skill-check` is available**, run validation and its security scan in one call against the skill package written in section 2. `--fix` can also rewrite the frontmatter `description` the user approved in step 4, which would leave SKILL.md out of step with `metadata.json`, so the call runs inside the description guard. Resolve `{descriptionGuardHelper}` ← first existing path in `{descriptionGuardProbeOrder}`, then run the three commands in order:
75
120
 
76
121
  ```bash
77
- npx skill-check check {skill_package} --fix --format json
122
+ uv run {descriptionGuardHelper} capture "{skill_package}/SKILL.md" > "{run_dir}/description-guard.json"
123
+ npx skill-check check "{skill_package}" --fix --format json
124
+ uv run {descriptionGuardHelper} verify-restore "{skill_package}/SKILL.md" --captured-file "{run_dir}/description-guard.json"
78
125
  ```
79
126
 
80
- This validates frontmatter, description, body limits, links, and formatting; runs the security scan; and auto-fixes deterministic issues (field ordering, slug format, required fields, trailing newlines).
127
+ **Guard outputs.** `capture` stages the approved description in `{run_dir}/description-guard.json` and `verify-restore` reads it there, so it never passes through a shell string. Bind `{guard_restored}` ← `restored` and `{guard_diff_kind}` ← `diff_kind` from `verify-restore`. When `{guard_restored}` is true, the approved description is back in SKILL.md, matching `metadata.json`: record the validation note "description restored after `skill-check --fix` ({guard_diff_kind})", which §6 lists with the auto-fixed issues. `verify-restore` refuses an empty or whitespace-only captured description, and a file it cannot read (exit 1, SKILL.md untouched): re-run it with `--captured-file "{skill_package}/metadata.json"`, whose `description` step 4 rendered, never with an empty value, and if that exits 1 too, record a high-severity issue: the guard could not check the description. When it exits 2 with JSON on stdout (the JSON carries `restore_error`), the restore could not be written, so record a high-severity issue: SKILL.md's description no longer matches `metadata.json`.
128
+
129
+ **If no `{descriptionGuardProbeOrder}` path exists**, never run `--fix` unguarded. Run `npx skill-check check "{skill_package}" --format json` instead, which validates and scans without fixing, and log the validation issue "description guard unavailable (`skf-description-guard.py` missing): skill-check ran without `--fix`".
81
130
 
82
131
  **Parse JSON output** to extract:
83
132
  - `scores[].score` — overall score (0-100); match the entry by `relativePath`/`skillId`
@@ -85,45 +134,35 @@ This validates frontmatter, description, body limits, links, and formatting; run
85
134
  - `fixed[]` — issues automatically corrected
86
135
  - `security[]` (when present) — security findings, recorded as advisory warnings (security issues do not block output)
87
136
 
88
- Record quality score, remaining diagnostics, and security findings as validation issues.
137
+ Bind `{quality_score}` ← that score, and record the remaining diagnostics and security findings as validation issues. `{quality_score}` is null when skill-check did not run.
89
138
 
90
- **If skill-check is not available**, run the shared frontmatter validator. Resolve `{frontmatterValidator}` from `{frontmatterValidatorProbeOrder}`; first existing path wins. If no candidate exists, log a high-severity issue ("frontmatter validator unavailable — both `npx skill-check` and `skf-validate-frontmatter.py` missing") and skip frontmatter validation.
139
+ **If skill-check is not available**, run the shared frontmatter validator. Resolve `{frontmatterValidator}` from `{frontmatterValidatorProbeOrder}`; first existing path wins. If no candidate exists, nothing can check the frontmatter: HARD HALT with **exit code 3 (resolution-failure)**, in interactive mode too: "**`{skill_package}` was written but not validated.** skill-check is unavailable and SKF's frontmatter validator (`skf-validate-frontmatter.py`) is missing from `{project-root}/_bmad/skf/shared/scripts/`, so re-install SKF, then re-run." Stage `{"phase": "write-and-validate", "halt_reason": "resolution-failure", "reason": "The skill was written but not validated: the frontmatter validator is missing.", "skill_package": "{skill_package}", "outputs": {<each deliverable §2 wrote, as "metadata", "skill_md" or "context_snippet" with its path>}, "details": {"cause": "frontmatter-validator-missing"}}` as `{run_dir}/halt.json` and run `uv run {emitEnvelopeHelper} emit-halt --workflow skf-quick-skill --run-dir "{run_dir}" --result-dir "{skill_package}" --target stderr < "{run_dir}/halt.json"`.
91
140
 
92
141
  ```bash
93
- uv run {frontmatterValidator} {skill_package}/SKILL.md --skill-dir-name {repo_name}
142
+ uv run {frontmatterValidator} "{skill_package}/SKILL.md" --skill-dir-name {repo_name}
94
143
  ```
95
144
 
96
- The validator emits JSON with `status` (`pass`/`fail`), `issues[]` (each with `severity`, `code`, `message`), and `frontmatter` (the parsed name/description). It checks frontmatter delimiters, name format (Unicode letters + digits + hyphens, no consecutive/trailing hyphens), name-directory match, description presence and length, and unknown fields against the agentskills.io spec. Record each `issues[]` entry as a validation issue with its reported severity. Missing frontmatter or missing required fields are high-severity — skills without valid frontmatter will fail `npx skills add` and `npx skill-check check`.
145
+ The validator emits JSON with `status` (`pass`/`fail`), `issues[]` (each with `severity`, `code`, `message`), and `frontmatter` (the parsed name/description). Record each `issues[]` entry as a validation issue with its reported severity.
97
146
 
98
147
  ### 5. Validate Body, Snippet, and Metadata via skf-validate-output.py
99
148
 
100
149
  Run the shared output validator against the on-disk skill package — it performs the body-structure, snippet-format, and metadata-shape checks. Pass `--skip-frontmatter` since §4 has already covered frontmatter.
101
150
 
102
- **Resolve `{outputValidator}`:** probe `{outputValidatorProbeOrder}` (installed first, dev fallback); first existing path wins. If neither candidate exists, log a high-severity issue ("output validator unavailable — `skf-validate-output.py` missing") and skip body/snippet/metadata validation.
151
+ **Resolve `{outputValidator}`** from `{outputValidatorProbeOrder}`; first existing path wins. If no candidate exists, HARD HALT with **exit code 3 (resolution-failure)**, in interactive mode too: "**`{skill_package}` was written but not validated.** SKF's output validator (`skf-validate-output.py`) is missing from `{project-root}/_bmad/skf/shared/scripts/`, so re-install SKF, then re-run." Stage `{"phase": "write-and-validate", "halt_reason": "resolution-failure", "reason": "The skill was written but not validated: the output validator is missing.", "skill_package": "{skill_package}", "outputs": {<each deliverable §2 wrote, as "metadata", "skill_md" or "context_snippet" with its path>}, "details": {"cause": "output-validator-missing"}}` as `{run_dir}/halt.json` and run `uv run {emitEnvelopeHelper} emit-halt --workflow skf-quick-skill --run-dir "{run_dir}" --result-dir "{skill_package}" --target stderr < "{run_dir}/halt.json"`. Otherwise run:
103
152
 
104
153
  ```bash
105
- python3 {outputValidator} {skill_package} --generated-by quick-skill --skip-frontmatter
154
+ uv run {outputValidator} "{skill_package}" --generated-by quick-skill --skip-frontmatter
106
155
  ```
107
156
 
108
157
  The validator emits JSON with `result` (PASS/FAIL), `validation.skill_md.body[]`, `validation.context_snippet.issues[]`, `validation.metadata.issues[]`, and a severity-bucketed `summary`. Record each issue as a validation issue at its reported severity.
109
158
 
110
- The validator covers:
111
-
112
- - **Body structure** — Overview, Description, Key Exports, Usage sections present (medium when missing)
113
- - **Context snippet** — `[{name} v{version}]|root: ...` first line, `|IMPORTANT:` second line, ~80–120-token length
114
- - **Metadata** — required string fields (`name`, `version`, `source_authority`, `language`, `generation_date`), `source_repo`, `generated_by`, `confidence_tier`, and `stats` numerics (`exports_documented`, `exports_public_api`, `exports_total`, `public_api_coverage`, `total_coverage`)
115
-
116
- ### 6. Security Scan (covered by §4)
117
-
118
- Security findings are already collected from the §4 invocation (no separate `npx` round trip needed — `skill-check check ... --fix --format json` runs the security scan by default). If skill-check was unavailable in §3, log "security scan skipped — skill-check unavailable" in validation results.
119
-
120
- ### 7. Report Validation Results
159
+ ### 6. Report Validation Results
121
160
 
122
161
  "**Validation complete:**
123
162
 
124
163
  **SKILL.md:** {pass/issues found} (quality score: {score}/100 if skill-check was available)
125
164
  {list any issues}
126
- {list any auto-fixed issues}
165
+ {list any auto-fixed issues, and the §4 description-guard note when the guard restored the description}
127
166
 
128
167
  **context-snippet.md:** {pass/issues found}
129
168
  {list any issues}
@@ -137,13 +176,13 @@ Security findings are already collected from the §4 invocation (no separate `np
137
176
  **Overall:** {pass / N issues found}
138
177
 
139
178
  {If issues found:}
140
- These issues are advisory for community-tier skills. You can proceed to finalize or go back to adjust.
179
+ These issues are advisory for community-tier skills: fix them in the written files, or re-run Quick Skill once the source or the hints change.
141
180
 
142
181
  **Proceeding to finalize...**"
143
182
 
144
- Set `validation_result` with pass/fail status, quality score, and issues list.
183
+ Set `validation_result` with pass/fail status, quality score, and issues list, and `{validation_issues}` ← `{"skill_md": <n>, "context_snippet": <n>, "metadata": <n>, "security": <n>}`, each `<n>` the number of entries the validators returned for that heading: `skill_md` counts skill-check's `diagnostics[]` (without skill-check, the frontmatter validator's `issues[]`) plus `validation.skill_md.body[]`; `context_snippet` counts `validation.context_snippet.issues[]`; `metadata` counts `validation.metadata.issues[]`; `security` counts skill-check's `security[]`. A check that did not run counts 0, and `fixed[]` and the guard note count nothing. Step 6 §3's summary carries `{quality_score}` and `{validation_issues}`.
145
184
 
146
- ### 8. Auto-Proceed to Finalize
185
+ ### 7. Auto-Proceed to Finalize
147
186
 
148
- Once deliverables are written to `{skill_package}` and validation is reported (advisory), load and execute {nextStepFile} to finalize.
187
+ Once deliverables are written to `{skill_package}` and validation is reported (advisory), load and execute {nextStepFile} to finalize; when `{headless_mode}` is true, print this step's `done` event and step 6's `start` event first (`references/halt-contract.md`).
149
188