bmad-module-skill-forge 2.0.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 (235) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.nvmrc +1 -1
  3. package/docs/_data/pinned.yaml +1 -1
  4. package/package.json +2 -2
  5. package/src/knowledge/skill-lifecycle.md +1 -1
  6. package/src/module-help.csv +2 -2
  7. package/src/shared/scripts/skf-comention-pairs.py +350 -0
  8. package/src/shared/scripts/skf-count-tokens.py +222 -0
  9. package/src/shared/scripts/skf-detect-docs.py +232 -1
  10. package/src/shared/scripts/skf-detect-language.py +77 -0
  11. package/src/shared/scripts/skf-detect-tools.py +105 -2
  12. package/src/shared/scripts/skf-enumerate-stack-skills.py +111 -2
  13. package/src/shared/scripts/skf-find-cycles.py +246 -0
  14. package/src/shared/scripts/skf-hash-content.py +487 -2
  15. package/src/shared/scripts/skf-manifest-ops.py +67 -1
  16. package/src/shared/scripts/skf-rebuild-managed-sections.py +180 -0
  17. package/src/shared/scripts/skf-recommend-scope-type.py +1 -2
  18. package/src/shared/scripts/skf-render-metadata-stats.py +499 -0
  19. package/src/shared/scripts/skf-rewrite-skill-name.py +308 -0
  20. package/src/shared/scripts/skf-shard-body.py +461 -0
  21. package/src/shared/scripts/skf-skill-inventory.py +139 -3
  22. package/src/shared/scripts/skf-structural-diff.py +307 -67
  23. package/src/shared/scripts/skf-validate-brief-schema.py +39 -1
  24. package/src/shared/scripts/skf-validate-feasibility-report.py +234 -0
  25. package/src/shared/scripts/skf-validate-frontmatter.py +17 -12
  26. package/src/shared/scripts/skf-validate-output.py +443 -10
  27. package/src/shared/scripts/skf-validate-pins.py +1 -1
  28. package/src/shared/scripts/skf-verify-no-trace.py +214 -0
  29. package/src/shared/scripts/skf-verify-provenance-completeness.py +439 -0
  30. package/src/skf-analyze-source/SKILL.md +17 -32
  31. package/src/skf-analyze-source/customize.toml +2 -0
  32. package/src/skf-analyze-source/references/auto-docs-only.md +116 -0
  33. package/src/skf-analyze-source/references/continue.md +8 -13
  34. package/src/skf-analyze-source/references/generate-briefs.md +28 -12
  35. package/src/skf-analyze-source/references/headless-contract.md +33 -0
  36. package/src/skf-analyze-source/references/health-check.md +1 -2
  37. package/src/skf-analyze-source/references/identify-units.md +25 -36
  38. package/src/skf-analyze-source/references/init.md +12 -25
  39. package/src/skf-analyze-source/references/map-and-detect.md +8 -20
  40. package/src/skf-analyze-source/references/recommend.md +4 -14
  41. package/src/skf-analyze-source/references/scan-project.md +3 -11
  42. package/src/skf-analyze-source/references/step-auto-scope.md +42 -180
  43. package/src/skf-analyze-source/references/unit-detection-heuristics.md +2 -2
  44. package/src/skf-audit-skill/SKILL.md +9 -6
  45. package/src/skf-audit-skill/customize.toml +2 -0
  46. package/src/skf-audit-skill/references/init.md +58 -32
  47. package/src/skf-audit-skill/references/re-index.md +15 -34
  48. package/src/skf-audit-skill/references/report.md +11 -58
  49. package/src/skf-audit-skill/references/semantic-diff.md +4 -22
  50. package/src/skf-audit-skill/references/severity-classify.md +53 -87
  51. package/src/skf-audit-skill/references/step-doc-drift.md +49 -19
  52. package/src/skf-audit-skill/references/structural-diff.md +43 -68
  53. package/src/skf-brief-skill/SKILL.md +7 -36
  54. package/src/skf-brief-skill/assets/scope-templates.md +1 -1
  55. package/src/skf-brief-skill/customize.toml +14 -0
  56. package/src/skf-brief-skill/references/analyze-target.md +6 -14
  57. package/src/skf-brief-skill/references/confirm-brief.md +2 -14
  58. package/src/skf-brief-skill/references/draft-checkpoint.md +8 -8
  59. package/src/skf-brief-skill/references/gather-intent.md +19 -22
  60. package/src/skf-brief-skill/references/headless-args.md +1 -1
  61. package/src/skf-brief-skill/references/health-check.md +1 -22
  62. package/src/skf-brief-skill/references/invocation-contract.md +37 -0
  63. package/src/skf-brief-skill/references/scope-definition.md +4 -14
  64. package/src/skf-brief-skill/references/step-auto-brief.md +1 -5
  65. package/src/skf-brief-skill/references/step-auto-validate.md +1 -5
  66. package/src/skf-brief-skill/references/version-resolution.md +1 -1
  67. package/src/skf-brief-skill/references/write-brief.md +17 -10
  68. package/src/skf-campaign/SKILL.md +15 -84
  69. package/src/skf-campaign/customize.toml +2 -0
  70. package/src/skf-campaign/manifest.yaml +4 -0
  71. package/src/skf-campaign/references/campaign-contracts.md +67 -0
  72. package/src/skf-campaign/references/campaign-directive-spec.md +14 -103
  73. package/src/skf-campaign/references/step-01-setup.md +4 -5
  74. package/src/skf-campaign/references/step-02-strategy.md +8 -3
  75. package/src/skf-campaign/references/step-03-pins.md +1 -1
  76. package/src/skf-campaign/references/step-04-provenance.md +1 -1
  77. package/src/skf-campaign/references/step-05-skill-loop.md +1 -1
  78. package/src/skf-campaign/references/step-06-batch.md +7 -6
  79. package/src/skf-campaign/references/step-11-maintenance.md +2 -2
  80. package/src/skf-campaign/references/step-resume.md +9 -8
  81. package/src/skf-campaign/scripts/campaign-deps.py +10 -1
  82. package/src/skf-campaign/scripts/campaign-render-batch.py +199 -0
  83. package/src/skf-campaign/scripts/campaign-status.py +162 -0
  84. package/src/skf-campaign/templates/campaign-brief-template.yaml +1 -1
  85. package/src/skf-create-skill/SKILL.md +14 -3
  86. package/src/skf-create-skill/assets/compile-assembly-rules.md +17 -38
  87. package/src/skf-create-skill/assets/skill-sections.md +9 -100
  88. package/src/skf-create-skill/assets/tessl-dismissal-rules.md +4 -13
  89. package/src/skf-create-skill/customize.toml +13 -0
  90. package/src/skf-create-skill/references/authoritative-files-protocol.md +7 -7
  91. package/src/skf-create-skill/references/compile.md +34 -47
  92. package/src/skf-create-skill/references/component-extraction.md +8 -35
  93. package/src/skf-create-skill/references/ecosystem-check.md +9 -25
  94. package/src/skf-create-skill/references/enrich.md +4 -17
  95. package/src/skf-create-skill/references/extract.md +14 -29
  96. package/src/skf-create-skill/references/extraction-patterns-tracing.md +1 -1
  97. package/src/skf-create-skill/references/extraction-patterns.md +7 -7
  98. package/src/skf-create-skill/references/generate-artifacts.md +9 -23
  99. package/src/skf-create-skill/references/health-check.md +1 -1
  100. package/src/skf-create-skill/references/load-brief.md +16 -18
  101. package/src/skf-create-skill/references/report.md +12 -15
  102. package/src/skf-create-skill/references/source-resolution-protocols.md +3 -3
  103. package/src/skf-create-skill/references/step-auto-shard.md +52 -25
  104. package/src/skf-create-skill/references/step-doc-rot.md +30 -12
  105. package/src/skf-create-skill/references/step-doc-sources.md +2 -2
  106. package/src/skf-create-skill/references/sub/ccc-discover.md +2 -13
  107. package/src/skf-create-skill/references/sub/fetch-docs.md +8 -50
  108. package/src/skf-create-skill/references/sub/fetch-temporal.md +5 -20
  109. package/src/skf-create-skill/references/tier-degradation-rules.md +6 -8
  110. package/src/skf-create-skill/references/validate.md +59 -28
  111. package/src/skf-create-skill/scripts/scan-doc-rot.py +245 -0
  112. package/src/skf-create-stack-skill/SKILL.md +15 -9
  113. package/src/skf-create-stack-skill/assets/provenance-map-schema.md +1 -1
  114. package/src/skf-create-stack-skill/customize.toml +10 -0
  115. package/src/skf-create-stack-skill/references/compile-stack.md +7 -8
  116. package/src/skf-create-stack-skill/references/compose-mode-rules.md +2 -13
  117. package/src/skf-create-stack-skill/references/detect-integrations.md +49 -54
  118. package/src/skf-create-stack-skill/references/detect-manifests.md +37 -30
  119. package/src/skf-create-stack-skill/references/generate-output.md +24 -75
  120. package/src/skf-create-stack-skill/references/init.md +9 -81
  121. package/src/skf-create-stack-skill/references/manifest-patterns.md +5 -35
  122. package/src/skf-create-stack-skill/references/parallel-extract.md +12 -27
  123. package/src/skf-create-stack-skill/references/rank-and-confirm.md +6 -6
  124. package/src/skf-create-stack-skill/references/report.md +27 -62
  125. package/src/skf-create-stack-skill/references/validate.md +35 -31
  126. package/src/skf-drop-skill/SKILL.md +20 -23
  127. package/src/skf-drop-skill/customize.toml +10 -0
  128. package/src/skf-drop-skill/references/execute.md +51 -31
  129. package/src/skf-drop-skill/references/headless-contract.md +18 -0
  130. package/src/skf-drop-skill/references/health-check.md +1 -13
  131. package/src/skf-drop-skill/references/report.md +42 -10
  132. package/src/skf-drop-skill/references/select.md +88 -48
  133. package/src/skf-drop-skill/scripts/dir-sizes.py +116 -0
  134. package/src/skf-export-skill/SKILL.md +17 -14
  135. package/src/skf-export-skill/assets/managed-section-format.md +2 -5
  136. package/src/skf-export-skill/customize.toml +10 -6
  137. package/src/skf-export-skill/references/generate-snippet.md +21 -35
  138. package/src/skf-export-skill/references/load-skill.md +44 -42
  139. package/src/skf-export-skill/references/multi-skill-mode.md +1 -1
  140. package/src/skf-export-skill/references/orphan-context-detection.md +11 -3
  141. package/src/skf-export-skill/references/package.md +27 -33
  142. package/src/skf-export-skill/references/preflight-snippet-root-probe.md +24 -5
  143. package/src/skf-export-skill/references/result-envelope.md +28 -0
  144. package/src/skf-export-skill/references/summary.md +11 -5
  145. package/src/skf-export-skill/references/token-report.md +42 -24
  146. package/src/skf-export-skill/references/update-context.md +32 -33
  147. package/src/skf-forger/SKILL.md +27 -39
  148. package/src/skf-forger/references/pipeline-mode.md +34 -0
  149. package/src/skf-forger/scripts/parse-pipeline.py +270 -0
  150. package/src/skf-quick-skill/SKILL.md +10 -60
  151. package/src/skf-quick-skill/customize.toml +9 -0
  152. package/src/skf-quick-skill/references/batch-mode.md +6 -4
  153. package/src/skf-quick-skill/references/compile.md +15 -52
  154. package/src/skf-quick-skill/references/ecosystem-check.md +5 -20
  155. package/src/skf-quick-skill/references/finalize.md +12 -6
  156. package/src/skf-quick-skill/references/halt-contract.md +54 -0
  157. package/src/skf-quick-skill/references/health-check.md +3 -4
  158. package/src/skf-quick-skill/references/quick-extract.md +7 -18
  159. package/src/skf-quick-skill/references/registry-resolution.md +1 -23
  160. package/src/skf-quick-skill/references/resolve-target.md +27 -34
  161. package/src/skf-quick-skill/references/write-and-validate.md +10 -25
  162. package/src/skf-refine-architecture/SKILL.md +14 -7
  163. package/src/skf-refine-architecture/customize.toml +9 -0
  164. package/src/skf-refine-architecture/references/compile.md +9 -7
  165. package/src/skf-refine-architecture/references/gap-analysis.md +21 -50
  166. package/src/skf-refine-architecture/references/health-check.md +1 -1
  167. package/src/skf-refine-architecture/references/improvements.md +9 -25
  168. package/src/skf-refine-architecture/references/init.md +9 -16
  169. package/src/skf-refine-architecture/references/issue-detection.md +10 -25
  170. package/src/skf-refine-architecture/references/refinement-rules.md +4 -16
  171. package/src/skf-refine-architecture/references/report.md +13 -10
  172. package/src/skf-rename-skill/SKILL.md +11 -21
  173. package/src/skf-rename-skill/customize.toml +10 -0
  174. package/src/skf-rename-skill/references/execute.md +107 -78
  175. package/src/skf-rename-skill/references/exit-codes.md +12 -0
  176. package/src/skf-rename-skill/references/report.md +16 -8
  177. package/src/skf-rename-skill/references/select.md +69 -42
  178. package/src/skf-rename-skill/scripts/skf-validate-rename-name.py +161 -0
  179. package/src/skf-setup/SKILL.md +20 -12
  180. package/src/skf-setup/customize.toml +10 -0
  181. package/src/skf-setup/references/auto-index.md +9 -10
  182. package/src/skf-setup/references/ccc-index.md +14 -15
  183. package/src/skf-setup/references/detect-and-tier.md +6 -8
  184. package/src/skf-setup/references/report.md +22 -31
  185. package/src/skf-setup/references/tier-rules.md +2 -32
  186. package/src/skf-setup/references/write-config.md +9 -10
  187. package/src/skf-test-skill/SKILL.md +10 -8
  188. package/src/skf-test-skill/customize.toml +2 -0
  189. package/src/skf-test-skill/references/coherence-check.md +19 -31
  190. package/src/skf-test-skill/references/coverage-check.md +109 -75
  191. package/src/skf-test-skill/references/detect-mode.md +10 -41
  192. package/src/skf-test-skill/references/external-validators.md +11 -19
  193. package/src/skf-test-skill/references/init.md +38 -20
  194. package/src/skf-test-skill/references/migration-section-rules.md +4 -4
  195. package/src/skf-test-skill/references/report.md +60 -40
  196. package/src/skf-test-skill/references/score.md +32 -64
  197. package/src/skf-test-skill/references/scoring-rules.md +6 -62
  198. package/src/skf-test-skill/references/source-access-protocol.md +6 -6
  199. package/src/skf-test-skill/references/step-hard-gate.md +1 -3
  200. package/src/skf-test-skill/scripts/aggregate-coherence.py +276 -0
  201. package/src/skf-test-skill/scripts/check-metadata-coherence.py +359 -0
  202. package/src/skf-test-skill/scripts/combine-external-scores.py +190 -0
  203. package/src/skf-test-skill/scripts/compute-score.py +131 -1
  204. package/src/skf-test-skill/scripts/reconcile-coverage.py +327 -0
  205. package/src/skf-test-skill/scripts/validate-inventory.py +251 -0
  206. package/src/skf-test-skill/scripts/verify-declared-numerator.py +192 -0
  207. package/src/skf-update-skill/SKILL.md +17 -5
  208. package/src/skf-update-skill/customize.toml +14 -0
  209. package/src/skf-update-skill/references/detect-changes.md +19 -37
  210. package/src/skf-update-skill/references/health-check.md +3 -9
  211. package/src/skf-update-skill/references/init.md +39 -32
  212. package/src/skf-update-skill/references/manual-section-rules.md +1 -2
  213. package/src/skf-update-skill/references/merge-conflict-rules.md +1 -52
  214. package/src/skf-update-skill/references/merge.md +13 -57
  215. package/src/skf-update-skill/references/re-extract.md +12 -24
  216. package/src/skf-update-skill/references/report.md +14 -7
  217. package/src/skf-update-skill/references/validate.md +32 -30
  218. package/src/skf-update-skill/references/write.md +86 -51
  219. package/src/skf-update-skill/scripts/skf-new-file-diff.py +167 -0
  220. package/src/skf-verify-stack/SKILL.md +11 -21
  221. package/src/skf-verify-stack/customize.toml +12 -3
  222. package/src/skf-verify-stack/references/coverage-patterns.md +1 -29
  223. package/src/skf-verify-stack/references/coverage.md +21 -10
  224. package/src/skf-verify-stack/references/exit-codes.md +14 -0
  225. package/src/skf-verify-stack/references/health-check.md +1 -1
  226. package/src/skf-verify-stack/references/init.md +20 -25
  227. package/src/skf-verify-stack/references/integration-verification-rules.md +10 -19
  228. package/src/skf-verify-stack/references/integrations.md +44 -49
  229. package/src/skf-verify-stack/references/report.md +28 -34
  230. package/src/skf-verify-stack/references/requirements.md +3 -3
  231. package/src/skf-verify-stack/references/synthesize.md +36 -39
  232. package/src/skf-verify-stack/scripts/skf-coverage-tally.py +196 -0
  233. package/src/skf-verify-stack/scripts/skf-report-delta.py +256 -0
  234. package/src/skf-verify-stack/scripts/skf-verdict-rollup.py +258 -0
  235. package/src/skf-rename-skill/references/rebuild-context.md +0 -110
@@ -2,7 +2,7 @@
2
2
  nextStepFile: 'scan-project.md'
3
3
  continueFile: 'continue.md'
4
4
  outputFile: '{forge_data_folder}/analyze-source-report-{project_name}.md'
5
- templateFile: 'templates/analysis-report-template.md'
5
+ templateFile: '{analysisReportTemplatePath}'
6
6
  ---
7
7
 
8
8
  <!-- Config: communicate in {communication_language}. -->
@@ -21,15 +21,19 @@ To initialize the analyze-source workflow by loading configuration, detecting co
21
21
 
22
22
  ## MANDATORY SEQUENCE
23
23
 
24
+ When `{headless_mode}` is true, every HARD HALT in this step emits the error envelope on **stderr** before exiting — shape and enum in `references/headless-contract.md` — using the exit code and `halt_reason` named at that HALT.
25
+
24
26
  ### 1. Check for Existing Report (Continuation Detection)
25
27
 
26
28
  Look for {outputFile}.
27
29
 
28
30
  **IF the file exists AND has `stepsCompleted` with entries:**
29
31
  - The report filename is keyed to `{project_name}` (the forge workspace), not the analyzed target — so a report from a *different* target can collide here. Before resuming, establish the requested target and compare it to the existing report:
30
- - Determine the requested target now: if `--project-path <path>` was passed at invocation, set `project_paths[]` from it (comma-split if multiple); otherwise collect the path(s) using the section-3 "Collect Project Path" prompt and store as `project_paths[]`. (Section 3 must NOT re-prompt when `project_paths[]` is already populated here.)
32
+ - Determine the requested target now: if `--project-path <path>` was passed at invocation, set `project_paths[]` from it (comma-split if multiple); otherwise collect the path(s) using the section-3 "Collect Project Path" prompt and store as `project_paths[]`. (Section 3 does not re-prompt when `project_paths[]` is already populated here.)
31
33
  - Read the existing report's frontmatter `project_paths`.
32
- - **IF the existing report's `project_paths` matches the requested target:** "**Found an existing analysis report. Resuming previous session...**" — Load, read entirely, then execute {continueFile}. **STOP HERE** — do not continue this sequence.
34
+ - **IF the existing report's `project_paths` matches the requested target:**
35
+ - **IF this invocation carries the `[auto]` flag (e.g. `AN[auto]`):** do not route to {continueFile} — auto mode is a single idempotent pass, not a resumable interactive session. Skip continuation and proceed to section 2; the `[auto]` check in §2b re-enters step-auto-scope.md, which re-runs cleanly and overwrites the prior auto report. (This keeps a re-invoked or interrupted auto run on the auto path instead of dropping it into the interactive chain.)
36
+ - **ELSE:** "**Found an existing analysis report. Resuming previous session...**" — Load, read entirely, then execute {continueFile}. **STOP HERE** — do not continue this sequence. ({continueFile} is mode-aware: a report written by a prior auto run resumes through the auto path, not the interactive chain.)
33
37
  - **ELSE (different target — stale collision):** the existing report belongs to another analysis. Archive it by renaming to `{forge_data_folder}/analyze-source-report-{project_name}-<UTC-timestamp>.md`, announce "**Existing report belongs to a different target — archived as <name>; starting a fresh analysis.**", then continue to section 2 (skip re-collecting the path in section 3 — it is already set).
34
38
 
35
39
  **IF the file does not exist OR stepsCompleted is empty:**
@@ -73,20 +77,16 @@ Look for {outputFile}.
73
77
  4. "**Auto mode activated — bypassing interactive analysis.**"
74
78
  5. **Route to auto-scope:** Load, read fully, then execute `references/step-auto-scope.md`. **STOP HERE** — do not continue to §3 or any subsequent section.
75
79
 
76
- **IF `{auto_mode}` is NOT true:**
80
+ **IF `{auto_mode}` is not true:**
77
81
  Continue to §3 as normal — the entire interactive flow below is unchanged.
78
82
 
79
83
  ### 3. Collect Project Path
80
84
 
81
- **Headless flag consumption:** If `project_paths[]` is already populated (e.g. collected by the section-1 stale-collision guard) OR `--project-path <path>` was passed at invocation, set/keep `project_paths[]` (comma-split the flag value if multiple paths were supplied), skip the prompt below, and proceed to validation. Otherwise prompt as today.
85
+ **Headless flag consumption:** If `project_paths[]` is already populated (e.g. collected by the section-1 stale-collision guard) OR `--project-path <path>` was passed at invocation, set/keep `project_paths[]` (comma-split the flag value if multiple paths were supplied), skip the prompt below, and proceed to validation. If `{headless_mode}` is true and no path is available from either source, HARD HALT with exit code 2 (`input-missing`): "**No project path — headless mode requires `--project-path`.**" (interactive prompting is unavailable headless). Otherwise prompt as today.
82
86
 
83
87
  **Per-path ref overrides (`--target-refs`):** If `--target-refs <mapping>` was passed at invocation, parse it as a comma-separated list of `path:ref` pairs (e.g., `owner/repo:v1.0.0,owner/repo2:main`). Build a `constituent_refs` map from the pairs. Each key must match an entry in `project_paths[]` (validated after path collection). When `--target-refs` is absent but multiple `project_paths` exist, set `constituent_refs` to `{}` (empty — all paths use default ref resolution). When only a single path exists, omit `constituent_refs` entirely (use `target_ref` if set on the brief). `constituent_refs` and `target_ref` are mutually exclusive — if both are supplied, HALT with: "`--target-refs` and `--target-ref` are mutually exclusive. Use `--target-refs` for multi-path analysis, or `--target-ref` for single-path."
84
88
 
85
- "**Welcome to Analyze Source the SKF decomposition engine.**
86
-
87
- I'll analyze your project to identify discrete skillable units and produce skill-brief.yaml files for each recommended unit.
88
-
89
- **Please provide the project root path(s) to analyze:**
89
+ "**Please provide the project root path(s) to analyze**I'll identify discrete skillable units and produce a skill-brief.yaml for each.
90
90
 
91
91
  This can be:
92
92
  - A single root directory of a repo or multi-service project
@@ -149,7 +149,7 @@ These units will be flagged as 'already skilled' during analysis. If source chan
149
149
 
150
150
  ### 6. Create Analysis Report
151
151
 
152
- Create {outputFile} from {templateFile}.
152
+ Create {outputFile} from {templateFile}. If the write fails, HARD HALT with exit code 4 (`write-failed`) per `references/headless-contract.md`.
153
153
 
154
154
  **Populate frontmatter:**
155
155
  ```yaml
@@ -183,18 +183,5 @@ nextWorkflow: ''
183
183
 
184
184
  ### 7. Proceed to Next Step
185
185
 
186
- Display: "**Proceeding to project scan...**"
187
-
188
- #### Menu Handling Logic:
189
-
190
- - After initialization is complete and report is created, immediately load, read entire file, then execute {nextStepFile}
191
-
192
- #### EXECUTION RULES:
193
-
194
- - This is an auto-proceed initialization step with no user choices at this point
195
- - Proceed directly to next step after setup
196
-
197
- ## CRITICAL STEP COMPLETION NOTE
198
-
199
- ONLY WHEN the output report has been created with populated frontmatter (project_paths, forge_tier, existing_skills) will you load and read fully {nextStepFile} to execute and begin the project scan.
186
+ Initialization is complete and the report is created — immediately load, read the entire file, then execute {nextStepFile}. This step has no user choices.
200
187
 
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  nextStepFile: 'recommend.md'
3
3
  outputFile: '{forge_data_folder}/analyze-source-report-{project_name}.md'
4
- heuristicsFile: 'references/unit-detection-heuristics.md'
4
+ heuristicsFile: '{unitDetectionHeuristicsPath}'
5
5
  ---
6
6
 
7
7
  <!-- Config: communicate in {communication_language}. -->
@@ -31,16 +31,16 @@ Load {heuristicsFile} for stack skill candidate detection rules.
31
31
 
32
32
  ### 2. Map Export Surfaces Per Unit (Subagent Fan-Out)
33
33
 
34
- DO NOT BE LAZY — For EACH qualifying unit, delegate deep analysis to a subagent so per-unit work runs in parallel and the parent's context stays clean.
34
+ For each qualifying unit, delegate deep analysis to a subagent so per-unit work runs in parallel and the parent's context stays clean.
35
35
 
36
36
  **Subagent fan-out protocol:**
37
37
 
38
- 1. **Build the qualifying-unit list.** Read the unit list produced upstream (Step §3 / §4 outputs already in workflow context — names, paths, scope types, languages, file counts). Do NOT re-scan the project here.
38
+ 1. **Build the qualifying-unit list.** Read the unit list produced upstream (Step §3 / §4 outputs already in workflow context — names, paths, scope types, languages, file counts). Do not re-scan the project here.
39
39
 
40
40
  2. **Delegate per-unit deep analysis to a subagent.** For each qualifying unit, launch a subagent task with these explicit constraints:
41
- - The subagent reads ONLY that unit's directory tree
41
+ - The subagent reads only that unit's directory tree
42
42
  - The subagent analyzes exports / usage / CCC signals / scripts+assets for that one unit
43
- - **The parent does NOT read the unit's source files before delegating** (avoid the implicit-read trap — the whole point of fan-out is to keep large source bodies out of the parent's context)
43
+ - **The parent does not read the unit's source files before delegating** (avoid the implicit-read trap — the whole point of fan-out is to keep large source bodies out of the parent's context)
44
44
 
45
45
  3. **Per-unit analysis the subagent performs (scaled by size-aware strategy):**
46
46
 
@@ -66,7 +66,7 @@ DO NOT BE LAZY — For EACH qualifying unit, delegate deep analysis to a subagen
66
66
  - Script/asset presence: check for `scripts/`, `bin/`, `assets/`, `templates/` directories and files matching detection signals in `{heuristicsFile}`
67
67
  - Analysis strategy used and coverage confidence
68
68
 
69
- 4. **Subagent return contract.** Each subagent returns ONLY this JSON object — no prose, no commentary, no markdown fences:
69
+ 4. **Subagent return contract.** Each subagent returns only this JSON object — no prose, no commentary, no markdown fences:
70
70
 
71
71
  ```json
72
72
  {
@@ -129,12 +129,7 @@ Identify cross-unit integration patterns:
129
129
 
130
130
  ### 5. Flag Stack Skill Candidates
131
131
 
132
- Using rules from {heuristicsFile}, check for stack skill indicators:
133
-
134
- 1. **Co-import frequency:** Two or more units imported together in 3+ files
135
- 2. **Integration adapter:** A unit exists primarily to bridge two other units
136
- 3. **Shared state:** Multiple units read/write to the same data store
137
- 4. **Orchestration layer:** A unit coordinates calls across multiple other units
132
+ Check each of the four stack-skill indicators defined in {heuristicsFile}'s Stack Skill Candidate Detection section — co-import frequency, integration adapter, shared state, orchestration layer — against the units.
138
133
 
139
134
  **For each candidate, document:**
140
135
  - Units involved
@@ -197,12 +192,5 @@ Display: "**Select:** [C] Continue to Recommendations | [D] Discover Additional
197
192
  - IF D: Accept a new repo path/URL from the user. Run a lightweight scan (directory structure + manifest detection from step 02) and classify (unit identification from step 03) for the new source only. Merge results into the existing report — append new units to the unit list, update `project_paths[]` in frontmatter. Then redisplay this step's export mapping for the new units before returning to the menu.
198
193
  - IF Any other: help user, then [Redisplay Menu Options](#8-present-menu-options)
199
194
 
200
- #### EXECUTION RULES:
201
-
202
- - ALWAYS halt and wait for user input after presenting menu
203
- - ONLY proceed to next step when user selects 'C'
204
-
205
- ## CRITICAL STEP COMPLETION NOTE
206
-
207
- ONLY WHEN both the Export Map and Integration Points sections have been appended to {outputFile} with complete findings, and frontmatter stepsCompleted and stack_skill_candidates have been updated, will you load and read fully {nextStepFile} to begin recommendations.
195
+ **GATE [default: C]** — present the menu and wait for the user's choice. If `{headless_mode}`: auto-proceed with [C] Continue past export/integration findings, log: "headless: auto-continue past integration analysis".
208
196
 
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  nextStepFile: 'generate-briefs.md'
3
3
  outputFile: '{forge_data_folder}/analyze-source-report-{project_name}.md'
4
- schemaFile: 'assets/skill-brief-schema.md'
4
+ schemaFile: '{briefSchemaPath}'
5
5
  advancedElicitationSkill: '/bmad-advanced-elicitation'
6
6
  partyModeSkill: '/bmad-party-mode'
7
7
  ---
@@ -38,7 +38,7 @@ Load {schemaFile} for reference on what skill-brief.yaml requires (so recommenda
38
38
 
39
39
  ### 2. Build Recommendation Cards
40
40
 
41
- For EACH qualifying unit, prepare a recommendation card:
41
+ For each qualifying unit, prepare a recommendation card:
42
42
 
43
43
  ```
44
44
  **Unit: {name}**
@@ -167,18 +167,8 @@ Display: "**Select an Option:** [A] Advanced Elicitation [P] Party Mode [D] Disc
167
167
  - IF P: Invoke {partyModeSkill}, and when finished redisplay the menu
168
168
  - IF D: Accept a new repo path/URL from the user. Run a lightweight scan + classify (subset of steps 02-03) for the new source only. Merge new units into the existing report and update `project_paths[]` in frontmatter. Run export mapping for the new units (same logic as step 04 section 2). Generate recommendation cards for the new units and present them for confirmation. Then redisplay this menu.
169
169
  - IF C: Save recommendations to {outputFile}, update frontmatter, then load, read entire file, then execute {nextStepFile}
170
- - IF X: HARD HALT with exit code 6 (`user-cancelled`). Emit the `SKF_ANALYZE_RESULT_JSON` envelope on stderr with `status: "error"`, `halt_reason: "user-cancelled"`, and counts/paths reflecting state at cancellation
170
+ - IF X: HARD HALT with exit code 6 (`user-cancelled`). Emit the error envelope on stderr with `halt_reason: "user-cancelled"` and counts/paths reflecting state at cancellation (shape in `references/headless-contract.md`)
171
171
  - IF Any other comments or queries: help user respond then [Redisplay Menu Options](#8-present-menu-options)
172
172
 
173
- #### EXECUTION RULES:
174
-
175
- - ALWAYS halt and wait for user input after presenting menu
176
- - **GATE [default: C]** — If `{headless_mode}`: accept all recommendations and auto-proceed, log: "headless: auto-accept all recommendations"
177
- - ONLY proceed to next step when user selects 'C'
178
- - After other menu items execution, return to this menu
179
- - User can chat or ask questions — always respond and then redisplay menu
180
-
181
- ## CRITICAL STEP COMPLETION NOTE
182
-
183
- ONLY WHEN all units have explicit user decisions (Y/N/M), the confirmed_units list is finalized in frontmatter, and the user has given final confirmation, will you load and read fully {nextStepFile} to begin brief generation.
173
+ **GATE [default: C]** — present the menu and wait for the user's choice. If `{headless_mode}`: accept all recommendations and auto-proceed, log: "headless: auto-accept all recommendations".
184
174
 
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  nextStepFile: 'identify-units.md'
3
3
  outputFile: '{forge_data_folder}/analyze-source-report-{project_name}.md'
4
- heuristicsFile: 'references/unit-detection-heuristics.md'
4
+ heuristicsFile: '{unitDetectionHeuristicsPath}'
5
5
  scanManifestsProbeOrder:
6
6
  - '{project-root}/_bmad/skf/shared/scripts/skf-scan-manifests.py'
7
7
  - '{project-root}/src/shared/scripts/skf-scan-manifests.py'
@@ -149,16 +149,8 @@ Display: "**Select:** [C] Continue to Unit Identification | [X] Cancel and exit"
149
149
  #### Menu Handling Logic:
150
150
 
151
151
  - IF C: Save scan results to {outputFile}, update frontmatter, then load, read entire file, then execute {nextStepFile}
152
- - IF X: HARD HALT with exit code 6 (`user-cancelled`). Emit the `SKF_ANALYZE_RESULT_JSON` envelope on stderr with `status: "error"`, `halt_reason: "user-cancelled"`, and counts/paths reflecting state at cancellation
152
+ - IF X: HARD HALT with exit code 6 (`user-cancelled`). Emit the error envelope on stderr with `halt_reason: "user-cancelled"` and counts/paths reflecting state at cancellation (shape in `references/headless-contract.md`)
153
153
  - IF Any other: help user, then [Redisplay Menu Options](#7-present-menu-options)
154
154
 
155
- #### EXECUTION RULES:
156
-
157
- - ALWAYS halt and wait for user input after presenting menu
158
- - **GATE [default: C]** — If `{headless_mode}`: auto-proceed with [C] Continue, log: "headless: auto-continue past scan results"
159
- - ONLY proceed to next step when user selects 'C'
160
-
161
- ## CRITICAL STEP COMPLETION NOTE
162
-
163
- ONLY WHEN the Project Scan section has been appended to {outputFile} with complete boundary, manifest, and entry point catalogs, and frontmatter stepsCompleted has been updated, will you load and read fully {nextStepFile} to begin unit identification.
155
+ **GATE [default: C]** — present the menu and wait for the user's choice. If `{headless_mode}`: auto-proceed with [C] Continue, log: "headless: auto-continue past scan results".
164
156
 
@@ -19,9 +19,6 @@ detectLanguageProbeOrder:
19
19
  languageCorporaProbeOrder:
20
20
  - '{project-root}/_bmad/skf/shared/scripts/skf-language-corpora.py'
21
21
  - '{project-root}/src/shared/scripts/skf-language-corpora.py'
22
- writeSkillBriefProbeOrder:
23
- - '{project-root}/_bmad/skf/shared/scripts/skf-write-skill-brief.py'
24
- - '{project-root}/src/shared/scripts/skf-write-skill-brief.py'
25
22
  ---
26
23
 
27
24
  <!-- Config: communicate in {communication_language}. -->
@@ -53,7 +50,7 @@ Apply the following heuristic to classify the input:
53
50
  | `github.com/{owner}/{repo}` (with or without `.git` suffix, with or without scheme prefix) | GitHub repo | §1 (standard auto-scope) |
54
51
  | `gitlab.com/...`, `bitbucket.org/...` | Git hosting | §1 (standard auto-scope) |
55
52
  | Starts with `/`, `./`, `~/`, or `~` | Local filesystem path | §1 (standard auto-scope) |
56
- | Any other `https://` or `http://` URL | Documentation URL | §0a (docs-only) |
53
+ | Any other `https://` or `http://` URL | Documentation URL | `references/auto-docs-only.md` (docs-only, via §0c) |
57
54
  | Anything else (SSH URLs, `git://`, bare hostnames, etc.) | Unclassified | §1 (standard auto-scope) |
58
55
 
59
56
  Store the classification result (documentation URL vs. repo/local/other). For all input types, continue to §0b (Pin Resolution).
@@ -77,13 +74,10 @@ uv run {validatePinsHelper} --repo-url {project_path} --pin {pin_value}
77
74
  Handle exit codes:
78
75
 
79
76
  - **Exit 0** (`status: "valid"`): Store `{pinned_ref}` = `resolved_ref`, `{pinned_ref_type}` = `ref_type`, `{pinned_version}` = `version`. Continue to §0c.
80
- - **Exit 1** (`status: "invalid"`): HARD HALT with exit code 3 (`resolution-failure`). Emit error: `"Version pin '{pin_value}' not found in {project_path}. Available matches: {suggestions}. Use a valid tag, branch, or omit --pin for latest."` Emit error envelope:
81
- ```
82
- SKF_ANALYZE_RESULT_JSON: {"status":"error","report_path":null,"brief_paths":[],"unit_counts":{"confirmed":0,"skipped":0,"maybe":0},"exit_code":3,"halt_reason":"pin-invalid","mode":"auto"}
83
- ```
84
- - **Exit 2** (error): HARD HALT with exit code 3 (`resolution-failure`). Emit error envelope with `halt_reason: "resolution-failure"`.
77
+ - **Exit 1** (`status: "invalid"`): HARD HALT with exit code 3 (`resolution-failure`). Emit error: `"Version pin '{pin_value}' not found in {project_path}. Available matches: {suggestions}. Use a valid tag, branch, or omit --pin for latest."` Emit the error envelope (shape in `references/headless-contract.md`) with `exit_code: 3`, `halt_reason: "pin-invalid"`, `mode: "auto"`.
78
+ - **Exit 2** (error): HARD HALT with exit code 3 (`resolution-failure`). Emit the error envelope with `halt_reason: "resolution-failure"`.
85
79
 
86
- **For repo URLs when `--pin` is NOT provided (default):**
80
+ **For repo URLs when `--pin` is not provided (default):**
87
81
 
88
82
  Using the same `{validatePinsHelper}` resolved above:
89
83
 
@@ -105,32 +99,35 @@ This section checks for existing skills matching the target before proceeding. I
105
99
 
106
100
  **Resolve `{skillInventoryHelper}`** from `{skillInventoryProbeOrder}`; first existing path wins; HALT if neither resolves.
107
101
 
102
+ Pass the target (`{project_path}`) so the helper computes the coexistence match set for you — do not re-match by hand:
103
+
108
104
  ```bash
109
- uv run {skillInventoryHelper} {skills_output_folder}
105
+ uv run {skillInventoryHelper} {skills_output_folder} --match-target {project_path}
110
106
  ```
111
107
 
112
- Parse the JSON output. If the exit code is non-zero or the `skills` array is empty, skip coexistence detection silently (no existing skills to conflict with) and continue to the next section: §0a for documentation URLs, §1 for all other input types.
108
+ Parse the JSON output. If the exit code is non-zero or the `skills` array is empty, skip coexistence detection silently (no existing skills to conflict with) and continue: load, read fully, then execute `references/auto-docs-only.md` for documentation URLs; §1 for all other input types.
113
109
 
114
- **2. Match target against existing skills:**
110
+ **2. Read the match set:**
115
111
 
116
- For each skill in the inventory, check two match conditions (either triggers a hit):
112
+ The helper already performed the match deterministically — scheme / trailing-`.git` / trailing-slash normalization, kebab expected-name derivation (§6 repo/package name, doc hostname per `references/auto-docs-only.md`), and case-insensitive comparison of both the normalized `source_repo` (URL match) and the derived name (name match). Read the top-level **`matches[]`** array from the JSON; do not normalize, derive, or compare anything in the prompt. Each entry is:
117
113
 
118
- - **URL match:** Normalize both the target URL/path and the skill's `metadata.source_repo` — strip scheme (`http://`, `https://`), strip trailing `.git`, strip trailing `/`, compare case-insensitively. A match on the normalized values is a hit.
119
- - **Name match:** Derive the expected skill name from the target (same logic as §6 for repo URLs, §0a for doc URLs — kebab-case from the project/domain name), then compare against each skill's `name`.
114
+ ```json
115
+ { "name": "...", "active_version": "...", "source_repo": "...", "active_path": "...", "match_reason": "url" | "name" | "both" }
116
+ ```
120
117
 
121
- **3. If zero matches:**
118
+ **3. If `matches[]` is empty:**
122
119
 
123
- Complete silently. Continue to §0a for documentation URLs, §1 for all other input types. No user output.
120
+ Complete silently. Continue: execute `references/auto-docs-only.md` for documentation URLs; §1 for all other input types. No user output.
124
121
 
125
- **4. If one or more matches — coexistence gate:**
122
+ **4. If `matches[]` has one or more entries — coexistence gate:**
126
123
 
127
- Present the user with the coexistence decision:
124
+ Present the user with the coexistence decision, one bullet per `matches[]` entry (`{skill_name}` = `matches[].name`, `{version}` = `matches[].active_version`, `{source_repo}` = `matches[].source_repo`):
128
125
 
129
126
  ```
130
127
  ⚠️ Existing skill(s) found for {target_name}:
131
128
 
132
129
  • {skill_name} (v{version}) — source: {source_repo}
133
- [repeat for each match]
130
+ [repeat for each entry in matches[]]
134
131
 
135
132
  Actions:
136
133
  [A]longside — Create a new wiki skill with "-wiki" suffix (existing skill untouched)
@@ -144,127 +141,21 @@ In headless mode (`{headless_mode}` is true): auto-select `[A]longside` and log:
144
141
 
145
142
  **5. Handle user selection:**
146
143
 
147
- - **[A]longside:** Set `{coexistence_suffix}` to `-wiki`. Continue to §0a for documentation URLs, §1 for all other input types. The existing skill is untouched.
144
+ - **[A]longside:** Set `{coexistence_suffix}` to `-wiki`. Continue: execute `references/auto-docs-only.md` for documentation URLs; §1 for all other input types. The existing skill is untouched.
148
145
 
149
- - **[M]erge:** If multiple skills match, prompt the user to select which one to merge into before proceeding. Emit a redirect envelope signaling the forger to route to the US workflow for the selected skill:
146
+ - **[M]erge:** If `matches[]` has more than one entry, prompt the user to select which one to merge into before proceeding. Read `{matched_skill_name}` = the selected entry's `matches[].name` and `{matched_active_path}` = its `matches[].active_path`. Emit a redirect envelope signaling the forger to route to the US workflow for the selected skill:
150
147
  ```
151
148
  SKF_ANALYZE_RESULT_JSON: {"status":"redirect","redirect_to":"US","skill_name":"{matched_skill_name}","skill_path":"{matched_active_path}","exit_code":0,"halt_reason":null,"mode":"auto","coexistence":"merge"}
152
149
  ```
153
150
  Write the result contract per `shared/references/output-contract-schema.md` with `status: "redirect"`.
154
- Chain to {nextStepFile} (health-check.md). **STOP HERE — do not proceed to §0a or §1.**
151
+ Chain to {nextStepFile} (health-check.md). **STOP HERE — do not proceed to the docs-only sub-flow or §1.**
155
152
 
156
153
  - **[S]kip:** Emit a skip envelope:
157
154
  ```
158
155
  SKF_ANALYZE_RESULT_JSON: {"status":"skipped","report_path":null,"brief_paths":[],"unit_counts":{"confirmed":0,"skipped":1,"maybe":0},"exit_code":0,"halt_reason":null,"mode":"auto","coexistence":"skip","skipped_reason":"Existing skill for {matched_skill_name}"}
159
156
  ```
160
157
  Write the result contract with `status: "skipped"`.
161
- Chain to {nextStepFile} (health-check.md). **STOP HERE — do not proceed to §0a or §1.**
162
-
163
- ### 0a. Docs-Only Short-Circuit
164
-
165
- This section handles documentation URLs that are not GitHub repos or local paths. It validates the URL, writes a minimal brief and analysis report, emits the envelope, and chains directly to health-check — skipping §1 through §11 entirely.
166
-
167
- **1. Validate URL reachability:**
168
-
169
- ```bash
170
- curl -sI --max-time 5 {url}
171
- ```
172
-
173
- - On **2xx/3xx** response: URL is reachable. Continue.
174
- - On **4xx/5xx**, DNS failure, or timeout: HARD HALT with exit code 3 (`resolution-failure`). Emit error message: `"Documentation URL unreachable: {url} — {status or error}"`. Emit error envelope:
175
- ```
176
- SKF_ANALYZE_RESULT_JSON: {"status":"error","report_path":null,"brief_paths":[],"unit_counts":{"confirmed":0,"skipped":0,"maybe":0},"exit_code":3,"halt_reason":"path-invalid","mode":"auto","source_type":"docs-only"}
177
- ```
178
-
179
- **2. Derive skill name from URL domain:**
180
-
181
- Extract the hostname from the URL (e.g., `docs.example.com` from `https://docs.example.com/guide/intro`), convert to kebab-case (replace `.` with `-`), yielding e.g. `docs-example-com`. If `{coexistence_suffix}` is non-empty, append it to the skill name (e.g., `docs-example-com-wiki`).
182
-
183
- **3. Write analysis report:**
184
-
185
- Update {outputFile} with docs-only results.
186
-
187
- **Update frontmatter:**
188
- ```yaml
189
- stepsCompleted: ['init', 'auto-scope']
190
- lastStep: 'auto-scope'
191
- source_type: docs-only
192
- confirmed_units:
193
- - name: '{skill_name}'
194
- shape: 'docs-only'
195
- confidence: 1.0
196
- export_count: 0
197
- package_count: 0
198
- ```
199
-
200
- **Append body section:**
201
- ```markdown
202
- ## Auto-Scope Analysis
203
-
204
- **Mode:** auto (docs-only short-circuit)
205
- **Source Type:** docs-only
206
- **Documentation URL:** {url}
207
- **Skill Name:** {skill_name}
208
- ```
209
-
210
- **4. Write skill brief via canonical writer:**
211
-
212
- **Resolve `{writeSkillBriefHelper}`** from `{writeSkillBriefProbeOrder}`; first existing path wins; HALT if neither resolves.
213
-
214
- Create directory `{forge_data_folder}/{skill_name}/` if it does not exist.
215
-
216
- Pipe the flat context JSON below into the resolved writer with the `--from-flat` flag:
217
-
218
- ```json
219
- {
220
- "name": "{skill_name}",
221
- "target_version": null,
222
- "detected_version": null,
223
- "source_type": "docs-only",
224
- "source_repo": "{url}",
225
- "language": "documentation",
226
- "description": "Skill created from documentation at {url}",
227
- "forge_tier": "{forge_tier}",
228
- "created": "{current_date}",
229
- "created_by": "{user_name}",
230
- "scope_type": "docs-only",
231
- "scope_include": [],
232
- "scope_exclude": [],
233
- "scope_notes": "Docs-only skill created from documentation URL",
234
- "scope_rationale": null,
235
- "scope_tier_a_include": null,
236
- "scope_amendments": null,
237
- "doc_urls": [{"url": "{url}", "label": "Primary Documentation"}],
238
- "scripts_intent": null,
239
- "assets_intent": null,
240
- "source_authority": "community",
241
- "target_ref": null,
242
- "source_ref": null,
243
- "version_resolved": "1.0.0"
244
- }
245
- ```
246
-
247
- ```bash
248
- echo '<context-json>' | uv run {writeSkillBriefHelper} write --target {forge_data_folder}/{skill_name}/skill-brief.yaml --from-flat
249
- ```
250
-
251
- **5. Emit success envelope:**
252
-
253
- ```
254
- SKF_ANALYZE_RESULT_JSON: {"status":"success","report_path":"{outputFile_path}","brief_paths":["{brief_path}"],"unit_counts":{"confirmed":1,"skipped":0,"maybe":0},"exit_code":0,"halt_reason":null,"mode":"auto","source_type":"docs-only"}
255
- ```
256
-
257
- If `{coexistence_suffix}` is non-empty (i.e., [A]longside was selected in §0c), include `"coexistence":"alongside"` in the envelope.
258
-
259
- The `source_type` field signals downstream consumers (BS) to skip repo-based enrichment.
260
-
261
- **6. Write result contract** per `shared/references/output-contract-schema.md`: the per-run record and latest copy, same as §10.
262
-
263
- If `{onCompleteCommand}` is non-empty, invoke it now with `--result-path={result_json_path}`.
264
-
265
- **7. Chain to health check:**
266
-
267
- Load, read fully, then execute {nextStepFile} to run the shared workflow health check. **Skip §1 through §11 entirely.**
158
+ Chain to {nextStepFile} (health-check.md). **STOP HERE — do not proceed to the docs-only sub-flow or §1.**
268
159
 
269
160
  ### 1. Load Context
270
161
 
@@ -355,22 +246,13 @@ uv run {shapeDetectHelper} --repo-url <project_path_or_url> \
355
246
 
356
247
  - **Exit 0 (shape classified):** Continue to §3a.
357
248
  - **Exit 1 (unknown shape):** Emit fallback message: "**Auto-scope could not classify this repo — switching to interactive mode.**" Load, read fully, then execute `references/scan-project.md`. **STOP HERE.**
358
- - **Exit 2 (error):** HARD HALT with exit code 3 (`resolution-failure`). Emit the error envelope:
359
- ```
360
- SKF_ANALYZE_RESULT_JSON: {"status":"error","report_path":null,"brief_paths":[],"unit_counts":{"confirmed":0,"skipped":0,"maybe":0},"exit_code":3,"halt_reason":"resolution-failure","mode":"auto"}
361
- ```
249
+ - **Exit 2 (error):** HARD HALT with exit code 3 (`resolution-failure`). Emit the error envelope (shape in `references/headless-contract.md`) with `exit_code: 3`, `halt_reason: "resolution-failure"`, `mode: "auto"`.
362
250
 
363
251
  ### 3a. Check Decomposition Thresholds
364
252
 
365
253
  Evaluate the shape detection output to determine whether this **monorepo** should be decomposed into multiple skills.
366
254
 
367
- **Threshold condition:**
368
-
369
- | Threshold | Condition | Signal |
370
- |-----------|-----------|--------|
371
- | Monorepo / multi-package | `package_count > 3` | 4+ packages — a decomposition **candidate** (empirically validated: fires on real 15-, 38-, and 442-package workspaces) |
372
-
373
- > A *single* package with a large API surface is **not** a decomposition trigger — it produces one cohesive skill that `skf-create-skill`'s auto-shard step splits into `references/` shards at the 400-line ceiling (a single library is one install / one import namespace; fragmenting it by source directory loses cohesion). Decomposition is for genuinely multi-package monorepos only.
255
+ Apply the **Decomposition Thresholds** ladder from `step-shape-detect.md` (loaded at §1). A *single* package with a large API surface is **not** a trigger — only a genuine multi-package monorepo is.
374
256
 
375
257
  **Decision:**
376
258
 
@@ -400,28 +282,19 @@ If genuinely unsure, **prefer merge** — a too-broad single skill is recoverabl
400
282
 
401
283
  ### 4. Map Shape to Scope
402
284
 
403
- Apply the shape→scope.type mapping:
404
-
405
- | Shape (from skf-shape-detect.py) | scope.type | Condition |
406
- |----------------------------------|------------|-----------|
407
- | `library-API` | `full-library` | export_count ≤ 200 |
408
- | `library-API` | `public-api` | export_count > 200 |
409
- | `reference-app` | `reference-app` | — |
410
- | `language-reference` | `full-library` | — |
411
- | `stack-compose` | `full-library` | Decomposition candidate when `package_count > 3` — cohesion-checked at §3b |
285
+ Apply the canonical **Shape → Scope Type Mapping** table from `step-shape-detect.md` (loaded at §1) — the single source of truth for this ladder (the `export_count > 200 public-api` split, the `language-reference` corpora caveat, and the `stack-compose` decomposition note).
412
286
 
413
287
  ### 5. Generate Include/Exclude Patterns
414
288
 
415
289
  Generate `scope.include` and `scope.exclude` arrays from the detected language and project structure.
416
290
 
417
- **Detect primary language** from manifest type (the same set shape detection classifies):
418
- - `package.json` → TypeScript/JavaScript
419
- - `pyproject.toml` → Python
420
- - `Cargo.toml` Rust
421
- - `go.mod` → Go
422
- - `pom.xml` → Java
423
- - `build.gradle` / `build.gradle.kts` Java or Kotlin (Kotlin when a `src/main/kotlin/` tree exists)
424
- - `Package.swift` → Swift
291
+ **Detect the primary language once, deterministically**, via the shared helper — the single source of truth for the manifest→language rule table (§6b resolves the same helper; do not restate the table in prose, where it drifts from the script). **Resolve `{detectLanguageHelper}`** from `{detectLanguageProbeOrder}` (first existing path wins). Pipe the §2 supported-manifest paths (and, for a manifest-less toolchain, the harvested `<tree_paths>`) as the file tree:
292
+
293
+ ```bash
294
+ echo '{"tree": [<§2 supported manifest paths + harvested tree paths>]}' | uv run {detectLanguageHelper}
295
+ ```
296
+
297
+ Read `.language` as `{detected_language}` (and `.confidence`) — the helper owns the `tsconfig.json` JS-vs-TS and `build.gradle` Java-vs-Kotlin disambiguation. §6 reuses `{detected_language}` for the brief's `language` field: detect once.
425
298
 
426
299
  **Default patterns (adjust based on actual project structure):**
427
300
 
@@ -450,14 +323,7 @@ scope:
450
323
 
451
324
  Determine the skill name from the project name or package name (kebab-case, lowercase). Use the manifest `name` field if available, otherwise derive from the project directory name. If `{coexistence_suffix}` is non-empty, append it to the skill name.
452
325
 
453
- Detect the primary language from the manifest ecosystem:
454
- - `npm` → `typescript` (or `javascript` if no `.ts` files in includes)
455
- - `python` → `python`
456
- - `rust` → `rust`
457
- - `go` → `go`
458
- - `maven` → `java`
459
- - `gradle` → `java` (or `kotlin` when a `src/main/kotlin/` tree exists)
460
- - `swift` → `swift`
326
+ For the brief's `language` field, **reuse `{detected_language}` from §5** — do not re-detect (the §5 helper already resolved js-vs-ts from `tsconfig.json` and Java-vs-Kotlin from the tree).
461
327
 
462
328
  ### 6b. Seed Companion Corpora (whole-language references only)
463
329
 
@@ -467,7 +333,7 @@ A whole-language skill's value is in the language's **prose** — the guide/Book
467
333
 
468
334
  **Resolve `{detectLanguageHelper}`** from `{detectLanguageProbeOrder}` and **`{languageCorporaHelper}`** from `{languageCorporaProbeOrder}` (first existing path wins).
469
335
 
470
- 1. **Derive the corpus language key `{corpus_language}`.** Prefer the §6 manifest language when non-empty. Otherwise — a manifest-less toolchain such as CPython or Ruby — resolve it from the file paths harvested in §2:
336
+ 1. **Derive the corpus language key `{corpus_language}`.** Prefer `{detected_language}` (from §5) when non-empty. Otherwise — a manifest-less toolchain such as CPython or Ruby — resolve it from the file paths harvested in §2:
471
337
  ```bash
472
338
  echo '{"tree": [<harvested §2 file paths>]}' | uv run {detectLanguageHelper}
473
339
  ```
@@ -514,7 +380,7 @@ After building all N scopes, continue to §7 with the full set of boundaries.
514
380
 
515
381
  ### 7. Write Analysis Report
516
382
 
517
- Update {outputFile} with auto-scope results.
383
+ Update {outputFile} with auto-scope results. If the write fails, HARD HALT with exit code 4 (`write-failed`) per `references/headless-contract.md`.
518
384
 
519
385
  **Update frontmatter:**
520
386
  ```yaml
@@ -596,9 +462,9 @@ For multi-scope (N > 1):
596
462
 
597
463
  **For each confirmed unit** (1 for single-scope, N for decomposition):
598
464
 
599
- Create directory `{forge_data_folder}/{skill_name}/` if it does not exist.
465
+ Create directory `{forge_data_folder}/{skill_name}/` if it does not exist. If a brief write fails, HARD HALT with exit code 4 (`write-failed`) per `references/headless-contract.md`.
600
466
 
601
- Write `{forge_data_folder}/{skill_name}/skill-brief.yaml` conforming to the skill-brief schema (`assets/skill-brief-schema.md`):
467
+ Write `{forge_data_folder}/{skill_name}/skill-brief.yaml` conforming to the skill-brief schema (`{briefSchemaPath}`):
602
468
 
603
469
  ```yaml
604
470
  name: '{skill_name}'
@@ -636,7 +502,7 @@ Loop over all N boundaries. For each boundary:
636
502
  - `description` references the parent project and boundary role (e.g., "Core library package of the my-monorepo project, providing...")
637
503
  - All N briefs share the same `version`, `source_repo`, `language`, `forge_tier`, `created`, `created_by` values as the parent project
638
504
 
639
- **Version detection:** Attempt to auto-detect the source version per the version detection rules in `assets/skill-brief-schema.md`. Fall back to `1.0.0` if detection fails.
505
+ **Version detection:** Attempt to auto-detect the source version per the version detection rules in `{briefSchemaPath}`. Fall back to `1.0.0` if detection fails.
640
506
 
641
507
  **Pin data (from §0b):** When `{pinned_ref}` is non-null, enrich the brief with pin data:
642
508
 
@@ -646,7 +512,7 @@ Loop over all N boundaries. For each boundary:
646
512
 
647
513
  When `{pinned_ref}` is null (no pin, no releases): leave `target_version` = null, `target_ref` = null — existing version detection applies unchanged.
648
514
 
649
- In the docs-only path (§0a), `--pin` is ignored (already skipped at §0b). No changes to §0a.
515
+ In the docs-only path (`references/auto-docs-only.md`), `--pin` is ignored (already skipped at §0b). No changes to that path.
650
516
 
651
517
  ### 9. Emit Result Envelope
652
518
 
@@ -656,22 +522,18 @@ Emit the `SKF_ANALYZE_RESULT_JSON` envelope on stdout:
656
522
  SKF_ANALYZE_RESULT_JSON: {"status":"success","report_path":"{outputFile_path}","brief_paths":["{brief_path_1}","{brief_path_2}",...,"{brief_path_N}"],"unit_counts":{"confirmed":N,"skipped":0,"maybe":0},"exit_code":0,"halt_reason":null,"mode":"auto"}
657
523
  ```
658
524
 
659
- `brief_paths` contains N paths (one per confirmed unit). `unit_counts.confirmed` is N. The envelope JSON format is structurally unchanged — `brief_paths` was already an array and `unit_counts.confirmed` was already a number. No breaking change for downstream consumers.
525
+ `brief_paths` contains N paths (one per confirmed unit). `unit_counts.confirmed` is N.
660
526
 
661
527
  If `{coexistence_suffix}` is non-empty (i.e., [A]longside was selected in §0c), include `"coexistence":"alongside"` in the envelope.
662
528
 
663
- When `{pinned_ref}` is non-null, include `"pinned_ref":"{pinned_ref}"` and `"pinned_version":"{pinned_version}"` in the envelope. These flow downstream to BS/CS for provenance recording. When `{pinned_ref}` is null, omit these fields (backward-compatible — existing consumers don't expect them).
529
+ When `{pinned_ref}` is non-null, include `"pinned_ref":"{pinned_ref}"` and `"pinned_version":"{pinned_version}"` in the envelope. These flow downstream to BS/CS for provenance recording. When `{pinned_ref}` is null, omit these fields.
664
530
 
665
531
  ### 10. Write Result Contract
666
532
 
667
- Write the result contract per `shared/references/output-contract-schema.md`: the per-run record at `{forge_data_folder}/analyze-source-result-{YYYYMMDD-HHmmss}.json` (UTC timestamp, resolution to seconds) and a copy at `{forge_data_folder}/analyze-source-result-latest.json`. `outputs` lists all N brief paths and `summary` includes the brief count N.
533
+ Write the result contract per `shared/references/output-contract-schema.md`: the per-run record at `{forge_data_folder}/analyze-source-result-{YYYYMMDD-HHmmss}.json` (UTC timestamp, resolution to seconds) and a copy at `{forge_data_folder}/analyze-source-result-latest.json`. `outputs` lists all N brief paths and `summary` includes the brief count N. If the per-run record cannot be written, HARD HALT with exit code 4 (`write-failed`) per `references/headless-contract.md`.
668
534
 
669
535
  If `{onCompleteCommand}` is non-empty, invoke it now with `--result-path={result_json_path}`.
670
536
 
671
537
  ### 11. Chain to Health Check
672
538
 
673
539
  Load, read fully, then execute {nextStepFile} to run the shared workflow health check.
674
-
675
- ## CRITICAL STEP COMPLETION NOTE
676
-
677
- ONLY WHEN the analysis report has been updated, the skill-brief.yaml written and validated, the result envelope emitted, and the result contract saved will you load and read fully {nextStepFile} to begin the health check.
@@ -77,7 +77,7 @@ Rules for identifying discrete skillable units within a project. A "skillable un
77
77
  - Scope type: inherits from the dominant constituent (typically `full-library` or `specific-modules`)
78
78
 
79
79
  **Detection heuristic (apply after initial classification, before user confirmation):**
80
- 1. Among the qualifying units, find groups of ≥2 boundaries where EITHER:
80
+ 1. Among the qualifying units, find groups of ≥2 boundaries where either:
81
81
  - **Mutual hard dependency:** Every constituent imports from at least one other constituent in the group, AND no constituent's public API is self-contained (removing any one breaks the others)
82
82
  - **Shared integration surface:** Constituents share types/traits defined in one constituent but consumed by all others, AND the consuming constituents have no independent barrel (their value depends on the shared definitions)
83
83
  2. For each detected group, propose merging into a single composite unit:
@@ -88,7 +88,7 @@ Rules for identifying discrete skillable units within a project. A "skillable un
88
88
 
89
89
  ## Disqualification Rules
90
90
 
91
- Do NOT recommend as a skillable unit if:
91
+ Do not recommend a boundary as a skillable unit when:
92
92
 
93
93
  1. **Too small**: Fewer than 3 source files or 100 lines of code
94
94
  2. **Generated code**: Auto-generated files (protobuf, GraphQL codegen, etc.)