bmad-module-skill-forge 1.9.0 → 2.0.1

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 (281) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.nvmrc +1 -1
  3. package/README.md +10 -5
  4. package/docs/_data/pinned.yaml +2 -2
  5. package/docs/agents.md +11 -2
  6. package/docs/architecture.md +5 -4
  7. package/docs/bmad-synergy.md +30 -7
  8. package/docs/campaign.md +172 -0
  9. package/docs/examples.md +7 -3
  10. package/docs/forge-auto.md +90 -0
  11. package/docs/getting-started.md +9 -0
  12. package/docs/how-it-works.md +6 -4
  13. package/docs/index.md +4 -3
  14. package/docs/skill-model.md +1 -1
  15. package/docs/troubleshooting.md +17 -1
  16. package/docs/verifying-a-skill.md +2 -2
  17. package/docs/why-skf.md +1 -1
  18. package/docs/workflows.md +64 -24
  19. package/package.json +2 -2
  20. package/src/knowledge/skill-lifecycle.md +1 -1
  21. package/src/module-help.csv +4 -3
  22. package/src/shared/data/language-corpora.json +32 -0
  23. package/src/shared/references/pipeline-contracts.md +6 -3
  24. package/src/shared/scripts/schemas/skill-brief.v1.json +6 -1
  25. package/src/shared/scripts/skf-comention-pairs.py +350 -0
  26. package/src/shared/scripts/skf-count-tokens.py +222 -0
  27. package/src/shared/scripts/skf-derive-assembly-shape.py +107 -0
  28. package/src/shared/scripts/skf-detect-docs.py +240 -4
  29. package/src/shared/scripts/skf-detect-language.py +82 -3
  30. package/src/shared/scripts/skf-detect-tools.py +105 -2
  31. package/src/shared/scripts/skf-emit-result-envelope.py +17 -0
  32. package/src/shared/scripts/skf-enumerate-stack-skills.py +111 -2
  33. package/src/shared/scripts/skf-extract-public-api.py +53 -0
  34. package/src/shared/scripts/skf-find-cycles.py +246 -0
  35. package/src/shared/scripts/skf-hash-content.py +487 -2
  36. package/src/shared/scripts/skf-language-corpora.py +100 -0
  37. package/src/shared/scripts/skf-manifest-ops.py +67 -1
  38. package/src/shared/scripts/skf-merge-doc-urls.py +244 -0
  39. package/src/shared/scripts/skf-preapply.py +1 -1
  40. package/src/shared/scripts/skf-rebuild-managed-sections.py +180 -0
  41. package/src/shared/scripts/skf-recommend-scope-type.py +1 -2
  42. package/src/shared/scripts/skf-render-metadata-stats.py +499 -0
  43. package/src/shared/scripts/skf-rewrite-skill-name.py +308 -0
  44. package/src/shared/scripts/skf-shape-detect.py +576 -25
  45. package/src/shared/scripts/skf-shard-body.py +461 -0
  46. package/src/shared/scripts/skf-skill-inventory.py +139 -3
  47. package/src/shared/scripts/skf-structural-diff.py +307 -67
  48. package/src/shared/scripts/skf-validate-brief-schema.py +41 -6
  49. package/src/shared/scripts/skf-validate-feasibility-report.py +234 -0
  50. package/src/shared/scripts/skf-validate-frontmatter.py +17 -12
  51. package/src/shared/scripts/skf-validate-output.py +443 -10
  52. package/src/shared/scripts/skf-validate-pins.py +3 -3
  53. package/src/shared/scripts/skf-verify-no-trace.py +214 -0
  54. package/src/shared/scripts/skf-verify-provenance-completeness.py +439 -0
  55. package/src/shared/scripts/skf-write-skill-brief.py +21 -5
  56. package/src/skf-analyze-source/SKILL.md +17 -32
  57. package/src/skf-analyze-source/assets/skill-brief-schema.md +1 -1
  58. package/src/skf-analyze-source/customize.toml +2 -0
  59. package/src/skf-analyze-source/references/auto-docs-only.md +116 -0
  60. package/src/skf-analyze-source/references/continue.md +8 -13
  61. package/src/skf-analyze-source/references/generate-briefs.md +28 -12
  62. package/src/skf-analyze-source/references/headless-contract.md +33 -0
  63. package/src/skf-analyze-source/references/health-check.md +1 -2
  64. package/src/skf-analyze-source/references/identify-units.md +25 -36
  65. package/src/skf-analyze-source/references/init.md +12 -25
  66. package/src/skf-analyze-source/references/map-and-detect.md +8 -20
  67. package/src/skf-analyze-source/references/recommend.md +4 -14
  68. package/src/skf-analyze-source/references/scan-project.md +3 -11
  69. package/src/skf-analyze-source/references/step-auto-scope.md +211 -197
  70. package/src/skf-analyze-source/references/step-shape-detect.md +20 -13
  71. package/src/skf-analyze-source/references/unit-detection-heuristics.md +2 -2
  72. package/src/skf-audit-skill/SKILL.md +9 -6
  73. package/src/skf-audit-skill/customize.toml +2 -0
  74. package/src/skf-audit-skill/references/init.md +58 -32
  75. package/src/skf-audit-skill/references/re-index.md +15 -34
  76. package/src/skf-audit-skill/references/report.md +11 -58
  77. package/src/skf-audit-skill/references/semantic-diff.md +4 -22
  78. package/src/skf-audit-skill/references/severity-classify.md +53 -87
  79. package/src/skf-audit-skill/references/step-doc-drift.md +49 -19
  80. package/src/skf-audit-skill/references/structural-diff.md +43 -68
  81. package/src/skf-brief-skill/SKILL.md +7 -36
  82. package/src/skf-brief-skill/assets/scope-templates.md +1 -1
  83. package/src/skf-brief-skill/assets/skill-brief-schema.md +1 -1
  84. package/src/skf-brief-skill/customize.toml +14 -0
  85. package/src/skf-brief-skill/references/analyze-target.md +13 -18
  86. package/src/skf-brief-skill/references/confirm-brief.md +2 -15
  87. package/src/skf-brief-skill/references/draft-checkpoint.md +8 -8
  88. package/src/skf-brief-skill/references/gather-intent.md +27 -24
  89. package/src/skf-brief-skill/references/headless-args.md +1 -1
  90. package/src/skf-brief-skill/references/health-check.md +1 -22
  91. package/src/skf-brief-skill/references/invocation-contract.md +37 -0
  92. package/src/skf-brief-skill/references/scope-definition.md +6 -15
  93. package/src/skf-brief-skill/references/step-auto-brief.md +22 -9
  94. package/src/skf-brief-skill/references/step-auto-validate.md +3 -7
  95. package/src/skf-brief-skill/references/version-resolution.md +1 -1
  96. package/src/skf-brief-skill/references/write-brief.md +19 -13
  97. package/src/skf-campaign/SKILL.md +121 -0
  98. package/src/skf-campaign/assets/campaign-state-schema.json +191 -0
  99. package/src/skf-campaign/customize.toml +75 -0
  100. package/src/skf-campaign/manifest.yaml +15 -0
  101. package/src/skf-campaign/references/campaign-contracts.md +67 -0
  102. package/src/skf-campaign/references/campaign-directive-spec.md +32 -0
  103. package/src/skf-campaign/references/health-check.md +35 -0
  104. package/src/skf-campaign/references/step-01-setup.md +121 -0
  105. package/src/skf-campaign/references/step-02-strategy.md +102 -0
  106. package/src/skf-campaign/references/step-03-pins.md +56 -0
  107. package/src/skf-campaign/references/step-04-provenance.md +63 -0
  108. package/src/skf-campaign/references/step-05-skill-loop.md +103 -0
  109. package/src/skf-campaign/references/step-06-batch.md +88 -0
  110. package/src/skf-campaign/references/step-07-capstone.md +63 -0
  111. package/src/skf-campaign/references/step-08-verify.md +75 -0
  112. package/src/skf-campaign/references/step-09-refine.md +83 -0
  113. package/src/skf-campaign/references/step-10-export.md +106 -0
  114. package/src/skf-campaign/references/step-11-maintenance.md +84 -0
  115. package/src/skf-campaign/references/step-resume.md +115 -0
  116. package/src/skf-campaign/scripts/.gitkeep +0 -0
  117. package/src/skf-campaign/scripts/campaign-deps.py +244 -0
  118. package/src/skf-campaign/scripts/campaign-parse-manifest.py +119 -0
  119. package/src/skf-campaign/scripts/campaign-provenance.py +247 -0
  120. package/src/skf-campaign/scripts/campaign-render-batch.py +199 -0
  121. package/src/skf-campaign/scripts/campaign-render-kickoff.py +158 -0
  122. package/src/skf-campaign/scripts/campaign-report.py +249 -0
  123. package/src/skf-campaign/scripts/campaign-status.py +162 -0
  124. package/src/skf-campaign/scripts/campaign-validate-pins.py +174 -0
  125. package/src/skf-campaign/scripts/campaign-validate-state.py +207 -0
  126. package/src/skf-campaign/templates/campaign-brief-template.yaml +34 -0
  127. package/src/skf-campaign/templates/campaign-report-template.md +54 -0
  128. package/src/skf-campaign/templates/kickoff-template.md +48 -0
  129. package/src/skf-create-skill/SKILL.md +15 -4
  130. package/src/skf-create-skill/assets/compile-assembly-rules.md +35 -34
  131. package/src/skf-create-skill/assets/skill-sections.md +9 -100
  132. package/src/skf-create-skill/assets/tessl-dismissal-rules.md +4 -13
  133. package/src/skf-create-skill/customize.toml +13 -0
  134. package/src/skf-create-skill/references/authoritative-files-protocol.md +7 -7
  135. package/src/skf-create-skill/references/compile.md +37 -47
  136. package/src/skf-create-skill/references/component-extraction.md +8 -35
  137. package/src/skf-create-skill/references/ecosystem-check.md +9 -25
  138. package/src/skf-create-skill/references/enrich.md +4 -17
  139. package/src/skf-create-skill/references/extract.md +20 -27
  140. package/src/skf-create-skill/references/extraction-patterns-tracing.md +1 -1
  141. package/src/skf-create-skill/references/extraction-patterns.md +10 -8
  142. package/src/skf-create-skill/references/generate-artifacts.md +20 -25
  143. package/src/skf-create-skill/references/health-check.md +2 -2
  144. package/src/skf-create-skill/references/load-brief.md +16 -18
  145. package/src/skf-create-skill/references/report.md +27 -14
  146. package/src/skf-create-skill/references/source-resolution-protocols.md +4 -4
  147. package/src/skf-create-skill/references/step-auto-shard.md +52 -25
  148. package/src/skf-create-skill/references/step-doc-rot.md +33 -15
  149. package/src/skf-create-skill/references/step-doc-sources.md +13 -4
  150. package/src/skf-create-skill/references/sub/ccc-discover.md +2 -13
  151. package/src/skf-create-skill/references/sub/fetch-docs.md +33 -46
  152. package/src/skf-create-skill/references/sub/fetch-temporal.md +5 -20
  153. package/src/skf-create-skill/references/tier-degradation-rules.md +6 -8
  154. package/src/skf-create-skill/references/validate.md +69 -29
  155. package/src/skf-create-skill/scripts/scan-doc-rot.py +245 -0
  156. package/src/skf-create-stack-skill/SKILL.md +15 -9
  157. package/src/skf-create-stack-skill/assets/provenance-map-schema.md +1 -1
  158. package/src/skf-create-stack-skill/customize.toml +10 -0
  159. package/src/skf-create-stack-skill/references/compile-stack.md +7 -8
  160. package/src/skf-create-stack-skill/references/compose-mode-rules.md +2 -13
  161. package/src/skf-create-stack-skill/references/detect-integrations.md +49 -54
  162. package/src/skf-create-stack-skill/references/detect-manifests.md +37 -30
  163. package/src/skf-create-stack-skill/references/generate-output.md +24 -75
  164. package/src/skf-create-stack-skill/references/init.md +9 -81
  165. package/src/skf-create-stack-skill/references/manifest-patterns.md +5 -35
  166. package/src/skf-create-stack-skill/references/parallel-extract.md +12 -27
  167. package/src/skf-create-stack-skill/references/rank-and-confirm.md +6 -6
  168. package/src/skf-create-stack-skill/references/report.md +27 -62
  169. package/src/skf-create-stack-skill/references/validate.md +35 -31
  170. package/src/skf-drop-skill/SKILL.md +20 -23
  171. package/src/skf-drop-skill/customize.toml +10 -0
  172. package/src/skf-drop-skill/references/execute.md +67 -36
  173. package/src/skf-drop-skill/references/headless-contract.md +18 -0
  174. package/src/skf-drop-skill/references/health-check.md +1 -13
  175. package/src/skf-drop-skill/references/report.md +44 -10
  176. package/src/skf-drop-skill/references/select.md +93 -48
  177. package/src/skf-drop-skill/scripts/dir-sizes.py +116 -0
  178. package/src/skf-export-skill/SKILL.md +17 -14
  179. package/src/skf-export-skill/assets/managed-section-format.md +2 -5
  180. package/src/skf-export-skill/customize.toml +10 -6
  181. package/src/skf-export-skill/references/generate-snippet.md +21 -35
  182. package/src/skf-export-skill/references/load-skill.md +44 -42
  183. package/src/skf-export-skill/references/multi-skill-mode.md +1 -1
  184. package/src/skf-export-skill/references/orphan-context-detection.md +11 -3
  185. package/src/skf-export-skill/references/package.md +27 -33
  186. package/src/skf-export-skill/references/preflight-snippet-root-probe.md +24 -5
  187. package/src/skf-export-skill/references/result-envelope.md +28 -0
  188. package/src/skf-export-skill/references/summary.md +11 -5
  189. package/src/skf-export-skill/references/token-report.md +42 -24
  190. package/src/skf-export-skill/references/update-context.md +32 -33
  191. package/src/skf-forger/SKILL.md +32 -39
  192. package/src/skf-forger/references/pipeline-mode.md +34 -0
  193. package/src/skf-forger/scripts/parse-pipeline.py +270 -0
  194. package/src/skf-quick-skill/SKILL.md +10 -60
  195. package/src/skf-quick-skill/customize.toml +9 -0
  196. package/src/skf-quick-skill/references/batch-mode.md +6 -4
  197. package/src/skf-quick-skill/references/compile.md +15 -52
  198. package/src/skf-quick-skill/references/ecosystem-check.md +5 -20
  199. package/src/skf-quick-skill/references/finalize.md +12 -6
  200. package/src/skf-quick-skill/references/halt-contract.md +54 -0
  201. package/src/skf-quick-skill/references/health-check.md +3 -4
  202. package/src/skf-quick-skill/references/quick-extract.md +7 -18
  203. package/src/skf-quick-skill/references/registry-resolution.md +1 -23
  204. package/src/skf-quick-skill/references/resolve-target.md +27 -34
  205. package/src/skf-quick-skill/references/write-and-validate.md +10 -25
  206. package/src/skf-refine-architecture/SKILL.md +16 -8
  207. package/src/skf-refine-architecture/customize.toml +9 -0
  208. package/src/skf-refine-architecture/references/compile.md +10 -8
  209. package/src/skf-refine-architecture/references/gap-analysis.md +21 -50
  210. package/src/skf-refine-architecture/references/health-check.md +1 -1
  211. package/src/skf-refine-architecture/references/improvements.md +9 -25
  212. package/src/skf-refine-architecture/references/init.md +9 -16
  213. package/src/skf-refine-architecture/references/issue-detection.md +10 -25
  214. package/src/skf-refine-architecture/references/refinement-rules.md +4 -16
  215. package/src/skf-refine-architecture/references/report.md +14 -11
  216. package/src/skf-rename-skill/SKILL.md +11 -21
  217. package/src/skf-rename-skill/customize.toml +10 -0
  218. package/src/skf-rename-skill/references/execute.md +112 -82
  219. package/src/skf-rename-skill/references/exit-codes.md +12 -0
  220. package/src/skf-rename-skill/references/report.md +16 -8
  221. package/src/skf-rename-skill/references/select.md +69 -42
  222. package/src/skf-rename-skill/scripts/skf-validate-rename-name.py +161 -0
  223. package/src/skf-setup/SKILL.md +21 -13
  224. package/src/skf-setup/customize.toml +10 -0
  225. package/src/skf-setup/references/auto-index.md +11 -10
  226. package/src/skf-setup/references/ccc-index.md +14 -15
  227. package/src/skf-setup/references/detect-and-tier.md +10 -8
  228. package/src/skf-setup/references/report.md +26 -32
  229. package/src/skf-setup/references/tier-rules.md +2 -32
  230. package/src/skf-setup/references/write-config.md +9 -10
  231. package/src/skf-test-skill/SKILL.md +10 -8
  232. package/src/skf-test-skill/customize.toml +2 -0
  233. package/src/skf-test-skill/references/coherence-check.md +19 -31
  234. package/src/skf-test-skill/references/coverage-check.md +111 -67
  235. package/src/skf-test-skill/references/detect-mode.md +10 -41
  236. package/src/skf-test-skill/references/external-validators.md +11 -19
  237. package/src/skf-test-skill/references/init.md +39 -21
  238. package/src/skf-test-skill/references/migration-section-rules.md +4 -4
  239. package/src/skf-test-skill/references/report.md +60 -40
  240. package/src/skf-test-skill/references/score.md +32 -64
  241. package/src/skf-test-skill/references/scoring-rules.md +6 -62
  242. package/src/skf-test-skill/references/source-access-protocol.md +15 -5
  243. package/src/skf-test-skill/references/step-hard-gate.md +1 -3
  244. package/src/skf-test-skill/scripts/aggregate-coherence.py +276 -0
  245. package/src/skf-test-skill/scripts/check-metadata-coherence.py +359 -0
  246. package/src/skf-test-skill/scripts/combine-external-scores.py +190 -0
  247. package/src/skf-test-skill/scripts/compute-score.py +135 -4
  248. package/src/skf-test-skill/scripts/reconcile-coverage.py +327 -0
  249. package/src/skf-test-skill/scripts/validate-inventory.py +251 -0
  250. package/src/skf-test-skill/scripts/verify-declared-numerator.py +192 -0
  251. package/src/skf-update-skill/SKILL.md +17 -5
  252. package/src/skf-update-skill/customize.toml +11 -6
  253. package/src/skf-update-skill/references/detect-changes.md +48 -36
  254. package/src/skf-update-skill/references/health-check.md +5 -11
  255. package/src/skf-update-skill/references/init.md +40 -32
  256. package/src/skf-update-skill/references/manual-section-rules.md +1 -2
  257. package/src/skf-update-skill/references/merge-conflict-rules.md +1 -52
  258. package/src/skf-update-skill/references/merge.md +13 -57
  259. package/src/skf-update-skill/references/re-extract.md +27 -25
  260. package/src/skf-update-skill/references/report.md +14 -7
  261. package/src/skf-update-skill/references/validate.md +32 -30
  262. package/src/skf-update-skill/references/write.md +86 -51
  263. package/src/skf-update-skill/scripts/skf-new-file-diff.py +167 -0
  264. package/src/skf-verify-stack/SKILL.md +11 -21
  265. package/src/skf-verify-stack/customize.toml +12 -3
  266. package/src/skf-verify-stack/references/coverage-patterns.md +1 -29
  267. package/src/skf-verify-stack/references/coverage.md +21 -10
  268. package/src/skf-verify-stack/references/exit-codes.md +14 -0
  269. package/src/skf-verify-stack/references/health-check.md +1 -1
  270. package/src/skf-verify-stack/references/init.md +20 -25
  271. package/src/skf-verify-stack/references/integration-verification-rules.md +10 -19
  272. package/src/skf-verify-stack/references/integrations.md +44 -49
  273. package/src/skf-verify-stack/references/report.md +28 -34
  274. package/src/skf-verify-stack/references/requirements.md +3 -3
  275. package/src/skf-verify-stack/references/synthesize.md +36 -39
  276. package/src/skf-verify-stack/scripts/skf-coverage-tally.py +196 -0
  277. package/src/skf-verify-stack/scripts/skf-report-delta.py +256 -0
  278. package/src/skf-verify-stack/scripts/skf-verdict-rollup.py +258 -0
  279. package/tools/cli/lib/ui.js +3 -2
  280. package/docs/deepwiki.md +0 -89
  281. package/src/skf-rename-skill/references/rebuild-context.md +0 -110
@@ -19,7 +19,7 @@ To finalize the skill by creating the active-version pointer, displaying the com
19
19
  - Create the active pointer via the shared helper — never `rm` + `ln -s` manually
20
20
  - Result contract writing is mandatory (pipeline consumers depend on it)
21
21
 
22
- ## MANDATORY SEQUENCE
22
+ ## Steps
23
23
 
24
24
  ### 1. Create Active Pointer (atomic flip, Windows-safe)
25
25
 
@@ -29,7 +29,7 @@ To finalize the skill by creating the active-version pointer, displaying the com
29
29
 
30
30
  Create or update the `active` pointer at `{skill_group}/active` pointing to `{version}` using the shared atomic-flip helper. The helper acquires an `flock` on `{skill_group}/active.skf-lock`, refuses to replace a non-link at `{skill_group}/active` (protecting against accidental `rm -rf` of a real directory), and uses a rename-over-symlink pattern so the update is atomic from a concurrent reader's perspective. On Windows the helper automatically falls back to a directory junction (`mklink /J`) when `os.symlink` fails with `PRIVILEGE_NOT_HELD` / `ACCESS_DENIED` — junctions require no admin elevation and resolve identically for `skf-skill-inventory`'s consumers:
31
31
 
32
- **Resolve `{atomicWriteHelper}`** from `{atomicWriteProbeOrder}`; first existing path wins. HALT if no candidate exists — the active-pointer flip MUST go through the atomic helper.
32
+ **Resolve `{atomicWriteHelper}`** from `{atomicWriteProbeOrder}`; first existing path wins. If no candidate exists, skip the flip the same way `--no-active-pointer` does: log "Active pointer: skipped atomic-write helper unavailable", omit the active-pointer line from the completion summary and outputs, and record `active_pointer: "skipped-helper-missing"` in the result-contract summary (§3) so consumers see why the pointer is absent. The deliverables are already on disk, so a missing helper degrades to "no pointer" rather than a failed run. There is no manual fallback: a hand-rolled `rm` + `ln -s` loses the helper's atomicity and non-link guard, risking a half-flipped pointer or an `rm -rf` into a real directory.
33
33
 
34
34
  ```bash
35
35
  python3 {atomicWriteHelper} flip-link \
@@ -37,9 +37,7 @@ python3 {atomicWriteHelper} flip-link \
37
37
  --target {version}
38
38
  ```
39
39
 
40
- The helper returns non-zero (helper exit 2) if `{skill_group}/active` already exists as a real directory or file rather than a link — in that case, HARD HALT the workflow with **exit code 7 (finalize-blocked)** per the SKILL.md exit-code map: "Refusing to flip `{skill_group}/active` — existing path is not a symlink or junction. Investigate manually; expected a link pointing at a version directory." Before exiting, emit the error result contract per SKILL.md "Result Contract on HARD HALT" (`phase: "finalize"`, `error.code: "finalize-blocked"`, `skill_package` set, `outputs` listing the deliverables already on disk from step 5). A common cause on Windows is a prior run that executed `ln -s` under git-bash without Developer Mode enabled, which silently wrote a full directory copy; remove that copy and retry.
41
-
42
- **Never `rm` + `ln -s` the active pointer manually.** The bare-rm pattern has two failure modes: (1) a concurrent reader sees a missing `active` mid-flip, and (2) a bug or typo that replaces `{skill_group}/active` with a plain directory turns the next manual `rm -rf {skill_group}/active` into data loss. The helper encapsulates both guards and the Windows junction fallback.
40
+ The helper returns non-zero (helper exit 2) if `{skill_group}/active` already exists as a real directory or file rather than a link — in that case, HARD HALT the workflow with **exit code 7 (finalize-blocked)** per the exit-code map in `references/halt-contract.md`: "Refusing to flip `{skill_group}/active` — existing path is not a symlink or junction. Investigate manually; expected a link pointing at a version directory." Before exiting, emit the error result contract per `references/halt-contract.md` (`phase: "finalize"`, `error.code: "finalize-blocked"`, `skill_package` set, `outputs` listing the deliverables already on disk from step 5). A common cause on Windows is a prior run that executed `ln -s` under git-bash without Developer Mode enabled, which silently wrote a full directory copy; remove that copy and retry.
43
41
 
44
42
  Confirm: "Active pointer: {skill_group}/active -> {version} ({kind})" where `{kind}` is `symlink` or `junction` as returned by the helper.
45
43
 
@@ -76,6 +74,14 @@ Confirm: "Active pointer: {skill_group}/active -> {version} ({kind})" where `{ki
76
74
 
77
75
  Write the result contract per `shared/references/output-contract-schema.md`: the per-run record at `{skill_package}/quick-skill-result-{YYYYMMDD-HHmmss}.json` (UTC timestamp, resolution to seconds) and a copy at `{skill_package}/quick-skill-result-latest.json` (stable path for pipeline consumers — copy, not symlink). Include `SKILL.md`, `context-snippet.md`, and `metadata.json` paths in `outputs` and export count in `summary`.
78
76
 
77
+ **Post-completion hook (optional).** If `{onCompleteCommand}` is non-empty (resolved at SKILL.md On Activation §3 from `workflow.on_complete`), invoke it after the result contract is finalized:
78
+
79
+ ```bash
80
+ {onCompleteCommand} --skill-package={skill_package}
81
+ ```
82
+
83
+ Log success/failure but never fail the workflow on a hook error — the skill is already written. The hook runs last so a git-add, registry registration, or notifier sees a complete package. When `{onCompleteCommand}` is empty (bundled default), skip the invocation entirely.
84
+
79
85
  ### 4. Chain to Health Check
80
86
 
81
- ONLY WHEN the active pointer has been created and the completion summary and result contract have been written will you then load, read the full file, and proceed to `{nextStepFile}`. The health-check step is the true terminal step — do not stop here even though the summary reads as final.
87
+ Once the active pointer, completion summary, result contract, and any post-completion hook are done, load and execute {nextStepFile}. Do not stop here health-check is the true terminal step even though the summary reads as final.
@@ -0,0 +1,54 @@
1
+ <!-- Config: communicate in {communication_language}. -->
2
+
3
+ # HARD HALT Contract
4
+
5
+ The exit-code map and error-result envelope every step emits on a HARD HALT. Any step loads this file on its failure path, so the wire format is available even if SKILL.md has been compacted mid-run.
6
+
7
+ ## Exit Codes
8
+
9
+ Every HARD HALT in this workflow exits with a stable, documented code so headless automators can branch on the failure class without grepping message text:
10
+
11
+ | Code | Meaning | Raised by |
12
+ | ---- | ---------------------- | ----------------------------------------------------------- |
13
+ | 0 | success | step 7 (terminal) |
14
+ | 3 | resolution-failure | step 1 (prose input §2, registry chain §3, version-tag miss §3a, language abort §4); step 3 (non-library shape §1.5, zero-exports §4.5) |
15
+ | 4 | write-failure | step 5 §2 (deliverable write failed) |
16
+ | 5 | overwrite-cancelled | step 5 §1 (user selected [N]) |
17
+ | 6 | user-cancelled | step 1 §1 ([X] Cancel and exit, or cancel-line affordance); step 2 §3 ([A] Abort at ecosystem-match gate); step 4 §6 (user selected [Q]) |
18
+ | 7 | finalize-blocked | step 6 §1 (active-pointer flip refused — non-link in place) |
19
+ | 8 | ecosystem-redirect | step 2 §3 ([I] Install at ecosystem-match gate — user opted to install the existing official skill instead of compiling a custom community skill) |
20
+
21
+ ## Result Contract on HARD HALT
22
+
23
+ In addition to the success-variant result contract written by step 6 §3, every HARD HALT must surface an **error variant** so headless automators don't silently break when `quick-skill-result-latest.json` is missing on failed runs.
24
+
25
+ **Always (every HARD HALT, regardless of phase)** — emit a single line on **stderr**:
26
+
27
+ ```
28
+ SKF_QUICK_SKILL_RESULT_JSON: {"status":"error","exit_code":<N>,"phase":"<slug>","error":{"code":"<class>","message":"<short>"},"outputs":{},"summary":{},"skill_package":"<path-or-null>"}
29
+ ```
30
+
31
+ One line, no pretty-print. Matches the prefix-and-envelope convention used by `skf-emit-result-envelope.py`.
32
+
33
+ **Additionally, when `{skill_package}` is known** (HALT at step 5 §1 onward) — write the same JSON object (without the `SKF_QUICK_SKILL_RESULT_JSON: ` prefix) to disk:
34
+
35
+ ```
36
+ {skill_package}/quick-skill-result-{YYYYMMDD-HHmmss}.json
37
+ {skill_package}/quick-skill-result-latest.json (copy, not symlink)
38
+ ```
39
+
40
+ so consumers that hardcode the `-latest.json` path see a deterministic file even on failed runs. HALTs at step 1/02/03/04 cannot write to disk because `{skill_package}` is computed only in step 5 §1; for those, the stderr envelope plus exit code is the contract.
41
+
42
+ **Schema:**
43
+
44
+ | Field | Type | Notes |
45
+ | --------------- | -------------- | ----------------------------------------------------------------------------------------------------------- |
46
+ | `status` | string | always `"error"` for HARD HALTs |
47
+ | `exit_code` | integer | matches the Exit Codes table above |
48
+ | `phase` | string | step slug where the HALT occurred (e.g. `resolve-target`, `compile`) |
49
+ | `error.code` | string | one of: `resolution-failure`, `write-failure`, `overwrite-cancelled`, `user-cancelled`, `finalize-blocked`, `ecosystem-redirect` |
50
+ | `error.message` | string | the user-facing message that was displayed |
51
+ | `error.details` | any | optional — phase-specific context (e.g. the failed file path) |
52
+ | `outputs` | object | empty `{}` on early HALTs; partial when files were already written |
53
+ | `summary` | object | empty `{}` on early HALTs |
54
+ | `skill_package` | string \| null | absolute path when known, `null` when HALT preceded step 5 §1 |
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  # `shared/health-check.md` resolves relative to the SKF module root
3
3
  # (`{project-root}/_bmad/skf/` when installed, `{project-root}/src/` during
4
- # development), NOT relative to this step file.
4
+ # development), not relative to this step file.
5
5
  nextStepFile: 'shared/health-check.md'
6
6
  ---
7
7
 
@@ -16,9 +16,8 @@ Chain to the shared workflow self-improvement health check at `{nextStepFile}`.
16
16
  ## Rules
17
17
 
18
18
  - No user-facing reports, file writes, or result contracts in this step — those belong in step 6
19
- - Delegate directly to `{nextStepFile}` with no additional commentary
20
- - Do not attempt any other action between loading this step and executing `{nextStepFile}`
19
+ - Delegate directly to `{nextStepFile}` with no additional commentary or intervening action
21
20
 
22
- ## MANDATORY SEQUENCE
21
+ ## Steps
23
22
 
24
23
  Load `{nextStepFile}`, read it fully, then proceed to execute it.
@@ -19,7 +19,7 @@ To read the resolved GitHub repository source and extract the public API surface
19
19
  - Do not begin compilation or write output files
20
20
  - If no exports found, use README content as fallback
21
21
 
22
- ## MANDATORY SEQUENCE
22
+ ## Steps
23
23
 
24
24
  **Ref-aware source reading:** When `source_ref` is set from tag resolution (see step 1), append `?ref={source_ref}` to all GitHub API content and tree requests (e.g., `gh api repos/{owner}/{repo}/contents/{path}?ref={source_ref}`) to read from the tagged version. When using web browsing, use the tagged URL format (e.g., `github.com/{owner}/{repo}/blob/{source_ref}/{path}`). This ensures extraction reads from the same source version resolved during tag resolution.
25
25
 
@@ -57,7 +57,7 @@ Quick-skill is designed to wrap a library's public API. The compiled SKILL.md wi
57
57
  Select: [C] Continue anyway · [A] Abort"
58
58
 
59
59
  - **IF C** — log "user accepted `{shape}` shape" and proceed to §2. Set `extraction_inventory.repo_shape` to the detected shape so the result contract carries the signal for automators.
60
- - **IF A** — HARD HALT with **exit code 3 (resolution-failure)** per the SKILL.md exit-code map: "Aborted. `{shape}` repos are best wrapped manually with `/skf-create-skill` from a brief, not auto-extracted." Before exiting, emit the error result contract per SKILL.md "Result Contract on HARD HALT" (`phase: "quick-extract"`, `error.code: "resolution-failure"`, `error.details: {repo_shape: "{shape}"}`, `skill_package: null`).
60
+ - **IF A** — HARD HALT with **exit code 3 (resolution-failure)** per the exit-code map in `references/halt-contract.md`: "Aborted. `{shape}` repos are best wrapped manually with `/skf-create-skill` from a brief, not auto-extracted." Before exiting, emit the error result contract per `references/halt-contract.md` (`phase: "quick-extract"`, `error.code: "resolution-failure"`, `error.details: {repo_shape: "{shape}"}`, `skill_package: null`).
61
61
 
62
62
  **GATE [default: C]** — In headless mode, log "headless: detected `{shape}` repo, continuing anyway" and proceed; the result contract's `summary.repo_shape` carries the signal so automators can flag low-quality outputs without re-parsing logs.
63
63
 
@@ -76,13 +76,13 @@ Fetch the manifest file and the top-level entry-point file(s) for the detected l
76
76
 
77
77
  **If `scope_hint` provided:** focus the entry-point fetch on the specified directories instead of repo root.
78
78
 
79
- For multi-module Maven (`<modules>`) and multi-project Gradle (`include(...)`) builds, fetch the parent manifest first, then loop §2+§3 per module. Sub-module fetches are safe to issue as one batched tool-call message N module fetches collapse to O(1) wall-clock time.
79
+ For multi-module Maven (`<modules>`) and multi-project Gradle (`include(...)`) builds, fetch the parent manifest first, then loop §2+§3 per module. Batch the sub-module fetches per the parallel-fetch directive at the top of this step.
80
80
 
81
81
  ### 3. Parse Manifest and Scan Exports
82
82
 
83
83
  Run the shared extractor against the contents fetched in §2. The helper does manifest parse + export scan in one invocation and emits a structured envelope ready to feed §4's inventory.
84
84
 
85
- **Resolve `{publicApiExtractor}`** from `{publicApiExtractorProbeOrder}`; first existing path wins. If no candidate exists, fall back to in-prompt parsing (the legacy per-language regex tables that this section replaces).
85
+ **Resolve `{publicApiExtractor}`** from `{publicApiExtractorProbeOrder}`; first existing path wins. If no candidate exists, fall back to in-prompt per-language regex parsing of the manifest and entry-point files.
86
86
 
87
87
  Build the input payload from §2's fetched files and pipe it to the helper:
88
88
 
@@ -129,7 +129,7 @@ extraction_inventory:
129
129
 
130
130
  ### 4.5. Zero-Exports Soft Gate (rescue mode)
131
131
 
132
- Run this gate **only when** `extraction_inventory.exports.length == 0` AND `extraction_inventory.description` is empty (no usable README content either). When either is non-empty, the README-fallback in §4 produces a usable skill and this section is skipped.
132
+ Run this gate **only when** `extraction_inventory.exports.length == 0` and `extraction_inventory.description` is empty (no usable README content either). When either is non-empty, the README-fallback in §4 produces a usable skill and this section is skipped.
133
133
 
134
134
  When both are empty, the compiled SKILL.md would be effectively empty — no API surface to document and no description to fall back on. Offer the user a chance to retry with hints before producing a degenerate output:
135
135
 
@@ -146,7 +146,7 @@ Select: [R] Retry with new hints · [P] Proceed anyway (low-confidence skill) ·
146
146
 
147
147
  - **IF R** — prompt for new `scope_hint` ("New scope hint (e.g. `src/server/`):") and optional new `language_hint` ("New language hint (or empty to keep `{language}`):"). Update the extraction context with the new hints, then **re-execute step 3 from §1** with the new values. Discards the prior empty inventory.
148
148
  - **IF P** — log "user accepted zero-exports outcome" and proceed to §5. The compiled skill will be README-content-only with confidence `low`. Record `zero_exports_rescue: "user-accepted"` in the inventory so the result contract summary surfaces it.
149
- - **IF A** — HARD HALT with **exit code 3 (resolution-failure)**: "Aborted. Run `/skf-create-skill` from a brief if you want a guided extraction with provenance tracking." Before exiting, emit the error result contract per SKILL.md "Result Contract on HARD HALT" (`phase: "quick-extract"`, `error.code: "resolution-failure"`, `error.details: {exports_found: 0, description_empty: true, language: "{language}", scope: "{scope_hint or 'entire repo'}"}`, `skill_package: null`).
149
+ - **IF A** — HARD HALT with **exit code 3 (resolution-failure)**: "Aborted. Run `/skf-create-skill` from a brief if you want a guided extraction with provenance tracking." Before exiting, emit the error result contract per `references/halt-contract.md` (`phase: "quick-extract"`, `error.code: "resolution-failure"`, `error.details: {exports_found: 0, description_empty: true, language: "{language}", scope: "{scope_hint or 'entire repo'}"}`, `skill_package: null`).
150
150
 
151
151
  **GATE [default: P]** — In headless mode, log "headless: zero exports + empty description, proceeding with low-confidence skill" and proceed; record `zero_exports_rescue: "auto-proceeded"` in the result contract summary so batch automators can re-queue these targets with stricter hints downstream. [P] preserves the pre-rescue behaviour for unattended pipelines.
152
152
 
@@ -164,16 +164,5 @@ Select: [R] Retry with new hints · [P] Proceed anyway (low-confidence skill) ·
164
164
 
165
165
  ### 6. Auto-Proceed to Compilation
166
166
 
167
- #### Menu Handling Logic:
168
-
169
- - After extraction summary, immediately load, read entire file, then execute {nextStepFile}
170
-
171
- #### EXECUTION RULES:
172
-
173
- - This is an auto-proceed step — extraction results flow directly to compilation
174
- - Proceed directly to next step after summary
175
-
176
- ## CRITICAL STEP COMPLETION NOTE
177
-
178
- ONLY WHEN extraction is complete and extraction_inventory is assembled (even if minimal/low-confidence) will you load and read fully `{nextStepFile}` to execute compilation.
167
+ Once extraction_inventory is assembled (even if minimal or low-confidence), load and execute {nextStepFile} to compile.
179
168
 
@@ -70,26 +70,4 @@ Please provide the GitHub URL directly, or check:
70
70
 
71
71
  **Hard halt** — cannot proceed without a resolved source.
72
72
 
73
- ## Language Detection
74
-
75
- After resolving to a GitHub repo, detect primary language from:
76
-
77
- 1. Manifest file presence:
78
- - `package.json` → JavaScript/TypeScript
79
- - `pyproject.toml` or `setup.py` → Python
80
- - `Cargo.toml` → Rust
81
- - `go.mod` → Go
82
- - `pom.xml` or `build.gradle` → Java
83
- 2. User-provided language hint (overrides detection)
84
- 3. GitHub API language field (if accessible)
85
-
86
- ## Manifest File Priority
87
-
88
- For each language, the primary manifest to read:
89
-
90
- | Language | Manifest | Key Fields |
91
- |----------|----------------|--------------------------------------------------------------------------|
92
- | JS/TS | package.json | name, version, description, main, exports, dependencies |
93
- | Python | pyproject.toml | project.name, project.version, project.description, project.dependencies |
94
- | Rust | Cargo.toml | package.name, package.version, package.description, dependencies |
95
- | Go | go.mod | module path, require list |
73
+ Language detection is authoritative in `resolve-target.md` §4 (Detect Language) — this file covers only the package-to-repo registry chain.
@@ -1,9 +1,12 @@
1
1
  ---
2
2
  nextStepFile: 'ecosystem-check.md'
3
- registryResolutionData: 'references/registry-resolution.md'
3
+ registryResolutionData: '{registryResolutionPath}'
4
4
  packageResolverProbeOrder:
5
5
  - '{project-root}/_bmad/skf/shared/scripts/skf-resolve-package.py'
6
6
  - '{project-root}/src/shared/scripts/skf-resolve-package.py'
7
+ detectLanguageProbeOrder:
8
+ - '{project-root}/_bmad/skf/shared/scripts/skf-detect-language.py'
9
+ - '{project-root}/src/shared/scripts/skf-detect-language.py'
7
10
  ---
8
11
 
9
12
  <!-- Config: communicate in {communication_language}. -->
@@ -19,7 +22,7 @@ To accept a GitHub URL or package name from the user, resolve it to a GitHub rep
19
22
  - Focus only on resolving the target to a GitHub repository — do not begin extraction or compilation
20
23
  - If resolution fails, hard halt with actionable guidance
21
24
 
22
- ## MANDATORY SEQUENCE
25
+ ## Steps
23
26
 
24
27
  ### 1. Accept User Input
25
28
 
@@ -41,7 +44,7 @@ Examples: `cocoindex`, `@tanstack/query`, `https://github.com/tursodatabase/limb
41
44
 
42
45
  Or type `cancel` / `exit` / `:q` / `[X]` to leave without writing anything."
43
46
 
44
- Wait for user input. **Cancel branch** — if the user types `cancel`, `exit`, `:q`, `[X]`, or selects `[X] Cancel and exit`, display `"Cancelled — no files were written."` and HARD HALT with **exit code 6 (user-cancelled)** per the SKILL.md exit-code map. Before exiting, emit the error result contract per SKILL.md "Result Contract on HARD HALT" (`phase: "resolve-target"`, `error.code: "user-cancelled"`, `skill_package: null`). Cancellation here is non-destructive — no files have been written yet.
47
+ Wait for user input. **Cancel branch** — if the user types `cancel`, `exit`, `:q`, `[X]`, or selects `[X] Cancel and exit`, display `"Cancelled — no files were written."` and HARD HALT with **exit code 6 (user-cancelled)** per the exit-code map in `references/halt-contract.md`. Before exiting, emit the error result contract per `references/halt-contract.md` (`phase: "resolve-target"`, `error.code: "user-cancelled"`, `skill_package: null`). Cancellation here is non-destructive — no files have been written yet.
45
48
 
46
49
  **GATE [default: use args]** — If `{headless_mode}` and a target (URL or package name) was provided as argument: use it as the target input and auto-proceed, log: "headless: using provided target". If no target provided in headless mode, HALT with: "headless mode requires a target argument."
47
50
 
@@ -79,7 +82,7 @@ If you are describing a skill you want to **create from scratch** rather than co
79
82
 
80
83
  Otherwise, paste the package name or GitHub URL of the library you want to wrap, and quick-skill will resolve it."
81
84
 
82
- **GATE [default: HALT]** — In headless mode, emit the same redirect message and HALT with **exit code 3 (resolution-failure)** per the SKILL.md exit-code map. Before exiting, emit the error result contract per SKILL.md "Result Contract on HARD HALT" (`phase: "resolve-target"`, `error.code: "resolution-failure"`, `skill_package: null`). Do not attempt registry lookups against prose input; that wastes ~3-4 round trips and produces a less actionable error message than the redirect above.
85
+ **GATE [default: HALT]** — In headless mode, emit the same redirect message and HALT with **exit code 3 (resolution-failure)** per the exit-code map in `references/halt-contract.md`. Before exiting, emit the error result contract per `references/halt-contract.md` (`phase: "resolve-target"`, `error.code: "resolution-failure"`, `skill_package: null`). Do not attempt registry lookups against prose input; that wastes ~3-4 round trips and produces a less actionable error message than the redirect above.
83
86
 
84
87
  ### 3. Registry Resolution
85
88
 
@@ -107,7 +110,7 @@ Check:
107
110
 
108
111
  **Provide the GitHub URL directly to continue.**"
109
112
 
110
- In interactive mode, wait for corrected input and loop back to step 2. In headless mode, emit the error result contract per SKILL.md "Result Contract on HARD HALT" (`phase: "resolve-target"`, `error.code: "resolution-failure"`, `skill_package: null`) and exit 3.
113
+ In interactive mode, wait for corrected input and loop back to step 2. In headless mode, emit the error result contract per `references/halt-contract.md` (`phase: "resolve-target"`, `error.code: "resolution-failure"`, `skill_package: null`) and exit 3.
111
114
 
112
115
  ### 3a. Verify Target Version Tag (when applicable)
113
116
 
@@ -135,35 +138,36 @@ Recent tags in this repo:
135
138
 
136
139
  Re-run with one of these tags, or omit the `@version` suffix to auto-detect from the default branch."
137
140
 
138
- Before exiting, emit the error result contract per SKILL.md "Result Contract on HARD HALT" (`phase: "resolve-target"`, `error.code: "resolution-failure"`, `error.details: {requested_version: "{target_version}", available_tags: [...top 5]}`, `skill_package: null`). In headless mode, exit immediately; do not loop.
141
+ Before exiting, emit the error result contract per `references/halt-contract.md` (`phase: "resolve-target"`, `error.code: "resolution-failure"`, `error.details: {requested_version: "{target_version}", available_tags: [...top 5]}`, `skill_package: null`). In headless mode, exit immediately; do not loop.
139
142
 
140
143
  ### 4. Detect Language
141
144
 
142
- Determine primary language from:
145
+ **Resolve `{detectLanguageHelper}`** from `{detectLanguageProbeOrder}`; first existing path wins. If no candidate exists (e.g. Python/`uv` unavailable), fall back to the manifest-priority walk documented in the helper's `--help` — `package.json` → JavaScript/TypeScript (TypeScript when a `tsconfig.json` is also present), `Cargo.toml` → Rust, `pyproject.toml`/`setup.py`/`setup.cfg` → Python, `go.mod` → Go, `pom.xml` → Java, `build.gradle.kts` → Kotlin, `build.gradle` → Kotlin when `src/main/kotlin/` exists else Java, `*.csproj`/`*.sln` → C#, `Gemfile` → Ruby, then extension frequency — applied by hand.
143
146
 
144
- 1. **User-provided language hint** (overrides detection — skip the ambiguity gate below).
145
- 2. **Manifest-presence scan** — check the repo root for ALL of these (priority order = first hit wins on auto-pick):
146
- - `package.json` → JavaScript/TypeScript
147
- - `pyproject.toml` or `setup.py` → Python
148
- - `Cargo.toml` → Rust
149
- - `go.mod` → Go
150
- - `pom.xml` → Java (or Kotlin if `src/main/kotlin/` is present)
151
- - `build.gradle.kts` or `build.gradle` → Kotlin (or Java if only `src/main/java/` is present)
147
+ Determine primary language:
152
148
 
153
- Collect every match into `detected_languages`.
149
+ 1. **User-provided language hint** (overrides detection) — set `language` to the hint and skip straight to §5. The disambiguation gate below does not run.
154
150
 
155
- 3. **Single-language case** (`len(detected_languages) <= 1`)set `language` to the detected value (or HALT in step 1 §3 if zero matches).
151
+ 2. **Delegate the rule walk to `{detectLanguageHelper}`**it is the single source of truth for the manifest → language rule table (including the `package.json` JS-vs-TS disambiguation); do not restate or re-derive it here. Fetch the repo file listing once (`gh api repos/{owner}/{repo}/git/trees/{source_ref or default branch}?recursive=1`, reading the `path` values), then hand the flat list to the script:
156
152
 
157
- 4. **Multi-language case** (`len(detected_languages) > 1`) — surface the choice rather than silently picking the first match. Multi-language repos (Python + JS bindings, or monorepos with mixed manifests) otherwise produce a skill for whichever manifest probe hits first, with no signal that the user might have wanted the other one.
153
+ ```bash
154
+ echo '{"tree": [<flat list of repo-relative file paths>]}' | uv run {detectLanguageHelper}
155
+ ```
156
+
157
+ The script returns `{language, confidence, detection_source, detected_languages}` after walking the deterministic rule table (manifest presence first, then extension-frequency fallback). `detected_languages` is the ordered, deduplicated set of every manifest-level match in priority order, with `detected_languages[0]` equal to the winning `language`.
158
+
159
+ 3. **Auto-pick** — set `language` to the returned `language`. If `detected_languages` is empty (the script recognized no manifest and no source extensions — `language` is `"unknown"`), treat it as a zero-match resolution and HALT with the step 1 §3 resolution-failure guidance so the user can supply a language hint or a different target.
160
+
161
+ 4. **Multi-language gate** (`len(detected_languages) > 1`) — the script found manifests for more than one language. Surface the choice rather than silently keeping the first match. Multi-language repos (Python + JS bindings, or monorepos with mixed manifests) otherwise produce a skill for whichever manifest sorts first in priority order, with no signal that the user might have wanted the other one.
158
162
 
159
163
  "**`{repo_name}` has manifests for multiple languages:** {detected_languages}.
160
164
 
161
- Primary guess: **{first_match}** (manifest-priority order). If you wanted a different language, abort and re-run with `--language-hint <lang>` or with the optional language hint at step 1 §1.
165
+ Primary guess: **{language}** (`detected_languages[0]`, manifest-priority order). If you wanted a different language, abort and re-run with `--language-hint <lang>` or with the optional language hint at step 1 §1.
162
166
 
163
- Select: [C] Continue with `{first_match}` · [A] Abort"
167
+ Select: [C] Continue with `{language}` · [A] Abort"
164
168
 
165
- - **IF C** — log "user accepted multi-manifest pick: `{first_match}`" and set `language` to the first match.
166
- - **IF A** — HARD HALT with **exit code 3 (resolution-failure)**: "Aborted to disambiguate language. Re-run with a `language_hint`." Before exiting, emit the error result contract per SKILL.md "Result Contract on HARD HALT" (`phase: "resolve-target"`, `error.code: "resolution-failure"`, `error.details: {detected_languages: [...], auto_pick: "{first_match}"}`, `skill_package: null`).
169
+ - **IF C** — log "user accepted multi-manifest pick: `{language}`" and keep `language`.
170
+ - **IF A** — HARD HALT with **exit code 3 (resolution-failure)**: "Aborted to disambiguate language. Re-run with a `language_hint`." Before exiting, emit the error result contract per `references/halt-contract.md` (`phase: "resolve-target"`, `error.code: "resolution-failure"`, `error.details: {detected_languages: [...], auto_pick: "{language}"}`, `skill_package: null`).
167
171
  - **GATE [default: C]** — Headless mode auto-proceeds with the manifest-priority pick; record `detected_languages` and `language_resolution: "auto-picked-first"` in the extraction context so the result contract surfaces the ambiguity downstream.
168
172
 
169
173
  ### 5. Confirm Resolution
@@ -179,16 +183,5 @@ Determine primary language from:
179
183
 
180
184
  ### 6. Proceed to Next Step
181
185
 
182
- #### Menu Handling Logic:
183
-
184
- - After successful resolution confirmation, immediately load, read entire file, then execute {nextStepFile}
185
-
186
- #### EXECUTION RULES:
187
-
188
- - This is an init step with auto-proceed after successful resolution
189
- - Proceed directly to next step after confirmation
190
-
191
- ## CRITICAL STEP COMPLETION NOTE
192
-
193
- ONLY WHEN the target has been successfully resolved to a GitHub repository with confirmed URL, name, and detected language will you load and read fully `{nextStepFile}` to execute the ecosystem check.
186
+ Once the target is resolved to a GitHub repository with confirmed URL, name, and detected language, load and execute {nextStepFile} for the ecosystem check.
194
187
 
@@ -18,12 +18,10 @@ To write the compiled SKILL.md, context-snippet.md, and metadata.json to the ver
18
18
 
19
19
  ## Rules
20
20
 
21
- - Write exactly what was compiled — do not modify content during writing
22
- - Validation is advisory — report issues but never block output
23
- - Do not modify compiled content post-validation — report only
21
+ - Write exactly what was compiled — do not modify content during writing or after validation
24
22
  - Community-tier validation (lighter than official requirements)
25
23
 
26
- ## MANDATORY SEQUENCE
24
+ ## Steps
27
25
 
28
26
  ### 1. Create Output Directory
29
27
 
@@ -39,7 +37,7 @@ If `{skill_package}` already exists, confirm with user before overwriting:
39
37
  "**Directory `{skill_package}` already exists.** Overwrite will replace the prior compiled output; validation results, result contracts, and any manual tweaks from the previous run will not be preserved. Overwrite existing files? [Y/N]"
40
38
 
41
39
  - **If user selects Y:** Proceed to section 2.
42
- - **If user selects N:** HARD HALT with **exit code 5 (overwrite-cancelled)** per the SKILL.md exit-code map: "Overwrite cancelled. Existing skill preserved. Run [QS] with a different skill name or remove the existing directory manually." Before exiting, emit the error result contract per SKILL.md "Result Contract on HARD HALT" (`phase: "write-and-validate"`, `error.code: "overwrite-cancelled"`, `skill_package` set to the existing path that was preserved). Disk write of the `-latest.json` envelope is REQUIRED here since `{skill_package}` is known.
40
+ - **If user selects N:** HARD HALT with **exit code 5 (overwrite-cancelled)** per the exit-code map in `references/halt-contract.md`: "Overwrite cancelled. Existing skill preserved. Run [QS] with a different skill name or remove the existing directory manually." Before exiting, emit the error result contract per `references/halt-contract.md` (`phase: "write-and-validate"`, `error.code: "overwrite-cancelled"`, `skill_package` set to the existing path that was preserved). Write the `-latest.json` envelope to disk here `{skill_package}` is known, so consumers that hardcode that path see a deterministic file even on this cancelled run.
43
41
 
44
42
  **GATE [default: Y]** — If `{headless_mode}` is true, auto-proceed with Y and log: "headless: overwriting existing `{skill_package}`".
45
43
 
@@ -53,7 +51,7 @@ Write the three compiled artifacts to the skill package so that validation in se
53
51
 
54
52
  Confirm after each write: "Written: SKILL.md" / "Written: context-snippet.md" / "Written: metadata.json". When `--skip-snippet` is active, log "Skipped: context-snippet.md (--skip-snippet)" instead of the snippet write confirmation.
55
53
 
56
- **If any write fails — HARD HALT (exit code 4, write-failure):** Before exiting, emit the error result contract per SKILL.md "Result Contract on HARD HALT" (`phase: "write-and-validate"`, `error.code: "write-failure"`, `error.details: {failed_path: <path>, error: <details>}`, `skill_package` set, `outputs` listing any files that did write successfully before the failure).
54
+ **If any write fails — HARD HALT (exit code 4, write-failure):** Before exiting, emit the error result contract per `references/halt-contract.md` (`phase: "write-and-validate"`, `error.code: "write-failure"`, `error.details: {failed_path: <path>, error: <details>}`, `skill_package` set, `outputs` listing any files that did write successfully before the failure).
57
55
 
58
56
  "**Write failed:** Could not write to `{file_path}`.
59
57
 
@@ -71,8 +69,6 @@ Run: `npx skill-check -h`
71
69
  - If succeeds (returns usage information): Continue to automated validation (section 4)
72
70
  - If fails (command not found or error): Skip to manual fallback in section 4
73
71
 
74
- **Important:** Use the verification command. Do not assume availability — empirical check required.
75
-
76
72
  ### 4. Validate SKILL.md via skill-check (if available)
77
73
 
78
74
  **If `npx skill-check` is available**, run automated validation + security scan in one invocation against the skill package written in section 2 (security scan is enabled by default when `--no-security-scan` is omitted, so the same call covers §6 and avoids paying the npx startup cost twice):
@@ -84,24 +80,24 @@ npx skill-check check {skill_package} --fix --format json
84
80
  This validates frontmatter, description, body limits, links, and formatting; runs the security scan; and auto-fixes deterministic issues (field ordering, slug format, required fields, trailing newlines).
85
81
 
86
82
  **Parse JSON output** to extract:
87
- - `scores[].score` — overall score (0-100); match the entry by `relativePath`/`skillId` (older skill-check builds exposed this as a top-level `qualityScore`)
83
+ - `scores[].score` — overall score (0-100); match the entry by `relativePath`/`skillId`
88
84
  - `diagnostics[]` — remaining issues after auto-fix
89
85
  - `fixed[]` — issues automatically corrected
90
86
  - `security[]` (when present) — security findings, recorded as advisory warnings (security issues do not block output)
91
87
 
92
88
  Record quality score, remaining diagnostics, and security findings as validation issues.
93
89
 
94
- **If skill-check is NOT available**, run the shared frontmatter validator instead of an LLM-walked checklist. Resolve `{frontmatterValidator}` from `{frontmatterValidatorProbeOrder}`; first existing path wins. If no candidate exists, log a high-severity issue ("frontmatter validator unavailable — both `npx skill-check` and `skf-validate-frontmatter.py` missing") and skip frontmatter validation.
90
+ **If skill-check is not available**, run the shared frontmatter validator. Resolve `{frontmatterValidator}` from `{frontmatterValidatorProbeOrder}`; first existing path wins. If no candidate exists, log a high-severity issue ("frontmatter validator unavailable — both `npx skill-check` and `skf-validate-frontmatter.py` missing") and skip frontmatter validation.
95
91
 
96
92
  ```bash
97
93
  uv run {frontmatterValidator} {skill_package}/SKILL.md --skill-dir-name {repo_name}
98
94
  ```
99
95
 
100
- The validator emits JSON with `status` (`pass`/`fail`), `issues[]` (each with `severity`, `code`, `message`), and `frontmatter` (the parsed name/description). It checks frontmatter delimiters, name format (Unicode letters + digits + hyphens, no consecutive/trailing hyphens), name-directory match, description presence and length, and unknown fields against the agentskills.io spec — the same shape this step would otherwise hand-walk. Record each `issues[]` entry as a validation issue with its reported severity. Missing frontmatter or missing required fields are high-severity — skills without valid frontmatter will fail `npx skills add` and `npx skill-check check`.
96
+ The validator emits JSON with `status` (`pass`/`fail`), `issues[]` (each with `severity`, `code`, `message`), and `frontmatter` (the parsed name/description). It checks frontmatter delimiters, name format (Unicode letters + digits + hyphens, no consecutive/trailing hyphens), name-directory match, description presence and length, and unknown fields against the agentskills.io spec. Record each `issues[]` entry as a validation issue with its reported severity. Missing frontmatter or missing required fields are high-severity — skills without valid frontmatter will fail `npx skills add` and `npx skill-check check`.
101
97
 
102
98
  ### 5. Validate Body, Snippet, and Metadata via skf-validate-output.py
103
99
 
104
- Run the shared output validator against the on-disk skill package — it performs the body-structure, snippet-format, and metadata-shape checks that this step previously walked by hand. Pass `--skip-frontmatter` since §4 has already covered frontmatter.
100
+ Run the shared output validator against the on-disk skill package — it performs the body-structure, snippet-format, and metadata-shape checks. Pass `--skip-frontmatter` since §4 has already covered frontmatter.
105
101
 
106
102
  **Resolve `{outputValidator}`:** probe `{outputValidatorProbeOrder}` (installed first, dev fallback); first existing path wins. If neither candidate exists, log a high-severity issue ("output validator unavailable — `skf-validate-output.py` missing") and skip body/snippet/metadata validation.
107
103
 
@@ -111,7 +107,7 @@ python3 {outputValidator} {skill_package} --generated-by quick-skill --skip-fron
111
107
 
112
108
  The validator emits JSON with `result` (PASS/FAIL), `validation.skill_md.body[]`, `validation.context_snippet.issues[]`, `validation.metadata.issues[]`, and a severity-bucketed `summary`. Record each issue as a validation issue at its reported severity.
113
109
 
114
- Coverage replaces these former hand-walked checklists:
110
+ The validator covers:
115
111
 
116
112
  - **Body structure** — Overview, Description, Key Exports, Usage sections present (medium when missing)
117
113
  - **Context snippet** — `[{name} v{version}]|root: ...` first line, `|IMPORTANT:` second line, ~80–120-token length
@@ -149,16 +145,5 @@ Set `validation_result` with pass/fail status, quality score, and issues list.
149
145
 
150
146
  ### 8. Auto-Proceed to Finalize
151
147
 
152
- #### Menu Handling Logic:
153
-
154
- - After validation report, immediately load, read entire file, then execute {nextStepFile}
155
-
156
- #### EXECUTION RULES:
157
-
158
- - This is an auto-proceed step — validation is advisory
159
- - Proceed directly to finalize step after reporting results
160
-
161
- ## CRITICAL STEP COMPLETION NOTE
162
-
163
- ONLY WHEN deliverables have been written to `{skill_package}` and validation checks are complete and results reported will you load and read fully `{nextStepFile}` to execute finalization.
148
+ Once deliverables are written to `{skill_package}` and validation is reported (advisory), load and execute {nextStepFile} to finalize.
164
149
 
@@ -50,8 +50,8 @@ These rules apply to every step in this workflow:
50
50
  |--------|--------|
51
51
  | **Inputs** | architecture_doc_path [required], vs_report_path [optional] |
52
52
  | **Flags** | `--headless` / `-H` (auto-resolve all gates); `--architecture-doc <path>` (skip step 1 prompt for the required input); `--vs-report-path <path>` (skip step 1 prompt for the optional VS report); `--scope-skills <names>` (comma-separated in-scope skill names; overrides scope derivation in gap analysis) |
53
- | **Gates** | step 1: Input Gate [use args] | step 5: Review Gate [C] |
54
- | **Outputs** | `refined-architecture-{project_name}.md` at `{outputFolderPath}`, plus `refine-architecture-result-{timestamp}.json` and `refine-architecture-result-latest.json` |
53
+ | **Gates** | step 1: Input Gate [use args] | step 5: Review Gate [C] continue / [X] cancel | step 6: Exit menu [R] review / [X] exit |
54
+ | **Outputs** | `refined-architecture-{arch_project_name}.md` at `{outputFolderPath}` (`{arch_project_name}` = the architecture doc's frontmatter `project_name`, else config `project_name` — resolved in init.md), plus `refine-architecture-result-{timestamp}.json` and `refine-architecture-result-latest.json` |
55
55
  | **Headless** | All gates auto-resolve with default action when `{headless_mode}` is true. Per-flag args (`--architecture-doc`, `--vs-report-path`) consumed at the gates that would otherwise prompt. |
56
56
  | **Exit codes** | See "Exit Codes" below |
57
57
 
@@ -63,11 +63,12 @@ Every HARD HALT in this workflow exits with a stable code so headless automators
63
63
  | ---- | -------------------- | -------------------------------------------------------------------------------------------- |
64
64
  | 0 | success | step 7 (terminal) |
65
65
  | 2 | input-missing / input-invalid | step 1 §1 (headless missing `architecture-doc` arg, or invalid path) → `input-missing`; non-existent file → `input-invalid` |
66
- | 3 | resolution-failure | step 1 §3 (`output_folder` or `forge_data_folder` unconfigured) |
67
- | 4 | write-failure | On-Activation §3 pre-flight write probe; step 1 §3c (RA state file write failed); step 5 §6 (refined-architecture write failed); step 6 §3 (result-contract write failed) |
66
+ | 3 | resolution-failure | On-Activation §5 (`output_folder` or `forge_data_folder` unconfigured) |
67
+ | 4 | write-failure | On-Activation §5 pre-flight write probe; step 1 §3c (RA state file write failed); step 5 §6 (refined-architecture write failed); step 6 §3 (result-contract write failed) |
68
68
  | 5 | state-conflict | step 1 §3 (no skills found — refinement requires ≥1 skill) |
69
69
  | 6 | user-cancelled | step 1 §1 prompt cancelled; any prompt that accepted `cancel`/`exit`/`:q`; step 5 review gate `[X]` |
70
70
  | 7 | inventory-unreliable | step 1 §2 (>20% skill-inventory warnings exceed budget) |
71
+ | 8 | recovery-failed | step 5 §1 (durability state insufficient to reconstruct Step 02-04 findings); step 6 §1 (`## Refinement Summary` absent from the compiled document) |
71
72
 
72
73
  ## Result Contract (Headless)
73
74
 
@@ -77,7 +78,7 @@ When `{headless_mode}` is true, step 6 emits a single-line JSON envelope on **st
77
78
  SKF_REFINE_ARCHITECTURE_RESULT_JSON: {"status":"success|error","refined_path":"…|null","gap_count":0,"issue_count":0,"improvement_count":0,"exit_code":0,"halt_reason":null}
78
79
  ```
79
80
 
80
- `status` is `"success"` on the terminal happy path, `"error"` on any HALT. `halt_reason` is one of: `null` (success), `"input-missing"`, `"input-invalid"`, `"insufficient-skills"`, `"output-folder-unconfigured"`, `"forge-folder-unconfigured"`, `"inventory-unreliable"`, `"write-failed"`, `"user-cancelled"`. `exit_code` matches the table above.
81
+ `status` is `"success"` on the terminal happy path, `"error"` on any HALT. `halt_reason` is one of: `null` (success), `"input-missing"`, `"input-invalid"`, `"insufficient-skills"`, `"output-folder-unconfigured"`, `"forge-folder-unconfigured"`, `"inventory-unreliable"`, `"write-failed"`, `"recovery-failed"`, `"user-cancelled"`. `exit_code` matches the table above.
81
82
 
82
83
  ## On Activation
83
84
 
@@ -109,10 +110,17 @@ SKF_REFINE_ARCHITECTURE_RESULT_JSON: {"status":"success|error","refined_path":"
109
110
 
110
111
  - `{refinementRulesPath}` ← `workflow.refinement_rules_path` if non-empty, else `references/refinement-rules.md`
111
112
  - `{outputFolderPath}` ← `workflow.output_folder_path` if non-empty, else `{output_folder}`
113
+ - `{onCompleteCommand}` ← `workflow.on_complete` if non-empty, else empty (no-op — report.md skips the hook invocation entirely)
112
114
 
113
- Stash both as workflow-context variables. Stage files reference them directly — no conditional at the usage site.
115
+ Stash all three as workflow-context variables. Stage files reference them directly — no conditional at the usage site.
114
116
 
115
- 5. **Pre-flight write probe.** Verify both `{outputFolderPath}` and `{forge_data_folder}` are writable. A read-only mount, full disk, or permissions-denied path otherwise only surfaces at init.md §3c's RA state file write by then the user has already gone through input prompts:
117
+ Also apply the array surfaces (not silent no-ops): run `workflow.activation_steps_prepend` now, treat `workflow.persistent_facts` as standing context for the run (`file:`-prefixed entries load their file/glob contents as facts), then run `workflow.activation_steps_append` after activation.
118
+
119
+ 5. **Pre-flight config + write probe.** Assert both output paths are configured, then probe writability — order matters: an empty path makes `mkdir -p ""` fail, which would misreport a *missing config* (exit 3) as a *write failure* (exit 4) and collapse the distinction the Result Contract draws.
120
+
121
+ **Config-completeness (exit 3).** If `{outputFolderPath}` is empty: HALT (exit code 3, `halt_reason: "output-folder-unconfigured"`) — "`output_folder` is not configured in config.yaml. Add an `output_folder` path and re-run [RA]." If `{forge_data_folder}` is empty: HALT (exit code 3, `halt_reason: "forge-folder-unconfigured"`) — "`forge_data_folder` is not configured in config.yaml. Add a `forge_data_folder` path and re-run [RA]."
122
+
123
+ **Write probe (exit 4).** With both paths now non-empty, verify each is writable — a read-only mount, full disk, or permissions-denied path otherwise only surfaces at init.md §3c's RA state file write, by which point the user has already gone through input prompts:
116
124
 
117
125
  ```bash
118
126
  for dir in "{outputFolderPath}" "{forge_data_folder}"; do
@@ -122,6 +130,6 @@ SKF_REFINE_ARCHITECTURE_RESULT_JSON: {"status":"success|error","refined_path":"
122
130
  done
123
131
  ```
124
132
 
125
- On any non-zero exit: HALT (exit code 4, `halt_reason: "write-failed"`). In headless mode, emit the error envelope per **Result Contract (Headless)** with `refined_path: null`.
133
+ On any non-zero exit: HALT (exit code 4, `halt_reason: "write-failed"`). In headless mode, every HALT above emits the error envelope per **Result Contract (Headless)** with `refined_path: null`.
126
134
 
127
135
  6. Load, read the full file, and then execute `references/init.md` to begin the workflow.
@@ -1,6 +1,8 @@
1
1
  # DO NOT EDIT -- overwritten on every update.
2
2
  #
3
3
  # Workflow customization surface for skf-refine-architecture.
4
+ # Team overrides: _bmad/custom/skf-refine-architecture.toml (under {project-root})
5
+ # Personal overrides: _bmad/custom/skf-refine-architecture.user.toml (under {project-root})
4
6
 
5
7
  [workflow]
6
8
 
@@ -47,3 +49,10 @@ refinement_rules_path = ""
47
49
  # refined-architecture artifacts to land under a curated docs tree.
48
50
 
49
51
  output_folder_path = ""
52
+
53
+ # Optional post-completion hook. When non-empty, invoked with
54
+ # `--result-path=<path>` after the refined architecture and result JSON are
55
+ # finalized (step 6). Use to index the refined doc, notify, or chain the next
56
+ # workflow. Failures are logged to workflow_warnings[] but never fail the run.
57
+
58
+ on_complete = ""
@@ -1,6 +1,7 @@
1
1
  ---
2
2
  nextStepFile: 'report.md'
3
- outputFile: '{outputFolderPath}/refined-architecture-{project_name}.md'
3
+ # {arch_project_name} resolved in init.md (arch-doc frontmatter project_name, else config project_name).
4
+ outputFile: '{outputFolderPath}/refined-architecture-{arch_project_name}.md'
4
5
  ---
5
6
 
6
7
  <!-- Config: communicate in {communication_language}. Compile the refined architecture document in {document_output_language}. -->
@@ -23,9 +24,9 @@ Produce the refined architecture document by starting with the original as a bas
23
24
 
24
25
  Load the complete original architecture document.
25
26
 
26
- This is the base. Every line of the original MUST appear in the refined document, unmodified.
27
+ This is the base. Every line of the original appears in the refined document unmodified — the workflow only adds annotations and subsections; dropping or rewording original content silently discards the user's architecture.
27
28
 
28
- **Context recovery check:** If gap, issue, or improvement findings from Steps 02-04 are not available in context (e.g., due to context degradation in long runs), attempt to read the durability state from `{forge_data_folder}/ra-state-{project_name}.md`. Parse the `<!-- [RA-GAPS] -->`, `<!-- [RA-ISSUES] -->`, and `<!-- [RA-IMPROVEMENTS] -->` comment blocks to recover the complete formatted findings (each block contains full citation text with evidence, not just counts). If a section is still missing or contains only summary counts after recovery, HALT: "⚠️ Context for the [Gaps|Issues|Improvements] analysis was lost and the durability state is insufficient to reconstruct findings. Re-run [RA] from the beginning — step 01 will reset the state file, then steps 02-04 will rebuild all findings."
29
+ **Context recovery check:** If gap, issue, or improvement findings from Steps 02-04 are not available in context (e.g., due to context degradation in long runs), attempt to read the durability state from `{forge_data_folder}/ra-state-{project_name}.md`. Parse the `<!-- [RA-GAPS] -->`, `<!-- [RA-ISSUES] -->`, and `<!-- [RA-IMPROVEMENTS] -->` comment blocks to recover the complete formatted findings (each block contains full citation text with evidence, not just counts). If a section is still missing or contains only summary counts after recovery, HALT (exit code 8, `halt_reason: "recovery-failed"`): "⚠️ Context for the [Gaps|Issues|Improvements] analysis was lost and the durability state is insufficient to reconstruct findings. Re-run [RA] from the beginning — step 01 will reset the state file, then steps 02-04 will rebuild all findings." In headless, emit the error envelope per SKILL.md "Result Contract (Headless)" with `refined_path: null`.
29
30
 
30
31
  ### 2. Insert Gap-Fill Subsections
31
32
 
@@ -112,6 +113,8 @@ Append a `## Refinement Summary` section containing:
112
113
 
113
114
  Write the complete refined architecture to `{outputFile}`.
114
115
 
116
+ On any write failure (read-only mount, disk full, permissions denied): HALT (exit code 4, `halt_reason: "write-failed"`) with the captured error. In headless, emit the error envelope per SKILL.md "Result Contract (Headless)" with `refined_path: null`. The On-Activation §5 write probe should have caught an unwritable output folder earlier — if it surfaces here, the filesystem state changed mid-workflow.
117
+
115
118
  ### 7. Present Compiled Document for Review
116
119
 
117
120
  "**Refined architecture compiled. Please review:**
@@ -134,16 +137,15 @@ Please review the refinements:
134
137
 
135
138
  ### 8. Present MENU OPTIONS
136
139
 
137
- Display: **Select:** [C] Continue to Final Report
140
+ Display: **Select:** [C] Continue to Final Report | [X] Cancel
138
141
 
139
- #### EXECUTION RULES:
142
+ #### GATE [default: C]
140
143
 
141
- - ALWAYS halt and wait for user input after presenting compilation
142
- - **GATE [default: C]** — If `{headless_mode}`: auto-proceed with [C] Continue, log: "headless: auto-approve compiled architecture"
143
- - ONLY proceed to next step when user approves and selects 'C'
144
+ This is a review gate: halt for the user's decision and do not chain onward until they approve — an unreviewed compile ships un-vetted refinements. Headless auto-selects [C] (log: "headless: auto-approve compiled architecture").
144
145
 
145
146
  #### Menu Handling Logic:
146
147
 
147
148
  - IF C: Load, read entire file, then execute {nextStepFile}
149
+ - IF cancel / exit / [X] / q / :q: HALT (exit code 6, `halt_reason: "user-cancelled"`) — display "Cancelled — refinement not finalized." In headless, emit the error envelope per SKILL.md "Result Contract (Headless)" with `refined_path: null`. These global cancel tokens pre-empt the feedback branch below.
148
150
  - IF Any other: Process as feedback, adjust specific refinements in the document, rewrite {outputFile}, redisplay preview, then [Redisplay Menu Options](#8-present-menu-options)
149
151