bmad-module-skill-forge 2.1.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 +51 -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 +14 -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 +117 -9
  75. package/src/shared/scripts/skf-detect-docs.py +892 -4
  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 +215 -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 +17 -6
  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 +55 -18
  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 -57
  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 -89
  348. package/src/skf-setup/references/detect-and-tier.md +58 -66
  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 -645
  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,20 +1,20 @@
1
1
  ---
2
2
  nextStepFile: 'analyze-target.md'
3
- ratifyTargetFile: 'confirm-brief.md'
4
- forgeTierFile: '{sidecar_path}/forge-tier.yaml'
3
+ autoBriefFile: 'references/step-auto-brief.md'
5
4
  headlessArgsFile: 'references/headless-args.md'
6
- headlessSourceAuthorityDetectionFile: 'references/headless-source-authority-detection.md'
5
+ ratifyFile: 'references/gather-intent-ratify.md'
6
+ forgeTierFile: '{sidecar_path}/forge-tier.yaml'
7
7
  portfolioSimilarityCheckFile: 'references/portfolio-similarity-check.md'
8
8
  draftCheckpointFile: 'references/draft-checkpoint.md'
9
+ githubProbeProbeOrder:
10
+ - '{project-root}/_bmad/skf/shared/scripts/skf-github-probe.py'
11
+ - '{project-root}/src/shared/scripts/skf-github-probe.py'
12
+ resolvePackageProbeOrder:
13
+ - '{project-root}/_bmad/skf/shared/scripts/skf-resolve-package.py'
14
+ - '{project-root}/src/shared/scripts/skf-resolve-package.py'
9
15
  validateBriefInputsProbeOrder:
10
16
  - '{project-root}/_bmad/skf/shared/scripts/skf-validate-brief-inputs.py'
11
17
  - '{project-root}/src/shared/scripts/skf-validate-brief-inputs.py'
12
- validateBriefSchemaProbeOrder:
13
- - '{project-root}/_bmad/skf/shared/scripts/skf-validate-brief-schema.py'
14
- - '{project-root}/src/shared/scripts/skf-validate-brief-schema.py'
15
- emitBriefEnvelopeProbeOrder:
16
- - '{project-root}/_bmad/skf/shared/scripts/skf-emit-brief-result-envelope.py'
17
- - '{project-root}/src/shared/scripts/skf-emit-brief-result-envelope.py'
18
18
  ---
19
19
 
20
20
  <!-- Config: communicate in {communication_language}. -->
@@ -32,15 +32,19 @@ emitBriefEnvelopeProbeOrder:
32
32
 
33
33
  ### 1. Discover Forge Tier
34
34
 
35
- **Pre-flight write probe.** Before any conversational state accumulates, verify `{forge_data_folder}` is writable. A read-only mount, full disk, or permissions-denied path otherwise only surfaces at step 5's atomic write — by then the user has invested 5–15 minutes. Run a single-byte write-and-remove probe:
35
+ **Pre-flight write probe and run folder.** Before any conversational state accumulates, verify `{forge_data_folder}` is writable, and create the run folder, where later steps stage what they hand to a helper (the repository's file list, fetched files, JSON payloads) instead of typing it into a command. A read-only mount, full disk, or permissions-denied path otherwise only surfaces at step 5's atomic write, after the user has invested 5–15 minutes. Run a single-byte write-and-remove probe, then create the folder:
36
36
 
37
37
  ```bash
38
38
  mkdir -p "{forge_data_folder}" && \
39
39
  printf 'probe' > "{forge_data_folder}/.skf-write-probe" && \
40
- rm "{forge_data_folder}/.skf-write-probe"
40
+ rm "{forge_data_folder}/.skf-write-probe" && \
41
+ mkdir -p "{project-root}/_bmad-output/.skf-run" && \
42
+ mktemp -d "{project-root}/_bmad-output/.skf-run/skf-brief-skill-XXXXXXXX"
41
43
  ```
42
44
 
43
- `mkdir -p` succeeds on a pre-existing read-only mount, but the `printf > file` redirect actually attempts a write — that catches read-only, disk-full, and permissions-denied uniformly. **On any non-zero exit:** HALT (exit code 4, `halt_reason: "write-failed"`) — `"**Error:** {forge_data_folder} is not writable: {captured stderr}. Verify the path exists, the mount is writable, and there is free disk space, then re-run."` In headless mode, emit the error envelope per **step 5 §4b** with `halt_reason: "write-failed"` (skill_name is not yet resolved here — use the placeholder convention documented in §4b). On success, continue silently to the forge-tier load below.
45
+ Bind `{run_dir}` ← the path the last command prints. Step 5, or step-auto-validate.md at the end of an `[auto]` run, removes the folder once the brief is written, and an `[X]` cancel removes it before it stops; any other halt leaves it in place with what the run staged. A step stages a payload there through a heredoc whose delimiter is quoted (`'SKF_JSON'`), so a quote or an apostrophe in it needs no escaping.
46
+
47
+ `mkdir -p` succeeds on a pre-existing read-only mount, but the `printf > file` redirect actually attempts a write, which catches read-only, disk-full, and permissions-denied uniformly. **On any non-zero exit:** emit the halt envelope first, `uv run {emitBriefEnvelopeHelper} emit --target stderr` with `halt_reason: "write-failed"` (SKILL.md Halt Contract), then HALT (exit code 4): `"**Error:** {forge_data_folder} or the run folder under {project-root}/_bmad-output/.skf-run/ is not writable: {captured stderr}. Verify the path exists, the mount is writable, and there is free disk space, then re-run."` On success, continue silently to the forge-tier load below.
44
48
 
45
49
  Attempt to load `{forgeTierFile}`:
46
50
 
@@ -54,24 +58,16 @@ Attempt to load `{forgeTierFile}`:
54
58
  - Display: "**Cannot read forge-tier.yaml** at `{forgeTierFile}` — the file exists but failed to parse: `{parser error message}`. The setup workflow can rewrite it cleanly. Until then, the brief workflow falls back to **Quick** tier (no extra tools assumed)."
55
59
  - Continue with `tier = "Quick"` and `tools = {}` — do not HALT. Record `tier_source: "fallback-corrupted-config"` for later diagnostics.
56
60
 
57
- **If not found:**
58
- - "**Cannot proceed.** forge-tier.yaml not found at `{forgeTierFile}`. Run the **setup** workflow first to configure your forge tier (Quick/Forge/Forge+/Deep)."
59
- - In headless mode, emit the error envelope per **step 5 §4b** with `halt_reason: "forge-tier-missing"` (`skill_name` is not yet resolved here — use the `"unknown"` placeholder convention documented in §4b).
60
- - HALT (exit code 3, `halt_reason: "forge-tier-missing"`) — do not proceed.
61
-
62
- ### 1b. Auto Mode Check
61
+ **If not found:** emit the halt envelope first, `uv run {emitBriefEnvelopeHelper} emit --target stderr` with `halt_reason: "forge-tier-missing"` (SKILL.md Halt Contract), then HALT (exit code 3): "**Cannot proceed.** forge-tier.yaml not found at `{forgeTierFile}`. Run the **setup** workflow first to configure your forge tier (Quick/Forge/Forge+/Deep)."
63
62
 
64
- **Check for `[auto]` flag:** If `[auto]` was passed as a bracket modifier in the pipeline context (e.g., `BS[auto]`), set `{auto_mode}` = true.
63
+ ### 1b. Route by Mode
65
64
 
66
- **IF `{auto_mode}` is true:**
65
+ The first route that applies runs, and it leaves this file:
67
66
 
68
- 1. **Load upstream brief path:** Read `brief_path` from the pipeline data context (passed by the forger from AN's `SKF_ANALYZE_RESULT_JSON` `brief_paths[]`). If `brief_path` is not available, HARD HALT with exit code 2 (`input-missing`): "**Auto mode requires `brief_path` in pipeline context — AN must run before BS[auto].**"
69
- 2. **Load source repo:** Read `source_repo` from the pipeline data context (the target repo URL or path, forwarded by the forger). If not available, attempt to extract it from the upstream brief at `brief_path`.
70
- 3. "**Auto mode activated — bypassing interactive brief workflow.**"
71
- 4. **Route to auto-brief:** Load, read fully, then execute `references/step-auto-brief.md`, and hand off there — do not fall through to §2 or any subsequent section of this file.
72
-
73
- **IF `{auto_mode}` is NOT true:**
74
- Continue to §2 as normal — the entire interactive flow below is unchanged.
67
+ - **`{auto_mode}` is true** (a pipeline's `BS[auto]`): read `brief_path` from the pipeline data context (the forger passes it from AN's `SKF_ANALYZE_RESULT_JSON` `brief_paths[]`). If `brief_path` is not available, emit the halt envelope first, `uv run {emitBriefEnvelopeHelper} emit --target stderr` with `halt_reason: "input-missing"` and `mode` `"auto"` (SKILL.md Halt Contract), then HARD HALT (exit code 2): "**Auto mode requires `brief_path` in pipeline context: AN must run before BS[auto].**"
68
+ Read `source_repo` from the pipeline data context too (the target the forger forwards), else from the upstream brief. Display "**Auto mode activated: bypassing the interactive brief workflow.**", then load, read fully, and execute `{autoBriefFile}`.
69
+ - **`{headless_mode}` is true:** load, read fully, and execute `{headlessArgsFile}`. Its input gate validates the arguments before any later section uses them, then continues at step 2, or ratifies the brief a `from_brief` argument names.
70
+ - **Otherwise** the run is interactive: continue at §2.
75
71
 
76
72
  ### 2. Welcome and Explain
77
73
 
@@ -92,11 +88,11 @@ Let's get started."
92
88
 
93
89
  ### 3. Gather Target Repository
94
90
 
95
- This section has four sub-flows. Execute exactly one branch — 3.1a *or* 3.2 *or* 3.3 — based on the user's response in 3.1, then end with the shared confirmation (3.1a is terminal for §3 and jumps directly to confirm-brief.md). Do not mix branches.
91
+ This section has five sub-flows. Execute exactly one branch, 3.1a *or* 3.2 *or* 3.3, based on the user's response in 3.1 (3.1b first resolves a package name to the repository 3.3 takes), then end with the shared confirmation (3.1a leaves this file for the ratify flow). Do not mix branches.
96
92
 
97
93
  #### 3.1 Collect target
98
94
 
99
- **Open-floor opening.** Lead with an open invitation so an expert can state everything in one breath rather than being walked through seven discrete prompts — costs almost nothing token-wise and sharply improves the conversational feel of this, the most question-heavy mode. A first-timer who pastes only a bare URL still gets the full guided sequence below, unchanged.
95
+ **Open-floor opening.** Lead with an open invitation, so an expert can state everything in one answer; a first-timer who pastes only a bare URL still gets the guided sequence below.
100
96
 
101
97
  "**What repository or documentation do you want to create a skill for?**
102
98
 
@@ -104,6 +100,7 @@ Tell me everything you have — the repo or docs, what you want to skill and why
104
100
 
105
101
  Provide one of:
106
102
  - A **GitHub URL** (e.g., `https://github.com/org/repo`)
103
+ - A **package name or registry page** (e.g., `zod`, `requests==2.31.0`, `https://www.npmjs.com/package/zod`), which I resolve to its GitHub repository
107
104
  - A **local path** (e.g., `/path/to/project`)
108
105
  - **Documentation URLs** for a docs-only skill (e.g., `https://docs.stripe.com/api`) — use this when no source code is available (SaaS, closed-source)
109
106
  - A **path to an existing `skill-brief.yaml`** (file path or a directory containing one) — use this to ratify a brief produced by another workflow (e.g. `skf-analyze-source`) without re-deriving fields
@@ -114,65 +111,42 @@ Or type `cancel` / `exit` / `[X]` to leave without writing anything.
114
111
 
115
112
  Wait for user response. **Parse the response for any of the fields the later sections collect** — `target_version` (§3b), intent (§4), scope hints (§5), source authority (§3.3), a proposed name (§6) — and pre-fill every field the user covered, holding them in workflow context. Sections §3b/§4/§5/§6/§7b then **acknowledge a pre-filled field instead of re-asking** ("I noted you're targeting v4.0.0"), and prompt only for the gaps. An expert who stated it all collapses to the §3.1 target branch plus the §7b description confirmation; a bare URL falls through to the full sequence. Then branch on the response for the target itself:
116
113
 
117
- - Empty input, `cancel`, `exit`, `[X]`, `q`, or `:q` → Display `"Cancelled — no brief was written."` and HALT (exit code 6, `halt_reason: "user-cancelled"`). Cancellation here is non-destructive — no files have been written yet by step 1. Headless mode never reaches this branch (the GATE in §8 short-circuits the interactive sub-flows).
118
- - Path that resolves to an existing `skill-brief.yaml` (file path ending in `skill-brief.yaml` that exists, OR a directory containing a `skill-brief.yaml`) → §3.1a
119
- - Documentation URLs only (no source location) → §3.2
120
- - GitHub URL or local filesystem path → §3.3
114
+ - Empty input, `cancel`, `exit`, `[X]`, `q`, or `:q` → Remove the run folder (`case "{run_dir}" in "{project-root}/_bmad-output/.skf-run/skf-brief-skill-"*) rm -rf "{run_dir}" ;; esac`), display `"Cancelled: no brief was written."` and HALT (exit code 6, `halt_reason: "user-cancelled"`).
121
115
  - Any other free-form question (e.g. "what is this?", "show me an example", "how does SKF work?") → answer briefly, re-display the prompt
122
-
123
- #### 3.1a Branch — Ratify existing brief
124
-
125
- This branch handles the AN→BS handoff: another workflow (typically `skf-analyze-source`) has already produced a `skill-brief.yaml`, and the user wants to review and confirm it without re-running gather-intent / analyze-target / scope-definition. **This §3.1a path is reached only interactively** — it is entered by typing a brief path at the §3.1 prompt, which headless mode never does. The headless equivalent is the §8 GATE `from_brief` route: it consumes a `from_brief` argument, runs the same schema validation, sets the same `ratify_mode`, hydrates from the same parsed payload, and jumps to step 4 exactly as `[R]` does below — see §8. Keep the two paths' hydration in sync.
126
-
127
- Resolve the path:
128
-
129
- - If the user's input ends in `skill-brief.yaml` and points at an existing file → that is the brief path.
130
- - Otherwise (input was a directory) → the brief path is `<input>/skill-brief.yaml`.
131
-
132
- **Validate the brief against the schema** before presenting it. Resolve `{validateBriefSchemaHelper}` from `{validateBriefSchemaProbeOrder}` (first existing path wins; HALT if no candidate exists), then:
116
+ - Otherwise read the target the response names (the URL, path or package name, without the sentence around it) with `{resolvePackageHelper}`, resolved from `{resolvePackageProbeOrder}` (first existing path wins). Write the target exactly as given on the line between the markers, quotes, backticks and `$` included. `--local-first` reads a target that names an existing file or folder (relative to the working folder, `~` expanded) as a `local-path`, whatever its shape: `skill-brief.yaml`, `briefs/skill-brief.yaml`, `libs/mylib` or a path with a space.
133
117
 
134
118
  ```bash
135
- uv run {validateBriefSchemaHelper} <resolved-brief-path>
119
+ uv run {resolvePackageHelper} parse-target --local-first <<'SKF_TARGET'
120
+ {target}
121
+ SKF_TARGET
136
122
  ```
137
123
 
138
- The script returns JSON `{valid, errors[], warnings[], halt_reason, brief}`. Apply the result:
124
+ Route on the `kind` it returns:
125
+ - `local-path`: a `skill-brief.yaml` file, or a folder that holds one → §3.1a; any other path → §3.3.
126
+ - `github` → §3.3, with its `url` as the target. A pinned version (`target_version` not null, as in `owner/repo@1.2.0`) pre-fills `target_version`, which §3b checks before it keeps it: a full X.Y.Z is acknowledged, and a partial pin (`owner/repo@1.2`) is only a hint that §3b names when it asks again; a `/tree/<ref>/<folder>` URL pre-fills `target_ref` ← `ref` and adds `subdir` to the scope hints.
127
+ - `package` or `registry-page` (`lodash`, `@scope/name@2.1.0`, `requests==2.31.0`, an npmjs.com, pypi.org or crates.io page) → §3.1b, which finds its repository; its `target_version`, when not null, pre-fills `target_version` the same way (`react@18` is a partial pin).
128
+ - `other-host`: documentation pages (a docs site, an API reference) → §3.2; a repository on another git host (GitLab, Bitbucket, Codeberg, a self-hosted forge) → display "**Brief Skill reads GitHub repositories and local folders.** `{url}` is on `{host}`: clone it and give me the local path, or paste its GitHub URL if it has one." and re-display the prompt.
129
+ - `unparsed`: several documentation URLs → §3.2; anything else → answer briefly and re-display the prompt.
139
130
 
140
- - **`valid: false`** — surface the `errors[]` messages and the `halt_reason` to the user, then re-display the §3.1 prompt for a corrected path (or another target altogether). Do not HALT — the user may simply have pointed at the wrong file. Example: `"**Brief at `{path}` is invalid:** {first error message}. Pick a different brief, or supply a repo / docs URL instead."`
141
- - **`valid: true`** — proceed with the parsed `brief` payload.
131
+ When `{resolvePackageHelper}` has no path, or the call prints no JSON, route the target by reading it yourself, by the same kinds (a path that exists is a `local-path`).
142
132
 
143
- Surface any non-empty `warnings[]` as a single grouped line (`"**Brief validation warnings:** {joined warnings}"`), then present the ratify menu:
133
+ #### 3.1a Branch: Ratify an Existing Brief
144
134
 
145
- ```
146
- **Existing brief detected at `{path}`.**
147
-
148
- - **Name:** {brief.name}
149
- - **Target:** {brief.source_repo}
150
- - **Description:** "{brief.description}"
151
- - **Created:** {brief.created} by {brief.created_by}
152
- - **Scope:** {brief.scope.type}
153
-
154
- Pick one:
155
- [R] Ratify — review in step 4 and write (overwriting this file once approved)
156
- [F] Start fresh — discard this brief and re-prompt for a target
157
- [X] Cancel and exit
158
- ```
135
+ The target is a `skill-brief.yaml`, or a folder holding one, that another workflow (typically `skf-analyze-source`) produced, to review and confirm instead of re-deriving. Load, read entirely, and execute `{ratifyFile}` with that path: it validates the brief, offers `[R]` Ratify, `[F]` Start fresh and `[X]` Cancel, and on `[R]` hands the run to step 4, past every later section of this file and steps 2 and 3.
159
136
 
160
- Wait for user response. Branch:
137
+ #### 3.1b Branch: Resolve a Package Name
161
138
 
162
- - **[R] Ratify** — Confirm overwrite up front: store `ratify_mode: true` and `ratify_source_path: <resolved-brief-path>` in workflow context. Hydrate the brief context variables from the parsed `brief` payload so step 4 has the same field set it normally derives from steps 1-3:
163
- - `name` ← `brief.name`; `version` ← `brief.version`; `target_version` ← `brief.target_version`
164
- - `target_ref` ← `brief.target_ref`; `source_ref` ← `brief.source_ref` (optional git refs; preserve when present)
165
- - `source_repo` ← `brief.source_repo`; `source_type` ← `brief.source_type`; `source_authority` ← `brief.source_authority`; `doc_urls` ← `brief.doc_urls`
166
- - `language` ← `brief.language`; `description` ← `brief.description`; `forge_tier` ← `brief.forge_tier`
167
- - `created` ← `brief.created`; `created_by` ← `brief.created_by`
168
- - `scope.type` / `scope.include` / `scope.exclude` / `scope.tier_a_include` / `scope.notes` / `scope.rationale` / `scope.amendments` ← `brief.scope.*` (preserve `tier_a_include` and the `amendments` log verbatim — do not re-derive or drop them)
169
- - `scripts_intent` ← `brief.scripts_intent`; `assets_intent` ← `brief.assets_intent`
139
+ The target names a package (or its registry page), not a repository. Ask the registries for the repository it is published from, with the same helper:
170
140
 
171
- Then load, read entirely, and execute `{ratifyTargetFile}` — bypassing §3.1b/§3.2/§3.3, §3b, §4, §5, §6, §7, §7b, and §8 entirely. Skip step 2 (analyze-target) and step 3 (scope-definition) — both would re-derive fields already on disk. The forward chain resumes at step 4 (confirm-brief) where the user gets the standard review pass and can still adjust fields inline via §4.
141
+ ```bash
142
+ uv run {resolvePackageHelper} resolve "{package_name}" --timeout 10 [--registry {registry}]
143
+ ```
172
144
 
173
- - **[F] Start fresh** — discard the loaded brief and re-display §3.1 above (the user is now at the same point as if they had typed nothing).
174
- - **[X] Cancel** — Display `"Cancelled — no brief was written."` and HALT (exit code 6, `halt_reason: "user-cancelled"`). Non-destructive.
175
- - **Any other input** — treat as a fresh §3.1 response and re-evaluate the routing branches above (a typed GitHub URL after seeing the menu means "I changed my mind, brief this repo instead").
145
+ Pass `--registry` when parse-target set `registry` (a registry page's, PyPI for a `==` pin, npm for a scoped name). The JSON's `status` is `ok`, `ambiguous` or `fallthrough` (exit 0, 3 or 1):
146
+
147
+ - **`ok`**: show "`{package_name}` is published from {resolved_url} ({registry_used})." and continue at §3.3 with `resolved_url` as the target. When `source_subdir` is set (the package's folder in a monorepo), add it to the scope hints.
148
+ - **`ambiguous`**: the name may belong to more than one project. Offer every candidate, numbered: `resolved_url` from `registry_used` first, then each `also_found_in` entry that has a `resolved_url`. Let the user pick one by number or paste the GitHub URL they mean, and continue at §3.3 with the pick; its `source_subdir`, when set, joins the scope hints.
149
+ - **`fallthrough`** (no registry gave a GitHub repository), or no JSON: display "**`{package_name}` did not resolve to a GitHub repository** on npm, PyPI or crates.io. Paste its GitHub URL or a local path." and re-display the §3.1 prompt.
176
150
 
177
151
  #### 3.2 Branch — Documentation URLs (docs-only)
178
152
 
@@ -180,7 +154,7 @@ Wait for user response. Branch:
180
154
  - Collect one or more doc URLs with optional labels
181
155
  - HEAD-check the collected URLs in parallel — do not loop sequentially. Issue all N `curl -sI {url}` (or equivalent) calls in a **single message with N parallel Bash calls**, then process the responses together. Each call must use a 5-second timeout (`curl -sI --max-time 5 {url}`) to bound worst-case wall-time on hung hosts. Per response:
182
156
  - On 2xx/3xx: silently accept.
183
- - On 4xx/5xx, DNS failure, or timeout: warn `"Could not reach {url} — {status or error}. Confirm the URL is correct, or proceed anyway."` Interactive: re-prompt for a corrected URL or `[K] Keep anyway`. Headless: keep the URL and log the warning — the brief still records it but the failure is now visible at brief-creation time instead of materializing hours later in skf-create-skill.
157
+ - On 4xx/5xx, DNS failure, or timeout: warn `"Could not reach {url} ({status or error}). Confirm the URL is correct, or proceed anyway."` and re-prompt for a corrected URL or `[K] Keep anyway`.
184
158
  - Set `source_authority: "community"` (forced for docs-only — T3 external documentation; the §3.3 source-authority prompt is skipped)
185
159
  - Note: `source_repo` becomes optional (can be set to the main doc site URL for reference)
186
160
 
@@ -189,17 +163,16 @@ Skip §3.3 and continue at "Confirm the target" below.
189
163
  #### 3.3 Branch — Source (GitHub URL or local path)
190
164
 
191
165
  - Set `source_type: "source"` (default)
192
- - **Pre-validate the target before continuing.** Issue these probes in a single message with parallel Bash calls:
193
- - **GitHub URL:** `curl -sI --max-time 5 {url}`. On a 4xx (typically 404 for a typo'd repo or org), warn `"GitHub returned {status} for {url} — confirm the URL is correct."` and re-prompt. On 2xx, accept.
194
- - **GitHub URL, in parallel:** `gh api repos/{owner}/{repo} --jq .name` (5-second timeout via `gh api --hostname github.com --method GET ... ` or just rely on default). On 403/404, warn `"GitHub API returned {status} for {owner}/{repo} — the repo may be private or your token may not have access. Step-02 will HALT here if this is not resolved. Continue anyway, or fix and re-prompt?"` and offer `[K] Keep anyway` / re-prompt for a corrected URL. Do not HALT — the canonical HALT still happens in step 2 §1, but surfacing access failures at URL-entry time prevents 5+ minutes of intent investment getting lost. On any other error (network failure, missing binary), log silently and let `gh auth status` below catch it. On 2xx, accept silently.
195
- - **GitHub URL, in parallel:** `gh auth status` — if it reports unauthenticated or the binary is missing, warn `"GitHub CLI not authenticated; step 2 will HALT when it tries to fetch the tree. Run 'gh auth login' before continuing, or supply a local clone path instead."` (Do not HALT here — let the user choose to fix or proceed; the canonical HALT still happens in step 2 §1's failure-class triage.)
166
+ - **Pre-validate the target before continuing.** An access problem caught at URL entry spares the user 5+ minutes of intent investment. Never HALT here: the canonical HALT stays in step 2 §1.
167
+ - **GitHub URL:** resolve `{githubProbeHelper}` from `{githubProbeProbeOrder}` (first existing path wins) and run `uv run {githubProbeHelper} repo --repo "{url}" --timeout 20`. It prints one JSON line, and tells a missing or logged-out `gh`, a repository that does not exist and one the account cannot read apart:
168
+ - `status: "ok"`: accept silently, a private repository that `gh` can read and a public one read without `gh` included.
169
+ - `status: "unavailable"`: warn with its `message`, which names the cause (`cause`) and the fix, and offer `[K] Keep anyway` or a corrected URL, which is probed the same way. On `[K]`, keep the URL: step 2 §1 reports the cause again if it still holds.
170
+ - No JSON (the helper is missing, or exits 1 or 2): continue silently; step 2 §1 checks the repository.
196
171
  - **Local path:** verify the directory exists (`test -d {path}`). If not, warn `"Local path {path} does not exist."` and re-prompt.
197
172
  - Optionally ask: "Are there any documentation URLs you'd like to include for supplemental context? (These will be fetched as T3 external references.)"
198
173
  - If yes: collect doc URLs into `doc_urls`
199
174
 
200
- **Source authority (this branch only — docs-only forces `community` in §3.2):**
201
-
202
- **Interactive only** — skip this prompt entirely when `{headless_mode}` is true; the GATE in §8 resolves source_authority headlessly via the detection branch documented there.
175
+ **Source authority (this branch only: docs-only forces `community` in §3.2):**
203
176
 
204
177
  "**Are you the maintainer of this library, or creating a community skill?**"
205
178
  - If maintainer: set `source_authority: "official"`
@@ -212,7 +185,7 @@ Default to `"community"` if user does not specify or skips.
212
185
 
213
186
  Confirm the target.
214
187
 
215
- **Draft-resume check (interactive only).** Now that the target is confirmed — and *before* the version prompt (§3b), intent (§4), or scope (§5) spend the user's time — offer to resume an in-progress draft that already covers this exact target, so a returning user re-types nothing. Keying on the target (not the not-yet-derived skill name) is what lets the offer fire this early. When the flow is interactive:
188
+ **Draft-resume check.** Now that the target is confirmed, and *before* the version prompt (§3b), intent (§4), or scope (§5) spend the user's time, offer to resume an in-progress draft that already covers this exact target, so a returning user re-types nothing. Keying on the target (not the not-yet-derived skill name) is what lets the offer fire this early:
216
189
 
217
190
  1. **Cheap pre-filter** — list any draft file that mentions the confirmed target at all:
218
191
 
@@ -224,24 +197,33 @@ Confirm the target.
224
197
 
225
198
  2. **Confirm each candidate on the target *field*, not free text.** Read the candidate draft's JSON and keep it only if its `target_repo` equals the confirmed target (source targets) or the target appears in its `doc_urls` (docs-only) — this rejects a draft that merely mentions the URL in its `intent` or `description`. Drop any candidate that has a finished `skill-brief.yaml` in the same directory (that brief is done; step 5's overwrite gate owns it).
226
199
 
227
- 3. If one or more live drafts survive, load `{draftCheckpointFile}` and follow Half 1 (Resume Check) against the most-recently-modified survivor; its directory basename is the candidate skill name. On `[Y]` resume, Half 1 restores every gathered answer and jumps straight to §8 — **§3b, §4, §5, §6, §7, and §7b are all skipped**. Otherwise (headless, no surviving draft, or every match already has a finished brief beside it) skip the load and continue to §3b.
200
+ 3. If one or more live drafts survive, load `{draftCheckpointFile}` and follow Half 1 (Resume Check) against the most-recently-modified survivor; its directory basename is the candidate skill name. On `[Y]` resume, Half 1 restores every answer the draft holds and jumps straight to §8, or to step 4 when the draft holds the scope too: **§3b, §4, §5, §6, §7, and §7b are all skipped**. Otherwise (no surviving draft, or every match already has a finished brief beside it) skip the load and continue to §3b.
228
201
 
229
202
  ### 3b. Gather Target Version
230
203
 
231
- This step only collects `target_version` and validates its shape with the regex below — auto-detection runs in step 2 and precedence/invariant resolution lands in step 5's writer script. The canonical precedence rules live in `references/version-resolution.md`; load it from step 2 / step 5 only when the relevant section needs it.
204
+ This step only collects `target_version` and checks its shape: auto-detection runs in step 2 and precedence/invariant resolution lands in step 5's writer script. The canonical precedence rules live in `references/version-resolution.md`; load it from step 2 / step 5 only when the relevant section needs it.
232
205
 
233
- **Headless:** if `target_version` was supplied as an argument, store it and skip the interactive prompt below. If `doc_urls` were also supplied, treat the version-vs-doc-URL confirmation prompt as auto-confirmed (Y).
206
+ When §3.1 pre-filled no version, ask:
234
207
 
235
208
  "**Are you targeting a specific version of this library?**
236
209
  (Leave blank to auto-detect from source)"
237
210
 
238
211
  {If source_type is "docs-only":}
239
- "Since this is a docs-only skill with no source code, specifying the version is recommended — otherwise it defaults to 1.0.0."
212
+ "Since this is a docs-only skill with no source code, specifying the version is recommended: otherwise it defaults to 1.0.0."
240
213
 
241
- Wait for user response.
214
+ Wait for user response. **If blank:** proceed without `target_version`: version will be auto-detected in step 02.
242
215
 
243
- **If user provides a version:** Validate the shape against `^v?\d+\.\d+\.\d+([.\-+][0-9A-Za-z][0-9A-Za-z.\-+]*)?$` (full X.Y.Z form, with optional `v` prefix and pre-release / build suffix; CalVer like `2024.04.01` accepted; partial forms like `1`, `1.2`, `v2`, `latest` rejected). On a match, store as `target_version` and set `version` to this value. On a non-match, warn `"'{value}' doesn't look like semver — write the explicit triple (e.g. 1.0.0). Fix it now or skip auto-detection?"` and re-prompt for a corrected value or blank to fall through to step 2 auto-detection.
244
- **If blank:** Proceed without `target_version` — version will be auto-detected in step 02.
216
+ **Check the version before you keep it.** For a version typed here, or one §3.1 pre-filled (from parse-target or from the free-form answer), resolve `{validateBriefInputsHelper}` from `{validateBriefInputsProbeOrder}` (first existing path wins; HALT if no candidate exists) and run its field-only check, with the version written as a JSON string:
217
+
218
+ ```bash
219
+ uv run {validateBriefInputsHelper} --only target_version <<'SKF_JSON'
220
+ {"target_version": "<the version>"}
221
+ SKF_JSON
222
+ ```
223
+
224
+ - **Exit 0** (`valid: true`): store it as `target_version` and set `version` to it. Acknowledge a pre-filled one ("I noted you're targeting v4.0.0") instead of asking.
225
+ - **Exit 1** (`valid: false`): keep nothing. Ask again, naming the value with its first error's `message`: `"{message}, or leave blank to auto-detect."` (for `react@18`, `'18' is a major version only`). Check the answer the same way; blank proceeds without `target_version`.
226
+ - **Exit 2** (the payload is not valid JSON, such as a quote left unescaped): write it again and re-run the check.
245
227
 
246
228
  {If target_version was set AND doc_urls are being collected (either docs-only primary or supplemental):}
247
229
 
@@ -252,7 +234,7 @@ Wait for user response.
252
234
 
253
235
  ### 4. Gather User Intent
254
236
 
255
- **First-timer rail (interactive only).** Before the intent prompt, check whether `{forge_data_folder}/` contains any prior briefs:
237
+ **First-timer rail.** Before the intent prompt, check whether `{forge_data_folder}/` contains any prior briefs:
256
238
 
257
239
  ```bash
258
240
  find "{forge_data_folder}" -maxdepth 2 -name "skill-brief.yaml" -print -quit
@@ -298,36 +280,14 @@ This will be used for the output directory and file naming. Want to use this nam
298
280
 
299
281
  Wait for confirmation or alternative.
300
282
 
301
- **Collision check (interactive and headless):** before locking the name, check whether `{forge_data_folder}/{name}/skill-brief.yaml` already exists. If it does:
302
-
303
- - Interactive: generate 1–3 non-colliding candidate alternates by scanning sibling directories under `{forge_data_folder}/`. Apply each rule that fires; skip rules whose precondition isn't met:
304
- 1. `{name}-v{N}` where `N` is the smallest positive integer that doesn't collide (e.g. `{name}-v2`, `{name}-v3`) — always applies
305
- 2. `{name}-{target_version}` if `target_version` is set and the suffix wouldn't collide (e.g. `marked-1.2.3`)
306
- 3. `{name}-{source_authority}` if `source_authority` is not `community` (e.g. `marked-internal` for an internal fork)
307
-
308
- Number the surviving alternates `[1] [2] [3]…` in the order produced (1 alternate for a community-authority brief with no `target_version`; 2–3 otherwise). Then present:
309
-
310
- ```
311
- **Heads up — a brief for `{name}` already exists at `{path}`.**
312
-
313
- Suggested alternates (none collide):
314
- [1] {alternate-1}
315
- {if a second alternate was produced:} [2] {alternate-2}
316
- {if a third alternate was produced:} [3] {alternate-3}
317
-
318
- Pick a number to use that name, type a different name, or press Enter to keep `{name}` and let step 5 §2b handle the overwrite prompt.
319
- ```
320
-
321
- On a numbered choice, replace `{name}` with the chosen alternate. On Enter, fall through to step 5's overwrite gate. On any other input, treat as a new candidate name and re-run the collision check against it.
322
-
323
- - Headless: log `"warn: skill name '{name}' collides with existing brief at {path}"` and proceed; the existing-brief overwrite policy in step 5 §2b is the canonical gate (HALT with `overwrite-cancelled` unless `force` was supplied).
283
+ **Collision check.** If `{forge_data_folder}/{name}/skill-brief.yaml` already exists, say so and offer up to three alternates that do not collide, numbered: `{name}-v{N}` with the smallest free `N`, `{name}-{target_version}` when `target_version` is set, and `{name}-{source_authority}` when the authority is not `community`. A number takes that name; a typed name is checked the same way; Enter keeps `{name}` and leaves the overwrite question to step 5 §2b.
324
284
 
325
- **Portfolio-similarity check.** When the flow is interactive AND forge tier is `Deep` AND `tools.qmd` is true in `forge-tier.yaml`, load `{portfolioSimilarityCheckFile}` and follow the procedure there to catch semantic near-duplicates that exact-name collision misses. Otherwise (headless, or tier below Deep, or qmd unavailable) skip the load — the check does not run.
326
-
327
- (The resume-a-draft offer for a returning user fires earlier, right after the target is confirmed in §3 — see the §3 "Draft-resume check" — so the intent, scope, and description a draft holds are spared *before* they get re-gathered here.)
285
+ **Portfolio-similarity check.** When forge tier is `Deep` AND `tools.qmd` is true in `forge-tier.yaml`, load `{portfolioSimilarityCheckFile}` and follow the procedure there to catch semantic near-duplicates that exact-name collision misses. Otherwise skip the load: the check does not run.
328
286
 
329
287
  ### 7. Summarize Gathered Intent
330
288
 
289
+ Compose the §7b description first, then show this summary, the description and the §8 menu in one message, and wait once:
290
+
331
291
  "**Here's what I've captured:**
332
292
 
333
293
  - **Target:** {repo URL or path}
@@ -340,84 +300,29 @@ Wait for confirmation or alternative.
340
300
  - **Target version:** {target_version} (user-specified)
341
301
  {If doc_urls collected:}
342
302
  - **Doc URLs:** {count} supplemental documentation URLs
343
- - **Forge tier:** {tier}
344
-
345
- Ready to analyze the target repository?"
346
-
347
- **Draft checkpoint.** When the flow is interactive, load `{draftCheckpointFile}` (or reuse it if already loaded for the §3 resume check) and follow Half 2 (Checkpoint Write) to persist the captured state atomically. Headless mode skips this — the run completes in a single invocation, no resume is meaningful.
303
+ - **Forge tier:** {tier}"
348
304
 
349
305
  ### 7b. Synthesize Skill Description
350
306
 
351
- The schema's `description` field is 1-3 sentences and surfaces in skill registries — it must exist by the time step 4 presents the brief. Synthesize it explicitly here, while the user's intent is fresh, instead of letting it fall out implicitly later.
352
-
353
- Compose a candidate 1-3 sentence description from the gathered material. **Write like a human library maintainer would** — what does an agent get from this skill, and when should it route here? Two facts must come through (what the skill is, when to use it); everything else is voice. Resist filling in the same skeleton every time.
354
-
355
- Load `{descriptionVoiceExamplesPath}` for the five voice examples (range of acceptable leads and structures) and the "do not template-stamp" guidance, then compose in that spirit. The asset documents what "in that spirit" means; the gathered material to draw on is the target repo, the user's intent, the version if set, and any scope hints.
307
+ The schema's `description` field is 1-3 sentences and surfaces in skill registries, so compose it here, while the intent is fresh. Load `{descriptionVoiceExamplesPath}` and compose a candidate in that spirit from the target repo, the user's intent, the version if set and any scope hints, in `{document_output_language}`, the language of the text the brief persists.
356
308
 
357
309
  **Whatever lead you choose, the description must contain a literal `Use when` clause somewhere** — validators test for that exact phrase, so alternatives like "Triggers on…" or "Reach for this when…" do not satisfy it on their own. The clause need not lead: a descriptive opener followed by `Use when …` is both good voice and validator-clean.
358
310
 
359
- Present:
311
+ Present it under the §7 summary:
360
312
 
361
313
  "**Proposed skill description:**
362
314
 
363
315
  > {synthesized description}
364
316
 
365
- This is the text agents read when deciding whether to route to your skill — it sits in the registry row alongside dozens of other skills. A specific 'use when…' trigger helps agents match real user requests; generic descriptions blend in and get skipped. Edit, replace, or accept as-is."
366
-
367
- Wait for user confirmation or alternative.
368
-
369
- **Soft sentence-count check (interactive only).** Before storing the accepted text, count terminal sentence punctuation (`.`, `!`, `?` followed by whitespace or end-of-string) — abbreviations like `e.g.` will inflate the count slightly but the check is a soft nudge, not a HALT. If the count exceeds 3, present:
370
-
371
- "**Heads up — that description reads as ~{N} sentences.** The conventional norm is 1-3 (it surfaces in registry rows alongside other skills, where length crowds out the trigger phrase). Tighten now, or accept as-is?"
372
-
373
- On `tighten` or a fresh edit: re-prompt for the description. On `accept` or any non-edit response: store the accepted text and proceed. Counts of 1-3 store silently.
374
-
375
- Store the accepted text as the brief's `description` field. The same field is re-presented in step 4 §3 for a final review pass — refinements there flow back to this value.
376
-
377
- **Headless:** if the `intent` argument was supplied, load `{descriptionVoiceExamplesPath}` and run the same synthesis against it (in `{document_output_language}`), then store the result. If `intent` was not supplied, fall back in priority order:
378
-
379
- 1. **GitHub repo description** — when `target_repo` is a GitHub URL, fetch `gh api repos/{owner}/{repo} --jq .description` (5-second timeout). If a non-empty description comes back, load `{descriptionVoiceExamplesPath}` and synthesize using the GitHub description as the seed in place of `intent`. Write the synthesized description in `{document_output_language}` regardless of the seed's language (the seed may be in any language; the output's language is dictated by the workflow's document-output configuration). Log `"info: description seeded from GitHub repo description"`. (The full `gh api repos` response is fetched again in step 2 §1; this lightweight `--jq .description` call only retrieves the one field.)
380
- 2. **Generic stub** — when no GitHub description is available (local-path target, GitHub repo with empty description, or `gh api` fails): derive from `target_repo` + `skill_name` (`"Use the {skill_name} skill to work with code or content from {target_repo}."`) — the generic fallback does not need the asset — and log `"warn: description synthesized without intent or repo description — narrow registry text."`
317
+ This is the text agents read when deciding whether to route to your skill, in a registry row beside dozens of others: a specific 'Use when' trigger helps agents match real requests. Edit it, replace it, or accept it with [C]."
381
318
 
382
319
  ### 8. Present MENU OPTIONS
383
320
 
384
- Display: "**Select:** [C] Continue to Target Analysis · [X] Cancel and exit"
321
+ End the §7 message with: "**Select:** edit the description or any field above · [C] Continue to Target Analysis · [X] Cancel and exit"
385
322
 
386
323
  #### Menu Handling Logic:
387
324
 
388
- - IF C: Load, read entire file, then execute {nextStepFile}
389
- - IF X: Treat as user-cancellation. Display `"Cancelled — no brief was written."` and HALT (exit code 6, `halt_reason: "user-cancelled"`). When `{headless_mode}` is true the GATE auto-proceeds and never reaches this branch — `[X]` is interactive-only. Cancellation here is non-destructive: no files have been written yet by step 1.
325
+ - IF C: when the description runs past three sentences, nudge once to tighten it (a long one crowds the trigger out of its registry row) and keep what the user settles on. Store it as the brief's `description`: step 4 §3 shows it again for a final pass. Load `{draftCheckpointFile}` (or reuse it from the §3 resume check) and follow Half 2 (Checkpoint Write), so the draft holds the gathered intent and the accepted description. Then load, read entire file, then execute {nextStepFile}
326
+ - IF X: Treat as user-cancellation. Remove the run folder (`case "{run_dir}" in "{project-root}/_bmad-output/.skf-run/skf-brief-skill-"*) rm -rf "{run_dir}" ;; esac`), display `"Cancelled: no brief was written."` and HALT (exit code 6, `halt_reason: "user-cancelled"`). No brief was written; a draft saved earlier stays for a later resume.
327
+ - IF an edit to the description or another field: apply it (a new name runs the §6 collision check again), show the summary and the description again, then [Redisplay Menu Options](#8-present-menu-options)
390
328
  - IF Any other: Help user, then [Redisplay Menu Options](#8-present-menu-options)
391
-
392
- #### Execution rules:
393
-
394
- - **Resolve `{validateBriefInputsHelper}`** from `{validateBriefInputsProbeOrder}`; first existing path wins. HALT if no candidate exists.
395
-
396
- - **GATE [default: use args]** — If `{headless_mode}`, consume pre-supplied arguments and auto-proceed. The full argument set (required/optional, defaults, halt codes, enum values) is documented in `{headlessArgsFile}` — load it now if you need to look up a specific argument. Validation is delegated to `{validateBriefInputsHelper}`; the table is the canonical operator-facing documentation, the script enforces it.
397
-
398
- **Preset merge (before validation).** Skip this merge entirely when a `from_brief` argument is present — presets seed a *derived* brief and have no meaning on the ratify route below. Otherwise: if the headless args include a `preset` field, load `{sidecar_path}/brief-presets/{preset}.yaml` and merge its contents as defaults — explicit args override preset values, key by key. The preset file is YAML; if it does not exist, log `"warn: preset '{name}' not found at {path} — proceeding without preset"` and continue (do not HALT). If it parses but contains unknown fields, log per-field warnings and pass through unchanged (the validator's KNOWN_FIELDS check will catch any that survive). Drop the `preset` key itself from the merged dict before passing to the validator (it is consumed at this level and is not a brief field).
399
-
400
- **Delegate validation to `{validateBriefInputsHelper}`** instead of reasoning through the table rules in prose:
401
-
402
- ```bash
403
- echo '<headless-args-as-json>' | uv run {validateBriefInputsHelper}
404
- ```
405
-
406
- The script returns a JSON envelope: `{valid, errors[], warnings[], normalized, halt_reason}`. Apply the result deterministically:
407
-
408
- - **`valid: false`** — emit the error envelope per **step 5 §4b** with the script's `halt_reason` (`"input-missing"` for absent required args / docs-only without doc_urls; `"input-invalid"` for enum violations, malformed semver, malformed kebab-case skill_name). Surface `errors[]` to the operator log so the failure is debuggable. HALT.
409
- - **`valid: true`** — consume the `normalized` object as the source of truth (it has defaults applied per the table). Surface `warnings[]` to the operator log but do not HALT. Auto-proceed.
410
-
411
- The script's `KNOWN_FIELDS` set must stay in sync with the table in `{headlessArgsFile}`.
412
-
413
- **Ratify route — `from_brief` present.** After a `valid: true` result, branch on `normalized.from_brief`. When it is set, this run ratifies a pre-authored brief instead of deriving one — the headless mirror of the interactive §3.1a `[R]` branch. Take this route *before* the source-authority detection and analyze-target routing below (both belong to the derive path and do not apply here):
414
-
415
- 1. **Resolve the brief path.** If `normalized.from_brief` ends in `skill-brief.yaml`, that is the path; otherwise treat it as a directory and use `<from_brief>/skill-brief.yaml`.
416
- 2. **Schema-validate.** Resolve `{validateBriefSchemaHelper}` from `{validateBriefSchemaProbeOrder}` (first existing path wins; HALT if no candidate exists), then run `uv run {validateBriefSchemaHelper} <resolved-brief-path>`. The script returns `{valid, errors[], warnings[], halt_reason, brief}`. Apply it — and note that, unlike the interactive §3.1a branch (which re-prompts because the operator might have a corrected path to offer), headless has no second chance, so an unusable brief is terminal:
417
- - **`valid: false`** with `halt_reason: "brief-missing"` (path absent / unreadable) — emit the error envelope per **step 5 §4b** with `halt_reason: "input-missing"`, surface `errors[]` to the operator log, HALT (exit 2).
418
- - **`valid: false`** with any other `halt_reason` (`brief-malformed` / `brief-invalid`) — emit the error envelope with `halt_reason: "input-invalid"`, surface `errors[]`, HALT (exit 2).
419
- - **`valid: true`** — surface any non-empty `warnings[]` to the operator log and proceed with the parsed `brief` payload.
420
- 3. **Hydrate and route.** Store `ratify_mode: true` and `ratify_source_path: <resolved-brief-path>` in workflow context, then hydrate the brief context variables from the parsed `brief` payload exactly as the §3.1a `[R]` branch does (the identical field-mapping list: `name`/`version`/`target_version`, `target_ref`/`source_ref`, `source_repo`/`source_type`/`source_authority`/`doc_urls`, `language`/`description`/`forge_tier`, `created`/`created_by`, `scope.type`/`scope.include`/`scope.exclude`/`scope.tier_a_include`/`scope.notes`/`scope.rationale`/`scope.amendments`, `scripts_intent`/`assets_intent` — preserving `target_ref`/`source_ref`/`tier_a_include`/`amendments` verbatim). Load, read entirely, and execute `{ratifyTargetFile}` — bypassing step 2 (analyze-target) and step 3 (scope-definition), both of which would re-derive fields already on disk. The forward chain resumes at step 4 (confirm-brief), which auto-confirms `[C]` under headless and proceeds to step 5's write (the step 5 §2b ratify branch auto-overwrites in place). Do **not** run the source-authority detection or the `[C] → {nextStepFile}` routing below — they belong to the derive path.
421
-
422
- **Headless source-authority detection (derive route only — no `from_brief`).** After consuming `normalized`, if `source_authority` is absent AND `source_type=source` AND `target_repo` is a GitHub URL, load `{headlessSourceAuthorityDetectionFile}` and follow the procedure there. Otherwise (precondition unmet, value already supplied, docs-only, or local-path) skip the load — `community` is the implicit default for the unmet branches.
423
-
@@ -1,23 +1,91 @@
1
- # Headless Argument Table
1
+ ---
2
+ nextStepFile: 'analyze-target.md'
3
+ ratifyFile: 'references/gather-intent-ratify.md'
4
+ validateBriefInputsProbeOrder:
5
+ - '{project-root}/_bmad/skf/shared/scripts/skf-validate-brief-inputs.py'
6
+ - '{project-root}/src/shared/scripts/skf-validate-brief-inputs.py'
7
+ ---
2
8
 
3
- Loaded by step 1 §8 only when `{headless_mode}` is true. Canonical operator-facing documentation for the argument set consumed at step 1's GATE; the `{validateBriefInputsHelper}` enforces these rules deterministically (its `KNOWN_FIELDS` set must stay in sync with this table).
9
+ <!-- Config: communicate in {communication_language}. -->
10
+
11
+ # Step 1 (Headless): Input Gate
12
+
13
+ Step 1 §1b loads this file when `{headless_mode}` is true outside `[auto]` mode, in place of step 1's interactive §2 to §8. The arguments are merged and validated here, before any section uses them, and every later value the run takes from an argument comes from the validated `normalized` object.
14
+
15
+ ## Arguments
16
+
17
+ `{validateBriefInputsHelper}` enforces this table.
4
18
 
5
19
  | Argument | Required | Default | Notes |
6
20
  |----------|----------|---------|-------|
7
- | `target_repo` | yes¹ | — | HALT (exit 2, `halt_reason: "input-missing"`) if absent. ¹Not required when `from_brief` is supplied — the ratify route derives the target from the brief and ignores `target_repo` (with a warning) if also passed |
8
- | `skill_name` | yes¹ | — | HALT (exit 2, `halt_reason: "input-missing"`) if absent; HALT (exit 2, `halt_reason: "input-invalid"`) if non-kebab. ¹Not required when `from_brief` is supplied — the ratify route derives the name from the brief and ignores `skill_name` (with a warning) if also passed |
9
- | `from_brief` | no | — | Path to a pre-authored `skill-brief.yaml` (a file, or a directory containing one) to **ratify** instead of deriving a brief. When present it is the source of truth and routes the step 1 §8 GATE to the headless ratify path — the mirror of the interactive §3.1a `[R]` branch: schema-validate the brief → skip analyze-target / scope-definition (no re-derivation) → write through the canonical writer, overwriting in place (no `force` needed). `target_repo` / `skill_name` become optional and are ignored if also passed. HALT (exit 2, `halt_reason: "input-missing"`) if the value is empty or the resolved path does not exist; HALT (exit 2, `halt_reason: "input-invalid"`) if the brief fails schema validation |
21
+ | `target_repo` | yes¹ | none | HALT (exit 2, `halt_reason: "input-missing"`) if absent. ¹Not required when `from_brief` is supplied: the ratify route takes the target from the brief and ignores `target_repo` (with a warning) if also passed |
22
+ | `skill_name` | yes¹ | none | HALT (exit 2, `halt_reason: "input-missing"`) if absent; HALT (exit 2, `halt_reason: "input-invalid"`) if not kebab-case. ¹Not required when `from_brief` is supplied: the ratify route takes the name from the brief and ignores `skill_name` (with a warning) if also passed |
23
+ | `from_brief` | no | none | Path to a pre-authored `skill-brief.yaml` (a file, or a folder holding one) to **ratify** instead of deriving a brief (§3): schema-validate it, skip steps 2 and 3, write through the canonical writer to `{forge_data_folder}/{name}/skill-brief.yaml` (no `force` needed when the brief already lives at that path; otherwise `force` applies as on the derive route). `target_repo` and `skill_name` become optional and are ignored if also passed. HALT (exit 2, `halt_reason: "input-missing"`) if the value is empty or the path does not exist; HALT (exit 2, `halt_reason: "input-invalid"`) if the brief fails schema validation |
10
24
  | `source_type` | no | `source` | If `docs-only`, `doc_urls` becomes required |
11
- | `doc_urls` | conditional | — | Required when `source_type=docs-only` (HALT exit 2, `halt_reason: "input-missing"` if empty). List of `url` or `url,label` |
12
- | `source_authority` | no | detected | `official` / `community` / `internal`. When absent and `target_repo` is a GitHub URL, step 1 §8 GATE probes `gh api user` and compares its login to the URL owner — match → `official`, otherwise → `community`. Local-path or `gh api user` failure → `community`. Forced to `community` when `source_type=docs-only` |
13
- | `target_version` | no | — | Auto-detected in step 2 if absent. Full X.Y.Z semver required (HALT exit 2, `halt_reason: "input-invalid"` on partial forms like `1`, `1.2`, `v2`) |
14
- | `scope_hint` | no | — | Free-text steering for §5 |
15
- | `language_hint` | no | — | Overrides language detection — consumed at step 2 §3: the detector still runs for the informational Detected-language line, but the hint becomes the confirmed language and the step 3 §4 low-confidence override does not fire |
16
- | `scope_type` | no | heuristic | `full-library` / `specific-modules` / `public-api` / `component-library` / `reference-app` / `docs-only`. When absent and `source_type=source`, step 3 §2c runs five signal-driven heuristics (component-registry presence, reference-app keywords, specific-module intent, narrow public API) and uses the first match; falls back to `full-library` only if no heuristic fires. `source_type=docs-only` always short-circuits to `docs-only` |
17
- | `include` | no | — | Comma-separated globs (used by step 3 §3) |
18
- | `exclude` | no | — | Comma-separated globs (used by step 3 §3) |
25
+ | `doc_urls` | conditional | none | Required when `source_type=docs-only` (HALT exit 2, `halt_reason: "input-missing"` if empty). List of `url` or `url,label` |
26
+ | `source_authority` | no | detected | `official` / `community` / `internal`. When absent and `target_repo` is a GitHub URL, §4 compares the `gh api user` login with the URL owner: a match is `official`, anything else `community`. A local path, or a failed `gh api user`, is `community`. Forced to `community` when `source_type=docs-only` |
27
+ | `target_version` | no | none | Auto-detected in step 2 if absent. Full X.Y.Z semver required (HALT exit 2, `halt_reason: "input-invalid"` on partial forms like `1`, `1.2`, `v2`) |
28
+ | `scope_hint` | no | none | Free-text scope steering, classified with `intent` into the scope-type signals at step 3 §2c |
29
+ | `language_hint` | no | none | Overrides language detection, consumed at step 2 §3: the detector still runs for the informational Detected-language line, but the hint becomes the confirmed language and the step 3 §4 low-confidence override does not fire |
30
+ | `scope_type` | no | heuristic | `full-library` / `specific-modules` / `public-api` / `component-library` / `reference-app` / `docs-only`. When absent and `source_type=source`, step 3 §2c recommends one from the `intent` and `scope_hint` arguments and step 2's analysis; `source_type=docs-only` always short-circuits to `docs-only` |
31
+ | `include` | no | the scope type's default | Comma-separated globs, used by step 3 §3 as given. When absent, step 3 §3 takes the scope type's headless default and names it in the envelope's `warnings`; a `scope_type=reference-app` argument halts here instead (§2), and a `reference-app` type the recommender picked, or a `specific-modules` `scope_type` argument whose `intent` and `scope_hint` name no module, halts at step 3 §3, each with `input-missing` (exit 2) |
32
+ | `exclude` | no | see Notes | Comma-separated globs. With an `include`, step 3 §3 uses them as given; without one, it adds them to the exclusions of the scope type's headless default and names them in its `warn:` line. When absent: none beside a given `include`, else the default's exclusions |
19
33
  | `scripts_intent` | no | `detect` | `detect` / `none` / free-text |
20
34
  | `assets_intent` | no | `detect` | `detect` / `none` / free-text |
21
- | `intent` | no | — | Free-text used to derive `description` in §7b |
22
- | `force` | no | — | Overwrite existing brief without prompting (consumed in step 5 §2b) |
23
- | `preset` | no | — | Name of a preset YAML file at `{sidecar_path}/brief-presets/{preset}.yaml`. Loaded at step 1 §8 GATE and merged as defaults; explicit args override preset values. Useful for repeated patterns (e.g. briefing 5 SaaS API SDKs with the same `source_authority`/`scope_type`/`scripts_intent`). The preset file is YAML containing any subset of the headless args above; unknown fields are ignored with a warning |
35
+ | `intent` | no | none | Free text the description is composed from (§5) |
36
+ | `force` | no | none | Overwrite an existing brief without prompting (consumed in step 5 §2b) |
37
+ | `preset` | no | none | Name of a preset YAML file at `{sidecar_path}/brief-presets/{preset}.yaml`, merged as defaults by §1: explicit arguments override preset values. Useful for repeated patterns (e.g. briefing 5 SaaS API SDKs with the same `source_authority`/`scope_type`/`scripts_intent`). The preset file is YAML holding any subset of the arguments above; unknown fields are ignored with a warning |
38
+
39
+ ## Sequence
40
+
41
+ **GATE [default: use args]**: consume the arguments in the order below and auto-proceed; nothing here prompts.
42
+
43
+ ### 1. Preset Merge
44
+
45
+ Skip this merge when a `from_brief` argument is present: a preset seeds a derived brief and means nothing on the ratify route. Otherwise, when the arguments hold a `preset`, load `{sidecar_path}/brief-presets/{preset}.yaml` and merge its keys as defaults, an explicit argument winning key by key. When the file does not exist, log `"warn: preset '{name}' not found at {path}; proceeding without preset"`, add it to `workflow_warnings[]` and continue. An unknown field the preset holds passes through: the validator warns about it in §2. Drop the `preset` key itself before validation: it is not a brief field.
46
+
47
+ ### 2. Validate the Arguments
48
+
49
+ Resolve `{validateBriefInputsHelper}` from `{validateBriefInputsProbeOrder}` (first existing path wins; HALT if no candidate exists). Stage the merged arguments as one JSON object in the run folder, then run the helper on the file:
50
+
51
+ ```bash
52
+ cat > "{run_dir}/headless-args.json" <<'SKF_JSON'
53
+ <the merged headless arguments, as one JSON object>
54
+ SKF_JSON
55
+ uv run {validateBriefInputsHelper} < "{run_dir}/headless-args.json"
56
+ ```
57
+
58
+ It returns `{valid, errors[], warnings[], normalized, halt_reason}`:
59
+
60
+ - **`valid: false`**: emit the halt envelope first, `uv run {emitBriefEnvelopeHelper} emit --target stderr` with the script's `halt_reason` (`input-missing` for an absent required argument, docs-only without `doc_urls`, or a `reference-app` `scope_type` without `include`; `input-invalid` for an enum violation, malformed semver or a `skill_name` that is not kebab-case) (SKILL.md Halt Contract), surface `errors[]` to the operator log, then HALT (exit code 2).
61
+ - **`valid: true`**: `normalized`, the arguments with the table's defaults applied, is the source of truth for the rest of the run. Log each `warnings[]` entry and add it to `workflow_warnings[]` as `<field>: <message>`.
62
+
63
+ ### 3. Ratify Route (`from_brief`)
64
+
65
+ When `normalized.from_brief` is set, this run ratifies a pre-authored brief instead of deriving one: load, read entirely, and execute `{ratifyFile}` with that path. It validates the brief and hands the run to step 4, so nothing below runs.
66
+
67
+ ### 4. Source Authority
68
+
69
+ When `normalized.source_authority` is absent, `source_type` is `source` and `target_repo` is a GitHub URL (`https://github.com/<owner>/<repo>`), probe the operator's login:
70
+
71
+ ```bash
72
+ gh api user --jq .login
73
+ ```
74
+
75
+ Compare it with `<owner>`, both lower-cased (GitHub owners match case-insensitively, but the API keeps the case): a match sets `source_authority: "official"`, another login `community`. When the call fails (`gh` missing or not logged in, no network), set `community`, log `"warn: source-authority detection skipped: gh api user failed"` and add it to `workflow_warnings[]`. In every other case `source_authority` is the value given, else `community`.
76
+
77
+ ### 5. Derive the Brief Fields
78
+
79
+ From `normalized`, before step 2 runs:
80
+
81
+ - **Version:** a `target_version` sets `version` too; without one, step 2 detects the version.
82
+ - **Doc URLs:** HEAD-check every `doc_urls` entry in parallel, all calls in one message, each `curl -sI --max-time 5 {url}`. Keep a URL that fails, log `"warn: could not reach {url} ({status or error})"` and add it to `workflow_warnings[]`: the failure shows now instead of in skf-create-skill.
83
+ - **Name collision:** when `{forge_data_folder}/{skill_name}/skill-brief.yaml` exists, log `"warn: skill name '{skill_name}' collides with existing brief at {path}"`, add it to `workflow_warnings[]` and proceed: step 5 §2b halts with `overwrite-cancelled` unless `force` was supplied.
84
+ - **Description:** compose 1-3 sentences in `{document_output_language}` that say what the skill is and contain a literal `Use when` clause, in the spirit of `{descriptionVoiceExamplesPath}` (load it), from the first seed available:
85
+ 1. `intent`.
86
+ 2. The repository's own description, when `target_repo` is a GitHub URL: `gh api repos/{owner}/{repo} --jq .description` (5-second timeout). When it is not empty, log `"info: description seeded from GitHub repo description"`.
87
+ 3. None (a local path, an empty description, a failed call): write `"Use the {skill_name} skill to work with code or content from {target_repo}."`, log `"warn: description synthesized without intent or repo description: narrow registry text."` and add it to `workflow_warnings[]`.
88
+
89
+ ### 6. Continue
90
+
91
+ Load, read entire file, then execute `{nextStepFile}` (step 2).
@@ -9,4 +9,4 @@ nextStepFile: 'shared/health-check.md'
9
9
 
10
10
  # Step 6: Workflow Health Check
11
11
 
12
- This is the terminal step of brief-skill. Load `{nextStepFile}`, read it fully, then execute it — do nothing else here (no user-facing reports, file writes, or result contracts; those were step 5). After `{nextStepFile}` returns control, the brief-skill workflow is fully complete: do not re-enter step 5 or step 6, load any further step file, or loop back into the workflow.
12
+ This is the terminal step of brief-skill. Load `{nextStepFile}`, read it fully, then execute it: do nothing else here (no user-facing reports, file writes, or result contracts; those were step 5). In a headless or `[auto]` run, the shared health check displays the `{result_envelope_line}` that write-brief.md §4b or step-auto-validate.md §3 bound as the run's last line. After `{nextStepFile}` returns control, the brief-skill workflow is fully complete: do not re-enter step 5 or step 6, load any further step file, or loop back into the workflow.