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
@@ -24,11 +24,28 @@ updateActiveSymlinkProbeOrder:
24
24
  manifestOpsProbeOrder:
25
25
  - '{project-root}/_bmad/skf/shared/scripts/skf-manifest-ops.py'
26
26
  - '{project-root}/src/shared/scripts/skf-manifest-ops.py'
27
- # Resolve `{rebuildManagedSectionsHelper}` similarly. §7.7 uses the
27
+ # Resolve `{rebuildManagedSectionsHelper}` similarly. §7 uses the
28
28
  # `replace` action for the surgical between-marker rewrite.
29
29
  rebuildManagedSectionsProbeOrder:
30
30
  - '{project-root}/_bmad/skf/shared/scripts/skf-rebuild-managed-sections.py'
31
31
  - '{project-root}/src/shared/scripts/skf-rebuild-managed-sections.py'
32
+ # Resolve `{rewriteSkillNameHelper}` similarly. §3 uses it for the four
33
+ # field-scoped in-file rename transforms (SKILL.md frontmatter `name`,
34
+ # metadata.json `name`, provenance-map.json `skill_name`, context-snippet
35
+ # header + `root:` paths) — each a JSON round-trip or anchored-region edit
36
+ # plus the atomic write in one call, so the LLM never hand-edits JSON (which
37
+ # risks key reorder/drop) or eyeballs "only within the frontmatter" (which
38
+ # mis-fires when {old_name} is a substring, e.g. rename -> renamer).
39
+ rewriteSkillNameProbeOrder:
40
+ - '{project-root}/_bmad/skf/shared/scripts/skf-rewrite-skill-name.py'
41
+ - '{project-root}/src/shared/scripts/skf-rewrite-skill-name.py'
42
+ # Resolve `{verifyNoTraceHelper}` similarly. §5 uses it for the commit-point
43
+ # no-trace gate: a fixed-file-set, name-token scan over affected_versions with
44
+ # the SKILL.md frontmatter/body region split (frontmatter = hard failure, body
45
+ # = advisory warning) and the directory-listing check, returned as JSON.
46
+ verifyNoTraceProbeOrder:
47
+ - '{project-root}/_bmad/skf/shared/scripts/skf-verify-no-trace.py'
48
+ - '{project-root}/src/shared/scripts/skf-verify-no-trace.py'
32
49
  ---
33
50
 
34
51
  <!-- Config: communicate in {communication_language}. -->
@@ -47,9 +64,17 @@ Execute the rename decisions recorded in step 1 as a transaction. Copy the old `
47
64
  - Do not proceed past a verification failure in section 5
48
65
  - Report each section's outcome as it completes
49
66
 
67
+ **Headless error envelope (self-contained).** Every HALT below that says *"emit the error envelope"* means: write this single line to **stderr**, mirroring SKILL.md's Result Contract (Headless) so this stage stays parseable even if SKILL.md is out of context on a `nextStepFile` chain —
68
+
69
+ ```
70
+ SKF_RENAME_SKILL_RESULT_JSON: {"status":"error","old_name":"{old_name}","new_name":"{new_name}","versions_renamed":[],"manifest_rekeyed":false,"context_files_updated":[],"exit_code":<code>,"halt_reason":"<reason>","headless_decisions":{headless_decisions}}
71
+ ```
72
+
73
+ Set `exit_code` and `halt_reason` to the values named at that HALT site (see `references/exit-codes.md`); `old_name`/`new_name` are both resolved by step 1 before this stage runs. `{headless_decisions}` is the audit trail carried from step 1 (the §6 source-authority override if it fired; `[]` otherwise) — emit it verbatim so a halt in this stage still preserves the decision trail.
74
+
50
75
  ## MANDATORY SEQUENCE
51
76
 
52
- **CRITICAL:** This is transactional. After section 1 (copy), the old skill is untouched. If any section between 2 and 7 fails, delete `{new_skill_group}` and `{new_forge_group}`, report the failure, and halt the old skill remains intact. Only section 8 (delete old) makes the operation irreversible. Do not skip, reorder, or improvise.
77
+ **Transactional boundary.** After section 1 (copy), the old skill is untouched; a failure in any of sections 2-7 deletes the two new directories (`{new_skill_group}`, `{new_forge_group}`), reports, and halts with the old skill intact. Section 8 (delete old) is the only irreversible point.
53
78
 
54
79
  ### 0. Re-read Version-Paths Knowledge + Resolve Helpers
55
80
 
@@ -57,12 +82,14 @@ Read `{versionPathsKnowledge}` again and confirm the templates (`{skill_package}
57
82
 
58
83
  **Resolve helpers** in parallel — these are independent file-existence checks that batch into one tool-call message:
59
84
 
60
- - `{atomicWriteHelper}` ← first existing path in `{atomicWriteProbeOrder}` (used in §3, §6 for crash-safe writes)
85
+ - `{atomicWriteHelper}` ← first existing path in `{atomicWriteProbeOrder}` (used in §6 for crash-safe manifest restore)
86
+ - `{rewriteSkillNameHelper}` ← first existing path in `{rewriteSkillNameProbeOrder}` (used in §3 for the field-scoped in-file rename transforms + atomic write)
61
87
  - `{updateActiveSymlinkHelper}` ← first existing path in `{updateActiveSymlinkProbeOrder}` (used in §4 for atomic symlink repair)
88
+ - `{verifyNoTraceHelper}` ← first existing path in `{verifyNoTraceProbeOrder}` (used in §5 for the deterministic no-trace commit gate)
62
89
  - `{manifestOpsHelper}` ← first existing path in `{manifestOpsProbeOrder}` (used in §6 for the manifest re-key)
63
- - `{rebuildManagedSectionsHelper}` ← first existing path in `{rebuildManagedSectionsProbeOrder}` (used in §7.7 for between-marker swap)
90
+ - `{rebuildManagedSectionsHelper}` ← first existing path in `{rebuildManagedSectionsProbeOrder}` (used in §7 for between-marker swap)
64
91
 
65
- If any helper has no existing candidate, release the lock and HALT (exit code 4, `halt_reason: "write-failed"`) — the rename's safety guarantees depend on these helpers and a fall-through to LLM-driven writes would silently regress atomicity.
92
+ If any helper has no existing candidate, release the lock and HALT (exit code 4, `halt_reason: "write-failed"`) — the rename's safety guarantees depend on these helpers, and a fall-through to LLM-driven writes/scans would silently regress atomicity (the write helpers) or the deterministic transform and commit-gate checks (`{rewriteSkillNameHelper}`, `{verifyNoTraceHelper}`).
66
93
 
67
94
  **Lock release contract:** every halt path in this step ends with `rm -f "{forge_data_folder}/{old_name}/.skf-rename.lock"` before exiting. The terminal health-check (step 4) is the success-path release.
68
95
 
@@ -70,15 +97,15 @@ If any helper has no existing candidate, release the lock and HALT (exit code 4,
70
97
 
71
98
  **Precondition:** Both `{new_skill_group}` and `{new_forge_group}` must NOT exist (step 1 validated this in the collision check, but verify again before copying).
72
99
 
73
- 1. If `{new_skill_group}` or `{new_forge_group}` exists on disk, halt with: "**Collision detected at execution time.** `{new_skill_group}` or `{new_forge_group}` now exists on disk — it did not exist during step 1 selection. Aborting before any files are touched."
100
+ 1. If `{new_skill_group}` or `{new_forge_group}` exists on disk: release the lock (`rm -f "{forge_data_folder}/{old_name}/.skf-rename.lock"`) and halt with "**Collision detected at execution time.** `{new_skill_group}` or `{new_forge_group}` now exists on disk — it did not exist during step 1 selection. Aborting before any files are touched." HALT (exit code 4, `halt_reason: "copy-failed"`). In headless, emit the error envelope.
74
101
 
75
102
  2. Copy `{old_skill_group}` to `{new_skill_group}` recursively:
76
103
  - Preserve file permissions, timestamps, and symlinks
77
104
  - Equivalent to `cp -a {old_skill_group} {new_skill_group}` (preserves symlinks) or `cp -r` followed by explicit symlink re-creation in section 4
78
- - If the copy fails: halt with "**Copy failed:** `{old_skill_group}` → `{new_skill_group}`: {error}. No files were modified. Old skill is intact."
105
+ - If the copy fails: release the lock (`rm -f "{forge_data_folder}/{old_name}/.skf-rename.lock"`) and halt with "**Copy failed:** `{old_skill_group}` → `{new_skill_group}`: {error}. No files were modified. Old skill is intact." HALT (exit code 4, `halt_reason: "copy-failed"`). In headless, emit the error envelope.
79
106
 
80
107
  3. Copy `{old_forge_group}` to `{new_forge_group}` the same way:
81
- - If the copy fails: **rollback** by deleting `{new_skill_group}` (just created in step 2), then halt with "**Copy failed:** `{old_forge_group}` → `{new_forge_group}`: {error}. Rolled back new skill_group. Old skill is intact."
108
+ - If the copy fails: **rollback** by deleting `{new_skill_group}` (just created in step 2), release the lock (`rm -f "{forge_data_folder}/{old_name}/.skf-rename.lock"`), then halt with "**Copy failed:** `{old_forge_group}` → `{new_forge_group}`: {error}. Rolled back new skill_group. Old skill is intact." HALT (exit code 4, `halt_reason: "copy-failed"`). In headless, emit the error envelope.
82
109
 
83
110
  **Rollback procedure for this section:** `rm -rf {new_skill_group}` and `rm -rf {new_forge_group}` (whichever exist). Old skill is untouched.
84
111
 
@@ -96,50 +123,32 @@ For each version `v` in `affected_versions`:
96
123
  **Rollback on any rename failure:**
97
124
 
98
125
  - `rm -rf {new_skill_group}` and `rm -rf {new_forge_group}`
99
- - Halt with: "**Inner directory rename failed** at `{v}/{old_name}`: {error}. Rolled back both new directories. Old skill is intact."
126
+ - Release the lock: `rm -f "{forge_data_folder}/{old_name}/.skf-rename.lock"`
127
+ - Halt with: "**Inner directory rename failed** at `{v}/{old_name}`: {error}. Rolled back both new directories. Old skill is intact." HALT (exit code 4, `halt_reason: "write-failed"`). In headless, emit the error envelope.
100
128
 
101
129
  Report: "**Renamed {count} inner directories** to `{new_name}/`."
102
130
 
103
131
  ### 3. Update File Contents Inside the New Location
104
132
 
105
- For each version `v` in `affected_versions`, operate on the files inside `{new_skill_group}/{v}/{new_name}/` (the freshly renamed inner directory) and `{new_forge_group}/{v}/`:
133
+ For each version `v` in `affected_versions`, operate on the files inside `{new_skill_group}/{v}/{new_name}/` (the freshly renamed inner directory) and `{new_forge_group}/{v}/`.
106
134
 
107
- **Write semantics (apply to 3a / 3b / 3c / 3d):** Compute the new file content in memory (LLM judgment work), then pipe it to `{atomicWriteHelper} write <target>` so the rewrite is staged in `<target>.skf-tmp`, fsync'd, and atomically renamed into place. A process kill or disk-full event mid-rewrite leaves the original file intact no half-written artifacts.
135
+ **Transform semantics (apply to 3a / 3b / 3c / 3d):** `{rewriteSkillNameHelper}` performs each field-scoped substitution AND the crash-safe write (stage to `<target>.skf-tmp`, fsync, atomic rename) in one call do NOT compute file content in the prompt. Each `--kind` edits exactly one field/region and leaves everything else byte-for-byte intact, so there is no key reorder/drop from hand-editing JSON and no wrong-region substitution when `{old_name}` is a substring (e.g. `rename` → `renamer`). Invoke it once per file:
108
136
 
109
137
  ```bash
110
- echo "{new_content}" | python3 {atomicWriteHelper} write "{target_path}"
138
+ python3 {rewriteSkillNameHelper} "{target_path}" \
139
+ --kind {skill-frontmatter|metadata-json|context-snippet|provenance-json} \
140
+ --old-name {old_name} --new-name {new_name}
111
141
  ```
112
142
 
113
- **3a. SKILL.md frontmatter:**
114
-
115
- - Path: `{new_skill_group}/{v}/{new_name}/SKILL.md`
116
- - In the YAML frontmatter (between the leading `---` markers), replace the `name:` field value from `{old_name}` to `{new_name}`
117
- - Only replace within the frontmatter block — do not substitute matches inside the body text
118
- - Pipe via `{atomicWriteHelper} write` per the write semantics above
119
- - If the file is missing, record it in `section3_warnings` and continue
143
+ Read the JSON result (`changed`, `wrote`, and per-kind fields). Exit 0 = processed (written only if the content changed). A non-zero exit — a missing structural region (no frontmatter delimiters), invalid JSON, or a write failure — is a **file update failure**: trigger the rollback below. Check file existence first: if the target file does not exist, skip the invocation and record it in `section3_warnings` per the per-item notes (a missing file is not a failure).
120
144
 
121
- **3b. metadata.json:**
145
+ **3a. SKILL.md frontmatter** — `--kind skill-frontmatter` on `{new_skill_group}/{v}/{new_name}/SKILL.md`. Replaces the top-level `name:` value inside the frontmatter block only (anchored on `^name:`, so a nested `name:` or a longer key like `renamed:` is untouched); body text is preserved verbatim, so a legitimate mention of `{old_name}` below the closing `---` survives. If the file is missing, record it in `section3_warnings` and continue.
122
146
 
123
- - Path: `{new_skill_group}/{v}/{new_name}/metadata.json`
124
- - Parse the JSON, set `name` = `{new_name}`, write back preserving formatting via `{atomicWriteHelper} write`
125
- - If the file is missing, record it in `section3_warnings` and continue
147
+ **3b. metadata.json** — `--kind metadata-json` on `{new_skill_group}/{v}/{new_name}/metadata.json`. Sets `name` = `{new_name}` via a JSON round-trip (key order preserved). If the file is missing, record it in `section3_warnings` and continue.
126
148
 
127
- **3c. context-snippet.md:**
149
+ **3c. context-snippet.md** — `--kind context-snippet` on `{new_skill_group}/{v}/{new_name}/context-snippet.md`. Rewrites the display header `[{old_name} v...]` → `[{new_name} v...]` (version suffix preserved) and every `root:` path: it parses `root: {prefix}{old_name}/`, keeps the prefix verbatim, and swaps the trailing `{old_name}/` segment for `{new_name}/` — handling any IDE prefix (`.claude/skills/`, `.windsurf/skills/`, `.github/skills/`, the draft `skills/` prefix) generically, and flattening the legacy `root: skills/{old_name}/active/{old_name}/` form to `root: skills/{new_name}/`. If the file is missing, record it in `section3_warnings` and continue.
128
150
 
129
- - Path: `{new_skill_group}/{v}/{new_name}/context-snippet.md`
130
- - Replace the display name header `[{old_name} v...]` → `[{new_name} v...]` (preserving the version suffix)
131
- - Rewrite every `root:` path that references the old name to use the new name. Parse the `root:` line as `root: {prefix}{old_name}/`, preserve the prefix as-is, and replace `{old_name}` with `{new_name}`. This generically handles any IDE's skill root path (e.g., `.claude/skills/`, `.windsurf/skills/`, `.github/skills/`) as well as the draft `skills/` prefix and legacy forms — no enumeration of known prefixes needed.
132
- - Example: `root: .windsurf/skills/{old_name}/` → `root: .windsurf/skills/{new_name}/`
133
- - Example: `root: skills/{old_name}/` → `root: skills/{new_name}/`
134
- - Legacy pre-fix form `root: skills/{old_name}/active/{old_name}/` → `root: skills/{new_name}/` (normalize to flat form during rename)
135
- - Pipe via `{atomicWriteHelper} write` per the write semantics above
136
- - If the file is missing, record it in `section3_warnings` and continue
137
-
138
- **3d. provenance-map.json:**
139
-
140
- - Path: `{new_forge_group}/{v}/provenance-map.json`
141
- - Parse JSON, set `skill_name` = `{new_name}`, write back via `{atomicWriteHelper} write`
142
- - If the file is missing (some versions may not have a provenance map), record it in `section3_warnings` and continue
151
+ **3d. provenance-map.json** `--kind provenance-json` on `{new_forge_group}/{v}/provenance-map.json`. Sets `skill_name` = `{new_name}` via a JSON round-trip. If the file is missing (some versions may not have a provenance map), record it in `section3_warnings` and continue.
143
152
 
144
153
  **Rollback on any update failure (not just a missing file):**
145
154
 
@@ -172,26 +181,24 @@ Recreate or repair the `active` symlink in `{new_skill_group}` via `{updateActiv
172
181
 
173
182
  ### 5. Verify — No Trace of `{old_name}` Inside the New Location
174
183
 
175
- This is the commit-point check. If any match is found, the rename is not safe to commit.
176
-
177
- For every version `v` in `affected_versions`, grep (literal substring, case-sensitive) for `{old_name}` in:
178
-
179
- - `{new_skill_group}/{v}/{new_name}/SKILL.md`
180
- - `{new_skill_group}/{v}/{new_name}/metadata.json`
181
- - `{new_skill_group}/{v}/{new_name}/context-snippet.md`
182
- - `{new_forge_group}/{v}/provenance-map.json`
184
+ This is the commit-point check. If any structural reference to `{old_name}` remains, the rename is not safe to commit. `{verifyNoTraceHelper}` performs the whole scan deterministically — a fixed-file-set, name-token scan across every `affected_versions` entry, the SKILL.md frontmatter/body region split, and the directory-listing check — and returns the verdict as JSON. Invoke it once:
183
185
 
184
- Also check the directory listing itself:
186
+ ```bash
187
+ python3 {verifyNoTraceHelper} "{new_skill_group}" \
188
+ --forge-group "{new_forge_group}" \
189
+ --old-name {old_name} --new-name {new_name} \
190
+ --versions {comma-separated affected_versions}
191
+ ```
185
192
 
186
- - `{new_skill_group}/{v}/` should contain `{new_name}/` and MUST NOT contain `{old_name}/`
193
+ Per version `v`, the helper scans `SKILL.md` (frontmatter matches → `hard_matches`; matches in the body below the closing `---` → `body_warnings`), `metadata.json`, `context-snippet.md`, and `provenance-map.json` (any match → `hard_matches`), plus the `{new_skill_group}/{v}/` listing (an `{old_name}/` directory present, or the `{new_name}/` directory missing `dir_violations`). It matches `{old_name}` only as a complete skill-name token — bounded by non-name characters — so a correctly-renamed `{new_name}` that contains `{old_name}` as a substring (e.g. `rename` → `rename-skill`) is never a false leftover, and the frontmatter=hard / body=warning split is applied by region with no meaning-interpretation. A missing file is recorded under `skipped`, not treated as a match. Exit 0 = clean; exit 1 = at least one hard match or dir violation.
187
194
 
188
- **Important nuance:** body text of SKILL.md may legitimately mention the old name (e.g., historical notes, changelog, cross-references). The grep is allowed to match within SKILL.md body text ONLY if the match is clearly informational (surrounding prose, not a structural reference). For the purposes of this step, treat any match in `metadata.json`, `context-snippet.md`, `provenance-map.json`, or the SKILL.md frontmatter block as a hard failure. Matches inside the SKILL.md body below the closing `---` are recorded as `verification_warnings` but do not block the rename.
195
+ Read the JSON and decide:
189
196
 
190
- **On hard failure (any structural reference to `{old_name}` remains):**
191
-
192
- - `rm -rf {new_skill_group}` and `rm -rf {new_forge_group}`
193
- - Release the lock: `rm -f "{forge_data_folder}/{old_name}/.skf-rename.lock"`
194
- - Halt with: "**Verification failed.** `{old_name}` still appears in: {list of paths}. Rolled back both new directories. Old skill is intact." HALT (exit code 5, `halt_reason: "verify-failed"`). In headless, emit the error envelope.
197
+ - **If `clean` is `true` (empty `hard_matches` AND empty `dir_violations`):** the rename is safe to commit. Set `verification_warnings` = the returned `body_warnings` (informational SKILL.md body mentions of `{old_name}` that are retained). Proceed.
198
+ - **If `clean` is `false`:** this is a hard failure —
199
+ - `rm -rf {new_skill_group}` and `rm -rf {new_forge_group}`
200
+ - Release the lock: `rm -f "{forge_data_folder}/{old_name}/.skf-rename.lock"`
201
+ - Halt with: "**Verification failed.** `{old_name}` still appears in: {the files from `hard_matches` plus any `dir_violations`}. Rolled back both new directories. Old skill is intact." HALT (exit code 5, `halt_reason: "verify-failed"`). In headless, emit the error envelope.
195
202
 
196
203
  Report: "**Verified** — no structural references to `{old_name}` remain inside the new location across {affected_versions_count} version(s). {if verification_warnings is non-empty: 'Informational body-text mentions retained in SKILL.md: {list}.'}"
197
204
 
@@ -227,26 +234,65 @@ Report: "**Manifest updated** — re-keyed `exports.{old_name}` → `exports.{ne
227
234
 
228
235
  ### 7. Rebuild Context Files
229
236
 
230
- Load `references/rebuild-context.md` and follow its per-IDE managed-section sweep. The reference resolves `target_context_files` from `config.yaml.ides` (via `{managedSectionLogic}`'s mapping table), iterates each context file, builds the exported skill set (version-aware, deprecated-excluded the manifest re-key from §6 is already in effect so `{new_name}` is present and `{old_name}` is absent), rewrites root paths via the §4d algorithm, assembles the new managed section, and invokes `{rebuildManagedSectionsHelper}` for the surgical between-marker swap.
237
+ After §6 re-keys the manifest from `{old_name}` to `{new_name}`, every IDE's context file (`CLAUDE.md`, `.cursorrules`, `AGENTS.md`, etc.) still carries the old name in its managed-section snippet rows. This section rewrites each one in-place via the surgical between-marker swap so the on-disk managed sections reflect the new name. It runs only on the success path the §4–§6 rollback jumps never reach here.
238
+
239
+ **7a. Resolve `target_context_files`.** Load the `ides` list from `config.yaml`. The installer writes IDE identifiers — map each to a context file and skill root via the "IDE → Context File Mapping" table in `{managedSectionLogic}`:
240
+
241
+ 1. For each entry in `config.yaml.ides`, look up its `context_file` and `skill_root` from the mapping table.
242
+ 2. For any entry not in the table, default to `{unknownIdeDefaultContextFile}` / `{unknownIdeDefaultSkillRoot}` and emit a warning: `Unknown IDE '{value}' in config.yaml — defaulting to {unknownIdeDefaultContextFile}`.
243
+ 3. Deduplicate by `context_file` — when multiple IDEs map to the same context file, use the first configured IDE's `skill_root`.
244
+ 4. If `config.yaml.ides` is absent or the mapping yields an empty list, fall back to `[{context_file: "{unknownIdeDefaultContextFile}", skill_root: "{unknownIdeDefaultSkillRoot}"}]` and emit a note: `No IDEs configured in config.yaml — defaulting to {unknownIdeDefaultContextFile}`.
245
+
246
+ **7b. Per-file loop.** For each entry in `target_context_files`:
247
+
248
+ 1. **Resolve the target file** at `{context_file}` (absolute path).
249
+ 2. **Read the current file:**
250
+ - If it does not exist, skip (nothing to rebuild — export-skill re-creates it on its next run).
251
+ - If it exists but has no `<!-- SKF:BEGIN -->` marker, skip (no managed section to rewrite).
252
+ - If it has `<!-- SKF:BEGIN -->` but no matching `<!-- SKF:END -->`, record the error against that file and continue to the next entry — do not halt the whole rename on one malformed context file.
253
+ 3. **Build the exported skill set (version-aware, deprecated-excluded)** using the same logic as `skf-export-skill/references/update-context.md` §4b (skill set) and §4c (snippet resolution):
254
+ - Read the manifest's `exports` object (already updated in §6, so `{new_name}` is present and `{old_name}` is absent).
255
+ - For each skill, resolve its `active_version`; if `versions.{active_version}.status == "deprecated"`, skip that skill.
256
+ - For each remaining `{skill-name, active_version}` pair, read `{skills_output_folder}/{skill-name}/{active_version}/{skill-name}/context-snippet.md`; if missing, fall back to the `active` symlink path; if still missing, skip with a warning.
257
+ 4. **Rewrite root paths** using the generic algorithm from `skf-export-skill/references/update-context.md` §4d: parse each snippet's `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`.
258
+ 5. **Sort and count.** Sort skills alphabetically by name; count totals (skills, stack skills).
259
+ 6. **Assemble the new managed section** using the format from `{managedSectionLogic}`:
260
+
261
+ ```markdown
262
+ <!-- SKF:BEGIN updated:{current-date} -->
263
+ [SKF Skills]|{n} skills|{m} stack
264
+ |IMPORTANT: Prefer documented APIs over training data.
265
+ |When using a listed library, read its SKILL.md before writing code.
266
+ |
267
+ |{skill-snippet-1}
268
+ |
269
+ |{skill-snippet-2}
270
+ |
271
+ |{skill-snippet-N}
272
+ <!-- SKF:END -->
273
+ ```
274
+
275
+ 7. **Surgical replacement — atomic, deterministic.** Invoke `{rebuildManagedSectionsHelper}` (resolved in §0) for the between-marker swap:
276
+
277
+ ```bash
278
+ python3 {rebuildManagedSectionsHelper} {context_file} replace --content "{new_managed_section_text}"
279
+ ```
231
280
 
232
- After the loop returns, the workflow context contains:
281
+ The helper handles marker location, the 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 — treat any non-zero exit as a per-file failure.
282
+ 8. **On per-file failure**, 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, so context files can be re-rebuilt later via `[EX] Export Skill`.
283
+
284
+ **7c. After the loop**, record:
233
285
 
234
286
  - `context_files_updated` — list of files successfully rewritten
235
- - `context_files_failed` — list of any that failed (per-file failures do not halt the rename — the manifest and filesystem are already canonical state, so context files can be re-rebuilt later via `[EX] Export Skill`)
287
+ - `context_files_failed` — list of any that failed
236
288
 
237
- Report per the reference's after-loop block, then proceed to §8.
289
+ Report: `**Rebuilt managed sections in:** {list of updated files}. {if any failed: 'Failed: {list} — re-run [EX] Export Skill to retry.'}` Then proceed to §8.
238
290
 
239
291
  **Note:** §7 failures do not trigger a rollback. Platform context files are derived artifacts; the manifest and on-disk skill directories are the canonical state.
240
292
 
241
293
  ### 8. Delete Old Directories (Point of No Return)
242
294
 
243
- This is the only section after which rollback is impossible. By this point:
244
-
245
- - `{new_skill_group}` is fully materialized with all inner directories renamed and files updated
246
- - `{new_forge_group}` is fully materialized with `skill_name` updated in every provenance map
247
- - No structural references to `{old_name}` remain inside either new directory (verified in section 5)
248
- - The manifest has been re-keyed (section 6)
249
- - Platform context files reference `{new_name}` (section 7, best-effort)
295
+ This is the only section after which rollback is impossible. Precondition: §1–7 have fully materialized and verified the new name (both new directories renamed, no `{old_name}` references remaining, manifest re-keyed, context files rebuilt best-effort) — only now is deleting the old name safe.
250
296
 
251
297
  Execute the deletes:
252
298
 
@@ -281,25 +327,9 @@ Store the following for step 3:
281
327
  - `section3_warnings` — list of missing file warnings (empty if none)
282
328
  - `verification_warnings` — list of informational SKILL.md body mentions of `{old_name}` retained (empty if none)
283
329
  - `deletion_errors` — list of post-commit deletion errors (empty if none)
330
+ - `headless_decisions` — the audit trail of confirmation gates auto-resolved under `{headless_mode}`, carried forward from step 1 unchanged (empty in interactive runs). Step 3 surfaces it in the result envelope and the per-run result JSON.
284
331
 
285
332
  ### 10. Load Next Step
286
333
 
287
334
  Load, read the full file, and then execute `{nextStepFile}`.
288
335
 
289
- ## Error Handling Summary
290
-
291
- | Section | Failure Mode | Reversible? | Recovery Action |
292
- |---------|--------------|-------------|-----------------|
293
- | 1 | Copy failure | Yes | Delete whichever new directory exists; old skill intact |
294
- | 2 | Inner rename failure | Yes | `rm -rf` both new directories; old skill intact |
295
- | 3 | File update failure | Yes | `rm -rf` both new directories; old skill intact |
296
- | 4 | `active` symlink repair failure | Yes | `rm -rf` both new directories; old skill intact |
297
- | 5 | Verification failure | Yes | `rm -rf` both new directories; old skill intact |
298
- | 6 | Manifest write failure | Yes | Restore manifest from backup; `rm -rf` both new directories; old skill intact |
299
- | 7 | Platform context rebuild failure | Per-file | Record errors, continue other platforms; do NOT rollback — manifest and disk are canonical |
300
- | 8 | Delete failure | **No** | Record deletion errors; new name is already committed; user removes remnants manually |
301
-
302
- ## CRITICAL STEP COMPLETION NOTE
303
-
304
- ONLY WHEN all execution sections have been attempted (copy, inner rename, file updates, symlink fix, verification, manifest re-key, context rebuild, old delete) and results have been stored in context, will you then load and read fully `{nextStepFile}` to generate the final report.
305
-
@@ -0,0 +1,12 @@
1
+ # Exit Codes — skf-rename-skill
2
+
3
+ Every HARD HALT in the rename workflow exits with a stable code so headless automators can branch on the failure class without grepping message text:
4
+
5
+ | Code | Meaning | Raised by |
6
+ | ---- | -------------------- | -------------------------------------------------------------------------------------------- |
7
+ | 0 | success | step 4 (terminal) |
8
+ | 2 | input-missing / input-invalid | step 1 §4/§5 (headless missing `old_name`/`new_name` arg) → `input-missing`; new name fails kebab-case / length / same-as-old → `input-invalid` |
9
+ | 3 | resolution-failure | step 1 §2 (manifest is malformed JSON); step 1 §3 (no skills found anywhere) |
10
+ | 4 | write-failure | On-Activation §4 pre-flight write probe (skills_output_folder / forge_data_folder unwritable); step 2 §1 (copy → `copy-failed`); step 2 §2 (inner-dir rename) / §3 (file content update) / §4 (symlink repair) → `write-failed`; step 2 §6 (manifest write → `manifest-write-failed`). step 2 §7 (context-file rewrite) is **best-effort and never halts** — per-file failures are recorded in `context_files_failed` and the rename still succeeds (manifest + disk are canonical; re-run `[EX] Export Skill` to retry). |
11
+ | 5 | state-conflict | step 1 §5 (name-collision check fails: target name already in use); step 1 §6 (source-authority="official" headless without `force_source_authority_in_headless`); concurrency lock collision (`halted-for-concurrent-run`); step 2 §5 (no-trace verification failed — `{old_name}` still present inside the new location → `verify-failed`; note this rollback is code 5, unlike the copy/write rollbacks at code 4) |
12
+ | 6 | user-cancelled | step 1 §6 (source-authority warning [N]); step 1 §8 confirmation gate `[N]`; any prompt that accepted `cancel`/`exit`/`:q` |
@@ -15,7 +15,7 @@ Present a clear, final summary of what the rename workflow changed — old and n
15
15
  - Focus only on reporting results stored in context by step 2 — do not re-execute any part of the rename
16
16
  - Do not hide verification warnings, context file rebuild failures, or deletion errors
17
17
  - Present next-steps guidance so the user knows which downstream workflows to run
18
- - Chains to the local health-check step via `{nextStepFile}` after completion the user-facing report is NOT the terminal step
18
+ - Chains to the local health-check step via `{nextStepFile}` after completion (see section 2)
19
19
 
20
20
  ## MANDATORY SEQUENCE
21
21
 
@@ -61,6 +61,10 @@ Informational: the old name still appears in SKILL.md body text (prose only, non
61
61
  {list each error}
62
62
  → The new name is fully committed. Remove the remnants manually with `rm -rf {path}`.
63
63
 
64
+ {if headless_decisions is non-empty:}
65
+ Headless auto-decisions:
66
+ {for each entry: "{gate}: took {taken_action} (default {default_action}) — {reason}"}
67
+
64
68
  ---
65
69
 
66
70
  **Next steps:**
@@ -71,21 +75,25 @@ Informational: the old name still appears in SKILL.md body text (prose only, non
71
75
 
72
76
  ### Result Contract
73
77
 
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`.
78
+ 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`, `versions_renamed`, and `headless_decisions` (the auto-resolved gate audit trail carried from step 1 — `[]` in interactive runs) in `summary`.
75
79
 
76
80
  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
81
 
78
82
  ```
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}
83
+ 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,"headless_decisions":{headless_decisions}}
80
84
  ```
81
85
 
82
- Substitute `{affected_versions}` and `{context_files_updated}` as JSON arrays; `manifest_rekeyed` is the boolean from step 2's context.
86
+ Substitute `{affected_versions}`, `{context_files_updated}`, and `{headless_decisions}` as JSON arrays; `manifest_rekeyed` is the boolean from step 2's context.
83
87
 
84
- ### 2. Chain to Health Check
88
+ **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, passing the per-run result path:
85
89
 
86
- ONLY WHEN the rename report has been rendered and the result contract saved will you then load, read the full file, and execute `{nextStepFile}`. The health-check step is the true terminal step — do not stop here even though the report reads as final.
90
+ ```bash
91
+ {onCompleteCommand} --result-path={skills_output_folder}/{new_name}/rename-skill-result-{timestamp}.json
92
+ ```
87
93
 
88
- ## CRITICAL STEP COMPLETION NOTE
94
+ Log success/failure but never fail the workflow on a hook error — the rename is already committed. The hook runs last so an audit-log emit, registry re-index, or notifier sees the completed rename. When `{onCompleteCommand}` is empty (bundled default), skip the invocation entirely.
89
95
 
90
- This step chains to the local health-check step (`{nextStepFile}`), which in turn delegates to `shared/health-check.md`. After the health check completes, the rename-skill workflow is fully done. Do not re-run any earlier step automatically — if the user wants another rename, they should re-invoke the workflow from the top.
96
+ ### 2. Chain to Health Check
97
+
98
+ ONLY WHEN the rename report has been rendered and the result contract saved will you then load, read the full file, and execute `{nextStepFile}`. The health-check step is the true terminal step — do not stop here even though the report reads as final.
91
99
 
@@ -1,6 +1,31 @@
1
1
  ---
2
2
  nextStepFile: 'execute.md'
3
3
  versionPathsKnowledge: 'knowledge/version-paths.md'
4
+ # Resolve `{manifestOpsHelper}` by probing `{manifestOpsProbeOrder}` in order
5
+ # (installed SKF module path first, src/ dev-checkout fallback); first existing
6
+ # path wins. §7 uses its `affected-versions` action to enumerate the versions a
7
+ # rename must touch — the union of manifest version keys and on-disk version
8
+ # dirs, deduped and semver-sorted (numeric, so 0.10.0 precedes 0.9.0). Unlike
9
+ # execute.md's write helpers this one is not atomicity-critical: if neither path
10
+ # resolves, §7 falls back to computing the union in the prompt.
11
+ manifestOpsProbeOrder:
12
+ - '{project-root}/_bmad/skf/shared/scripts/skf-manifest-ops.py'
13
+ - '{project-root}/src/shared/scripts/skf-manifest-ops.py'
14
+ # Resolve `{skillInventoryHelper}` by probing `{skillInventoryProbeOrder}`
15
+ # (installed SKF module path first, src/ dev-checkout fallback). §3 uses it to
16
+ # enumerate the rename candidates: the union of manifest `exports` and on-disk
17
+ # skill directories, each with its version list and active version — computing
18
+ # that union/count in the prompt has one correct answer per input. §3 falls
19
+ # back to an in-prompt scan if neither path resolves.
20
+ skillInventoryProbeOrder:
21
+ - '{project-root}/_bmad/skf/shared/scripts/skf-skill-inventory.py'
22
+ - '{project-root}/src/shared/scripts/skf-skill-inventory.py'
23
+ # `{renameNameValidator}` is this skill's own deterministic new-name gate. §5
24
+ # uses it for the format / length / identity / collision checks (one correct
25
+ # answer per (name, filesystem, manifest) state) and the interrupted-rename
26
+ # recovery fingerprint; §5 falls back to the same checks in-prompt if Python is
27
+ # unavailable.
28
+ renameNameValidator: 'scripts/skf-validate-rename-name.py'
4
29
  ---
5
30
 
6
31
  <!-- Config: communicate in {communication_language}. -->
@@ -18,6 +43,14 @@ Identify the skill the user wants to rename, validate the new name against the a
18
43
  - Do not accept a new name that fails validation (kebab-case, length, uniqueness)
19
44
  - Present the list of affected versions clearly so the user understands the scope
20
45
 
46
+ **Headless error envelope (self-contained).** Where a halt below says *"emit the error envelope per SKILL.md 'Result Contract (Headless)'"*, write this single line to **stderr** (restated here so selection halts stay parseable even if SKILL.md is out of context) —
47
+
48
+ ```
49
+ SKF_RENAME_SKILL_RESULT_JSON: {"status":"error","old_name":"…|null","new_name":"…|null","versions_renamed":[],"manifest_rekeyed":false,"context_files_updated":[],"exit_code":<code>,"halt_reason":"<reason>","headless_decisions":[]}
50
+ ```
51
+
52
+ Use the `old_name`/`new_name`, `exit_code`, and `halt_reason` named at each halt site (see `references/exit-codes.md`) — `old_name`/`new_name` are `null` until resolved in §4/§5. `headless_decisions` is `[]` at every selection-stage halt: the only decision this step records (the §6 source-authority override) means *proceed*, so no recorded decision is ever paired with a halt here.
53
+
21
54
  ## MANDATORY SEQUENCE
22
55
 
23
56
  ### 1. Load Knowledge
@@ -44,19 +77,19 @@ Load `{skills_output_folder}/.export-manifest.json` if it exists.
44
77
 
45
78
  ### 3. List Available Skills
46
79
 
47
- Build and display a summary of every skill available for rename. Start with the manifest (if any), then augment with on-disk scan.
80
+ Enumerate every skill available for rename deterministically. Resolve `{skillInventoryHelper}` first existing path in `{skillInventoryProbeOrder}` and run:
48
81
 
49
- For each skill in the manifest's `exports` (if `manifest_exists` and entries exist):
82
+ ```bash
83
+ python3 {skillInventoryHelper} {skills_output_folder}
84
+ ```
50
85
 
51
- 1. Read `active_version` from the manifest entry
52
- 2. Count the number of versions in the skill's `versions` map
53
- 3. Display `{skill-name} ({n} versions, active: {active_version})`
86
+ Read the JSON. Each entry in `skills[]` carries `name`, its `versions` array, and `active_version` (the helper unions the manifest `exports` with the on-disk directories and dedupes, so manifest-tracked and orphaned skills both appear). A skill whose `name` is absent from `manifest.exports` is a draft/orphan the rename workflow can still handle — annotate it "(not in manifest)".
54
87
 
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.
88
+ **If `{skillInventoryHelper}` has no existing candidate** (neither probe path resolves — e.g. Python/`uv` unavailable): build the list in the prompt instead — read `exports` from the manifest (if `manifest_exists`), scan `{skills_output_folder}/` for top-level directories, union the two, and read each one's `active_version` and version count. Directories absent from `exports` are the "(not in manifest)" entries.
56
89
 
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`.
90
+ **If the 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
91
 
59
- Display the combined list:
92
+ Display the list, one line per skill as `{name} ({n} versions, active: {active_version})` (append "(not in manifest)" for orphans):
60
93
 
61
94
  ```
62
95
  **Rename Skill — select target**
@@ -108,42 +141,38 @@ printf '%s\n%s\n' "$$" "$(date -u +%Y-%m-%dT%H:%M:%SZ)" > "$LOCK"
108
141
 
109
142
  **Release contract:**
110
143
 
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.
144
+ - This run owns the lock only after the `printf … > "$LOCK"` line above runs — i.e. once §4b has cleared the live-PID check and written this run's PID. The live-PID collision halt directly above is the **sole exception**: it exits *before* that line, so the lock belongs to the other live run and this run must **never** delete it (clearing a live lock it just honored would let a third invocation run concurrently).
145
+ - The terminal health-check step (step 4) deletes the lock as its final action on the success path.
146
+ - **Every halt from §5 onward — after this run has acquired the lock — must delete it before exiting** (`rm -f "$LOCK"` per halt site): the §5 input/format/collision halts, the §6 source-authority and cancel halts, the §8 cancel and dry-run exits, and execute.md's copy/verify/manifest/write rollbacks. Otherwise the next attempt would see a stale lock from this run.
113
147
 
114
148
  ### 5. Ask for New Name
115
149
 
116
150
  "**What is the new name for this skill?**
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."
151
+ The new name must be kebab-case: lowercase alphanumeric with hyphens, 1-64 characters, matching the regex `^[a-z0-9]([a-z0-9-]*[a-z0-9])?$` (starts and ends with a lowercase letter or digit; a single letter or digit is valid). Or type `cancel` / `exit` / `:q` to abort."
118
152
 
119
153
  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
154
 
121
155
  - 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"`).
122
156
 
123
- Apply the following validations in order:
124
-
125
- 1. **Kebab-case format:** Must match `^[a-z][a-z0-9-]*[a-z0-9]$` (or `^[a-z0-9]$` for the single-character case). If it fails:
126
- "**Invalid name format.** The new name must be lowercase alphanumeric with hyphens, starting with a letter and ending with a letter or digit. Try again."
127
- Re-ask.
157
+ **Validate the candidate deterministically.** Run `{renameNameValidator}` (a per-skill helper, always shipped with the skill) — it applies format, length, identity, and collision in that order and returns the verdict as JSON:
128
158
 
129
- 2. **Length:** Must be 1-64 characters per the agentskills.io spec. If it fails:
130
- "**Invalid name length.** The new name must be 1-64 characters. Try again."
131
- Re-ask.
159
+ ```bash
160
+ python3 {renameNameValidator} \
161
+ --old-name {old_name} --new-name {candidate} \
162
+ --skills-output-folder {skills_output_folder} \
163
+ --forge-data-folder {forge_data_folder}
164
+ ```
132
165
 
133
- 3. **Same as old name:** If the new name equals `old_name`:
134
- "**The new name is identical to the current name.** Nothing to rename. Try again or abort the workflow."
135
- Re-ask.
166
+ The checks: **format** = the kebab regex `^[a-z0-9]([a-z0-9-]*[a-z0-9])?$` (the module's canonical rule, same as `skf-validate-output.py` / `skf-validate-brief-inputs.py`, so a digit-leading name like `3d-tools` renames cleanly); **length** = 1-64 characters (agentskills.io spec); **identity** = differs from `{old_name}`; **collision** = the name is not a manifest `exports` key, a `{skills_output_folder}` directory, or a `{forge_data_folder}` directory.
136
167
 
137
- 4. **Collision check:** The new name MUST NOT collide with any existing skill:
138
- - It must not appear as a key in `exports` in the manifest
139
- - It must not exist as a top-level directory in `{skills_output_folder}/`
140
- - It must not exist as a top-level directory in `{forge_data_folder}/`
168
+ Read `valid`, `first_failure`, `checks`, and `interrupted_rename`. If `valid` is true, store the input as `new_name` and proceed to §6. Otherwise branch on `first_failure` interactive: display the message and re-ask; headless: release the lock (`rm -f {forge_data_folder}/{old_name}/.skf-rename.lock`), HALT with the mapped code, and emit the error envelope:
141
169
 
142
- If any collision is detected:
143
- "**Name collision.** `{new-name}` already exists at: {list the colliding locations}. Pick a different name."
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.
170
+ - **`format`** "**Invalid name format.** The new name must be lowercase alphanumeric with hyphens, starting and ending with a lowercase letter or digit. Try again." (headless HALT: exit code 2, `halt_reason: "input-invalid"`)
171
+ - **`length`** → "**Invalid name length.** The new name must be 1-64 characters. Try again." (headless HALT: exit code 2, `halt_reason: "input-invalid"`)
172
+ - **`identity`** "**The new name is identical to the current name.** Nothing to rename. Try again or abort the workflow." (headless HALT: exit code 2, `halt_reason: "input-invalid"`)
173
+ - **`collision`** → "**Name collision.** `{new-name}` already exists at: {the `path` of each entry in `checks.collision.locations`}. Pick a different name." When `interrupted_rename` is true, append: "This may be a stranded partial rename from an earlier interrupted run — `{new_name}` was staged but `{old_name}` was never removed. Confirm the `{new_name}` directories are not a skill you want to keep, then clean them up (`rm -rf {skills_output_folder}/{new_name} {forge_data_folder}/{new_name}`) and re-run this rename." — this gives headless pipelines a named recovery path instead of a dead-end collision halt. (headless HALT: exit code 5, `halt_reason: "name-collision"`)
145
174
 
146
- Only after all four validations pass, store the input as `new_name`.
175
+ **If `{renameNameValidator}` cannot run** (Python/`uv` unavailable): apply the same four checks in the same order in the prompt — the kebab regex, the 1-64 length bound, inequality with `{old_name}`, and the three-source collision lookup (plus the interrupted-rename fingerprint above) — using the identical messages and halt mapping.
147
176
 
148
177
  ### 6. Source Authority Check
149
178
 
@@ -176,14 +205,15 @@ Wait for response.
176
205
 
177
206
  ### 7. Enumerate Affected Versions
178
207
 
179
- List all versions for `old_name`:
208
+ Resolve `{manifestOpsHelper}` first existing path in `{manifestOpsProbeOrder}` (installed SKF module path first, `src/` dev-checkout fallback). Enumerate every version the rename must touch deterministically via its `affected-versions` action:
180
209
 
181
- 1. Read every key under `exports.{old_name}.versions` in the manifest
182
- 2. Also list every directory under `{skills_output_folder}/{old_name}/` that looks like a version (any entry that is not `active`)
183
- 3. Union the two sets — this handles both manifest-tracked and orphaned on-disk versions
184
- 4. Sort descending where possible (newest first)
210
+ ```bash
211
+ python3 {manifestOpsHelper} {skills_output_folder} affected-versions {old_name}
212
+ ```
185
213
 
186
- Store the sorted list as `affected_versions` and count it as `affected_versions_count`.
214
+ Read the JSON result. Store `affected_versions` = `result.affected_versions` and `affected_versions_count` = `result.count`. The helper unions the manifest's `exports.{old_name}.versions` keys with the on-disk version directories under `{skills_output_folder}/{old_name}/` (every entry that is not the `active` symlink), so it handles both manifest-tracked and orphaned on-disk versions, deduplicates, and applies a **numeric** semver-descending sort (so `0.10.0` correctly precedes `0.9.0`, which a lexical sort gets wrong). An incomplete union would risk leaving a version internally un-renamed in the new copy — a leftover that step 2 §5 only catches for the versions it was told about.
215
+
216
+ **If `{manifestOpsHelper}` has no existing candidate** (neither probe path resolves — e.g. Python/`uv` unavailable): compute `affected_versions` in the prompt instead — read every key under `exports.{old_name}.versions` in the manifest, list every directory under `{skills_output_folder}/{old_name}/` that is not `active`, union the two sets, and sort descending (newest first, comparing version components numerically). Store the list as `affected_versions` and its length as `affected_versions_count`.
187
217
 
188
218
  Also resolve the four outer paths using the templates from `{versionPathsKnowledge}`:
189
219
 
@@ -225,11 +255,11 @@ directories are removed and the old skill remains intact.
225
255
  Proceed? [Y/N]
226
256
  ```
227
257
 
228
- **GATE [default: Y]** — If `{headless_mode}`: auto-proceed with [Y], log: "headless: auto-confirmed rename {old_name} → {new_name}"
258
+ **GATE [default: Y]** — If `{headless_mode}`: auto-proceed with [Y] and append `{gate: "confirm-rename", default_action: "proceed", taken_action: "proceed", reason: "headless auto-confirm"}` to `headless_decisions[]` (log line: "headless: auto-confirmed rename {old_name} → {new_name}"). Skip this append when `--dry-run` is set — a dry run does not execute the rename, so there is no confirmation to record.
229
259
 
230
260
  Wait for explicit user response.
231
261
 
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.
262
+ **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`, `versions_renamed: {affected_versions}`, and `headless_decisions: {headless_decisions}` (carries the §6 source-authority override entry if it fired, else `[]`), then HALT (exit code 0). No copy, no manifest re-key, no delete.
233
263
 
234
264
  - **If `Y`** → proceed to section 9
235
265
  - **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`.
@@ -248,12 +278,9 @@ Store the following decisions in workflow context for step 2:
248
278
  - `old_forge_group` — absolute path `{forge_data_folder}/{old_name}/`
249
279
  - `new_forge_group` — absolute path `{forge_data_folder}/{new_name}/`
250
280
  - `source_authority_override` — boolean (true if the user acknowledged the `"official"` warning, false/absent otherwise)
281
+ - `headless_decisions` — the audit trail of confirmation gates auto-resolved under `{headless_mode}` (the §6 source-authority override and the §8 auto-confirm entries appended above). Initialize to `[]`; in interactive runs it stays `[]`. Step 2 carries it forward and step 3 surfaces it in the result envelope.
251
282
 
252
283
  ### 10. Load Next Step
253
284
 
254
285
  Load, read the full file, and then execute `{nextStepFile}`.
255
286
 
256
- ## CRITICAL STEP COMPLETION NOTE
257
-
258
- ONLY WHEN the user has confirmed with `Y` at the confirmation gate AND all selection decisions have been stored in context, will you then load and read fully `{nextStepFile}` to execute the rename.
259
-