bmad-module-skill-forge 2.1.0 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (435) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/README.md +51 -49
  3. package/docs/404.md +10 -8
  4. package/docs/_data/pinned.yaml +22 -13
  5. package/docs/_internal/STABILITY.md +58 -35
  6. package/docs/agents.md +39 -53
  7. package/docs/architecture.md +65 -51
  8. package/docs/bmad-synergy.md +53 -51
  9. package/docs/campaign.md +127 -75
  10. package/docs/concepts.md +34 -28
  11. package/docs/examples.md +70 -68
  12. package/docs/forge-auto.md +34 -31
  13. package/docs/getting-started.md +118 -57
  14. package/docs/how-it-works.md +25 -21
  15. package/docs/index.md +15 -15
  16. package/docs/skill-model.md +70 -59
  17. package/docs/troubleshooting.md +135 -18
  18. package/docs/verifying-a-skill.md +83 -57
  19. package/docs/why-skf.md +24 -22
  20. package/docs/workflows.md +274 -110
  21. package/package.json +18 -10
  22. package/src/forger/preferences.yaml +8 -1
  23. package/src/knowledge/agentskills-spec.md +2 -0
  24. package/src/knowledge/ccc-bridge.md +40 -24
  25. package/src/knowledge/confidence-tiers.md +9 -5
  26. package/src/knowledge/overview.md +3 -3
  27. package/src/knowledge/progressive-capability.md +8 -8
  28. package/src/knowledge/provenance-tracking.md +9 -5
  29. package/src/knowledge/qmd-registry.md +2 -2
  30. package/src/knowledge/skf-knowledge-index.csv +2 -2
  31. package/src/knowledge/skill-lifecycle.md +18 -11
  32. package/src/knowledge/split-body-strategy.md +0 -3
  33. package/src/knowledge/tool-resolution.md +4 -2
  34. package/src/knowledge/version-paths.md +101 -15
  35. package/src/module-help.csv +3 -3
  36. package/src/module.yaml +10 -0
  37. package/src/shared/data/ast-grep-recipes.yaml +608 -0
  38. package/src/shared/data/ide-context-files.json +30 -0
  39. package/src/shared/health-check.md +32 -12
  40. package/src/shared/references/description-guard-protocol.md +14 -9
  41. package/src/shared/references/feasibility-report-schema.md +19 -13
  42. package/src/shared/references/headless-gate-convention.md +55 -3
  43. package/src/shared/references/output-contract-schema.md +19 -8
  44. package/src/shared/references/pipeline-contracts.md +94 -29
  45. package/src/shared/references/tessl-review.md +77 -0
  46. package/src/shared/scripts/schemas/skf-analyze-result-envelope.v1.json +194 -0
  47. package/src/shared/scripts/schemas/skf-audit-result-envelope.v1.json +192 -0
  48. package/src/shared/scripts/schemas/skf-brief-result-envelope.v1.json +32 -4
  49. package/src/shared/scripts/schemas/skf-campaign-result-envelope.v1.json +174 -0
  50. package/src/shared/scripts/schemas/skf-create-skill-result-envelope.v1.json +284 -0
  51. package/src/shared/scripts/schemas/skf-drop-skill-result-envelope.v1.json +164 -0
  52. package/src/shared/scripts/schemas/skf-export-result-envelope.v1.json +160 -0
  53. package/src/shared/scripts/schemas/skf-quick-skill-result-envelope.v1.json +261 -0
  54. package/src/shared/scripts/schemas/skf-refine-architecture-result-envelope.v1.json +192 -0
  55. package/src/shared/scripts/schemas/skf-rename-skill-result-envelope.v1.json +179 -0
  56. package/src/shared/scripts/schemas/skf-setup-result-envelope.v1.json +27 -11
  57. package/src/shared/scripts/schemas/skf-stack-result-envelope.v1.json +176 -0
  58. package/src/shared/scripts/schemas/skf-test-result-envelope.v1.json +173 -0
  59. package/src/shared/scripts/schemas/skf-update-result-envelope.v1.json +19 -5
  60. package/src/shared/scripts/schemas/skf-verify-stack-result-envelope.v1.json +180 -0
  61. package/src/shared/scripts/schemas/skill-brief.v1.json +34 -0
  62. package/src/shared/scripts/schemas/workspace-detection.v1.json +1 -1
  63. package/src/shared/scripts/skf-atomic-write.py +30 -14
  64. package/src/shared/scripts/skf-build-change-manifest.py +2203 -24
  65. package/src/shared/scripts/skf-ccc-git-hygiene.py +532 -0
  66. package/src/shared/scripts/skf-check-unit-records.py +184 -0
  67. package/src/shared/scripts/skf-check-workspace-drift.py +538 -9
  68. package/src/shared/scripts/skf-classify-changed-files.py +694 -0
  69. package/src/shared/scripts/skf-comention-pairs.py +1333 -123
  70. package/src/shared/scripts/skf-compare-file-hashes.py +1 -1
  71. package/src/shared/scripts/skf-count-imports.py +1867 -0
  72. package/src/shared/scripts/skf-count-tokens.py +1 -1
  73. package/src/shared/scripts/skf-derive-assembly-shape.py +3 -2
  74. package/src/shared/scripts/skf-description-guard.py +117 -9
  75. package/src/shared/scripts/skf-detect-docs.py +892 -4
  76. package/src/shared/scripts/skf-detect-language.py +486 -107
  77. package/src/shared/scripts/skf-detect-registry.py +887 -0
  78. package/src/shared/scripts/skf-detect-scripts-assets.py +1 -1
  79. package/src/shared/scripts/skf-detect-tools.py +215 -27
  80. package/src/shared/scripts/skf-detect-workspaces.py +506 -30
  81. package/src/shared/scripts/skf-disqualify-candidates.py +821 -182
  82. package/src/shared/scripts/skf-emit-brief-result-envelope.py +69 -191
  83. package/src/shared/scripts/skf-emit-result-envelope.py +1604 -106
  84. package/src/shared/scripts/skf-enumerate-stack-skills.py +986 -117
  85. package/src/shared/scripts/skf-extract-public-api.py +4084 -85
  86. package/src/shared/scripts/skf-extraction-inventory.py +746 -0
  87. package/src/shared/scripts/skf-extraction-snapshot.py +539 -0
  88. package/src/shared/scripts/skf-fetch-temporal.py +674 -0
  89. package/src/shared/scripts/skf-find-cycles.py +97 -29
  90. package/src/shared/scripts/skf-find-test-report.py +476 -0
  91. package/src/shared/scripts/skf-forge-tier-rw.py +444 -203
  92. package/src/shared/scripts/skf-github-fetch.py +365 -0
  93. package/src/shared/scripts/skf-github-probe.py +661 -0
  94. package/src/shared/scripts/skf-hash-content.py +166 -12
  95. package/src/shared/scripts/skf-language-corpora.py +1 -1
  96. package/src/shared/scripts/skf-load-provenance.py +159 -27
  97. package/src/shared/scripts/skf-manifest-ops.py +1 -1
  98. package/src/shared/scripts/skf-merge-ccc-exclusions.py +2307 -223
  99. package/src/shared/scripts/skf-merge-doc-urls.py +1 -1
  100. package/src/shared/scripts/skf-names-present.py +221 -0
  101. package/src/shared/scripts/skf-pair-intersect.py +119 -28
  102. package/src/shared/scripts/skf-parse-gaps.py +1384 -0
  103. package/src/shared/scripts/skf-preapply.py +1 -1
  104. package/src/shared/scripts/skf-preflight.py +161 -27
  105. package/src/shared/scripts/skf-promote-staged.py +430 -0
  106. package/src/shared/scripts/skf-provenance-gap-dispatch.py +39 -7
  107. package/src/shared/scripts/skf-qmd-classify-collections.py +229 -45
  108. package/src/shared/scripts/skf-quick-batch.py +774 -0
  109. package/src/shared/scripts/skf-rebuild-managed-sections.py +972 -88
  110. package/src/shared/scripts/skf-recommend-scope-type.py +323 -156
  111. package/src/shared/scripts/skf-render-metadata-stats.py +156 -12
  112. package/src/shared/scripts/skf-render-quick-metadata.py +132 -28
  113. package/src/shared/scripts/skf-render-stack-metadata.py +976 -0
  114. package/src/shared/scripts/skf-resolve-authoritative-files.py +128 -13
  115. package/src/shared/scripts/skf-resolve-package.py +523 -106
  116. package/src/shared/scripts/skf-rewrite-skill-name.py +433 -47
  117. package/src/shared/scripts/skf-run-lock.py +577 -0
  118. package/src/shared/scripts/skf-scan-manifests.py +998 -57
  119. package/src/shared/scripts/skf-scan-skill-md-structure.py +1341 -37
  120. package/src/shared/scripts/skf-severity-classify.py +712 -108
  121. package/src/shared/scripts/skf-shape-detect.py +298 -204
  122. package/src/shared/scripts/skf-shard-body.py +9 -8
  123. package/src/shared/scripts/skf-skill-inventory.py +2412 -89
  124. package/src/shared/scripts/skf-skills-module.py +472 -0
  125. package/src/shared/scripts/skf-source-tree.py +1796 -0
  126. package/src/shared/scripts/skf-structural-diff.py +670 -119
  127. package/src/shared/scripts/skf-tessl-review.py +706 -0
  128. package/src/shared/scripts/skf-update-active-symlink.py +5 -5
  129. package/src/shared/scripts/skf-update-run-state.py +624 -0
  130. package/src/shared/scripts/skf-validate-brief-inputs.py +92 -29
  131. package/src/shared/scripts/skf-validate-brief-schema.py +4 -1
  132. package/src/shared/scripts/skf-validate-feasibility-report.py +577 -66
  133. package/src/shared/scripts/skf-validate-frontmatter.py +103 -26
  134. package/src/shared/scripts/skf-validate-output.py +712 -64
  135. package/src/shared/scripts/skf-validate-pins.py +1 -1
  136. package/src/shared/scripts/skf-verify-no-trace.py +116 -10
  137. package/src/shared/scripts/skf-verify-provenance-completeness.py +2919 -54
  138. package/src/shared/scripts/skf-write-skill-brief.py +367 -19
  139. package/src/shared/tool-requirements.yaml +201 -0
  140. package/src/skf-analyze-source/SKILL.md +41 -36
  141. package/src/skf-analyze-source/assets/skill-brief-schema.md +7 -8
  142. package/src/skf-analyze-source/customize.toml +36 -24
  143. package/src/skf-analyze-source/references/auto-docs-only.md +58 -20
  144. package/src/skf-analyze-source/references/continue.md +2 -13
  145. package/src/skf-analyze-source/references/discover-additional-source.md +147 -0
  146. package/src/skf-analyze-source/references/generate-briefs.md +121 -55
  147. package/src/skf-analyze-source/references/headless-contract.md +42 -15
  148. package/src/skf-analyze-source/references/identify-units.md +96 -110
  149. package/src/skf-analyze-source/references/init.md +73 -71
  150. package/src/skf-analyze-source/references/map-and-detect.md +123 -105
  151. package/src/skf-analyze-source/references/map-unit-exports.md +68 -0
  152. package/src/skf-analyze-source/references/recommend.md +51 -70
  153. package/src/skf-analyze-source/references/scan-project.md +60 -84
  154. package/src/skf-analyze-source/references/scan-root.md +39 -0
  155. package/src/skf-analyze-source/references/step-auto-scope-coexistence.md +47 -0
  156. package/src/skf-analyze-source/references/step-auto-scope-corpora.md +53 -0
  157. package/src/skf-analyze-source/references/step-auto-scope-split.md +91 -0
  158. package/src/skf-analyze-source/references/step-auto-scope.md +208 -293
  159. package/src/skf-analyze-source/references/step-shape-detect.md +14 -12
  160. package/src/skf-analyze-source/references/unit-detection-heuristics.md +37 -42
  161. package/src/skf-audit-skill/SKILL.md +43 -51
  162. package/src/skf-audit-skill/assets/drift-report-template.md +27 -3
  163. package/src/skf-audit-skill/customize.toml +41 -20
  164. package/src/skf-audit-skill/references/constituent-freshness.md +91 -0
  165. package/src/skf-audit-skill/references/doc-drift.md +141 -0
  166. package/src/skf-audit-skill/references/headless-contract.md +29 -0
  167. package/src/skf-audit-skill/references/init.md +148 -210
  168. package/src/skf-audit-skill/references/re-index.md +96 -108
  169. package/src/skf-audit-skill/references/report.md +96 -33
  170. package/src/skf-audit-skill/references/semantic-diff.md +27 -18
  171. package/src/skf-audit-skill/references/severity-classify.md +79 -65
  172. package/src/skf-audit-skill/references/severity-rules.md +15 -6
  173. package/src/skf-audit-skill/references/structural-diff.md +75 -90
  174. package/src/skf-audit-skill/references/upstream-checkout.md +77 -0
  175. package/src/skf-audit-skill/scripts/render-drift-tables.py +685 -0
  176. package/src/skf-brief-skill/SKILL.md +36 -25
  177. package/src/skf-brief-skill/assets/description-voice-examples.md +1 -1
  178. package/src/skf-brief-skill/assets/scope-templates.md +17 -24
  179. package/src/skf-brief-skill/assets/skill-brief-schema.md +29 -15
  180. package/src/skf-brief-skill/customize.toml +48 -20
  181. package/src/skf-brief-skill/references/analyze-target.md +142 -125
  182. package/src/skf-brief-skill/references/confirm-brief.md +10 -8
  183. package/src/skf-brief-skill/references/draft-checkpoint.md +36 -17
  184. package/src/skf-brief-skill/references/gather-intent-ratify.md +68 -0
  185. package/src/skf-brief-skill/references/gather-intent.md +87 -182
  186. package/src/skf-brief-skill/references/headless-args.md +84 -16
  187. package/src/skf-brief-skill/references/health-check.md +1 -1
  188. package/src/skf-brief-skill/references/invocation-contract.md +18 -13
  189. package/src/skf-brief-skill/references/portfolio-similarity-check.md +1 -1
  190. package/src/skf-brief-skill/references/qmd-collection-registration.md +7 -10
  191. package/src/skf-brief-skill/references/scope-definition.md +123 -47
  192. package/src/skf-brief-skill/references/step-auto-brief.md +24 -80
  193. package/src/skf-brief-skill/references/step-auto-validate.md +20 -121
  194. package/src/skf-brief-skill/references/version-resolution.md +3 -2
  195. package/src/skf-brief-skill/references/write-brief.md +66 -57
  196. package/src/skf-campaign/SKILL.md +31 -34
  197. package/src/skf-campaign/assets/campaign-state-schema.json +25 -4
  198. package/src/skf-campaign/customize.toml +47 -16
  199. package/src/skf-campaign/references/campaign-contracts.md +39 -29
  200. package/src/skf-campaign/references/campaign-directive-spec.md +4 -2
  201. package/src/skf-campaign/references/health-check.md +7 -16
  202. package/src/skf-campaign/references/step-01-setup.md +46 -84
  203. package/src/skf-campaign/references/step-02-strategy.md +31 -30
  204. package/src/skf-campaign/references/step-03-pins.md +26 -18
  205. package/src/skf-campaign/references/step-04-provenance.md +24 -23
  206. package/src/skf-campaign/references/step-05-skill-loop.md +67 -48
  207. package/src/skf-campaign/references/step-06-batch.md +41 -34
  208. package/src/skf-campaign/references/step-07-capstone.md +40 -25
  209. package/src/skf-campaign/references/step-08-verify.md +28 -29
  210. package/src/skf-campaign/references/step-09-refine.md +29 -30
  211. package/src/skf-campaign/references/step-10-export.md +48 -36
  212. package/src/skf-campaign/references/step-11-maintenance.md +31 -34
  213. package/src/skf-campaign/references/step-resume.md +37 -68
  214. package/src/skf-campaign/scripts/campaign-deps.py +57 -18
  215. package/src/skf-campaign/scripts/campaign-parse-manifest.py +361 -54
  216. package/src/skf-campaign/scripts/campaign-provenance.py +96 -53
  217. package/src/skf-campaign/scripts/campaign-quality-gate.py +592 -0
  218. package/src/skf-campaign/scripts/campaign-render-batch.py +257 -49
  219. package/src/skf-campaign/scripts/campaign-render-kickoff.py +343 -50
  220. package/src/skf-campaign/scripts/campaign-report.py +204 -37
  221. package/src/skf-campaign/scripts/campaign-state.py +1128 -0
  222. package/src/skf-campaign/scripts/campaign-status.py +10 -74
  223. package/src/skf-campaign/scripts/campaign-validate-pins.py +30 -3
  224. package/src/skf-campaign/scripts/campaign-validate-state.py +34 -4
  225. package/src/skf-campaign/templates/campaign-brief-template.yaml +4 -5
  226. package/src/skf-campaign/templates/campaign-report-template.md +5 -1
  227. package/src/skf-campaign/templates/kickoff-template.md +0 -14
  228. package/src/skf-create-skill/SKILL.md +27 -20
  229. package/src/skf-create-skill/assets/compile-assembly-rules.md +6 -5
  230. package/src/skf-create-skill/assets/skill-sections.md +17 -6
  231. package/src/skf-create-skill/customize.toml +20 -8
  232. package/src/skf-create-skill/references/authoritative-files-protocol.md +41 -42
  233. package/src/skf-create-skill/references/batch-mode.md +81 -0
  234. package/src/skf-create-skill/references/ccc-index-check.md +27 -0
  235. package/src/skf-create-skill/references/compile.md +107 -29
  236. package/src/skf-create-skill/references/component-extraction.md +113 -91
  237. package/src/skf-create-skill/references/enrich.md +41 -23
  238. package/src/skf-create-skill/references/entry-points-by-hand.md +20 -0
  239. package/src/skf-create-skill/references/extract.md +200 -161
  240. package/src/skf-create-skill/references/extraction-patterns-by-hand.md +141 -0
  241. package/src/skf-create-skill/references/extraction-patterns-tracing.md +2 -2
  242. package/src/skf-create-skill/references/extraction-patterns.md +584 -196
  243. package/src/skf-create-skill/references/generate-artifacts.md +145 -93
  244. package/src/skf-create-skill/references/health-check.md +1 -1
  245. package/src/skf-create-skill/references/load-brief.md +53 -36
  246. package/src/skf-create-skill/references/relabel-rule.md +12 -0
  247. package/src/skf-create-skill/references/report.md +28 -59
  248. package/src/skf-create-skill/references/source-resolution-protocols.md +49 -155
  249. package/src/skf-create-skill/references/step-auto-shard.md +20 -93
  250. package/src/skf-create-skill/references/step-doc-rot.md +44 -60
  251. package/src/skf-create-skill/references/step-doc-sources.md +55 -18
  252. package/src/skf-create-skill/references/sub/ccc-discover.md +18 -7
  253. package/src/skf-create-skill/references/sub/fetch-docs.md +106 -57
  254. package/src/skf-create-skill/references/sub/fetch-temporal.md +53 -166
  255. package/src/skf-create-skill/references/tier-degradation-rules.md +18 -9
  256. package/src/skf-create-skill/references/validate.md +173 -99
  257. package/src/skf-create-skill/scripts/scan-doc-rot.py +232 -99
  258. package/src/skf-create-stack-skill/SKILL.md +29 -56
  259. package/src/skf-create-stack-skill/assets/metadata-contract.md +51 -0
  260. package/src/skf-create-stack-skill/assets/provenance-map-schema.md +15 -15
  261. package/src/skf-create-stack-skill/assets/stack-skill-template.md +23 -57
  262. package/src/skf-create-stack-skill/customize.toml +23 -12
  263. package/src/skf-create-stack-skill/references/compile-stack.md +57 -66
  264. package/src/skf-create-stack-skill/references/compose-mode-rules.md +24 -44
  265. package/src/skf-create-stack-skill/references/detect-integrations.md +92 -95
  266. package/src/skf-create-stack-skill/references/detect-manifests.md +46 -71
  267. package/src/skf-create-stack-skill/references/generate-output.md +138 -128
  268. package/src/skf-create-stack-skill/references/init.md +90 -32
  269. package/src/skf-create-stack-skill/references/integration-patterns.md +1 -17
  270. package/src/skf-create-stack-skill/references/invocation-contract.md +34 -0
  271. package/src/skf-create-stack-skill/references/manifest-patterns.md +32 -20
  272. package/src/skf-create-stack-skill/references/parallel-extract.md +112 -38
  273. package/src/skf-create-stack-skill/references/rank-and-confirm.md +57 -75
  274. package/src/skf-create-stack-skill/references/report.md +39 -33
  275. package/src/skf-create-stack-skill/references/validate.md +20 -39
  276. package/src/skf-drop-skill/SKILL.md +28 -51
  277. package/src/skf-drop-skill/customize.toml +44 -30
  278. package/src/skf-drop-skill/references/execute.md +79 -146
  279. package/src/skf-drop-skill/references/invocation-contract.md +64 -0
  280. package/src/skf-drop-skill/references/report.md +46 -30
  281. package/src/skf-drop-skill/references/select.md +118 -124
  282. package/src/skf-drop-skill/scripts/dir-sizes.py +54 -26
  283. package/src/skf-drop-skill/scripts/drop-roster.py +322 -0
  284. package/src/skf-export-skill/SKILL.md +40 -62
  285. package/src/skf-export-skill/assets/managed-section-format.md +14 -50
  286. package/src/skf-export-skill/assets/snippet-format.md +3 -1
  287. package/src/skf-export-skill/customize.toml +42 -13
  288. package/src/skf-export-skill/references/generate-snippet.md +54 -46
  289. package/src/skf-export-skill/references/health-check.md +2 -0
  290. package/src/skf-export-skill/references/invocation-contract.md +15 -0
  291. package/src/skf-export-skill/references/load-skill.md +88 -62
  292. package/src/skf-export-skill/references/manifest-rebuild.md +9 -10
  293. package/src/skf-export-skill/references/multi-skill-mode.md +4 -4
  294. package/src/skf-export-skill/references/orphan-context-detection.md +13 -5
  295. package/src/skf-export-skill/references/orphan-row-detection.md +31 -22
  296. package/src/skf-export-skill/references/package.md +15 -73
  297. package/src/skf-export-skill/references/preflight-snippet-root-probe.md +51 -70
  298. package/src/skf-export-skill/references/result-envelope.md +31 -16
  299. package/src/skf-export-skill/references/summary.md +41 -17
  300. package/src/skf-export-skill/references/token-report.md +4 -12
  301. package/src/skf-export-skill/references/update-context.md +118 -237
  302. package/src/skf-forger/SKILL.md +61 -37
  303. package/src/skf-forger/bmad-skill-manifest.yaml +4 -1
  304. package/src/skf-forger/customize.toml +43 -0
  305. package/src/skf-forger/references/pipeline-mode.md +73 -18
  306. package/src/skf-forger/scripts/forge-status.py +299 -0
  307. package/src/skf-forger/scripts/parse-pipeline.py +322 -54
  308. package/src/skf-forger/scripts/pipeline-gate.py +428 -0
  309. package/src/skf-forger/scripts/pipeline-journal.py +1052 -0
  310. package/src/skf-quick-skill/SKILL.md +54 -53
  311. package/src/skf-quick-skill/assets/skill-template.md +4 -2
  312. package/src/skf-quick-skill/customize.toml +51 -20
  313. package/src/skf-quick-skill/references/batch-mode.md +74 -21
  314. package/src/skf-quick-skill/references/compile.md +30 -31
  315. package/src/skf-quick-skill/references/ecosystem-check.md +7 -57
  316. package/src/skf-quick-skill/references/finalize.md +69 -18
  317. package/src/skf-quick-skill/references/halt-contract.md +41 -29
  318. package/src/skf-quick-skill/references/health-check.md +5 -3
  319. package/src/skf-quick-skill/references/quick-extract.md +114 -45
  320. package/src/skf-quick-skill/references/registry-resolution.md +9 -64
  321. package/src/skf-quick-skill/references/resolve-target.md +116 -66
  322. package/src/skf-quick-skill/references/write-and-validate.md +79 -40
  323. package/src/skf-refine-architecture/SKILL.md +43 -53
  324. package/src/skf-refine-architecture/customize.toml +49 -20
  325. package/src/skf-refine-architecture/references/compile.md +97 -54
  326. package/src/skf-refine-architecture/references/exit-codes.md +30 -0
  327. package/src/skf-refine-architecture/references/finding-storage.md +21 -0
  328. package/src/skf-refine-architecture/references/gap-analysis.md +101 -38
  329. package/src/skf-refine-architecture/references/improvements.md +14 -20
  330. package/src/skf-refine-architecture/references/init.md +98 -57
  331. package/src/skf-refine-architecture/references/issue-detection.md +32 -39
  332. package/src/skf-refine-architecture/references/refinement-rules.md +37 -48
  333. package/src/skf-refine-architecture/references/report.md +65 -54
  334. package/src/skf-refine-architecture/scripts/skf-check-preservation.py +1619 -0
  335. package/src/skf-rename-skill/SKILL.md +19 -54
  336. package/src/skf-rename-skill/customize.toml +32 -26
  337. package/src/skf-rename-skill/references/execute.md +230 -184
  338. package/src/skf-rename-skill/references/exit-codes.md +7 -7
  339. package/src/skf-rename-skill/references/health-check.md +1 -7
  340. package/src/skf-rename-skill/references/invocation-contract.md +25 -0
  341. package/src/skf-rename-skill/references/report.md +63 -52
  342. package/src/skf-rename-skill/references/select.md +197 -115
  343. package/src/skf-rename-skill/scripts/skf-validate-rename-name.py +161 -21
  344. package/src/skf-setup/SKILL.md +26 -26
  345. package/src/skf-setup/customize.toml +14 -10
  346. package/src/skf-setup/references/auto-index.md +50 -63
  347. package/src/skf-setup/references/ccc-index.md +29 -89
  348. package/src/skf-setup/references/detect-and-tier.md +58 -66
  349. package/src/skf-setup/references/health-check.md +2 -0
  350. package/src/skf-setup/references/invocation-contract.md +14 -0
  351. package/src/skf-setup/references/report.md +43 -166
  352. package/src/skf-setup/references/tier-rules.md +5 -5
  353. package/src/skf-setup/references/write-config.md +34 -57
  354. package/src/skf-test-skill/SKILL.md +17 -57
  355. package/src/skf-test-skill/assets/output-section-formats.md +33 -34
  356. package/src/skf-test-skill/customize.toml +27 -13
  357. package/src/skf-test-skill/references/coherence-check.md +134 -62
  358. package/src/skf-test-skill/references/coverage-check-tiers.md +35 -0
  359. package/src/skf-test-skill/references/coverage-check.md +217 -254
  360. package/src/skf-test-skill/references/detect-mode.md +5 -5
  361. package/src/skf-test-skill/references/external-validators.md +94 -82
  362. package/src/skf-test-skill/references/health-check.md +6 -7
  363. package/src/skf-test-skill/references/init.md +163 -88
  364. package/src/skf-test-skill/references/invocation-contract.md +66 -0
  365. package/src/skf-test-skill/references/migration-section-rules.md +5 -2
  366. package/src/skf-test-skill/references/report.md +162 -142
  367. package/src/skf-test-skill/references/score.md +80 -107
  368. package/src/skf-test-skill/references/scoring-rules.md +41 -155
  369. package/src/skf-test-skill/references/source-access-protocol.md +19 -92
  370. package/src/skf-test-skill/references/step-hard-gate.md +51 -33
  371. package/src/skf-test-skill/scripts/aggregate-coherence.py +218 -30
  372. package/src/skf-test-skill/scripts/build-result-context.py +287 -0
  373. package/src/skf-test-skill/scripts/check-metadata-coherence.py +37 -4
  374. package/src/skf-test-skill/scripts/combine-external-scores.py +23 -6
  375. package/src/skf-test-skill/scripts/compute-score.py +223 -45
  376. package/src/skf-test-skill/scripts/gap-ledger.py +1381 -0
  377. package/src/skf-test-skill/scripts/hard-gate.py +203 -0
  378. package/src/skf-test-skill/scripts/load-coverage-inputs.py +760 -0
  379. package/src/skf-test-skill/scripts/locate-export-segments.py +835 -0
  380. package/src/skf-test-skill/scripts/reconcile-coverage.py +273 -79
  381. package/src/skf-test-skill/scripts/score-signatures.py +459 -0
  382. package/src/skf-test-skill/scripts/stage-helper-payload.py +148 -0
  383. package/src/skf-test-skill/scripts/validate-inventory.py +311 -16
  384. package/src/skf-test-skill/scripts/verify-declared-numerator.py +127 -52
  385. package/src/skf-test-skill/templates/test-report-template.md +21 -15
  386. package/src/skf-update-skill/SKILL.md +38 -25
  387. package/src/skf-update-skill/customize.toml +27 -12
  388. package/src/skf-update-skill/references/detect-changes.md +233 -222
  389. package/src/skf-update-skill/references/gap-driven.md +336 -0
  390. package/src/skf-update-skill/references/health-check.md +31 -5
  391. package/src/skf-update-skill/references/init.md +250 -84
  392. package/src/skf-update-skill/references/invocation-contract.md +12 -0
  393. package/src/skf-update-skill/references/manual-section-rules.md +6 -23
  394. package/src/skf-update-skill/references/merge.md +180 -47
  395. package/src/skf-update-skill/references/re-extract.md +53 -262
  396. package/src/skf-update-skill/references/report.md +100 -35
  397. package/src/skf-update-skill/references/write.md +331 -149
  398. package/src/skf-update-skill/scripts/skf-new-file-diff.py +29 -7
  399. package/src/skf-verify-stack/SKILL.md +23 -42
  400. package/src/skf-verify-stack/assets/feasibility-report-template.md +11 -5
  401. package/src/skf-verify-stack/customize.toml +55 -22
  402. package/src/skf-verify-stack/references/coverage-patterns.md +17 -8
  403. package/src/skf-verify-stack/references/coverage.md +67 -64
  404. package/src/skf-verify-stack/references/exit-codes.md +21 -8
  405. package/src/skf-verify-stack/references/init.md +107 -62
  406. package/src/skf-verify-stack/references/integration-verification-rules.md +12 -13
  407. package/src/skf-verify-stack/references/integrations.md +106 -65
  408. package/src/skf-verify-stack/references/report.md +59 -42
  409. package/src/skf-verify-stack/references/requirements.md +32 -9
  410. package/src/skf-verify-stack/references/synthesize.md +53 -39
  411. package/src/skf-verify-stack/scripts/skf-coverage-tally.py +398 -52
  412. package/src/skf-verify-stack/scripts/skf-previous-report.py +330 -0
  413. package/src/skf-verify-stack/scripts/skf-report-delta.py +453 -49
  414. package/src/skf-verify-stack/scripts/skf-verdict-rollup.py +240 -27
  415. package/tools/cli/commands/install.js +11 -4
  416. package/tools/cli/commands/status.js +15 -3
  417. package/tools/cli/commands/update.js +11 -4
  418. package/tools/cli/lib/tool-check.js +320 -0
  419. package/tools/cli/lib/version-check.js +22 -9
  420. package/tools/cli/skf-cli.js +4 -1
  421. package/.gitattributes +0 -16
  422. package/.nvmrc +0 -1
  423. package/docs/_internal/RELEASING.md +0 -645
  424. package/release-audits/v1.0.0-launch-audit.md +0 -728
  425. package/src/skf-audit-skill/references/step-doc-drift.md +0 -177
  426. package/src/skf-brief-skill/references/headless-source-authority-detection.md +0 -26
  427. package/src/skf-campaign/manifest.yaml +0 -15
  428. package/src/skf-create-skill/assets/tessl-dismissal-rules.md +0 -106
  429. package/src/skf-create-skill/references/ecosystem-check.md +0 -74
  430. package/src/skf-drop-skill/references/headless-contract.md +0 -18
  431. package/src/skf-update-skill/references/merge-conflict-rules.md +0 -15
  432. package/src/skf-update-skill/references/remote-source-resolution.md +0 -98
  433. package/src/skf-update-skill/references/validate.md +0 -124
  434. package/tools/validate-docs-drift.js +0 -233
  435. package/tools/validate-docs-links.js +0 -665
@@ -1,23 +1,16 @@
1
1
  # /// script
2
- # requires-python = ">=3.9"
2
+ # requires-python = ">=3.11"
3
3
  # dependencies = ["pyyaml"]
4
4
  # ///
5
- """Campaign Status — deterministic state summary + optional backup-drift verdict.
5
+ """Campaign Status: a deterministic summary of the campaign state.
6
6
 
7
- Collapses two in-prompt determinism leaks into one helper the LLM calls instead
8
- of hand-deriving:
9
-
10
- - `campaign status` and the resume summary block tallied `skills[]` by status
11
- ("N completed / M total, K pending, ...") in-prompt over a 15+ skill array.
12
- - the `.bak` recovery path compared `primary` vs `backup` timestamps and stage
13
- numbers by hand (an ISO-8601 + int compare across two YAML files).
14
-
15
- Both are mechanical, one-correct-answer computations. This script owns them so
16
- identical state always yields identical output.
7
+ `campaign status` and step-resume's summary block tallied `skills[]` by status
8
+ ("N completed / M total, K pending, ...") in the prompt, over a 15+ skill
9
+ array. That count is mechanical, with one correct answer, so this script owns
10
+ it and identical state always yields identical output.
17
11
 
18
12
  CLI:
19
13
  uv run campaign-status.py --state-file <path>
20
- uv run campaign-status.py --state-file <path> --backup-file <path>
21
14
 
22
15
  Output (JSON on stdout):
23
16
  {
@@ -25,12 +18,7 @@ Output (JSON on stdout):
25
18
  "current_stage": 0,
26
19
  "last_updated": "...",
27
20
  "total": 0, "completed": 0, "pending": 0,
28
- "active": 0, "failed": 0, "skipped": 0,
29
- "backup_comparison": null | {
30
- "primary_behind": bool,
31
- "primary_last_updated": "...", "backup_last_updated": "...",
32
- "primary_stage": 0, "backup_stage": 0
33
- }
21
+ "active": 0, "failed": 0, "skipped": 0
34
22
  }
35
23
 
36
24
  Exit codes:
@@ -43,7 +31,6 @@ from __future__ import annotations
43
31
  import argparse
44
32
  import json
45
33
  import sys
46
- from datetime import datetime
47
34
  from pathlib import Path
48
35
  from typing import Any, Dict, Optional
49
36
 
@@ -68,16 +55,6 @@ def _load_state(path: Path) -> Optional[Dict[str, Any]]:
68
55
  return data if isinstance(data, dict) else None
69
56
 
70
57
 
71
- def _parse_iso(value: Any) -> Optional[datetime]:
72
- if not isinstance(value, str) or not value:
73
- return None
74
- text = value[:-1] + "+00:00" if value.endswith("Z") else value
75
- try:
76
- return datetime.fromisoformat(text)
77
- except (ValueError, TypeError):
78
- return None
79
-
80
-
81
58
  def _counts(state: Dict[str, Any]) -> Dict[str, int]:
82
59
  skills = state.get("skills", []) or []
83
60
  tally = {s: 0 for s in STATUSES}
@@ -89,38 +66,7 @@ def _counts(state: Dict[str, Any]) -> Dict[str, int]:
89
66
  return tally
90
67
 
91
68
 
92
- def _compare_backup(primary: Dict[str, Any], backup: Dict[str, Any]) -> Dict[str, Any]:
93
- p_c = primary.get("campaign", {}) or {}
94
- b_c = backup.get("campaign", {}) or {}
95
- p_updated = p_c.get("last_updated")
96
- b_updated = b_c.get("last_updated")
97
- p_stage = p_c.get("current_stage")
98
- b_stage = b_c.get("current_stage")
99
-
100
- stage_behind = (
101
- isinstance(p_stage, int) and isinstance(b_stage, int) and p_stage < b_stage
102
- )
103
-
104
- ts_behind = False
105
- p_ts = _parse_iso(p_updated)
106
- b_ts = _parse_iso(b_updated)
107
- if p_ts is not None and b_ts is not None:
108
- try:
109
- ts_behind = p_ts < b_ts
110
- except TypeError:
111
- # naive vs aware datetime — cannot order; defer to stage compare.
112
- ts_behind = False
113
-
114
- return {
115
- "primary_behind": bool(stage_behind or ts_behind),
116
- "primary_last_updated": p_updated,
117
- "backup_last_updated": b_updated,
118
- "primary_stage": p_stage,
119
- "backup_stage": b_stage,
120
- }
121
-
122
-
123
- def run(state_file: str, backup_file: Optional[str]) -> int:
69
+ def run(state_file: str) -> int:
124
70
  state = _load_state(Path(state_file))
125
71
  if state is None:
126
72
  return _err(f"State not readable as a mapping: {state_file}", "STATE_UNREADABLE")
@@ -131,14 +77,8 @@ def run(state_file: str, backup_file: Optional[str]) -> int:
131
77
  "current_stage": campaign.get("current_stage"),
132
78
  "last_updated": campaign.get("last_updated"),
133
79
  **_counts(state),
134
- "backup_comparison": None,
135
80
  }
136
81
 
137
- if backup_file:
138
- backup = _load_state(Path(backup_file))
139
- if backup is not None:
140
- result["backup_comparison"] = _compare_backup(state, backup)
141
-
142
82
  json.dump(result, sys.stdout, separators=(",", ":"), default=str)
143
83
  sys.stdout.write("\n")
144
84
  return 0
@@ -147,15 +87,11 @@ def run(state_file: str, backup_file: Optional[str]) -> int:
147
87
  def main(argv: Optional[list] = None) -> int:
148
88
  parser = argparse.ArgumentParser(
149
89
  prog="campaign-status",
150
- description="Summarize campaign state and (optionally) compare it to its backup.",
90
+ description="Summarize the campaign state.",
151
91
  )
152
92
  parser.add_argument("--state-file", required=True, help="Path to _campaign-state.yaml")
153
- parser.add_argument(
154
- "--backup-file",
155
- help="Path to _campaign-state.yaml.bak; when given, emit backup_comparison",
156
- )
157
93
  args = parser.parse_args(argv)
158
- return run(args.state_file, args.backup_file)
94
+ return run(args.state_file)
159
95
 
160
96
 
161
97
  if __name__ == "__main__":
@@ -1,5 +1,5 @@
1
1
  # /// script
2
- # requires-python = ">=3.9"
2
+ # requires-python = ">=3.11"
3
3
  # dependencies = ["pyyaml"]
4
4
  # ///
5
5
  """Campaign Validate Pins — validate all version pins in a campaign state file.
@@ -37,7 +37,8 @@ Output (JSON on stdout):
37
37
  Exit codes:
38
38
  0 all valid/resolved
39
39
  1 one or more invalid pins
40
- 2 error (missing files, bad YAML, gh unavailable)
40
+ 2 error (missing files, bad YAML, gh unavailable), or INVALID_BRIEF: a
41
+ brief that is no mapping, or a target with no name or no repo_url
41
42
  """
42
43
 
43
44
  from __future__ import annotations
@@ -47,7 +48,7 @@ import importlib.util
47
48
  import json
48
49
  import sys
49
50
  from pathlib import Path
50
- from typing import Any, Dict, List
51
+ from typing import Any, Dict, List, Optional
51
52
 
52
53
  import yaml
53
54
 
@@ -72,6 +73,25 @@ def _load_yaml(path: Path) -> Any:
72
73
  return yaml.safe_load(f)
73
74
 
74
75
 
76
+ def _malformed_target(targets: List[Any]) -> Optional[str]:
77
+ """Why the first brief target with no name or no repo_url is unusable, or None.
78
+
79
+ Names the target by its 1-based number, and by its name when it has one,
80
+ and says which key it lacks.
81
+ """
82
+ for number, target in enumerate(targets, start=1):
83
+ if not isinstance(target, dict):
84
+ return f"Brief target {number} is not a mapping"
85
+ missing = [
86
+ key for key in ("name", "repo_url")
87
+ if not (isinstance(target.get(key), str) and target[key].strip())
88
+ ]
89
+ if missing:
90
+ named = "" if "name" in missing else f" ({target['name']})"
91
+ return f"Brief target {number}{named} has no {' and no '.join(missing)}"
92
+ return None
93
+
94
+
75
95
  def run(state_file: str, brief_file: str) -> int:
76
96
  state_path = Path(state_file)
77
97
  brief_path = Path(brief_file)
@@ -101,10 +121,17 @@ def run(state_file: str, brief_file: str) -> int:
101
121
  _emit_error("State file 'skills' is not an array", "INVALID_STATE")
102
122
  return 2
103
123
 
124
+ if not isinstance(brief, dict):
125
+ _emit_error("Brief file is not a YAML mapping", "INVALID_BRIEF")
126
+ return 2
104
127
  targets = brief.get("targets", [])
105
128
  if not isinstance(targets, list):
106
129
  _emit_error("Brief file 'targets' is not an array", "INVALID_BRIEF")
107
130
  return 2
131
+ malformed = _malformed_target(targets)
132
+ if malformed is not None:
133
+ _emit_error(malformed, "INVALID_BRIEF")
134
+ return 2
108
135
 
109
136
  name_to_repo: Dict[str, str] = {}
110
137
  for target in targets:
@@ -1,5 +1,5 @@
1
1
  # /// script
2
- # requires-python = ">=3.9"
2
+ # requires-python = ">=3.11"
3
3
  # dependencies = ["pyyaml", "jsonschema>=4.0"]
4
4
  # ///
5
5
  """Campaign Validate State — schema check for _campaign-state.yaml on disk.
@@ -14,7 +14,11 @@ multi-session campaign.
14
14
  Loads the campaign state YAML, validates it against
15
15
  `assets/campaign-state-schema.json` (resolved relative to this script unless
16
16
  `--schema-file` overrides), and emits skill-friendly error records the calling
17
- step can forward verbatim.
17
+ step can forward verbatim. A `date-time` field must parse as ISO-8601 with a
18
+ UTC offset (`2026-05-01T00:00:00Z` or `+00:00`): the schema's `format` is only
19
+ an annotation to a JSON Schema validator, so it is checked here, and an
20
+ invented or offset-less timestamp fails instead of misordering the backup
21
+ comparison and the report's durations.
18
22
 
19
23
  CLI:
20
24
  uv run campaign-validate-state.py --state-file <path>
@@ -43,11 +47,29 @@ from pathlib import Path
43
47
  from typing import Any
44
48
 
45
49
  import yaml
46
- from jsonschema import Draft7Validator
50
+ from jsonschema import Draft7Validator, FormatChecker
47
51
 
48
52
  DEFAULT_SCHEMA_PATH = Path(__file__).resolve().parent.parent / "assets" / "campaign-state-schema.json"
49
53
 
50
54
 
55
+ def _is_date_time(instance: Any) -> bool:
56
+ """ISO-8601 date and time with a UTC offset; anything but a string is the type check's."""
57
+ if not isinstance(instance, str):
58
+ return True
59
+ text = instance[:-1] + "+00:00" if instance.endswith(("Z", "z")) else instance
60
+ if "T" not in text and "t" not in text:
61
+ return False
62
+ try:
63
+ parsed = datetime.datetime.fromisoformat(text)
64
+ except ValueError:
65
+ return False
66
+ return parsed.tzinfo is not None
67
+
68
+
69
+ FORMAT_CHECKER = FormatChecker(formats=())
70
+ FORMAT_CHECKER.checks("date-time")(_is_date_time)
71
+
72
+
51
73
  def _emit(envelope: dict) -> None:
52
74
  json.dump(envelope, sys.stdout, separators=(",", ":"), default=str)
53
75
  sys.stdout.write("\n")
@@ -115,6 +137,14 @@ def _translate(err) -> dict:
115
137
  "field": field,
116
138
  "message": f"State validation failed: `{field}` — {err.message}",
117
139
  }
140
+ if validator == "format":
141
+ return {
142
+ "field": field,
143
+ "message": (
144
+ f"State validation failed: `{field}` value `{inst}` is not an ISO-8601 date and time "
145
+ f"with a UTC offset (e.g. `2026-05-01T00:00:00Z`)."
146
+ ),
147
+ }
118
148
  if validator in ("minimum", "maximum"):
119
149
  return {
120
150
  "field": field,
@@ -127,7 +157,7 @@ def _translate(err) -> dict:
127
157
 
128
158
 
129
159
  def validate_state(state: dict, schema: dict) -> dict:
130
- validator = Draft7Validator(schema)
160
+ validator = Draft7Validator(schema, format_checker=FORMAT_CHECKER)
131
161
  errors = [
132
162
  _translate(err)
133
163
  for err in sorted(validator.iter_errors(state), key=lambda e: list(e.absolute_path))
@@ -1,5 +1,5 @@
1
- # Machine-generated campaign brief — resume context for fresh sessions
2
- # Populated by step-01-setup.md from operator inputs
1
+ # Machine-generated campaign brief: resume context for fresh sessions
2
+ # Written by campaign-state.py init from the parsed targets
3
3
 
4
4
  # Campaign identifier
5
5
  campaign_name: ""
@@ -15,6 +15,8 @@ targets: []
15
15
  # tier: "A" # A (full pipeline) or B (batch)
16
16
  # pin: null # version pin, or null for latest
17
17
  # depends_on: [] # list of skill names this target depends on
18
+ # plus any other field the target's source gave it, such as a language or
19
+ # scope hint
18
20
 
19
21
  # Quality thresholds applied to all skills in this campaign
20
22
  quality_gate:
@@ -22,9 +24,6 @@ quality_gate:
22
24
  soft_target: 90
23
25
  soft_fallback: 80
24
26
 
25
- # Where health findings are routed: "local" (project-local) or "improvement" (shared queue)
26
- health_findings_queue: "local"
27
-
28
27
  # Optional path to the architecture document the verify (Stage 7) and refine
29
28
  # (Stage 8) stages consume. Empty string means those stages discover it at
30
29
  # runtime (docs/architecture.md, then _bmad-output/planning-artifacts/architecture.md).
@@ -21,6 +21,10 @@
21
21
  |------|------|--------|---------------|-----|-------------|
22
22
  {{skills_table}}
23
23
 
24
+ ## Export Gate
25
+
26
+ {{export_gate_section}}
27
+
24
28
  ## Quality Scores
25
29
 
26
30
  | Metric | Value |
@@ -37,7 +41,7 @@
37
41
 
38
42
  - **Total workarounds applied:** {{total_workarounds}}
39
43
  - **Skills with workarounds:** {{skills_with_workarounds}}
40
- - **Doc-rot corrections:** tracked per-skill in health-check findings (not aggregated in campaign state)
44
+ - **Doc-rot corrections:** counted among the workarounds, one `[doc-rot]` entry for each correction a skill's doc-rot step kept
41
45
 
42
46
  ## Workarounds Applied
43
47
 
@@ -4,7 +4,6 @@
4
4
 
5
5
  - **Campaign:** {{campaign_name}}
6
6
  - **Current Stage:** {{current_stage}}
7
- - **Quality Gate:** {{quality_gate_summary}}
8
7
 
9
8
  ## Skill Identity
10
9
 
@@ -33,16 +32,3 @@
33
32
  ## Workarounds Applied
34
33
 
35
34
  {{workarounds_list}}
36
-
37
- ## Pipeline Instructions
38
-
39
- Execute the standard forge pipeline for **{{skill_name}}**:
40
-
41
- 1. **AN** (Analyze) — scope and source intelligence
42
- 2. **BS** (Brief Synthesis) — generate or validate the skill brief
43
- 3. **CS** (Compile Skill) — compile the SKILL.md artifact
44
- 4. **TS** (Test Skill) — run health-check validation
45
-
46
- **Parameters:**
47
- - Pin: {{pin}}
48
- - Quality target: {{quality_gate_summary}}
@@ -7,77 +7,84 @@ description: Compile a skill from a brief. Supports --batch for multiple briefs.
7
7
 
8
8
  ## Overview
9
9
 
10
- Compiles a verified agent skill from a skill-brief.yaml and source code, producing an agentskills.io-compliant SKILL.md with provenance map, evidence report, and progressive disclosure references. The workflow is mostly autonomous with three interaction points — after ecosystem check (if match found), after source extraction (to confirm findings), and after content quality review (when tessl produces suggestions). Steps adapt behavior based on forge tier (Quick/Forge/Forge+/Deep). Zero hallucination tolerance: every instruction in the output must trace to source code with a confidence tier citation. A single run is not resumable — if it is interrupted mid-compile, re-run from the brief (only `--batch` checkpoints progress across briefs).
10
+ Compiles a verified agent skill from a skill-brief.yaml and the source code or documentation it names, producing an agentskills.io-compliant SKILL.md with provenance map, evidence report, and progressive disclosure references. The workflow is mostly autonomous: it stops for the user in step 1 when no brief is named and several exist, in step 3 when several tags match the brief's version, for each authoritative AI documentation file the brief's scope leaves out (step 3 §2a), after source extraction (to confirm findings), at step 3c when a source brief extracted no export and none of its `doc_urls` could be fetched, and, for a component library, at step 3d's demo-exclusion and registry prompts. When the user has opted in to Tessl Review, step 6 also records Tessl's review of the skill as advice; it never stops the run. Steps adapt behavior based on forge tier (Quick/Forge/Forge+/Deep). Zero hallucination tolerance: every statement in the output carries a provenance citation, and content that cannot be cited is left out. A single run is not resumable: if it is interrupted mid-compile, re-run from the brief (only `--batch` checkpoints progress across briefs).
11
11
 
12
12
  ## Conventions
13
13
 
14
14
  - Bare paths (e.g. `references/<name>.md`) resolve from the skill root.
15
- - `references/` holds prompt content carved out of SKILL.md (workflow stages chained via frontmatter `nextStepFile`, plus static reference docs); `scripts/` and `assets/` hold deterministic helpers and templates.
15
+ - **Module-level path exception:** bare paths beginning with `knowledge/` or `shared/` resolve from the SKF module root (`{project-root}/_bmad/skf/` installed, `src/` in dev), not the skill root.
16
+ - **Sibling skills:** a path that names another SKF skill's folder (`skf-<name>/...`) resolves from the SKF module root, and that skill must be installed with this one.
17
+ - `references/` holds prompt content carved out of SKILL.md (workflow stages chained via frontmatter `nextStepFile`, plus static reference docs) and `references/sub/` the conditional sub-steps; a `nextStepFile` is relative to its own stage file (so a sub-step that returns to a main stage names it in the parent folder). `scripts/` and `assets/` hold deterministic helpers and templates.
16
18
  - `{skill-root}` resolves to this skill's installed directory (where `customize.toml` lives, if present).
17
19
  - `{project-root}`-prefixed paths resolve from the project working directory.
18
20
  - `{skill-name}` resolves to the skill directory's basename.
19
21
 
20
22
  ## Role
21
23
 
22
- You are operating in Ferris Architect mode — a skill compilation engine performing structural extraction and assembly. Apply zero hallucination tolerance: uncitable content is excluded, not guessed.
24
+ You are operating in Ferris Architect mode: a skill compilation engine performing structural extraction and assembly.
23
25
 
24
26
  ## Workflow Rules
25
27
 
26
28
  These rules apply to every step in this workflow:
27
29
 
28
- - Never include content in SKILL.md that cannot be cited to source code
30
+ - Never include content in SKILL.md without a provenance citation: `[AST:]` or `[SRC:]` for code (T1 and T1-low), `[QMD:]` for T2 context or `[EXT:]` for T3 documentation, in the forms `assets/skill-sections.md` gives
31
+ - Never write into a skill folder SKF did not generate — generate-artifacts §1 runs the inventory's write check before creating any directory; without the helper it writes only into a skill folder that does not exist yet
29
32
  - Only load one step file at a time — never preload future steps
33
+ - Once step 3 §2b has bound `{source_tree}` (the private tree a remote source is read from), every HALT after it first runs `uv run {sourceTreeHelper} close --tree "{source_tree}"` from `{project-root}` and goes on whatever it prints. Step 7 removes the tree on a run that finishes, and a later run removes one a stopped run left behind, seven days on
34
+ - Every HARD HALT in steps 1 to 7 emits the result envelope before it stops, in every mode. Each HALT names its exit code, `halt_reason` and phase where it fires, and its emit command. Stage `{"phase": "<phase>", "halt_reason": "<halt_reason>", "reason": "<the halt message, one line>", "summary": {"halt_reason": "<halt_reason>", "evidence_report": null}}` as `{run_dir}/halt.json` (add `"path"` when the halt names a file or folder; once step 7 has promoted the package, add `"skill_package"` and `"outputs"` and set `summary.evidence_report` to `{forge_version}/evidence-report.md`), then run `uv run {emitEnvelopeHelper} emit-halt --workflow skf-create-skill --run-dir "{run_dir}" --target stderr < "{run_dir}/halt.json"`, adding `--result-dir "{forge_version}"` once step 7 has created `{forge_version}`, so the emitter also writes the halt's `create-skill-result-*.json` and its `-latest.json` copy there. Display the line it prints, then stop with the exit code; under `--batch` the halt ends only its brief: go to `references/batch-mode.md` §3, which records it and takes the next brief. If `{emitEnvelopeHelper}` resolved no path, display the halt message alone. The schema, `shared/scripts/schemas/skf-create-skill-result-envelope.v1.json`, lists every `halt_reason` with its exit code
30
35
  - Always communicate in `{communication_language}`
31
- - If `{headless_mode}` is true, auto-proceed through confirmation gates with their default action, logging each auto-decision to the in-context `headless_decisions[]` buffer AND appending it as a JSON line to the on-disk auto-decision sink (established at step 1 §3) the moment it lands, so the audit trail survives context compaction before step 5 first writes the evidence report
36
+ - If `{headless_mode}` is true, auto-proceed through confirmation gates with their default action
37
+ - Every decision the run takes without asking (each gate a headless run resolves by its default, step 1's tier override and its pick of the only brief) is recorded the moment it is taken: stage `{"step": "<step>", "gate": "<gate>", "decision": "<action>", "rationale": "<why>", "timestamp": "<ISO-8601>"}`, plus `"value"` or `"fallback"` where the gate names one, as `{run_dir}/decision.json` and run `uv run {emitEnvelopeHelper} record --workflow skf-create-skill --run-dir "{run_dir}" --decision < "{run_dir}/decision.json"`. The run sink it appends to, `{run_dir}/headless-decisions.jsonl`, is the brief's one decision trail: it survives context compaction, step 5 §7 renders the evidence report's `## Auto-Decisions` table from it, and the result envelope and contract carry it
32
38
 
33
39
  ## Stages
34
40
 
35
41
  | # | Step | File | Auto-proceed |
36
42
  |---|------|------|--------------|
37
- | 1 | Load Brief | references/load-brief.md | Yes |
38
- | 2 | Ecosystem Check | references/ecosystem-check.md | Conditional |
43
+ | 1 | Load Brief | references/load-brief.md | Conditional |
39
44
  | 2b | CCC Discover | references/sub/ccc-discover.md | Yes |
40
45
  | 3 | Extract | references/extract.md | No (confirm) |
41
46
  | 3b | Fetch Temporal | references/sub/fetch-temporal.md | Yes |
42
- | 3c | Fetch Docs | references/sub/fetch-docs.md | Yes |
47
+ | 3c | Fetch Docs | references/sub/fetch-docs.md | Conditional |
43
48
  | 3d | Component Extraction | references/component-extraction.md | Conditional |
44
49
  | 4 | Enrich | references/enrich.md | Yes |
45
50
  | 5 | Compile | references/compile.md | Yes |
46
51
  | 5a | Doc Sources | references/step-doc-sources.md | Yes |
47
52
  | 5b | Auto-Shard | references/step-auto-shard.md | Yes |
48
53
  | 5c | Doc-Rot | references/step-doc-rot.md | Yes |
49
- | 6 | Validate | references/validate.md | Conditional |
54
+ | 6 | Validate | references/validate.md | Yes |
50
55
  | 7 | Generate Artifacts | references/generate-artifacts.md | Yes |
51
56
  | 8 | Report | references/report.md | Yes |
52
57
  | 9 | Workflow Health Check | references/health-check.md | Yes |
53
58
 
54
- *Sub-steps under `references/sub/` are conditional branches (CCC discovery, temporal/doc enrichment) kept out of the top-level step count so main-line steps 1–9 drive the workflow. Step 3d (Component Extraction) stays top-level as an alternative main step that replaces the standard extraction path when `scope.type: "component-library"`.*
59
+ *Sub-steps under `references/sub/` are conditional branches (CCC discovery, temporal and doc enrichment), lettered by the place they take in the run and kept out of the main-line step count. Step 3d (Component Extraction) is a branch inside step 3 for a `component-library` brief: extract §2c loads it in place of §4 to §4c and resumes at its §5, before Gate 2.*
55
60
 
56
61
  ## Invocation Contract
57
62
 
58
63
  | Aspect | Detail |
59
64
  |--------|--------|
60
- | **Inputs** | brief_path (path to skill-brief.yaml) [required], --batch [optional] |
61
- | **Gates** | step 2: Choice Gate [P] (if match) | step 3: Review Gate [C] | step 6: Content-Quality Gate [C] (if novel tessl suggestions) |
62
- | **Outputs** | SKILL.md, context-snippet.md, metadata.json, provenance-map.json, evidence-report.md, references/ |
63
- | **Headless** | All gates auto-resolve with default action when `{headless_mode}` is true |
65
+ | **Inputs** | brief_path (a skill-brief.yaml path or a skill name) [optional: without it, step 1 offers the briefs in `{forge_data_folder}`, and a headless run halts unless there is one], --batch [optional: the briefs or folders of briefs after it, `{forge_data_folder}` when none is given, each validated before the first compiles] |
66
+ | **Gates** | step 1: Brief Selection (no brief named and several in `{forge_data_folder}`; headless: HARD HALT `brief-missing`, exit 2; one brief: picked and recorded as gate `brief-selection`) | step 3: Tag Choice Gate (several tags match the brief's version; headless: the first in priority order) | step 3 §2a: Authoritative-File Gate [P]/[S]/[U] (an authoritative AI documentation file outside the brief's scope; headless: deferred-headless, one auto-decision per path) | step 3: Review Gate [C]/[R] (with the zero-export warning when a source brief without `doc_urls` extracted no export; [R] with it or the head-cap warning) | step 3c: Zero-Export Gate [C]/[R] (a source brief with no export whose every `doc_urls` fetch failed) | step 3d: Demo-Exclusion Gate [Y], then Registry Gate [Y] (candidate found) or [S] (none found), component-library scope only, each skipped once the brief holds `scope.demo_patterns` or `scope.registry_path`, which step 3d writes when a user confirms or gives the patterns or the registry path |
67
+ | **Outputs** | SKILL.md, context-snippet.md, metadata.json, provenance-map.json, evidence-report.md, extraction-rules.yaml, references/; per brief, the result contract (`create-skill-result-{YYYYMMDD-HHmmss}.json` and its `-latest.json` copy in `{forge_version}`) and one `SKF_CREATE_SKILL_RESULT_JSON` line on stdout, on stderr at a HARD HALT |
68
+ | **Headless** | All gates auto-resolve with default action when `{headless_mode}` is true; each auto-decision reaches the envelope's and the result contract's `headless_decisions` |
69
+ | **Exit codes** | 0 for a finished brief; at a HARD HALT 2 (the brief is missing, malformed or invalid), 3 (no forge config, source, helper or documentation), 4 (a write failed), 5 (a refused or broken package), 6 (the user chose to refine the scope). A `--batch` run exits with the highest code among its briefs, 0 when every brief finished |
64
70
 
65
71
  ## On Activation
66
72
 
67
73
  1. Load config from `{project-root}/_bmad/skf/config.yaml` and resolve:
68
74
  - `output_folder`, `user_name`, `communication_language`, `document_output_language`, `sidecar_path`, `skills_output_folder`, `forge_data_folder`
69
75
 
70
- 2. **Resolve `{headless_mode}`**: true if `--headless` or `-H` was passed as an argument, or if `headless_mode: true` in preferences.yaml. Default: false.
76
+ 2. **Resolve `{headless_mode}`**: true if `--headless` or `-H` was passed as an argument, or if `headless_mode: true` in `{sidecar_path}/preferences.yaml`. Default: false.
71
77
 
72
78
  3. **Resolve workflow customization.** Run:
73
79
 
74
80
  ```bash
75
- python3 {project-root}/_bmad/scripts/resolve_customization.py \
76
- --skill {skill-root} --key workflow
81
+ uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --project-root {project-root} --key workflow
77
82
  ```
78
83
 
79
- The script merges the three customization layers per `bmad-customize`'s structural merge rules (scalars override, arrays append): `{skill-root}/customize.toml` (bundled defaults), `_bmad/custom/skf-create-skill.toml` under `{project-root}` (team overrides, committed), and `_bmad/custom/skf-create-skill.user.toml` under `{project-root}` (personal overrides, gitignored). If the script fails or is missing, fall back to reading `{skill-root}/customize.toml` directly.
84
+ It merges the bundled `{skill-root}/customize.toml` with `{project-root}/_bmad/custom/skf-create-skill.toml` (team overrides, committed) and `.user.toml` (personal overrides, gitignored). When it exits non-zero, prints no JSON or is missing, print one line, `[activation/warn] customization_resolver_unavailable: <reason>` (`<reason>`: its first stderr line, `not found` when the script is missing, `no JSON` when it printed none). If the resolver cannot run, read `{skill-root}/customize.toml` alone and use its bundled defaults: the `{project-root}/_bmad/custom/` overrides do not apply to this run. In that case keep the reason as `{customization_resolver_unavailable}` (unset when the resolver ran) for step 1 §0 to record in each brief's run folder.
80
85
 
81
- Apply the resolved values so the surface is not a silent no-op: execute each entry in `workflow.activation_steps_prepend` in order now; treat every entry in `workflow.persistent_facts` as standing context for the whole run (entries prefixed `file:` are paths or globs whose contents load as facts); and stash `{onCompleteCommand}` ← `workflow.on_complete` (empty string = no-op) for the final stage to invoke after the result JSON and metadata.json are finalized. After activation completes, execute each entry in `workflow.activation_steps_append` in order.
86
+ Apply the resolved values so the surface is not a silent no-op: execute each entry in `workflow.activation_steps_prepend` in order now; treat every entry in `workflow.persistent_facts` as standing context for the whole run (entries prefixed `file:` are paths or globs whose contents load as facts), except a `!` entry and the entry it names (`!file:{project-root}/**/project-context.md` drops the bundled project-context default); and stash `{onCompleteCommand}` ← `workflow.on_complete` (empty string = no-op) for step 8 to invoke once each brief's result contract is written. After activation completes, execute each entry in `workflow.activation_steps_append` in order.
82
87
 
83
- 4. Load, read the full file, and then execute `references/load-brief.md` to begin the workflow.
88
+ 4. Resolve `{emitEnvelopeHelper}` ← the first existing path of `{project-root}/_bmad/skf/shared/scripts/skf-emit-result-envelope.py` and `{project-root}/src/shared/scripts/skf-emit-result-envelope.py`, the shared emitter every result envelope, result contract and recorded decision goes through.
89
+
90
+ 5. If `--batch` was given, load, read the full file, and then execute `references/batch-mode.md`: it validates every brief first, runs steps 1 to 8 for each one and the health check once. Otherwise load, read the full file, and then execute `references/load-brief.md` to begin the workflow.
@@ -16,12 +16,12 @@ description: >
16
16
 
17
17
  - `name`: lowercase alphanumeric + hyphens only, must match the skill output directory name. Prefer gerund form (`processing-pdfs`, `analyzing-spreadsheets`) for clarity.
18
18
  - `description`: non-empty, max 1024 chars, optimized for agent discovery. Use third-person voice ("Processes Excel files..." not "I can help you..." or "You can use this to...") and include a trigger phrase so agents know when to match. **The description must contain a literal `Use when` clause somewhere** — `skill-check`'s `description.use_when_phrase` rule tests for that exact phrase anywhere in the string, so `Triggers on …` or `Reach for this when …` on their own score below 100 with a `description should contain "Use when" phrasing` warning. The lead is still free: a descriptive opener followed by a `Use when …` clause (`Charts and visualizations powered by D3.js. Use when plotting data …`) passes cleanly, and the other two phrases are fine as *additional* text. When using `Use when `, follow with a **gerund** (`Use when building/processing/analyzing X…`) or a noun-phrase clause (`Use when the user requests to "X"`); never a bare indicative verb like `builds`/`processes`, because `skill-check --fix` will prepend a literal `Use when ` to a description missing the trigger phrase, producing ungrammatical output (`Use when builds X…`). Inconsistent point-of-view or a missing trigger phrase causes discovery problems since the description is injected into the system prompt. See `skf-brief-skill/assets/description-voice-examples.md` for the canonical voice palette.
19
- - **The `description` cannot contain angle brackets** — neither standalone placeholders like `<name>`, `<component>`, `<path>`, nor inline generics like `` `Array<T>` `` or `` `Meta<typeof X>` ``. Both `skill-check`'s `description_field` validator and `tessl`'s deterministic description check parse the frontmatter description as a raw string and reject any `<` or `>`, regardless of markdown context (backticks do not protect content here). A rejected description fails the review with 0% score. When the natural phrasing would use angle brackets:
20
- - Prefer the curly-brace form in prose: `{name}`, `{component-id}`, `{path}` — readable and tessl-safe.
19
+ - **The `description` cannot contain angle brackets** — neither standalone placeholders like `<name>`, `<component>`, `<path>`, nor inline generics like `` `Array<T>` `` or `` `Meta<typeof X>` ``. The Claude platform does not accept a skill description that contains XML tags, and the description is read as a raw string, so backticks do not protect content here. No validator SKF runs catches this (skill-check has no such rule and Tessl Review accepts angle brackets), so SKF enforces it itself. When the natural phrasing would use angle brackets:
20
+ - Prefer the curly-brace form in prose: `{name}`, `{component-id}`, `{path}` — readable and free of angle brackets.
21
21
  - Uppercase placeholders are also acceptable: `NAME`, `COMPONENT_ID`.
22
22
  - For code-ish fragments, use curly braces in place of angle brackets inside the backticks: `` `Meta{typeof X}` ``, `` `Array{T}` ``.
23
23
 
24
- Authors should not rely on remembering this — step 5 §2a enforces it via a pre-write sanitization pass that unconditionally replaces every `<` with `{` and every `>` with `}` in the frontmatter `description`. See step 5 §2a for the rule and `assets/tessl-dismissal-rules.md` (`description-xml-tags-guarded-upstream`) for the recovery path if a downstream tool rewrites the description after §2a has run.
24
+ Authors should not rely on remembering this — step 5 §2a enforces it via a pre-write sanitization pass that unconditionally replaces every `<` with `{` and every `>` with `}` in the frontmatter `description`. See step 5 §2a for the rule and step 6 §6 for the check that applies it again if a later tool rewrites the description after §2a has run.
25
25
  - Only `name` and `description` in frontmatter — `version` and `author` go in metadata.json
26
26
  - No other frontmatter fields for standard skills (only `name`, `description`, `license`, `compatibility`, `metadata`, `allowed-tools` are permitted by spec)
27
27
 
@@ -100,6 +100,7 @@ These sections form the essential standalone body. Target: **under 300 lines tot
100
100
  <!-- [/MANUAL:additional-notes] -->
101
101
  ```
102
102
  - Place after Quick Start and after Key API Summary sections
103
+ - **Carry an earlier build's blocks.** Step 7 replaces an earlier build of this version whole, so when `{skills_output_folder}/{name}/{version}/{name}/SKILL.md` exists (`{version}` with build metadata stripped, as step 7 §1 does), carry its hand-written blocks into this SKILL.md. A block runs from `<!-- [MANUAL:<id>] -->` to the first `<!-- [/MANUAL:<id>] -->` after it, and it is hand-written unless it holds nothing but whitespace or the seeded note above (a note of the user's own in an HTML comment is hand-written). Put each hand-written block's interior, byte for byte, in place of the seeded note of the marker with its id, and append a block whose id has no marker here at the end of this section. Step 6 then validates SKILL.md with the blocks in, and step 7's promotion checks each one arrived and carries the earlier build's `scripts/[MANUAL]/` and `assets/[MANUAL]/` files. When the earlier build holds a hand-written block or such a file, record the decision: stage `{"step": "compile", "gate": "manual-carry-forward", "decision": "carry", "rationale": "<the earlier build's folder, its block ids and its [MANUAL]/ files>", "timestamp": "<ISO-8601>"}` as `{run_dir}/decision.json` and run `uv run {emitEnvelopeHelper} record --workflow skf-create-skill --run-dir "{run_dir}" --decision < "{run_dir}/decision.json"`.
103
104
 
104
105
  ### Tier 2 — Reference-Eligible (can be extracted by split-body)
105
106
 
@@ -268,7 +269,7 @@ Replace per-function subsections with `references/pattern-*.md` groupings: one r
268
269
 
269
270
  - `stats.exports_documented` MAY be set to the Pattern Surface row count as a proxy, but its semantics change: it counts authored pattern surfaces, not public exports. Emit an adjacent `stats.pattern_surfaces_documented` with the same integer so downstream consumers (test-skill, feasibility, discovery) can discriminate.
270
271
  - `exports_public_api` / `exports_internal` / `exports_total` are not meaningful for a reference app — omit them, or set all three to the Pattern Surface count with a note in `stats.notes`: `"reference-app: export counts are pattern-surface proxies, not library exports"`.
271
- - Do not fabricate signature / type-coverage data from pattern surfaces. skf-test-skill will skip those categories when metadata flags a reference-app (same skip path as `stackSkill` once that flag is wired — see scoring-rules.md).
272
+ - Do not fabricate signature / type-coverage data from pattern surfaces. skf-test-skill skips those categories when metadata flags a reference-app (`referenceApp`, the same skip path as `stackSkill`; its `scripts/compute-score.py` redistributes their weights).
272
273
  - Do not emit `effective_denominator` for reference-app scope, even when the source is a monorepo. `effective_denominator` counts public exports from the authoring-surface barrel — a library concept that `pattern_surfaces_documented` already replaces here. A reference-app-in-monorepo literally satisfies `compile.md` §4's emit-conditions (condition 1 arm (a) + non-`full-library` + stratified `scope.notes`), so this carve-out takes precedence: pattern-surface coverage is the reference-app basis, and skf-test-skill skips library-export coverage for it.
273
274
 
274
275
  **Language / spec-reference sub-shape:** A reference app that documents an engine- or spec-versioned **language** — a query language, grammar, or DSL (e.g. SurrealQL @ SurrealDB) whose value is construct idioms rather than wiring or exports — is a recognized reference-app sub-shape. Keep `scope.type: "reference-app"` (there is no separate enum value), so every carve-out above applies unchanged (`pattern_surfaces_documented` proxy, no `effective_denominator`, test-skill signature/type skip). Adapt the three overrides to the language's surface instead of app wiring:
@@ -297,7 +298,7 @@ A **whole-language reference** is a compiler/interpreter repo (rustc, CPython, t
297
298
 
298
299
  **GATE — apply ONLY when this is a whole-language reference.** The brief carries ≥1 `doc_urls` entry with `source: language-registry` (equivalently, `skf-derive-assembly-shape.py` returns `assembly_shape: "whole-language-reference"`). This is a structured, schema-validated signal — not a `scope.notes` substring — so an ordinary `full-library` library, a parser *library* (pest/lalrpop — its code IS the product, so §6b seeds no corpora), a component-library, a reference-app (including the language/spec-reference DSL sub-shape, which stays `scope.type: reference-app` and is handled by the reference-app override above), and a docs-only brief all fail the gate. When the gate does not fire, **skip this entire section** — the standard Tier 1 (sections 1–8) and Tier 2 (9–11) layout and the signature-fidelity rule run unchanged, so non-whole-language skills assemble byte-identically.
299
300
 
300
- When the gate fires, the assembler has a `language_guide[]` artifact from step 3c §4a (the retained corpora prose, carved out of the T3-vs-T1 conflict rule). Apply these overrides:
301
+ When the gate fires, the assembler has a `language_guide[]` artifact, which step 5 §1 builds from the registry pages step 3c §4a kept (the retained corpora prose, carved out of the T3-vs-T1 conflict rule). Apply these overrides:
301
302
 
302
303
  **Empty-guide guard (check first):** If `language_guide[]` is absent or every entry's `prose` is null (all registry corpora failed to fetch), do not emit a thin Language Guide above a full internals section — fall back to the standard layout and record a warning in `evidence-report.md`: "Whole-language reference gated but no Language-Guide prose was retained — assembled as a standard library skill." This prevents the inverse-value outcome (prose section empty, compiler internals dominant).
303
304
 
@@ -140,7 +140,8 @@ Indexed pipe-delimited format for CLAUDE.md managed section (~80-120 tokens per
140
140
  // "scripts": [{ "file": "scripts/{name}", "purpose": "{description}", "source_file": "{source-path}", "confidence": "T1-low" }],
141
141
  // "assets": [{ "file": "assets/{name}", "purpose": "{description}", "source_file": "{source-path}", "confidence": "T1-low" }],
142
142
  // doc_sources[] — include ONLY when doc detection ran; omit if detection was skipped entirely
143
- // "doc_sources": [{ "url": "https://...", "detected_via": "homepageUrl|readme_link|pages_api|docs_folder|readme_always", "content_hash": "sha256:{hex}|null", "recorded_at": "ISO-8601" }],
143
+ // "doc_sources": [{ "url": "https://...", "detected_via": "homepageUrl|readme_link|pages_api|docs_folder|readme_always|brief_doc_urls", "content_hash": "sha256:{hex}|null", "recorded_at": "ISO-8601" }],
144
+ // detected_via "brief_doc_urls" = docs-only skills: the brief's doc_urls (plus subpages step 3c fetched), hashed by `skf-detect-docs.py hash-urls`
144
145
  "generated_by": "{quick-skill|create-skill}",
145
146
  "dependencies": [],
146
147
  "compatibility": "{semver-range}"
@@ -193,7 +194,7 @@ Each reference file includes:
193
194
  "source_line": 42,
194
195
  "confidence": "T1",
195
196
  "extraction_method": "ast-grep",
196
- "ast_node_type": "export_function_declaration",
197
+ "ast_node_type": "export_statement",
197
198
  "signature_source": "T1"
198
199
  }
199
200
  ],
@@ -202,7 +203,7 @@ Each reference file includes:
202
203
  "libraries": ["lib-a", "lib-b"],
203
204
  "pattern_type": "provider-consumer",
204
205
  "detection_method": "co-import grep|architecture_co_mention|inferred_from_shared_domain",
205
- "co_import_files": [{"file": "src/app.ts", "line": 5}],
206
+ "co_import_files": [{"path": "src/app.ts", "line_a": 5, "line_b": 7}],
206
207
  "confidence": "T1|T2|T3"
207
208
  }
208
209
  ],
@@ -281,10 +282,13 @@ t2_future_count: {N}
281
282
  ## Validation Results
282
283
  - Schema: {pass/fail} (quality score: {score}/100)
283
284
  - Frontmatter: {pass/fail}
284
- - Body: {pass/fail} {split-body applied if applicable}
285
+ - Body: {pass/fail} {body split applied if applicable}
285
286
  - Security: {pass/warn/skipped}
286
- - Content Quality (tessl): {pass/warn/skipped} (score: {score}%)
287
+ - Description angle brackets: {none | re-sanitized ({count} substitutions) | not checked — no description}
288
+ - Tessl Review: {tessl_summary}
287
289
  - Metadata: {pass/fail}
290
+ - Provenance labels: {pass | relabeled {N} to match extraction_method: {export names}}{; WARN, no node kind found: {export names}}
291
+ - Provenance lines: {pass | findings | fixed {N} source lines, {M} citation prefixes and {K} node kinds | not run: verifier missing | not run: verifier error}{; second run: verifier error}{; unverified, no definition line found: {export names}}{; WARN: {each line, citation or node-kind warning §7a lists}}{; source lines not checked: no local source tree}{; node kinds not checked: no ast-grep CLI | unrecognized ast-grep}{; node kinds unchecked: {export name (reason) for each node_kinds_unchecked item}}{; node kinds skipped: {N} in files ast-grep has no language for}
288
292
 
289
293
  ## Quality Score Breakdown
290
294
  - Frontmatter (30%): {score} | Description (30%): {score} | Body (20%): {score} | Links (10%): {score} | File (10%): {score}
@@ -300,8 +304,15 @@ t2_future_count: {N}
300
304
 
301
305
  ## Remaining Warnings
302
306
  - {any warnings from extraction or validation}
307
+
308
+ ## Tessl Review
309
+ - Result: {tessl_summary}
310
+ - Workspace: {tessl_workspace or —} · tessl {tessl_version or —} · Run: {tessl_run_id or —}
311
+ - Validation findings: {each {tessl_validation} finding as `name (status): message`, or "none"}
312
+ - Description suggestions (to act on one, edit the description in the brief and re-run create-skill): {each of {tessl_description_suggestions}, or "none"}
313
+ - Content suggestions (advisory, not applied): {each of {tessl_content_suggestions} with its `(not applicable: <rule-id>)` mark, or "none"}
303
314
  ```
304
315
 
305
316
  **Frontmatter — pinned detection contract:** the `t2_future_count` field is the authoritative forward-looking-annotation count for downstream gate checks (e.g. skf-test-skill §2b migration-section rule). Emit **always**, even when 0 — omission is indistinguishable from "no T2-future data" and silently flips the gate into Case 2/3 for a Case-1 skill. `generated` and `forge_tier` mirror the narrative header for consumers that read only the frontmatter. Downstream gate rules parse `t2_future_count` from frontmatter, not prose — prose drift (heading renames, alternate phrasings like "forward-looking annotations") silently breaks grep-based detection.
306
317
 
307
- **Description Guard slot:** populated by step 6 §0 (create-skill) and §0 (update-skill) when the guard protocol fires. `Restored: true` indicates that an external tool (typically `skill-check --fix` or `split-body`) rewrote the frontmatter `description` and the guard restored the pre-tool value. When `Restored: false`, leave `Triggering tool`, `Original description preserved`, and `Notes` as `—`. When `Restored: true`, fill all four fields: tool name, whether the original was successfully written back, and a one-sentence note describing what the tool had changed (e.g., "replaced with generic summary", "truncated at 80 chars", "angle-bracket tokens re-introduced"). Downstream test-skill assertions can grep for `Restored: true` to detect unintended tool rewrites without parsing free-form warning prose.
318
+ **Description Guard slot:** populated by step 6 §0 (create-skill) and §0 (update-skill) when the guard protocol fires. `Restored: true` indicates that an external tool (typically `skill-check --fix`, create-skill's `skf-shard-body.py` body split or update-skill's `split-body`) rewrote the frontmatter `description` and the guard restored the pre-tool value. When `Restored: false`, leave `Triggering tool`, `Original description preserved`, and `Notes` as the no-fire dash the template above shows. When `Restored: true`, fill all four fields: tool name, whether the original was successfully written back, and a one-sentence note describing what the tool had changed (e.g., "replaced with generic summary", "truncated at 80 chars", "angle-bracket tokens re-introduced"). Downstream test-skill assertions can grep for `Restored: true` to detect unintended tool rewrites without parsing free-form warning prose.