bmad-module-skill-forge 1.4.1 → 1.5.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 (230) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/README.md +0 -8
  3. package/docs/_data/pinned.yaml +1 -1
  4. package/docs/_internal/STABILITY.md +1 -1
  5. package/docs/architecture.md +2 -2
  6. package/docs/examples.md +1 -1
  7. package/docs/workflows.md +5 -5
  8. package/package.json +2 -2
  9. package/src/README.md +1 -1
  10. package/src/knowledge/ccc-bridge.md +12 -12
  11. package/src/knowledge/qmd-registry.md +5 -5
  12. package/src/shared/health-check.md +5 -5
  13. package/src/shared/references/description-guard-protocol.md +100 -0
  14. package/src/shared/references/output-contract-schema.md +1 -1
  15. package/src/shared/scripts/schemas/skf-brief-result-envelope.v1.json +6 -6
  16. package/src/shared/scripts/schemas/skf-setup-result-envelope.v1.json +9 -3
  17. package/src/shared/scripts/schemas/skf-update-result-envelope.v1.json +149 -0
  18. package/src/shared/scripts/schemas/skill-brief.v1.json +22 -2
  19. package/src/shared/scripts/skf-build-change-manifest.py +420 -0
  20. package/src/shared/scripts/skf-check-workspace-drift.py +321 -0
  21. package/src/shared/scripts/skf-compare-file-hashes.py +357 -0
  22. package/src/shared/scripts/skf-description-guard.py +359 -0
  23. package/src/shared/scripts/skf-detect-language.py +2 -2
  24. package/src/shared/scripts/skf-detect-scripts-assets.py +613 -0
  25. package/src/shared/scripts/skf-detect-tools.py +97 -8
  26. package/src/shared/scripts/skf-detect-workspaces.py +1 -1
  27. package/src/shared/scripts/skf-disqualify-candidates.py +576 -0
  28. package/src/shared/scripts/skf-emit-brief-result-envelope.py +3 -3
  29. package/src/shared/scripts/skf-emit-result-envelope.py +93 -9
  30. package/src/shared/scripts/skf-enumerate-stack-skills.py +514 -0
  31. package/src/shared/scripts/skf-forge-tier-rw.py +11 -11
  32. package/src/shared/scripts/skf-hash-content.py +284 -0
  33. package/src/shared/scripts/skf-load-provenance.py +295 -0
  34. package/src/shared/scripts/skf-merge-ccc-exclusions.py +34 -4
  35. package/src/shared/scripts/skf-pair-intersect.py +250 -0
  36. package/src/shared/scripts/skf-provenance-gap-dispatch.py +433 -0
  37. package/src/shared/scripts/skf-qmd-classify-collections.py +42 -8
  38. package/src/shared/scripts/skf-recommend-scope-type.py +2 -2
  39. package/src/shared/scripts/skf-render-quick-metadata.py +2 -2
  40. package/src/shared/scripts/skf-resolve-authoritative-files.py +504 -0
  41. package/src/shared/scripts/skf-scan-manifests.py +738 -0
  42. package/src/shared/scripts/skf-scan-skill-md-structure.py +375 -0
  43. package/src/shared/scripts/skf-update-active-symlink.py +315 -0
  44. package/src/shared/scripts/skf-validate-brief-inputs.py +5 -5
  45. package/src/shared/scripts/skf-validate-brief-schema.py +348 -0
  46. package/src/shared/scripts/skf-write-skill-brief.py +61 -5
  47. package/src/skf-analyze-source/SKILL.md +69 -16
  48. package/src/skf-analyze-source/assets/skill-brief-schema.md +1 -1
  49. package/src/skf-analyze-source/customize.toml +55 -0
  50. package/src/skf-analyze-source/{steps-c/step-01b-continue.md → references/continue.md} +12 -12
  51. package/src/skf-analyze-source/{steps-c/step-06-generate-briefs.md → references/generate-briefs.md} +29 -10
  52. package/src/skf-analyze-source/{steps-c/step-07-health-check.md → references/health-check.md} +5 -3
  53. package/src/skf-analyze-source/{steps-c/step-03-identify-units.md → references/identify-units.md} +44 -14
  54. package/src/skf-analyze-source/{steps-c/step-01-init.md → references/init.md} +27 -6
  55. package/src/skf-analyze-source/{steps-c/step-04-map-and-detect.md → references/map-and-detect.md} +52 -25
  56. package/src/skf-analyze-source/{steps-c/step-05-recommend.md → references/recommend.md} +15 -8
  57. package/src/skf-analyze-source/{steps-c/step-02-scan-project.md → references/scan-project.md} +12 -10
  58. package/src/skf-analyze-source/references/unit-detection-heuristics.md +2 -0
  59. package/src/skf-analyze-source/templates/analysis-report-template.md +6 -6
  60. package/src/skf-audit-skill/SKILL.md +66 -15
  61. package/src/skf-audit-skill/assets/drift-report-template.md +6 -5
  62. package/src/skf-audit-skill/customize.toml +49 -0
  63. package/src/skf-audit-skill/{steps-c/step-07-health-check.md → references/health-check.md} +5 -3
  64. package/src/skf-audit-skill/{steps-c/step-01-init.md → references/init.md} +57 -19
  65. package/src/skf-audit-skill/{steps-c/step-02-re-index.md → references/re-index.md} +11 -11
  66. package/src/skf-audit-skill/{steps-c/step-06-report.md → references/report.md} +25 -7
  67. package/src/skf-audit-skill/{steps-c/step-04-semantic-diff.md → references/semantic-diff.md} +6 -6
  68. package/src/skf-audit-skill/{steps-c/step-05-severity-classify.md → references/severity-classify.md} +5 -5
  69. package/src/skf-audit-skill/references/severity-rules.md +2 -0
  70. package/src/skf-audit-skill/{steps-c/step-03-structural-diff.md → references/structural-diff.md} +29 -17
  71. package/src/skf-brief-skill/SKILL.md +48 -18
  72. package/src/skf-brief-skill/assets/description-voice-examples.md +1 -1
  73. package/src/skf-brief-skill/assets/skill-brief-schema.md +32 -2
  74. package/src/skf-brief-skill/customize.toml +44 -0
  75. package/src/skf-brief-skill/{steps-c/step-02-analyze-target.md → references/analyze-target.md} +5 -5
  76. package/src/skf-brief-skill/{steps-c/step-04-confirm-brief.md → references/confirm-brief.md} +13 -10
  77. package/src/skf-brief-skill/references/draft-checkpoint.md +4 -4
  78. package/src/skf-brief-skill/{steps-c/step-01-gather-intent.md → references/gather-intent.md} +24 -24
  79. package/src/skf-brief-skill/references/headless-args.md +9 -9
  80. package/src/skf-brief-skill/references/headless-source-authority-detection.md +1 -1
  81. package/src/skf-brief-skill/{steps-c/step-06-health-check.md → references/health-check.md} +4 -2
  82. package/src/skf-brief-skill/references/portfolio-similarity-check.md +2 -2
  83. package/src/skf-brief-skill/references/qmd-collection-registration.md +1 -1
  84. package/src/skf-brief-skill/{steps-c/step-03-scope-definition.md → references/scope-definition.md} +19 -16
  85. package/src/skf-brief-skill/references/version-resolution.md +2 -2
  86. package/src/skf-brief-skill/{steps-c/step-05-write-brief.md → references/write-brief.md} +11 -10
  87. package/src/skf-create-skill/SKILL.md +25 -19
  88. package/src/skf-create-skill/assets/compile-assembly-rules.md +3 -3
  89. package/src/skf-create-skill/assets/skill-sections.md +5 -5
  90. package/src/skf-create-skill/assets/tessl-dismissal-rules.md +11 -11
  91. package/src/skf-create-skill/customize.toml +35 -0
  92. package/src/skf-create-skill/references/authoritative-files-protocol.md +142 -0
  93. package/src/skf-create-skill/{steps-c/step-05-compile.md → references/compile.md} +16 -16
  94. package/src/skf-create-skill/{steps-c/step-03d-component-extraction.md → references/component-extraction.md} +16 -16
  95. package/src/skf-create-skill/{steps-c/step-02-ecosystem-check.md → references/ecosystem-check.md} +4 -4
  96. package/src/skf-create-skill/{steps-c/step-04-enrich.md → references/enrich.md} +3 -3
  97. package/src/skf-create-skill/{steps-c/step-03-extract.md → references/extract.md} +52 -120
  98. package/src/skf-create-skill/references/extraction-patterns.md +8 -8
  99. package/src/skf-create-skill/{steps-c/step-07-generate-artifacts.md → references/generate-artifacts.md} +11 -11
  100. package/src/skf-create-skill/{steps-c/step-09-health-check.md → references/health-check.md} +4 -2
  101. package/src/skf-create-skill/{steps-c/step-01-load-brief.md → references/load-brief.md} +40 -32
  102. package/src/skf-create-skill/{steps-c/step-08-report.md → references/report.md} +8 -8
  103. package/src/skf-create-skill/references/source-resolution-protocols.md +6 -6
  104. package/src/skf-create-skill/{steps-c/sub/step-02b-ccc-discover.md → references/sub/ccc-discover.md} +5 -5
  105. package/src/skf-create-skill/{steps-c/sub/step-03c-fetch-docs.md → references/sub/fetch-docs.md} +28 -12
  106. package/src/skf-create-skill/{steps-c/sub/step-03b-fetch-temporal.md → references/sub/fetch-temporal.md} +81 -50
  107. package/src/skf-create-skill/{steps-c/step-06-validate.md → references/validate.md} +46 -26
  108. package/src/skf-create-stack-skill/SKILL.md +76 -17
  109. package/src/skf-create-stack-skill/assets/provenance-map-schema.md +102 -0
  110. package/src/skf-create-stack-skill/assets/stack-skill-template.md +1 -1
  111. package/src/skf-create-stack-skill/customize.toml +46 -0
  112. package/src/skf-create-stack-skill/{steps-c/step-06-compile-stack.md → references/compile-stack.md} +6 -5
  113. package/src/skf-create-stack-skill/references/compose-mode-rules.md +3 -1
  114. package/src/skf-create-stack-skill/{steps-c/step-05-detect-integrations.md → references/detect-integrations.md} +32 -11
  115. package/src/skf-create-stack-skill/{steps-c/step-02-detect-manifests.md → references/detect-manifests.md} +28 -28
  116. package/src/skf-create-stack-skill/{steps-c/step-07-generate-output.md → references/generate-output.md} +11 -85
  117. package/src/skf-create-stack-skill/{steps-c/step-10-health-check.md → references/health-check.md} +4 -2
  118. package/src/skf-create-stack-skill/{steps-c/step-01-init.md → references/init.md} +70 -4
  119. package/src/skf-create-stack-skill/references/integration-patterns.md +2 -0
  120. package/src/skf-create-stack-skill/references/manifest-patterns.md +2 -0
  121. package/src/skf-create-stack-skill/{steps-c/step-04-parallel-extract.md → references/parallel-extract.md} +40 -17
  122. package/src/skf-create-stack-skill/{steps-c/step-03-rank-and-confirm.md → references/rank-and-confirm.md} +5 -4
  123. package/src/skf-create-stack-skill/{steps-c/step-09-report.md → references/report.md} +3 -3
  124. package/src/skf-create-stack-skill/{steps-c/step-08-validate.md → references/validate.md} +6 -6
  125. package/src/skf-drop-skill/SKILL.md +84 -12
  126. package/src/skf-drop-skill/customize.toml +57 -0
  127. package/src/skf-drop-skill/{steps-c/step-02-execute.md → references/execute.md} +49 -34
  128. package/src/skf-drop-skill/{steps-c/step-04-health-check.md → references/health-check.md} +6 -4
  129. package/src/skf-drop-skill/{steps-c/step-03-report.md → references/report.md} +13 -5
  130. package/src/skf-drop-skill/{steps-c/step-01-select.md → references/select.md} +63 -15
  131. package/src/skf-export-skill/SKILL.md +85 -16
  132. package/src/skf-export-skill/assets/managed-section-format.md +3 -3
  133. package/src/skf-export-skill/assets/snippet-format.md +2 -2
  134. package/src/skf-export-skill/customize.toml +49 -0
  135. package/src/skf-export-skill/{steps-c/step-03-generate-snippet.md → references/generate-snippet.md} +11 -11
  136. package/src/skf-export-skill/{steps-c/step-07-health-check.md → references/health-check.md} +6 -4
  137. package/src/skf-export-skill/{steps-c/step-01-load-skill.md → references/load-skill.md} +11 -49
  138. package/src/skf-export-skill/references/manifest-rebuild.md +68 -0
  139. package/src/skf-export-skill/references/multi-skill-mode.md +38 -0
  140. package/src/skf-export-skill/references/orphan-context-detection.md +75 -0
  141. package/src/skf-export-skill/references/orphan-row-detection.md +102 -0
  142. package/src/skf-export-skill/{steps-c/step-02-package.md → references/package.md} +7 -7
  143. package/src/skf-export-skill/references/preflight-snippet-root-probe.md +74 -0
  144. package/src/skf-export-skill/{steps-c/step-06-summary.md → references/summary.md} +20 -8
  145. package/src/skf-export-skill/{steps-c/step-05-token-report.md → references/token-report.md} +5 -5
  146. package/src/skf-export-skill/{steps-c/step-04-update-context.md → references/update-context.md} +109 -113
  147. package/src/skf-quick-skill/SKILL.md +63 -123
  148. package/src/skf-quick-skill/customize.toml +44 -0
  149. package/src/skf-quick-skill/references/batch-mode.md +102 -0
  150. package/src/skf-quick-skill/{steps-c/step-04-compile.md → references/compile.md} +10 -10
  151. package/src/skf-quick-skill/{steps-c/step-02-ecosystem-check.md → references/ecosystem-check.md} +5 -5
  152. package/src/skf-quick-skill/{steps-c/step-06-finalize.md → references/finalize.md} +7 -7
  153. package/src/skf-quick-skill/{steps-c/step-07-health-check.md → references/health-check.md} +3 -3
  154. package/src/skf-quick-skill/{steps-c/step-03-quick-extract.md → references/quick-extract.md} +5 -5
  155. package/src/skf-quick-skill/references/registry-resolution.md +2 -0
  156. package/src/skf-quick-skill/{steps-c/step-01-resolve-target.md → references/resolve-target.md} +14 -10
  157. package/src/skf-quick-skill/{steps-c/step-05-write-and-validate.md → references/write-and-validate.md} +4 -4
  158. package/src/skf-refine-architecture/SKILL.md +86 -16
  159. package/src/skf-refine-architecture/customize.toml +49 -0
  160. package/src/skf-refine-architecture/{steps-c/step-05-compile.md → references/compile.md} +4 -4
  161. package/src/skf-refine-architecture/{steps-c/step-02-gap-analysis.md → references/gap-analysis.md} +5 -5
  162. package/src/skf-refine-architecture/{steps-c/step-07-health-check.md → references/health-check.md} +6 -4
  163. package/src/skf-refine-architecture/{steps-c/step-04-improvements.md → references/improvements.md} +5 -5
  164. package/src/skf-refine-architecture/references/init.md +144 -0
  165. package/src/skf-refine-architecture/{steps-c/step-03-issue-detection.md → references/issue-detection.md} +5 -5
  166. package/src/skf-refine-architecture/references/refinement-rules.md +2 -0
  167. package/src/skf-refine-architecture/{steps-c/step-06-report.md → references/report.md} +14 -5
  168. package/src/skf-rename-skill/SKILL.md +82 -12
  169. package/src/skf-rename-skill/customize.toml +52 -0
  170. package/src/skf-rename-skill/{steps-c/step-02-execute.md → references/execute.md} +94 -99
  171. package/src/skf-rename-skill/references/health-check.md +30 -0
  172. package/src/skf-rename-skill/references/rebuild-context.md +110 -0
  173. package/src/skf-rename-skill/{steps-c/step-03-report.md → references/report.md} +13 -5
  174. package/src/skf-rename-skill/{steps-c/step-01-select.md → references/select.md} +59 -20
  175. package/src/skf-setup/SKILL.md +35 -35
  176. package/src/skf-setup/customize.toml +33 -0
  177. package/src/skf-setup/{steps-c/step-03-auto-index.md → references/auto-index.md} +10 -18
  178. package/src/skf-setup/{steps-c/step-01b-ccc-index.md → references/ccc-index.md} +16 -31
  179. package/src/skf-setup/{steps-c/step-01-detect-and-tier.md → references/detect-and-tier.md} +23 -10
  180. package/src/skf-setup/{steps-c/step-05-health-check.md → references/health-check.md} +1 -1
  181. package/src/skf-setup/{steps-c/step-04-report.md → references/report.md} +21 -19
  182. package/src/skf-setup/references/tier-rules.md +1 -1
  183. package/src/skf-setup/{steps-c/step-02-write-config.md → references/write-config.md} +14 -13
  184. package/src/skf-test-skill/SKILL.md +77 -15
  185. package/src/skf-test-skill/customize.toml +54 -0
  186. package/src/skf-test-skill/{steps-c/step-04-coherence-check.md → references/coherence-check.md} +28 -71
  187. package/src/skf-test-skill/{steps-c/step-03-coverage-check.md → references/coverage-check.md} +16 -39
  188. package/src/skf-test-skill/{steps-c/step-02-detect-mode.md → references/detect-mode.md} +4 -26
  189. package/src/skf-test-skill/{steps-c/step-04b-external-validators.md → references/external-validators.md} +6 -28
  190. package/src/skf-test-skill/references/health-check.md +14 -0
  191. package/src/skf-test-skill/{steps-c/step-01-init.md → references/init.md} +21 -37
  192. package/src/skf-test-skill/references/migration-section-rules.md +4 -2
  193. package/src/skf-test-skill/{steps-c/step-06-report.md → references/report.md} +41 -51
  194. package/src/skf-test-skill/{steps-c/step-05-score.md → references/score.md} +26 -43
  195. package/src/skf-test-skill/references/scoring-rules.md +8 -6
  196. package/src/skf-test-skill/references/source-access-protocol.md +7 -5
  197. package/src/skf-test-skill/scripts/compute-score.py +88 -17
  198. package/src/skf-test-skill/templates/test-report-template.md +13 -13
  199. package/src/skf-update-skill/SKILL.md +23 -14
  200. package/src/skf-update-skill/customize.toml +44 -0
  201. package/src/skf-update-skill/{steps-c/step-02-detect-changes.md → references/detect-changes.md} +176 -68
  202. package/src/skf-update-skill/references/health-check.md +32 -0
  203. package/src/skf-update-skill/{steps-c/step-01-init.md → references/init.md} +56 -8
  204. package/src/skf-update-skill/references/manual-section-rules.md +4 -0
  205. package/src/skf-update-skill/references/merge-conflict-rules.md +4 -0
  206. package/src/skf-update-skill/{steps-c/step-04-merge.md → references/merge.md} +8 -8
  207. package/src/skf-update-skill/{steps-c/step-03-re-extract.md → references/re-extract.md} +53 -44
  208. package/src/skf-update-skill/references/remote-source-resolution.md +5 -1
  209. package/src/skf-update-skill/references/report.md +214 -0
  210. package/src/skf-update-skill/{steps-c/step-05-validate.md → references/validate.md} +5 -5
  211. package/src/skf-update-skill/{steps-c/step-06-write.md → references/write.md} +73 -51
  212. package/src/skf-verify-stack/SKILL.md +89 -17
  213. package/src/skf-verify-stack/assets/feasibility-report-template.md +4 -4
  214. package/src/skf-verify-stack/customize.toml +50 -0
  215. package/src/skf-verify-stack/references/coverage-patterns.md +2 -2
  216. package/src/skf-verify-stack/{steps-c/step-02-coverage.md → references/coverage.md} +7 -7
  217. package/src/skf-verify-stack/{steps-c/step-07-health-check.md → references/health-check.md} +7 -5
  218. package/src/skf-verify-stack/references/init.md +166 -0
  219. package/src/skf-verify-stack/references/integration-verification-rules.md +1 -1
  220. package/src/skf-verify-stack/{steps-c/step-03-integrations.md → references/integrations.md} +12 -12
  221. package/src/skf-verify-stack/{steps-c/step-06-report.md → references/report.md} +22 -41
  222. package/src/skf-verify-stack/{steps-c/step-04-requirements.md → references/requirements.md} +7 -7
  223. package/src/skf-verify-stack/{steps-c/step-05-synthesize.md → references/synthesize.md} +8 -8
  224. package/tools/validate-docs-drift.js +1 -1
  225. package/src/skf-refine-architecture/steps-c/step-01-init.md +0 -136
  226. package/src/skf-rename-skill/steps-c/step-04-health-check.md +0 -22
  227. package/src/skf-test-skill/steps-c/step-07-health-check.md +0 -25
  228. package/src/skf-update-skill/steps-c/step-07-report.md +0 -148
  229. package/src/skf-update-skill/steps-c/step-08-health-check.md +0 -22
  230. package/src/skf-verify-stack/steps-c/step-01-init.md +0 -178
@@ -0,0 +1,110 @@
1
+ ---
2
+ # Static reference loaded by execute.md §7. The carve removes ~70
3
+ # lines of context-rebuild loop logic from the main execute.md so
4
+ # the §1–§6 + §8–§10 critical-path stays tight; §7 itself is always
5
+ # reached on the success path so this file loads on every successful
6
+ # rename, but the rollback paths (§4–§6 failure jumps) skip §7
7
+ # entirely and never load this reference.
8
+ ---
9
+
10
+ <!-- Config: communicate in {communication_language}. Render the rebuilt-files report in {document_output_language}. -->
11
+
12
+ # Rename: Rebuild Context Files (per-IDE managed-section sweep)
13
+
14
+ ## Purpose
15
+
16
+ After §6 re-keys the manifest from `{old_name}` to `{new_name}`, every IDE's context file (`CLAUDE.md`, `.cursorrules`, `AGENTS.md`, etc.) still contains the old name in its managed-section snippet rows. This step rewrites each one in-place via the surgical between-marker swap so the on-disk managed sections reflect the new name.
17
+
18
+ Loaded by `execute.md` §7 once `manifest_updated == true` (§6 succeeded) and the rollback paths in §4–§6 were not taken.
19
+
20
+ ## Resolve target_context_files
21
+
22
+ Load the `ides` list from `config.yaml`. The installer writes IDE identifiers — these must be mapped to context files and skill roots using the "IDE → Context File Mapping" table in `{managedSectionLogic}`:
23
+
24
+ 1. For each entry in `config.yaml.ides`, look up its `context_file` and `skill_root` from the mapping table.
25
+ 2. For any entry not found in the table, default to AGENTS.md / `.agents/skills/` and emit a warning: `Unknown IDE '{value}' in config.yaml — defaulting to AGENTS.md`.
26
+ 3. Deduplicate by `context_file` — when multiple IDEs map to the same context file, use the first configured IDE's `skill_root`.
27
+ 4. If `config.yaml.ides` is absent or the mapping yields an empty list, fall back to `[{context_file: "AGENTS.md", skill_root: ".agents/skills/"}]` and emit a note: `No IDEs configured in config.yaml — defaulting to AGENTS.md`.
28
+
29
+ Store the result as `target_context_files`.
30
+
31
+ ## Per-file loop
32
+
33
+ For each entry in `target_context_files`:
34
+
35
+ ### 1. Resolve target file
36
+
37
+ Resolve the absolute path at `{context_file}`.
38
+
39
+ ### 2. Read the current file
40
+
41
+ - If the file does not exist, skip this context file (nothing to rebuild — the file will be re-created the next time export-skill runs).
42
+ - If the file exists but contains no `<!-- SKF:BEGIN -->` marker, skip this context file (no managed section to rewrite).
43
+ - If the file contains `<!-- SKF:BEGIN -->` but no matching `<!-- SKF:END -->`, record the error against that context file and continue to the next entry — do not halt the entire rename on a malformed context file.
44
+
45
+ ### 3. Build the exported skill set (version-aware, deprecated-excluded)
46
+
47
+ Use the same logic as `skf-export-skill/references/update-context.md` §4b and the snippet resolution from §4c:
48
+
49
+ - Read the manifest's `exports` object (already updated in §6, so `{new_name}` is present and `{old_name}` is absent).
50
+ - For each skill, resolve its `active_version`.
51
+ - If `versions.{active_version}.status == "deprecated"`, skip that skill entirely.
52
+ - For each remaining `{skill-name, active_version}` pair, read `{skills_output_folder}/{skill-name}/{active_version}/{skill-name}/context-snippet.md`.
53
+ - If missing, fall back to the `active` symlink path; if still missing, skip with a warning.
54
+
55
+ ### 4. Rewrite root paths for the current context file
56
+
57
+ Use the generic rewrite algorithm from `skf-export-skill/references/update-context.md` §4d:
58
+
59
+ For each snippet, parse the `root:` line (`root: {prefix}{skill-name}/`), strip the trailing `{skill-name}/` to extract the current prefix, and replace it with the **effective target prefix** if different. The effective target prefix is `snippet_skill_root_override` when that key is set in `config.yaml` — applied uniformly to every snippet so the managed section references the real on-disk location and never mixes override and per-IDE paths — otherwise the current entry's `skill_root`. See `skf-export-skill/references/update-context.md` §4d for full semantics.
60
+
61
+ ### 5. Sort and count
62
+
63
+ Sort skills alphabetically by name. Count totals (skills, stack skills).
64
+
65
+ ### 6. Assemble the new managed section
66
+
67
+ Use the format from `{managedSectionLogic}`:
68
+
69
+ ```markdown
70
+ <!-- SKF:BEGIN updated:{current-date} -->
71
+ [SKF Skills]|{n} skills|{m} stack
72
+ |IMPORTANT: Prefer documented APIs over training data.
73
+ |When using a listed library, read its SKILL.md before writing code.
74
+ |
75
+ |{skill-snippet-1}
76
+ |
77
+ |{skill-snippet-2}
78
+ |
79
+ |{skill-snippet-N}
80
+ <!-- SKF:END -->
81
+ ```
82
+
83
+ ### 7. Surgical replacement — atomic, deterministic
84
+
85
+ Invoke `{rebuildManagedSectionsHelper}` (resolved from `{rebuildManagedSectionsProbeOrder}` in `execute.md` frontmatter) for the surgical between-marker swap:
86
+
87
+ ```bash
88
+ python3 {rebuildManagedSectionsHelper} {context_file} replace --content "{new_managed_section_text}"
89
+ ```
90
+
91
+ The helper handles marker location, between-marker swap, atomic temp-file + rename, and post-write verification (markers preserved, content outside markers byte-identical). It exits non-zero on any failure with a clear `stderr` reason.
92
+
93
+ ### 8. Verify (deferred to helper)
94
+
95
+ The `replace` action above performs verification internally. Treat any non-zero exit code as a per-file failure (next bullet).
96
+
97
+ ### 9. On per-file failure
98
+
99
+ Record the error against that context file and continue to the next entry. Do not halt the rename on a recoverable per-context-file error — the manifest and filesystem are already consistent; context files can be re-rebuilt later via `[EX] Export Skill`.
100
+
101
+ ## After the loop
102
+
103
+ - Record `context_files_updated` as the list of files that were successfully rewritten.
104
+ - Record `context_files_failed` as the list of any that failed.
105
+
106
+ Report: `**Rebuilt managed sections in:** {list of updated files}. {if any failed: 'Failed: {list} — re-run [EX] Export Skill to retry.'}`
107
+
108
+ ## Rollback semantics
109
+
110
+ §7 failures **do not** trigger a rollback. The manifest and filesystem are the canonical state — context files are derived artifacts that can be regenerated at any time via `[EX] Export Skill`. The rename is considered successful as soon as §6 lands, even if §7 partially or fully fails to rewrite context files.
@@ -1,7 +1,9 @@
1
1
  ---
2
- nextStepFile: './step-04-health-check.md'
2
+ nextStepFile: 'health-check.md'
3
3
  ---
4
4
 
5
+ <!-- Config: communicate in {communication_language}. Render the report block in {document_output_language}. -->
6
+
5
7
  # Step 3: Report Rename Results
6
8
 
7
9
  ## STEP GOAL:
@@ -10,15 +12,13 @@ Present a clear, final summary of what the rename workflow changed — old and n
10
12
 
11
13
  ## Rules
12
14
 
13
- - Focus only on reporting results stored in context by step-02 — do not re-execute any part of the rename
15
+ - Focus only on reporting results stored in context by step 2 — do not re-execute any part of the rename
14
16
  - Do not hide verification warnings, context file rebuild failures, or deletion errors
15
17
  - Present next-steps guidance so the user knows which downstream workflows to run
16
18
  - Chains to the local health-check step via `{nextStepFile}` after completion — the user-facing report is NOT the terminal step
17
19
 
18
20
  ## MANDATORY SEQUENCE
19
21
 
20
- **CRITICAL:** Follow this sequence exactly.
21
-
22
22
  ### 1. Render the Report
23
23
 
24
24
  Display the following block, filling in values from context:
@@ -71,7 +71,15 @@ Informational: the old name still appears in SKILL.md body text (prose only, non
71
71
 
72
72
  ### Result Contract
73
73
 
74
- Write the result contract per `shared/references/output-contract-schema.md`: the per-run record at `{skills_output_folder}/{new_name}/rename-skill-result-{YYYYMMDD-HHmmss}.json` (UTC timestamp, resolution to seconds) and a copy at `{skills_output_folder}/{new_name}/rename-skill-result-latest.json` (stable path for pipeline consumers — copy, not symlink). Include all updated file paths (SKILL.md, metadata.json, context-snippet.md, provenance-map.json) in `outputs`; include `old_name`, `new_name`, and `versions_renamed` in `summary`.
74
+ Write the result contract per `shared/references/output-contract-schema.md`: the per-run record at `{skills_output_folder}/{new_name}/rename-skill-result-{timestamp}.json` (reuse the activation-stored `{timestamp}`, resolution to seconds) and a copy at `{skills_output_folder}/{new_name}/rename-skill-result-latest.json` (stable path for pipeline consumers — copy, not symlink). Include all updated file paths (SKILL.md, metadata.json, context-snippet.md, provenance-map.json) in `outputs`; include `old_name`, `new_name`, and `versions_renamed` in `summary`.
75
+
76
+ When `{headless_mode}` is true, also emit the single-line envelope on **stdout** before chaining to step 4 (matches the SKILL.md "Result Contract (Headless)" shape):
77
+
78
+ ```
79
+ SKF_RENAME_SKILL_RESULT_JSON: {"status":"success","old_name":"{old_name}","new_name":"{new_name}","versions_renamed":{affected_versions},"manifest_rekeyed":{manifest_rekeyed},"context_files_updated":{context_files_updated},"exit_code":0,"halt_reason":null}
80
+ ```
81
+
82
+ Substitute `{affected_versions}` and `{context_files_updated}` as JSON arrays; `manifest_rekeyed` is the boolean from step 2's context.
75
83
 
76
84
  ### 2. Chain to Health Check
77
85
 
@@ -1,13 +1,15 @@
1
1
  ---
2
- nextStepFile: './step-02-execute.md'
2
+ nextStepFile: 'execute.md'
3
3
  versionPathsKnowledge: 'knowledge/version-paths.md'
4
4
  ---
5
5
 
6
+ <!-- Config: communicate in {communication_language}. -->
7
+
6
8
  # Step 1: Select Rename Target
7
9
 
8
10
  ## STEP GOAL:
9
11
 
10
- Identify the skill the user wants to rename, validate the new name against the agentskills.io spec (kebab-case, length, uniqueness), warn about source authority implications, enumerate every version that will be touched, and obtain explicit user confirmation before any filesystem operation is scheduled. Every selection decision is stored in context so step-02 can execute the rename transactionally.
12
+ Identify the skill the user wants to rename, validate the new name against the agentskills.io spec (kebab-case, length, uniqueness), warn about source authority implications, enumerate every version that will be touched, and obtain explicit user confirmation before any filesystem operation is scheduled. Every selection decision is stored in context so step 2 can execute the rename transactionally.
11
13
 
12
14
  ## Rules
13
15
 
@@ -18,8 +20,6 @@ Identify the skill the user wants to rename, validate the new name against the a
18
20
 
19
21
  ## MANDATORY SEQUENCE
20
22
 
21
- **CRITICAL:** Follow this sequence exactly. Do not skip, reorder, or improvise unless user explicitly requests a change.
22
-
23
23
  ### 1. Load Knowledge
24
24
 
25
25
  Read `{versionPathsKnowledge}` completely and extract:
@@ -28,19 +28,19 @@ Read `{versionPathsKnowledge}` completely and extract:
28
28
  - Export manifest v2 schema (`schema_version`, `exports`, `active_version`, `versions` map, `status` field values)
29
29
  - The Rename section under "Skill Management Operations" — the complete list of 9 locations that must be updated coherently
30
30
 
31
- You will use these templates and rules to build directory paths, enumerate affected versions, and plan the transactional rename in step-02.
31
+ You will use these templates and rules to build directory paths, enumerate affected versions, and plan the transactional rename in step 2.
32
32
 
33
33
  ### 2. Read Export Manifest
34
34
 
35
35
  Load `{skills_output_folder}/.export-manifest.json` if it exists.
36
36
 
37
- **If the file is missing or empty:** Treat as an empty manifest — proceed to section 3 and rely entirely on the on-disk directory scan. Drafted or never-exported skills can still be renamed. Store `manifest_exists = false` for later use in step-02 (section 6 will not attempt to update a manifest that does not exist).
37
+ **If the file is missing or empty:** Treat as an empty manifest — proceed to section 3 and rely entirely on the on-disk directory scan. Drafted or never-exported skills can still be renamed. Store `manifest_exists = false` for later use in step 2 (section 6 will not attempt to update a manifest that does not exist).
38
38
 
39
- **If the file exists but contains no `exports` entries:** Same handling — proceed to section 3 with the directory scan. Store `manifest_exists = true` so step-02 still touches the (empty) manifest on write.
39
+ **If the file exists but contains no `exports` entries:** Same handling — proceed to section 3 with the directory scan. Store `manifest_exists = true` so step 2 still touches the (empty) manifest on write.
40
40
 
41
41
  **If the file exists with entries:** Parse JSON and verify `schema_version` is `"2"`. If the manifest is v1 (no `schema_version` field), note this but continue — treat every entry as having a single active version derived from its current state. Store `manifest_exists = true`.
42
42
 
43
- **Hard halt condition:** If the file exists but is malformed (not valid JSON), halt with: "**Export manifest is corrupt** at `{skills_output_folder}/.export-manifest.json` — fix or remove the file before renaming."
43
+ **Hard halt condition:** If the file exists but is malformed (not valid JSON), halt with: "**Export manifest is corrupt** at `{skills_output_folder}/.export-manifest.json` — fix or remove the file before renaming." HALT (exit code 3, `halt_reason: "manifest-corrupt"`). In headless mode, emit the error envelope per SKILL.md "Result Contract (Headless)" with `old_name: null`, `new_name: null`.
44
44
 
45
45
  ### 3. List Available Skills
46
46
 
@@ -54,7 +54,7 @@ For each skill in the manifest's `exports` (if `manifest_exists` and entries exi
54
54
 
55
55
  Also scan `{skills_output_folder}/` for any top-level directories that are NOT present in the manifest's `exports` object. Record these as "(not in manifest)" — they represent draft or orphaned skills that the rename workflow can also handle. When the manifest is missing or empty, every on-disk skill appears in this category.
56
56
 
57
- **If the combined list is empty** (no manifest entries AND no on-disk skill directories): halt with "**Rename Skill — nothing to rename.** No skills found in `{skills_output_folder}/`. Run `[CS] Create Skill` first."
57
+ **If the combined list is empty** (no manifest entries AND no on-disk skill directories): halt with "**Rename Skill — nothing to rename.** No skills found in `{skills_output_folder}/`. Run `[CS] Create Skill` first." HALT (exit code 3, `halt_reason: "nothing-to-rename"`). In headless mode, emit the error envelope with `old_name: null`, `new_name: null`.
58
58
 
59
59
  Display the combined list:
60
60
 
@@ -70,20 +70,55 @@ Available skills:
70
70
  ### 4. Ask Which Skill
71
71
 
72
72
  "**Which skill would you like to rename?**
73
- Enter the skill name or its number from the list above."
73
+ Enter the skill name or its number from the list above, or `cancel` / `exit` / `:q` to abort."
74
74
 
75
- Wait for user input. Accept either the numeric index or the skill name (exact match). **GATE [default: use args]** — If `{headless_mode}` and old skill name was provided as argument: select that skill and auto-proceed. If not provided, HALT: "headless mode requires old_name argument."
75
+ Wait for user input. Accept either the numeric index or the skill name (exact match). **GATE [default: use args]** — If `{headless_mode}` and old skill name was provided as argument: select that skill and auto-proceed. If not provided, HALT (exit code 2, `halt_reason: "input-missing"`): "headless mode requires old_name argument." In headless, emit the error envelope.
76
76
 
77
- **If the user's input does not match any listed skill:** Re-display the list and ask again.
77
+ - If the user enters `cancel`, `exit`, `[X]`, `q`, or `:q`: Display "Cancelled no changes were made." and HALT (exit code 6, `halt_reason: "user-cancelled"`).
78
+ - **If the user's input does not match any listed skill:** Re-display the list and ask again.
78
79
 
79
80
  Store the selection as `old_name`.
80
81
 
82
+ ### 4b. Concurrency Guard
83
+
84
+ Two concurrent rename runs against the same `old_name` would corrupt state mid-copy: one would `rm -rf` the other's freshly-staged new directories, or both would race on the manifest re-key. The lock below catches the common accidental-double-invoke case. It is a **best-effort PID-file guard**, not a held flock — the LLM-driven workflow spans many turn boundaries and no single bash invocation can hold flock across them.
85
+
86
+ **Mirror this exactly so the guard works the same way every run:**
87
+
88
+ ```bash
89
+ LOCK={forge_data_folder}/{old_name}/.skf-rename.lock
90
+ mkdir -p "$(dirname "$LOCK")"
91
+
92
+ if [ -f "$LOCK" ]; then
93
+ HELD_PID=$(head -n1 "$LOCK" 2>/dev/null | awk '{print $1}')
94
+ if [ -n "$HELD_PID" ] && kill -0 "$HELD_PID" 2>/dev/null; then
95
+ echo "skf-rename-skill: another rename is in progress (pid=$HELD_PID, started $(awk 'NR==2' "$LOCK" 2>/dev/null))"
96
+ exit 1
97
+ fi
98
+ echo "skf-rename-skill: clearing stale lock from pid=$HELD_PID"
99
+ fi
100
+
101
+ printf '%s\n%s\n' "$$" "$(date -u +%Y-%m-%dT%H:%M:%SZ)" > "$LOCK"
102
+ ```
103
+
104
+ **Halt protocol on live-PID collision:**
105
+
106
+ - Display: `"**Another rename is in progress.** The skill {old_name} is locked by pid={HELD_PID} (started {timestamp from line 2 of the lock file}). Wait for that run to finish, or — if you know that pid is no longer running — delete {LOCK} manually and re-run."`
107
+ - HALT (exit code 5, `halt_reason: "halted-for-concurrent-run"`). In `{headless_mode}`, emit the error envelope per SKILL.md "Result Contract (Headless)" with `old_name: "{old_name}"`, `new_name: null`. **No `headless_decisions[]` entry** — this is a hard halt before any gate fires.
108
+
109
+ **Release contract:**
110
+
111
+ - The terminal health-check step (step 4) deletes the lock as its final action.
112
+ - **Every halted-for-\* path in this workflow must delete the lock before exiting** — otherwise the next attempt would see a stale lock from this run. The lock-release is a single `rm -f "$LOCK"` per halt site.
113
+
81
114
  ### 5. Ask for New Name
82
115
 
83
116
  "**What is the new name for this skill?**
84
- The new name must be kebab-case: lowercase alphanumeric with hyphens, 1-64 characters, matching the regex `^[a-z][a-z0-9-]*[a-z0-9]$` (single-character names may be a single lowercase letter or digit)."
117
+ The new name must be kebab-case: lowercase alphanumeric with hyphens, 1-64 characters, matching the regex `^[a-z][a-z0-9-]*[a-z0-9]$` (single-character names may be a single lowercase letter or digit). Or type `cancel` / `exit` / `:q` to abort."
85
118
 
86
- Wait for user input. Trim whitespace. **GATE [default: use args]** — If `{headless_mode}` and new_name was provided as argument: use it and auto-proceed through validation. If not provided, HALT: "headless mode requires new_name argument."
119
+ Wait for user input. Trim whitespace. **GATE [default: use args]** — If `{headless_mode}` and new_name was provided as argument: use it and auto-proceed through validation. If not provided, release the lock and HALT (exit code 2, `halt_reason: "input-missing"`): "headless mode requires new_name argument." In headless, emit the error envelope.
120
+
121
+ - If the user enters `cancel`, `exit`, `[X]`, `q`, or `:q`: release the lock (`rm -f {forge_data_folder}/{old_name}/.skf-rename.lock`), display "Cancelled — no changes were made.", and HALT (exit code 6, `halt_reason: "user-cancelled"`).
87
122
 
88
123
  Apply the following validations in order:
89
124
 
@@ -106,7 +141,7 @@ Apply the following validations in order:
106
141
 
107
142
  If any collision is detected:
108
143
  "**Name collision.** `{new-name}` already exists at: {list the colliding locations}. Pick a different name."
109
- Re-ask.
144
+ Re-ask. In headless mode, instead of re-asking, release the lock and HALT (exit code 5, `halt_reason: "name-collision"`) and emit the error envelope.
110
145
 
111
146
  Only after all four validations pass, store the input as `new_name`.
112
147
 
@@ -129,11 +164,13 @@ registry will still get the original name. Rename is a LOCAL operation only —
129
164
  does not rename anything at the registry.
130
165
  ```
131
166
 
132
- Ask: "**Continue anyway?** [Y/N]"
167
+ Ask: "**Continue anyway?** [Y/N] (or `cancel` / `exit` / `:q` to abort)"
133
168
 
134
169
  Wait for response.
135
- - **If `N`** or anything other than `Y` → "**Cancelled.** No changes were made." HALT the workflow.
136
- - **If `Y`** → proceed.
170
+ - **If `N`** (or `cancel` / `exit` / `[X]` / `:q`) release the lock (`rm -f {forge_data_folder}/{old_name}/.skf-rename.lock`), display "**Cancelled.** No changes were made.", HALT (exit code 6, `halt_reason: "user-cancelled"`).
171
+ - **If `Y`** → proceed. Set `source_authority_override = true`.
172
+
173
+ **Headless behavior:** If `{headless_mode}` is true AND `{forceSourceAuthorityInHeadless}` is `"true"`, auto-proceed and record `{gate: "source-authority", default_action: "halt", taken_action: "proceed", reason: "force_source_authority_in_headless override"}` in `headless_decisions[]`. Otherwise, release the lock and HALT (exit code 5, `halt_reason: "source-authority-blocked"`) and emit the error envelope — the safe default protects against silent registry-divergence on `published`-tagged skills.
137
174
 
138
175
  **If `source_authority` is absent, or any value other than `"official"`:** skip the warning and proceed.
139
176
 
@@ -192,13 +229,15 @@ Proceed? [Y/N]
192
229
 
193
230
  Wait for explicit user response.
194
231
 
232
+ **If `--dry-run` was passed**: skip the Y/N prompt entirely. Release the lock (`rm -f {forge_data_folder}/{old_name}/.skf-rename.lock`), display "**[DRY RUN] No changes were made — preview above shows what would be renamed.**", and emit the success envelope per SKILL.md "Result Contract (Headless)" with `status: "dry-run"`, the resolved `old_name`, `new_name`, and `versions_renamed: {affected_versions}`, then HALT (exit code 0). No copy, no manifest re-key, no delete.
233
+
195
234
  - **If `Y`** → proceed to section 9
196
- - **If `N`** → "**Cancelled.** No changes were made." HALT the workflow
235
+ - **If `N`** (or `cancel` / `exit` / `[X]` / `:q`) release the lock (`rm -f {forge_data_folder}/{old_name}/.skf-rename.lock`), display "**Cancelled.** No changes were made.", HALT (exit code 6, `halt_reason: "user-cancelled"`). In headless mode, emit the error envelope per SKILL.md "Result Contract (Headless)" with the resolved `old_name` and `new_name`.
197
236
  - **Any other input** → re-display the confirmation and ask again
198
237
 
199
238
  ### 9. Store Decisions in Context
200
239
 
201
- Store the following decisions in workflow context for step-02:
240
+ Store the following decisions in workflow context for step 2:
202
241
 
203
242
  - `old_name` — the current skill name
204
243
  - `new_name` — the validated new name
@@ -1,13 +1,21 @@
1
1
  ---
2
2
  name: skf-setup
3
- description: Initialize forge environment, detect tools, and set capability tier (Quick/Forge/Forge+/Deep). Use when the user requests to "set up" or "initialize the forge."
3
+ description: Initialize forge environment, detect tools, and set capability tier (Quick/Forge/Forge+/Deep). Use when the user requests to "set up" or "initialize the forge".
4
4
  ---
5
5
 
6
6
  # Setup Forge
7
7
 
8
8
  ## Overview
9
9
 
10
- Initializes the forge environment by detecting available tools, determining the capability tier (Quick/Forge/Forge+/Deep), and writing persistent configuration to `{project-root}/_bmad/_memory/forger-sidecar/`. When `ccc` (cocoindex-code) is available, also augments `.cocoindex_code/settings.yml` with SKF exclusion patterns and creates or refreshes the project's semantic-search index. On Deep tier, reconciles the QMD collection registry; whenever ccc is available, reconciles the CCC index registry as well. The workflow is autonomous with one optional gate — orphaned QMD collection removal in step 3 (Deep tier only; default action: Keep) — which auto-resolves to the default when `{headless_mode}` is true.
10
+ Initializes the forge environment by detecting available tools, determining the capability tier (Quick/Forge/Forge+/Deep), and writing persistent configuration to `{project-root}/_bmad/_memory/forger-sidecar/`. When `ccc` (cocoindex-code) is available, also augments `.cocoindex_code/settings.yml` with SKF exclusion patterns and creates or refreshes the project's semantic-search index. On Deep tier, reconciles the QMD collection registry; whenever ccc is available, reconciles the CCC index registry as well. The workflow is autonomous with one optional gate — orphaned QMD collection removal in step 3 (Deep tier only; default action: Keep) — which auto-resolves non-interactively when `{headless_mode}` is true or when `--orphan-action=<keep|remove>` is passed.
11
+
12
+ ## Conventions
13
+
14
+ - Bare paths (e.g. `references/<name>.md`) resolve from the skill root.
15
+ - `references/` holds prompt content carved out of SKILL.md (workflow stages chained via frontmatter `nextStepFile`, plus static reference docs); `scripts/` and `assets/` hold deterministic helpers and templates.
16
+ - `{skill-root}` resolves to this skill's installed directory (where `customize.toml` lives, if present).
17
+ - `{project-root}`-prefixed paths resolve from the project working directory.
18
+ - `{skill-name}` resolves to the skill directory's basename.
11
19
 
12
20
  ## Role
13
21
 
@@ -15,56 +23,48 @@ You are a system executor performing environment resolution. Run each step in se
15
23
 
16
24
  ## Workflow Rules
17
25
 
18
- These rules apply to every step in this workflow:
19
-
20
- - Autonomous with one optional gate (step 3 orphan-removal prompt; default: Keep) — all other steps auto-proceed with no user interaction until the final report
21
- - Read each step file completely before taking any action
22
- - Follow the mandatory sequence in each step exactly — do not skip, reorder, or optimize
23
- - Only load one step file at a time — never preload future steps
24
- - Always communicate in `{communication_language}`
25
- - If `{headless_mode}` is true, auto-proceed through confirmation gates with their default action and log each auto-decision
26
+ - One optional gate (step 3 orphan-removal prompt; default: Keep). Every other step auto-proceeds.
27
+ - Only load one step file at a time — never preload future steps.
28
+ - Communicate in `{communication_language}`.
29
+ - If `{headless_mode}` is true, or if `{orphan_action}` is non-null, auto-resolve the gate non-interactively and log the decision.
26
30
 
27
31
  ## Stages
28
32
 
29
- | # | Step | File | Auto-proceed |
30
- |---|------|------|--------------|
31
- | 1 | Detect Tools & Set Tier | steps-c/step-01-detect-and-tier.md | Yes |
32
- | 1b | CCC Index (only when ccc is available) | steps-c/step-01b-ccc-index.md | Yes |
33
- | 2 | Write Config | steps-c/step-02-write-config.md | Yes |
34
- | 3 | QMD + CCC Registry Hygiene | steps-c/step-03-auto-index.md | Yes |
35
- | 4 | Report | steps-c/step-04-report.md | Yes |
36
- | 5 | Workflow Health Check | steps-c/step-05-health-check.md | Yes |
33
+ All stages auto-proceed except the optional orphan-removal gate in step 3.
34
+
35
+ | # | Step | File |
36
+ |---|------|------|
37
+ | 1 | Detect Tools & Set Tier | references/detect-and-tier.md |
38
+ | 1b | CCC Index (only when ccc is available) | references/ccc-index.md |
39
+ | 2 | Write Config | references/write-config.md |
40
+ | 3 | QMD + CCC Registry Hygiene | references/auto-index.md |
41
+ | 4 | Report | references/report.md |
42
+ | 5 | Workflow Health Check | references/health-check.md |
37
43
 
38
44
  ## Invocation Contract
39
45
 
40
46
  | Aspect | Detail |
41
47
  |--------|--------|
42
48
  | **Inputs** | (none) |
43
- | **Flags** | `--headless` / `-H` (skip prompts, auto-resolve gates to defaults); `--require-tier=<Quick\|Forge\|Forge+\|Deep>` (halt with failure if calculated tier does not satisfy the requirement) |
44
- | **Gates** | One optional: orphaned QMD collection removal (step 3, Deep tier only; default: Keep) |
49
+ | **Flags** | `--headless` / `-H` (skip prompts, auto-resolve gates to defaults); `--require-tier=<Quick\|Forge\|Forge+\|Deep>` (halt with failure if calculated tier does not satisfy the requirement); `--orphan-action=<keep\|remove>` (resolve the orphan-removal gate non-interactively, even outside `--headless`); `--ccc-skip-index` (skip CCC indexing; envelope `ccc_index.status` becomes `"skipped"`); `--quiet` (suppress the human-readable FORGE STATUS banner — pipelines and expert re-runners get the envelope only) |
50
+ | **Gates** | One optional: orphaned QMD collection removal (step 3, Deep tier only; default: Keep, or whatever `--orphan-action` set) |
45
51
  | **Outputs** | `forger-sidecar/forge-tier.yaml`, `forger-sidecar/preferences.yaml`, `{forge_data_folder}/`; when ccc is available, `.cocoindex_code/settings.yml` (exclusion patterns merged) and the project ccc index |
46
- | **Headless** | All gates auto-resolve with default action when `{headless_mode}` is true. step-04 emits a single-line `SKF_SETUP_RESULT_JSON: {…}` envelope after the human-readable banner so pipelines can parse the outcome without reading forge-tier.yaml. Schema documented in `steps-c/step-04-report.md` §4. |
47
- | **Failure modes** | `--require-tier` not satisfied → step-04 prints a "REQUIRED TIER NOT MET" block, the JSON envelope sets `"require_tier_satisfied": false`, and the workflow halts before step-05. |
52
+ | **Headless** | All gates auto-resolve with default action when `{headless_mode}` is true. Under `--headless` or `--quiet`, step 4 emits a single-line `SKF_SETUP_RESULT_JSON: {…}` envelope as the only stdout line — the FORGE STATUS banner is suppressed. Branch on the envelope's top-level `status` field (one of `success`, `tier_failure`, `write_failure`, `blocked`) — `skf-emit-result-envelope.py` derives it from the payload, so pipelines never compose it from `require_tier_satisfied` + `error`. Schema in `references/report.md` §4. |
53
+ | **Failure modes** | `--require-tier` not satisfied → status becomes `tier_failure`, the envelope sets `"require_tier_satisfied": false`, and the workflow halts before step 5 (interactive runs also print a "REQUIRED TIER NOT MET" block). |
48
54
  | **Exit codes** | The workflow runs as an LLM-driven sequence rather than a CLI process, so "exit code" describes the agent's terminal state for a calling pipeline that reads `SKF_SETUP_RESULT_JSON`. **0 — success** (no JSON `error` field, all writes completed, `require_tier_satisfied` is `true` or `null`). **1 — required-tier failure** (`require_tier_satisfied` is `false`; envelope still emitted with full state for diagnosis). **2 — write failure** (forge-tier.yaml or preferences.yaml could not be written; envelope `error` field names the path and reason). Pipelines should branch on the JSON `require_tier_satisfied` and `error` fields rather than process exit codes. |
49
55
 
50
56
  ## On Activation
51
57
 
52
- 1. **Probe `uv` runtime.** Run `uv --version`. Every step in this workflow invokes shared Python helpers via `uv run` (PEP 723 inline metadata is what auto-resolves `pyyaml` for the helpers that need it see `docs/getting-started.md`). If `uv` is missing, halt now with a single cohesive diagnostic rather than letting five separate steps each fail with `uv: command not found`:
53
-
54
- "**Setup cannot proceed: `uv` is not installed.** SKF helpers depend on `uv` to auto-resolve their Python dependencies. Install it from <https://docs.astral.sh/uv/getting-started/installation/> and re-run `/skf-setup`. (See the Prerequisites section in <https://docs.astral.sh/uv/getting-started/installation/> or the SKF docs at `docs/getting-started.md` for details.)"
55
-
56
- 2. Load config from `{project-root}/_bmad/skf/config.yaml` and resolve:
57
- - `project_name` (from installer-generated config.yaml, not module.yaml), `output_folder`, `user_name`, `communication_language`, `document_output_language`
58
- - `skills_output_folder`, `forge_data_folder`, `sidecar_path`
58
+ > **Halt contract for headless/quiet runs.** Any halt below MUST first emit a blocked envelope when `{headless_mode}` or `{quiet_mode}` is true, before printing the human diagnostic. Pipe `{"phase":"<phase>","reason":"<reason>","path":"<path>"}` to `python3 <helper> emit-blocked` where `<helper>` is the first existing path of `{project-root}/_bmad/skf/shared/scripts/skf-emit-result-envelope.py` then `{project-root}/src/shared/scripts/skf-emit-result-envelope.py`. The `emit-blocked` subcommand declares zero dependencies (no `uv`, no `pyyaml`), so it works even when `uv` itself is the thing that's missing.
59
59
 
60
- **If the file does not exist**, halt with a single cohesive "wrong directory" diagnostic rather than failing later with a generic file-read error from a downstream step:
60
+ 1. **Parse invocation flags FIRST** (so every halt below knows whether to emit an envelope): `{headless_mode}` (true on `--headless` / `-H`), `{require_tier}` (`--require-tier=<Quick|Forge|Forge+|Deep>`, case-sensitive; null if absent or unparseable), `{orphan_action}` (`--orphan-action=<keep|remove>`; null if absent), `{ccc_skip_index}` (true on `--ccc-skip-index`), `{quiet_mode}` (true on `--quiet`).
61
61
 
62
- "**Setup cannot proceed: `{project-root}/_bmad/skf/config.yaml` was not found.** This directory does not appear to be an SKF-initialised project. From the project root, run `npx bmad-module-skill-forge install` (or `npx bmad-method install` and add SKF as a custom module — see `docs/getting-started.md`), then re-run `/skf-setup`. If you ARE in the right project but the file was deleted, restore it from version control or re-run the SKF installer."
62
+ 2. **Probe `uv` runtime.** Run `uv --version`. Every step invokes shared Python helpers via `uv run` (PEP 723 inline metadata auto-resolves `pyyaml`). If `uv` is missing, halt with phase `on-activation:uv-missing` and the human diagnostic:
63
63
 
64
- **If the file exists but is malformed YAML**, halt and surface the parser error along with the file path so the user can fix it directly: "**Setup cannot proceed: `{project-root}/_bmad/skf/config.yaml` is not valid YAML.** Parser error: {error_message}. Open the file and repair the YAML, or restore from version control."
64
+ "**Setup cannot proceed: `uv` is not installed.** SKF helpers depend on `uv` to auto-resolve their Python dependencies. Install it from <https://docs.astral.sh/uv/getting-started/installation/> and re-run `/skf-setup`."
65
65
 
66
- 3. **Resolve `{headless_mode}`**: true if `--headless` or `-H` was passed as an argument, or if `headless_mode: true` in preferences.yaml. Default: false.
66
+ 3. **Load config** from `{project-root}/_bmad/skf/config.yaml` and resolve `project_name`, `output_folder`, `user_name`, `communication_language`, `document_output_language`, `skills_output_folder`, `forge_data_folder`, `sidecar_path`. Halt with phase `on-activation:config-missing` if the file does not exist, or `on-activation:config-malformed` if the YAML is invalid, with the matching human diagnostic.
67
67
 
68
- 4. **Resolve `{require_tier}`**: parse `--require-tier=<value>` from the invocation arguments. Accept exactly `Quick`, `Forge`, `Forge+`, or `Deep` (case-sensitive). If absent or unparseable, leave as null (no tier requirement).
68
+ 4. **Reconcile `{headless_mode}`** with `preferences.yaml`: OR the parsed flag with `headless_mode: true` from the YAML.
69
69
 
70
- 5. Load, read the full file, and then execute `./steps-c/step-01-detect-and-tier.md` to begin the workflow.
70
+ 5. Execute `references/detect-and-tier.md`.
@@ -0,0 +1,33 @@
1
+ # DO NOT EDIT -- overwritten on every update.
2
+ #
3
+ # Workflow customization surface for skf-setup.
4
+
5
+ [workflow]
6
+
7
+ # --- Configurable below. Overrides merge per BMad structural rules: ---
8
+ # scalars: override wins • arrays (persistent_facts, activation_steps_*): append
9
+ # arrays-of-tables with `code`/`id`: replace matching items, append new ones.
10
+
11
+ # Steps to run before the standard activation (uv probe, config load).
12
+ # Overrides append. Use for org-wide pre-flight checks (auth, network,
13
+ # compliance) that must precede any forge setup work.
14
+
15
+ activation_steps_prepend = []
16
+
17
+ # Steps to run after activation but before the first stage executes.
18
+ # Overrides append. Use for context loads or banner customization that
19
+ # should run once activation completes successfully.
20
+
21
+ activation_steps_append = []
22
+
23
+ # Persistent facts the workflow keeps in mind for the whole run
24
+ # (standards, compliance constraints, stylistic guardrails). Overrides
25
+ # append.
26
+ #
27
+ # Each entry is either:
28
+ # - a literal sentence, e.g. "Forge writes must be reproducible in CI."
29
+ # - a file reference prefixed with `file:`, e.g.
30
+ # "file:{project-root}/docs/forge-policy.md" (globs supported; file
31
+ # contents are loaded and treated as facts).
32
+
33
+ persistent_facts = []
@@ -1,5 +1,5 @@
1
1
  ---
2
- nextStepFile: './step-04-report.md'
2
+ nextStepFile: 'report.md'
3
3
  # Resolve `{qmdClassifyHelper}` and `{forgeTierRwHelper}` by probing the
4
4
  # corresponding `*ProbeOrder` arrays (installed SKF module path first, src/
5
5
  # dev-checkout fallback); first existing path wins. HALT if neither resolves
@@ -35,7 +35,7 @@ For Quick and Forge tiers, skip silently and proceed (QMD is not available; ccc
35
35
 
36
36
  ### 1. Check Tier
37
37
 
38
- Read `{calculated_tier}` and `{ccc}` from context (set by step-01).
38
+ Read `{calculated_tier}` and `{ccc}` from context (set by step 1).
39
39
 
40
40
  **If `{calculated_tier}` is Quick or Forge AND `{ccc}` is false:** No registry hygiene needed. Set `{hygiene_result: "skipped", hygiene_healthy: 0, hygiene_orphaned_removed: 0, hygiene_orphaned_kept: 0, hygiene_stale_cleaned: 0, ccc_registry_stale_cleaned: 0, ccc_registry_stale_removed_paths: []}`. Proceed directly to section 5 (Auto-Proceed) — no output, no messaging.
41
41
 
@@ -47,31 +47,23 @@ Read `{calculated_tier}` and `{ccc}` from context (set by step-01).
47
47
 
48
48
  ### 2. Classify Live QMD Collections vs Registry
49
49
 
50
- List live QMD collections:
51
-
52
- ```bash
53
- qmd collection list
54
- ```
55
-
56
- Parse the output into a comma-separated string of collection names and store as `{live_collections}` (raw — including any foreign collections owned by other tools sharing the QMD daemon; the classifier filters them out).
57
-
58
- **Error handling:** If `qmd collection list` fails (daemon down, daemon errors), set `{hygiene_result: "qmd_unavailable", hygiene_healthy: 0, hygiene_orphaned_removed: 0, hygiene_orphaned_kept: 0, hygiene_stale_cleaned: 0}`, log the error, and skip directly to section 4 (which will still run the ccc-prune branch if `{ccc}` is true).
59
-
60
- Run the classifier. Invoke via `uv run` so the script's PEP 723 PyYAML dependency resolves automatically (`docs/getting-started.md` documents uv as the runtime prereq for exactly this); bare `python3` would `ModuleNotFoundError` on a fresh interpreter.
50
+ Run the classifier — it owns the `qmd collection list` invocation and stdout parsing. Invoke via `uv run`:
61
51
 
62
52
  ```bash
63
53
  uv run {qmdClassifyHelper} \
64
- --live-names "{live_collections}" \
65
54
  --registry-from-yaml "{project-root}/_bmad/_memory/forger-sidecar/forge-tier.yaml"
66
55
  ```
67
56
 
68
- The script (see `src/shared/scripts/skf-qmd-classify-collections.py` docstring for the full schema) applies the forge-namespace suffix filter (`-brief | -temporal | -docs | -extraction`) to `{live_collections}` before classifying collections owned by unrelated tools are silently excluded from the orphan / healthy / stale sets and counted under `foreign_filtered_count` for telemetry only. This is the PR #244 incident protection: collections like Hindsight memory banks that happen to live in the same QMD daemon never enter any classification that could lead to data loss.
57
+ The script (see `src/shared/scripts/skf-qmd-classify-collections.py` docstring for the full schema) invokes `qmd collection list` itself, applies the forge-namespace suffix filter (`-brief | -temporal | -docs | -extraction`) before classifying, and exits non-zero with an error message on stderr if the daemon is down. Collections owned by unrelated tools are silently excluded from the orphan / healthy / stale sets and counted under `foreign_filtered_count` for telemetry only. This is the PR #244 incident protection: foreign collections never enter any classification that could lead to data loss.
58
+
59
+ **Error handling:** If the script exits non-zero, set `{hygiene_result: "qmd_unavailable", hygiene_healthy: 0, hygiene_orphaned_removed: 0, hygiene_orphaned_kept: 0, hygiene_stale_cleaned: 0}` and skip directly to section 4 (which will still run the ccc-prune branch if `{ccc}` is true).
69
60
 
70
61
  **Parse the JSON output and set context flags:**
71
62
 
72
63
  - `{hygiene_healthy}` ← `len(healthy)`
73
64
  - `{orphaned_collections}` ← `orphaned` (the list — used in section 3)
74
65
  - `{stale_collections}` ← `stale` (the list — used in section 4)
66
+ - `{live_collections}` ← comma-join of `live_names` (used in §4's clean-stale invocation; the script owns the raw set, the prompt only forwards it)
75
67
  - `{foreign_filtered_count}` ← `foreign_filtered_count`
76
68
 
77
69
  Set `{hygiene_result: "completed"}`.
@@ -80,7 +72,7 @@ Set `{hygiene_result: "completed"}`.
80
72
 
81
73
  **If `{orphaned_collections}` is empty:** Set `{hygiene_orphaned_removed: 0, hygiene_orphaned_kept: 0}` and skip to section 4.
82
74
 
83
- **Headless gate.** If `{headless_mode}` is true, auto-resolve to the default action **Keep** without prompting: log `"Auto-decision (headless): kept {len(orphaned_collections)} orphaned forge collection(s)"`, set `{hygiene_orphaned_removed: 0, hygiene_orphaned_kept: len(orphaned_collections)}`, and skip to section 4. This matches the workflow contract (`Headless: All gates auto-resolve with default action when {headless_mode} is true`) declared in the Invocation Contract.
75
+ **Non-interactive resolution.** If `{orphan_action}` is non-null, resolve the gate without prompting using that value: log `"Auto-decision (--orphan-action={value}): kept|removed {len(orphaned_collections)} orphaned forge collection(s)"`. If `{orphan_action}` is `"keep"`, set `{hygiene_orphaned_removed: 0, hygiene_orphaned_kept: len(orphaned_collections)}` and skip to section 4. If `"remove"`, fall through to the removal block below (still no user prompt). Independently, if `{headless_mode}` is true and `{orphan_action}` is null, auto-resolve to the default **Keep** with the equivalent log line and skip to section 4. The two paths compose: `--orphan-action` overrides the headless default; `--headless` without `--orphan-action` keeps backward-compatible behavior.
84
76
 
85
77
  **If `{headless_mode}` is false**, display to the user:
86
78
 
@@ -118,11 +110,11 @@ uv run {forgeTierRwHelper} clean-stale \
118
110
 
119
111
  The script reads the registry, computes set-difference operations (qmd: registry − live; ccc: filter where `path` does not exist on disk), and atomically rewrites forge-tier.yaml only when something actually changed (mtime preserved on idempotent re-runs). The CI ephemeral-mount caveat for ccc-registry pruning is logged in the script's WARNING message (per PR #248).
120
112
 
121
- **Parse the JSON output and set context flags for step-04:**
113
+ **Parse the JSON output and set context flags for step 4:**
122
114
 
123
115
  - `{hygiene_stale_cleaned}` ← `len(qmd_removed)`
124
116
  - `{ccc_registry_stale_cleaned}` ← `len(ccc_removed)`
125
- - `{ccc_registry_stale_removed_paths}` ← `ccc_removed` (the list — step-04 folds individual paths into envelope warnings)
117
+ - `{ccc_registry_stale_removed_paths}` ← `ccc_removed` (the list — step 4 folds individual paths into envelope warnings)
126
118
 
127
119
  If `{hygiene_stale_cleaned}` > 0, display: "**Cleaned {hygiene_stale_cleaned} stale QMD registry entry/entries** (collection no longer exists in QMD)."
128
120