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.
- package/.claude-plugin/marketplace.json +1 -1
- package/README.md +51 -49
- package/docs/404.md +10 -8
- package/docs/_data/pinned.yaml +22 -13
- package/docs/_internal/STABILITY.md +58 -35
- package/docs/agents.md +39 -53
- package/docs/architecture.md +65 -51
- package/docs/bmad-synergy.md +53 -51
- package/docs/campaign.md +127 -75
- package/docs/concepts.md +34 -28
- package/docs/examples.md +70 -68
- package/docs/forge-auto.md +34 -31
- package/docs/getting-started.md +118 -57
- package/docs/how-it-works.md +25 -21
- package/docs/index.md +15 -15
- package/docs/skill-model.md +70 -59
- package/docs/troubleshooting.md +135 -18
- package/docs/verifying-a-skill.md +83 -57
- package/docs/why-skf.md +24 -22
- package/docs/workflows.md +274 -110
- package/package.json +18 -10
- package/src/forger/preferences.yaml +8 -1
- package/src/knowledge/agentskills-spec.md +2 -0
- package/src/knowledge/ccc-bridge.md +40 -24
- package/src/knowledge/confidence-tiers.md +9 -5
- package/src/knowledge/overview.md +3 -3
- package/src/knowledge/progressive-capability.md +8 -8
- package/src/knowledge/provenance-tracking.md +9 -5
- package/src/knowledge/qmd-registry.md +2 -2
- package/src/knowledge/skf-knowledge-index.csv +2 -2
- package/src/knowledge/skill-lifecycle.md +18 -11
- package/src/knowledge/split-body-strategy.md +0 -3
- package/src/knowledge/tool-resolution.md +4 -2
- package/src/knowledge/version-paths.md +101 -15
- package/src/module-help.csv +3 -3
- package/src/module.yaml +10 -0
- package/src/shared/data/ast-grep-recipes.yaml +608 -0
- package/src/shared/data/ide-context-files.json +30 -0
- package/src/shared/health-check.md +32 -12
- package/src/shared/references/description-guard-protocol.md +14 -9
- package/src/shared/references/feasibility-report-schema.md +19 -13
- package/src/shared/references/headless-gate-convention.md +55 -3
- package/src/shared/references/output-contract-schema.md +19 -8
- package/src/shared/references/pipeline-contracts.md +94 -29
- package/src/shared/references/tessl-review.md +77 -0
- package/src/shared/scripts/schemas/skf-analyze-result-envelope.v1.json +194 -0
- package/src/shared/scripts/schemas/skf-audit-result-envelope.v1.json +192 -0
- package/src/shared/scripts/schemas/skf-brief-result-envelope.v1.json +32 -4
- package/src/shared/scripts/schemas/skf-campaign-result-envelope.v1.json +174 -0
- package/src/shared/scripts/schemas/skf-create-skill-result-envelope.v1.json +284 -0
- package/src/shared/scripts/schemas/skf-drop-skill-result-envelope.v1.json +164 -0
- package/src/shared/scripts/schemas/skf-export-result-envelope.v1.json +160 -0
- package/src/shared/scripts/schemas/skf-quick-skill-result-envelope.v1.json +261 -0
- package/src/shared/scripts/schemas/skf-refine-architecture-result-envelope.v1.json +192 -0
- package/src/shared/scripts/schemas/skf-rename-skill-result-envelope.v1.json +179 -0
- package/src/shared/scripts/schemas/skf-setup-result-envelope.v1.json +27 -11
- package/src/shared/scripts/schemas/skf-stack-result-envelope.v1.json +176 -0
- package/src/shared/scripts/schemas/skf-test-result-envelope.v1.json +173 -0
- package/src/shared/scripts/schemas/skf-update-result-envelope.v1.json +19 -5
- package/src/shared/scripts/schemas/skf-verify-stack-result-envelope.v1.json +180 -0
- package/src/shared/scripts/schemas/skill-brief.v1.json +34 -0
- package/src/shared/scripts/schemas/workspace-detection.v1.json +1 -1
- package/src/shared/scripts/skf-atomic-write.py +30 -14
- package/src/shared/scripts/skf-build-change-manifest.py +2203 -24
- package/src/shared/scripts/skf-ccc-git-hygiene.py +532 -0
- package/src/shared/scripts/skf-check-unit-records.py +184 -0
- package/src/shared/scripts/skf-check-workspace-drift.py +538 -9
- package/src/shared/scripts/skf-classify-changed-files.py +694 -0
- package/src/shared/scripts/skf-comention-pairs.py +1333 -123
- package/src/shared/scripts/skf-compare-file-hashes.py +1 -1
- package/src/shared/scripts/skf-count-imports.py +1867 -0
- package/src/shared/scripts/skf-count-tokens.py +1 -1
- package/src/shared/scripts/skf-derive-assembly-shape.py +3 -2
- package/src/shared/scripts/skf-description-guard.py +117 -9
- package/src/shared/scripts/skf-detect-docs.py +892 -4
- package/src/shared/scripts/skf-detect-language.py +486 -107
- package/src/shared/scripts/skf-detect-registry.py +887 -0
- package/src/shared/scripts/skf-detect-scripts-assets.py +1 -1
- package/src/shared/scripts/skf-detect-tools.py +215 -27
- package/src/shared/scripts/skf-detect-workspaces.py +506 -30
- package/src/shared/scripts/skf-disqualify-candidates.py +821 -182
- package/src/shared/scripts/skf-emit-brief-result-envelope.py +69 -191
- package/src/shared/scripts/skf-emit-result-envelope.py +1604 -106
- package/src/shared/scripts/skf-enumerate-stack-skills.py +986 -117
- package/src/shared/scripts/skf-extract-public-api.py +4084 -85
- package/src/shared/scripts/skf-extraction-inventory.py +746 -0
- package/src/shared/scripts/skf-extraction-snapshot.py +539 -0
- package/src/shared/scripts/skf-fetch-temporal.py +674 -0
- package/src/shared/scripts/skf-find-cycles.py +97 -29
- package/src/shared/scripts/skf-find-test-report.py +476 -0
- package/src/shared/scripts/skf-forge-tier-rw.py +444 -203
- package/src/shared/scripts/skf-github-fetch.py +365 -0
- package/src/shared/scripts/skf-github-probe.py +661 -0
- package/src/shared/scripts/skf-hash-content.py +166 -12
- package/src/shared/scripts/skf-language-corpora.py +1 -1
- package/src/shared/scripts/skf-load-provenance.py +159 -27
- package/src/shared/scripts/skf-manifest-ops.py +1 -1
- package/src/shared/scripts/skf-merge-ccc-exclusions.py +2307 -223
- package/src/shared/scripts/skf-merge-doc-urls.py +1 -1
- package/src/shared/scripts/skf-names-present.py +221 -0
- package/src/shared/scripts/skf-pair-intersect.py +119 -28
- package/src/shared/scripts/skf-parse-gaps.py +1384 -0
- package/src/shared/scripts/skf-preapply.py +1 -1
- package/src/shared/scripts/skf-preflight.py +161 -27
- package/src/shared/scripts/skf-promote-staged.py +430 -0
- package/src/shared/scripts/skf-provenance-gap-dispatch.py +39 -7
- package/src/shared/scripts/skf-qmd-classify-collections.py +229 -45
- package/src/shared/scripts/skf-quick-batch.py +774 -0
- package/src/shared/scripts/skf-rebuild-managed-sections.py +972 -88
- package/src/shared/scripts/skf-recommend-scope-type.py +323 -156
- package/src/shared/scripts/skf-render-metadata-stats.py +156 -12
- package/src/shared/scripts/skf-render-quick-metadata.py +132 -28
- package/src/shared/scripts/skf-render-stack-metadata.py +976 -0
- package/src/shared/scripts/skf-resolve-authoritative-files.py +128 -13
- package/src/shared/scripts/skf-resolve-package.py +523 -106
- package/src/shared/scripts/skf-rewrite-skill-name.py +433 -47
- package/src/shared/scripts/skf-run-lock.py +577 -0
- package/src/shared/scripts/skf-scan-manifests.py +998 -57
- package/src/shared/scripts/skf-scan-skill-md-structure.py +1341 -37
- package/src/shared/scripts/skf-severity-classify.py +712 -108
- package/src/shared/scripts/skf-shape-detect.py +298 -204
- package/src/shared/scripts/skf-shard-body.py +9 -8
- package/src/shared/scripts/skf-skill-inventory.py +2412 -89
- package/src/shared/scripts/skf-skills-module.py +472 -0
- package/src/shared/scripts/skf-source-tree.py +1796 -0
- package/src/shared/scripts/skf-structural-diff.py +670 -119
- package/src/shared/scripts/skf-tessl-review.py +706 -0
- package/src/shared/scripts/skf-update-active-symlink.py +5 -5
- package/src/shared/scripts/skf-update-run-state.py +624 -0
- package/src/shared/scripts/skf-validate-brief-inputs.py +92 -29
- package/src/shared/scripts/skf-validate-brief-schema.py +4 -1
- package/src/shared/scripts/skf-validate-feasibility-report.py +577 -66
- package/src/shared/scripts/skf-validate-frontmatter.py +103 -26
- package/src/shared/scripts/skf-validate-output.py +712 -64
- package/src/shared/scripts/skf-validate-pins.py +1 -1
- package/src/shared/scripts/skf-verify-no-trace.py +116 -10
- package/src/shared/scripts/skf-verify-provenance-completeness.py +2919 -54
- package/src/shared/scripts/skf-write-skill-brief.py +367 -19
- package/src/shared/tool-requirements.yaml +201 -0
- package/src/skf-analyze-source/SKILL.md +41 -36
- package/src/skf-analyze-source/assets/skill-brief-schema.md +7 -8
- package/src/skf-analyze-source/customize.toml +36 -24
- package/src/skf-analyze-source/references/auto-docs-only.md +58 -20
- package/src/skf-analyze-source/references/continue.md +2 -13
- package/src/skf-analyze-source/references/discover-additional-source.md +147 -0
- package/src/skf-analyze-source/references/generate-briefs.md +121 -55
- package/src/skf-analyze-source/references/headless-contract.md +42 -15
- package/src/skf-analyze-source/references/identify-units.md +96 -110
- package/src/skf-analyze-source/references/init.md +73 -71
- package/src/skf-analyze-source/references/map-and-detect.md +123 -105
- package/src/skf-analyze-source/references/map-unit-exports.md +68 -0
- package/src/skf-analyze-source/references/recommend.md +51 -70
- package/src/skf-analyze-source/references/scan-project.md +60 -84
- package/src/skf-analyze-source/references/scan-root.md +39 -0
- package/src/skf-analyze-source/references/step-auto-scope-coexistence.md +47 -0
- package/src/skf-analyze-source/references/step-auto-scope-corpora.md +53 -0
- package/src/skf-analyze-source/references/step-auto-scope-split.md +91 -0
- package/src/skf-analyze-source/references/step-auto-scope.md +208 -293
- package/src/skf-analyze-source/references/step-shape-detect.md +14 -12
- package/src/skf-analyze-source/references/unit-detection-heuristics.md +37 -42
- package/src/skf-audit-skill/SKILL.md +43 -51
- package/src/skf-audit-skill/assets/drift-report-template.md +27 -3
- package/src/skf-audit-skill/customize.toml +41 -20
- package/src/skf-audit-skill/references/constituent-freshness.md +91 -0
- package/src/skf-audit-skill/references/doc-drift.md +141 -0
- package/src/skf-audit-skill/references/headless-contract.md +29 -0
- package/src/skf-audit-skill/references/init.md +148 -210
- package/src/skf-audit-skill/references/re-index.md +96 -108
- package/src/skf-audit-skill/references/report.md +96 -33
- package/src/skf-audit-skill/references/semantic-diff.md +27 -18
- package/src/skf-audit-skill/references/severity-classify.md +79 -65
- package/src/skf-audit-skill/references/severity-rules.md +15 -6
- package/src/skf-audit-skill/references/structural-diff.md +75 -90
- package/src/skf-audit-skill/references/upstream-checkout.md +77 -0
- package/src/skf-audit-skill/scripts/render-drift-tables.py +685 -0
- package/src/skf-brief-skill/SKILL.md +36 -25
- package/src/skf-brief-skill/assets/description-voice-examples.md +1 -1
- package/src/skf-brief-skill/assets/scope-templates.md +17 -24
- package/src/skf-brief-skill/assets/skill-brief-schema.md +29 -15
- package/src/skf-brief-skill/customize.toml +48 -20
- package/src/skf-brief-skill/references/analyze-target.md +142 -125
- package/src/skf-brief-skill/references/confirm-brief.md +10 -8
- package/src/skf-brief-skill/references/draft-checkpoint.md +36 -17
- package/src/skf-brief-skill/references/gather-intent-ratify.md +68 -0
- package/src/skf-brief-skill/references/gather-intent.md +87 -182
- package/src/skf-brief-skill/references/headless-args.md +84 -16
- package/src/skf-brief-skill/references/health-check.md +1 -1
- package/src/skf-brief-skill/references/invocation-contract.md +18 -13
- package/src/skf-brief-skill/references/portfolio-similarity-check.md +1 -1
- package/src/skf-brief-skill/references/qmd-collection-registration.md +7 -10
- package/src/skf-brief-skill/references/scope-definition.md +123 -47
- package/src/skf-brief-skill/references/step-auto-brief.md +24 -80
- package/src/skf-brief-skill/references/step-auto-validate.md +20 -121
- package/src/skf-brief-skill/references/version-resolution.md +3 -2
- package/src/skf-brief-skill/references/write-brief.md +66 -57
- package/src/skf-campaign/SKILL.md +31 -34
- package/src/skf-campaign/assets/campaign-state-schema.json +25 -4
- package/src/skf-campaign/customize.toml +47 -16
- package/src/skf-campaign/references/campaign-contracts.md +39 -29
- package/src/skf-campaign/references/campaign-directive-spec.md +4 -2
- package/src/skf-campaign/references/health-check.md +7 -16
- package/src/skf-campaign/references/step-01-setup.md +46 -84
- package/src/skf-campaign/references/step-02-strategy.md +31 -30
- package/src/skf-campaign/references/step-03-pins.md +26 -18
- package/src/skf-campaign/references/step-04-provenance.md +24 -23
- package/src/skf-campaign/references/step-05-skill-loop.md +67 -48
- package/src/skf-campaign/references/step-06-batch.md +41 -34
- package/src/skf-campaign/references/step-07-capstone.md +40 -25
- package/src/skf-campaign/references/step-08-verify.md +28 -29
- package/src/skf-campaign/references/step-09-refine.md +29 -30
- package/src/skf-campaign/references/step-10-export.md +48 -36
- package/src/skf-campaign/references/step-11-maintenance.md +31 -34
- package/src/skf-campaign/references/step-resume.md +37 -68
- package/src/skf-campaign/scripts/campaign-deps.py +57 -18
- package/src/skf-campaign/scripts/campaign-parse-manifest.py +361 -54
- package/src/skf-campaign/scripts/campaign-provenance.py +96 -53
- package/src/skf-campaign/scripts/campaign-quality-gate.py +592 -0
- package/src/skf-campaign/scripts/campaign-render-batch.py +257 -49
- package/src/skf-campaign/scripts/campaign-render-kickoff.py +343 -50
- package/src/skf-campaign/scripts/campaign-report.py +204 -37
- package/src/skf-campaign/scripts/campaign-state.py +1128 -0
- package/src/skf-campaign/scripts/campaign-status.py +10 -74
- package/src/skf-campaign/scripts/campaign-validate-pins.py +30 -3
- package/src/skf-campaign/scripts/campaign-validate-state.py +34 -4
- package/src/skf-campaign/templates/campaign-brief-template.yaml +4 -5
- package/src/skf-campaign/templates/campaign-report-template.md +5 -1
- package/src/skf-campaign/templates/kickoff-template.md +0 -14
- package/src/skf-create-skill/SKILL.md +27 -20
- package/src/skf-create-skill/assets/compile-assembly-rules.md +6 -5
- package/src/skf-create-skill/assets/skill-sections.md +17 -6
- package/src/skf-create-skill/customize.toml +20 -8
- package/src/skf-create-skill/references/authoritative-files-protocol.md +41 -42
- package/src/skf-create-skill/references/batch-mode.md +81 -0
- package/src/skf-create-skill/references/ccc-index-check.md +27 -0
- package/src/skf-create-skill/references/compile.md +107 -29
- package/src/skf-create-skill/references/component-extraction.md +113 -91
- package/src/skf-create-skill/references/enrich.md +41 -23
- package/src/skf-create-skill/references/entry-points-by-hand.md +20 -0
- package/src/skf-create-skill/references/extract.md +200 -161
- package/src/skf-create-skill/references/extraction-patterns-by-hand.md +141 -0
- package/src/skf-create-skill/references/extraction-patterns-tracing.md +2 -2
- package/src/skf-create-skill/references/extraction-patterns.md +584 -196
- package/src/skf-create-skill/references/generate-artifacts.md +145 -93
- package/src/skf-create-skill/references/health-check.md +1 -1
- package/src/skf-create-skill/references/load-brief.md +53 -36
- package/src/skf-create-skill/references/relabel-rule.md +12 -0
- package/src/skf-create-skill/references/report.md +28 -59
- package/src/skf-create-skill/references/source-resolution-protocols.md +49 -155
- package/src/skf-create-skill/references/step-auto-shard.md +20 -93
- package/src/skf-create-skill/references/step-doc-rot.md +44 -60
- package/src/skf-create-skill/references/step-doc-sources.md +55 -18
- package/src/skf-create-skill/references/sub/ccc-discover.md +18 -7
- package/src/skf-create-skill/references/sub/fetch-docs.md +106 -57
- package/src/skf-create-skill/references/sub/fetch-temporal.md +53 -166
- package/src/skf-create-skill/references/tier-degradation-rules.md +18 -9
- package/src/skf-create-skill/references/validate.md +173 -99
- package/src/skf-create-skill/scripts/scan-doc-rot.py +232 -99
- package/src/skf-create-stack-skill/SKILL.md +29 -56
- package/src/skf-create-stack-skill/assets/metadata-contract.md +51 -0
- package/src/skf-create-stack-skill/assets/provenance-map-schema.md +15 -15
- package/src/skf-create-stack-skill/assets/stack-skill-template.md +23 -57
- package/src/skf-create-stack-skill/customize.toml +23 -12
- package/src/skf-create-stack-skill/references/compile-stack.md +57 -66
- package/src/skf-create-stack-skill/references/compose-mode-rules.md +24 -44
- package/src/skf-create-stack-skill/references/detect-integrations.md +92 -95
- package/src/skf-create-stack-skill/references/detect-manifests.md +46 -71
- package/src/skf-create-stack-skill/references/generate-output.md +138 -128
- package/src/skf-create-stack-skill/references/init.md +90 -32
- package/src/skf-create-stack-skill/references/integration-patterns.md +1 -17
- package/src/skf-create-stack-skill/references/invocation-contract.md +34 -0
- package/src/skf-create-stack-skill/references/manifest-patterns.md +32 -20
- package/src/skf-create-stack-skill/references/parallel-extract.md +112 -38
- package/src/skf-create-stack-skill/references/rank-and-confirm.md +57 -75
- package/src/skf-create-stack-skill/references/report.md +39 -33
- package/src/skf-create-stack-skill/references/validate.md +20 -39
- package/src/skf-drop-skill/SKILL.md +28 -51
- package/src/skf-drop-skill/customize.toml +44 -30
- package/src/skf-drop-skill/references/execute.md +79 -146
- package/src/skf-drop-skill/references/invocation-contract.md +64 -0
- package/src/skf-drop-skill/references/report.md +46 -30
- package/src/skf-drop-skill/references/select.md +118 -124
- package/src/skf-drop-skill/scripts/dir-sizes.py +54 -26
- package/src/skf-drop-skill/scripts/drop-roster.py +322 -0
- package/src/skf-export-skill/SKILL.md +40 -62
- package/src/skf-export-skill/assets/managed-section-format.md +14 -50
- package/src/skf-export-skill/assets/snippet-format.md +3 -1
- package/src/skf-export-skill/customize.toml +42 -13
- package/src/skf-export-skill/references/generate-snippet.md +54 -46
- package/src/skf-export-skill/references/health-check.md +2 -0
- package/src/skf-export-skill/references/invocation-contract.md +15 -0
- package/src/skf-export-skill/references/load-skill.md +88 -62
- package/src/skf-export-skill/references/manifest-rebuild.md +9 -10
- package/src/skf-export-skill/references/multi-skill-mode.md +4 -4
- package/src/skf-export-skill/references/orphan-context-detection.md +13 -5
- package/src/skf-export-skill/references/orphan-row-detection.md +31 -22
- package/src/skf-export-skill/references/package.md +15 -73
- package/src/skf-export-skill/references/preflight-snippet-root-probe.md +51 -70
- package/src/skf-export-skill/references/result-envelope.md +31 -16
- package/src/skf-export-skill/references/summary.md +41 -17
- package/src/skf-export-skill/references/token-report.md +4 -12
- package/src/skf-export-skill/references/update-context.md +118 -237
- package/src/skf-forger/SKILL.md +61 -37
- package/src/skf-forger/bmad-skill-manifest.yaml +4 -1
- package/src/skf-forger/customize.toml +43 -0
- package/src/skf-forger/references/pipeline-mode.md +73 -18
- package/src/skf-forger/scripts/forge-status.py +299 -0
- package/src/skf-forger/scripts/parse-pipeline.py +322 -54
- package/src/skf-forger/scripts/pipeline-gate.py +428 -0
- package/src/skf-forger/scripts/pipeline-journal.py +1052 -0
- package/src/skf-quick-skill/SKILL.md +54 -53
- package/src/skf-quick-skill/assets/skill-template.md +4 -2
- package/src/skf-quick-skill/customize.toml +51 -20
- package/src/skf-quick-skill/references/batch-mode.md +74 -21
- package/src/skf-quick-skill/references/compile.md +30 -31
- package/src/skf-quick-skill/references/ecosystem-check.md +7 -57
- package/src/skf-quick-skill/references/finalize.md +69 -18
- package/src/skf-quick-skill/references/halt-contract.md +41 -29
- package/src/skf-quick-skill/references/health-check.md +5 -3
- package/src/skf-quick-skill/references/quick-extract.md +114 -45
- package/src/skf-quick-skill/references/registry-resolution.md +9 -64
- package/src/skf-quick-skill/references/resolve-target.md +116 -66
- package/src/skf-quick-skill/references/write-and-validate.md +79 -40
- package/src/skf-refine-architecture/SKILL.md +43 -53
- package/src/skf-refine-architecture/customize.toml +49 -20
- package/src/skf-refine-architecture/references/compile.md +97 -54
- package/src/skf-refine-architecture/references/exit-codes.md +30 -0
- package/src/skf-refine-architecture/references/finding-storage.md +21 -0
- package/src/skf-refine-architecture/references/gap-analysis.md +101 -38
- package/src/skf-refine-architecture/references/improvements.md +14 -20
- package/src/skf-refine-architecture/references/init.md +98 -57
- package/src/skf-refine-architecture/references/issue-detection.md +32 -39
- package/src/skf-refine-architecture/references/refinement-rules.md +37 -48
- package/src/skf-refine-architecture/references/report.md +65 -54
- package/src/skf-refine-architecture/scripts/skf-check-preservation.py +1619 -0
- package/src/skf-rename-skill/SKILL.md +19 -54
- package/src/skf-rename-skill/customize.toml +32 -26
- package/src/skf-rename-skill/references/execute.md +230 -184
- package/src/skf-rename-skill/references/exit-codes.md +7 -7
- package/src/skf-rename-skill/references/health-check.md +1 -7
- package/src/skf-rename-skill/references/invocation-contract.md +25 -0
- package/src/skf-rename-skill/references/report.md +63 -52
- package/src/skf-rename-skill/references/select.md +197 -115
- package/src/skf-rename-skill/scripts/skf-validate-rename-name.py +161 -21
- package/src/skf-setup/SKILL.md +26 -26
- package/src/skf-setup/customize.toml +14 -10
- package/src/skf-setup/references/auto-index.md +50 -63
- package/src/skf-setup/references/ccc-index.md +29 -89
- package/src/skf-setup/references/detect-and-tier.md +58 -66
- package/src/skf-setup/references/health-check.md +2 -0
- package/src/skf-setup/references/invocation-contract.md +14 -0
- package/src/skf-setup/references/report.md +43 -166
- package/src/skf-setup/references/tier-rules.md +5 -5
- package/src/skf-setup/references/write-config.md +34 -57
- package/src/skf-test-skill/SKILL.md +17 -57
- package/src/skf-test-skill/assets/output-section-formats.md +33 -34
- package/src/skf-test-skill/customize.toml +27 -13
- package/src/skf-test-skill/references/coherence-check.md +134 -62
- package/src/skf-test-skill/references/coverage-check-tiers.md +35 -0
- package/src/skf-test-skill/references/coverage-check.md +217 -254
- package/src/skf-test-skill/references/detect-mode.md +5 -5
- package/src/skf-test-skill/references/external-validators.md +94 -82
- package/src/skf-test-skill/references/health-check.md +6 -7
- package/src/skf-test-skill/references/init.md +163 -88
- package/src/skf-test-skill/references/invocation-contract.md +66 -0
- package/src/skf-test-skill/references/migration-section-rules.md +5 -2
- package/src/skf-test-skill/references/report.md +162 -142
- package/src/skf-test-skill/references/score.md +80 -107
- package/src/skf-test-skill/references/scoring-rules.md +41 -155
- package/src/skf-test-skill/references/source-access-protocol.md +19 -92
- package/src/skf-test-skill/references/step-hard-gate.md +51 -33
- package/src/skf-test-skill/scripts/aggregate-coherence.py +218 -30
- package/src/skf-test-skill/scripts/build-result-context.py +287 -0
- package/src/skf-test-skill/scripts/check-metadata-coherence.py +37 -4
- package/src/skf-test-skill/scripts/combine-external-scores.py +23 -6
- package/src/skf-test-skill/scripts/compute-score.py +223 -45
- package/src/skf-test-skill/scripts/gap-ledger.py +1381 -0
- package/src/skf-test-skill/scripts/hard-gate.py +203 -0
- package/src/skf-test-skill/scripts/load-coverage-inputs.py +760 -0
- package/src/skf-test-skill/scripts/locate-export-segments.py +835 -0
- package/src/skf-test-skill/scripts/reconcile-coverage.py +273 -79
- package/src/skf-test-skill/scripts/score-signatures.py +459 -0
- package/src/skf-test-skill/scripts/stage-helper-payload.py +148 -0
- package/src/skf-test-skill/scripts/validate-inventory.py +311 -16
- package/src/skf-test-skill/scripts/verify-declared-numerator.py +127 -52
- package/src/skf-test-skill/templates/test-report-template.md +21 -15
- package/src/skf-update-skill/SKILL.md +38 -25
- package/src/skf-update-skill/customize.toml +27 -12
- package/src/skf-update-skill/references/detect-changes.md +233 -222
- package/src/skf-update-skill/references/gap-driven.md +336 -0
- package/src/skf-update-skill/references/health-check.md +31 -5
- package/src/skf-update-skill/references/init.md +250 -84
- package/src/skf-update-skill/references/invocation-contract.md +12 -0
- package/src/skf-update-skill/references/manual-section-rules.md +6 -23
- package/src/skf-update-skill/references/merge.md +180 -47
- package/src/skf-update-skill/references/re-extract.md +53 -262
- package/src/skf-update-skill/references/report.md +100 -35
- package/src/skf-update-skill/references/write.md +331 -149
- package/src/skf-update-skill/scripts/skf-new-file-diff.py +29 -7
- package/src/skf-verify-stack/SKILL.md +23 -42
- package/src/skf-verify-stack/assets/feasibility-report-template.md +11 -5
- package/src/skf-verify-stack/customize.toml +55 -22
- package/src/skf-verify-stack/references/coverage-patterns.md +17 -8
- package/src/skf-verify-stack/references/coverage.md +67 -64
- package/src/skf-verify-stack/references/exit-codes.md +21 -8
- package/src/skf-verify-stack/references/init.md +107 -62
- package/src/skf-verify-stack/references/integration-verification-rules.md +12 -13
- package/src/skf-verify-stack/references/integrations.md +106 -65
- package/src/skf-verify-stack/references/report.md +59 -42
- package/src/skf-verify-stack/references/requirements.md +32 -9
- package/src/skf-verify-stack/references/synthesize.md +53 -39
- package/src/skf-verify-stack/scripts/skf-coverage-tally.py +398 -52
- package/src/skf-verify-stack/scripts/skf-previous-report.py +330 -0
- package/src/skf-verify-stack/scripts/skf-report-delta.py +453 -49
- package/src/skf-verify-stack/scripts/skf-verdict-rollup.py +240 -27
- package/tools/cli/commands/install.js +11 -4
- package/tools/cli/commands/status.js +15 -3
- package/tools/cli/commands/update.js +11 -4
- package/tools/cli/lib/tool-check.js +320 -0
- package/tools/cli/lib/version-check.js +22 -9
- package/tools/cli/skf-cli.js +4 -1
- package/.gitattributes +0 -16
- package/.nvmrc +0 -1
- package/docs/_internal/RELEASING.md +0 -645
- package/release-audits/v1.0.0-launch-audit.md +0 -728
- package/src/skf-audit-skill/references/step-doc-drift.md +0 -177
- package/src/skf-brief-skill/references/headless-source-authority-detection.md +0 -26
- package/src/skf-campaign/manifest.yaml +0 -15
- package/src/skf-create-skill/assets/tessl-dismissal-rules.md +0 -106
- package/src/skf-create-skill/references/ecosystem-check.md +0 -74
- package/src/skf-drop-skill/references/headless-contract.md +0 -18
- package/src/skf-update-skill/references/merge-conflict-rules.md +0 -15
- package/src/skf-update-skill/references/remote-source-resolution.md +0 -98
- package/src/skf-update-skill/references/validate.md +0 -124
- package/tools/validate-docs-drift.js +0 -233
- package/tools/validate-docs-links.js +0 -665
|
@@ -1,23 +1,16 @@
|
|
|
1
1
|
# /// script
|
|
2
|
-
# requires-python = ">=3.
|
|
2
|
+
# requires-python = ">=3.11"
|
|
3
3
|
# dependencies = ["pyyaml"]
|
|
4
4
|
# ///
|
|
5
|
-
"""Campaign Status
|
|
5
|
+
"""Campaign Status: a deterministic summary of the campaign state.
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
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
|
|
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
|
|
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
|
|
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.
|
|
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.
|
|
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
|
|
2
|
-
#
|
|
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:**
|
|
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
|
|
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
|
-
-
|
|
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
|
|
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
|
|
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
|
|
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 |
|
|
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 |
|
|
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 |
|
|
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
|
|
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 (
|
|
61
|
-
| **Gates** | step 2: Choice Gate [P] (
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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.
|
|
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>` ``.
|
|
20
|
-
- Prefer the curly-brace form in prose: `{name}`, `{component-id}`, `{path}` — readable and
|
|
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
|
|
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
|
|
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": "
|
|
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": [{"
|
|
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} {
|
|
285
|
+
- Body: {pass/fail} {body split applied if applicable}
|
|
285
286
|
- Security: {pass/warn/skipped}
|
|
286
|
-
-
|
|
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
|
|
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.
|