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,8 +1,8 @@
|
|
|
1
1
|
# DO NOT EDIT -- overwritten on every update.
|
|
2
2
|
#
|
|
3
3
|
# Workflow customization surface for skf-export-skill.
|
|
4
|
-
# Team overrides: _bmad/custom/skf-export-skill.toml
|
|
5
|
-
# Personal overrides: _bmad/custom/skf-export-skill.user.toml
|
|
4
|
+
# Team overrides: {project-root}/_bmad/custom/skf-export-skill.toml
|
|
5
|
+
# Personal overrides: {project-root}/_bmad/custom/skf-export-skill.user.toml
|
|
6
6
|
|
|
7
7
|
[workflow]
|
|
8
8
|
|
|
@@ -10,7 +10,9 @@
|
|
|
10
10
|
# scalars: override wins • arrays (persistent_facts, activation_steps_*): append
|
|
11
11
|
# arrays-of-tables with `code`/`id`: replace matching items, append new ones.
|
|
12
12
|
|
|
13
|
-
# Steps
|
|
13
|
+
# Steps SKILL.md On Activation step 3 runs once this file resolves: after
|
|
14
|
+
# the config load (step 1) and the headless flag (step 2), before step 4
|
|
15
|
+
# resolves the helpers and creates the run folder, and before any stage.
|
|
14
16
|
# Overrides append. Use for org-wide pre-flight checks (auth, network,
|
|
15
17
|
# compliance) that must precede any export work.
|
|
16
18
|
|
|
@@ -26,28 +28,55 @@ activation_steps_append = []
|
|
|
26
28
|
# (publishing standards, distribution-instruction house style, snippet
|
|
27
29
|
# token-budget guardrails). Overrides append.
|
|
28
30
|
#
|
|
29
|
-
# Each entry is
|
|
31
|
+
# Each entry is one of:
|
|
30
32
|
# - a literal sentence, e.g. "All exported skills must include a CHANGELOG entry."
|
|
31
33
|
# - a file reference prefixed with `file:`, e.g.
|
|
32
34
|
# "file:{project-root}/docs/export-policy.md" (globs supported; file
|
|
33
35
|
# contents are loaded and treated as facts).
|
|
36
|
+
# - an entry prefixed with `!`, which loads nothing and drops each earlier
|
|
37
|
+
# entry it names.
|
|
38
|
+
#
|
|
39
|
+
# The default below loads every project-context.md under {project-root}.
|
|
40
|
+
# Overrides append, so they cannot delete it; to stop loading those files,
|
|
41
|
+
# set in {project-root}/_bmad/custom/skf-export-skill.toml:
|
|
42
|
+
# persistent_facts = ["!file:{project-root}/**/project-context.md"]
|
|
34
43
|
|
|
35
44
|
persistent_facts = [
|
|
36
45
|
"file:{project-root}/**/project-context.md",
|
|
37
46
|
]
|
|
38
47
|
|
|
39
|
-
# Optional post-export hook
|
|
40
|
-
#
|
|
41
|
-
# (before the terminal health-check step)
|
|
42
|
-
#
|
|
43
|
-
#
|
|
48
|
+
# Optional post-export hook: a shell command, not an instruction. When
|
|
49
|
+
# non-empty, step 6 runs `<value> --result-path="<per-run result JSON>"`
|
|
50
|
+
# after it writes that file (before the terminal health-check step); a
|
|
51
|
+
# --dry-run writes none and never invokes it. Example:
|
|
52
|
+
# on_complete = "scripts/publish-skill.sh". Useful for downstream
|
|
53
|
+
# distribution, notification, or pipeline chaining. A failure shows as a
|
|
54
|
+
# warning line in the run's output and never fails the workflow.
|
|
55
|
+
# Empty = no-op (default).
|
|
44
56
|
|
|
45
57
|
on_complete = ""
|
|
46
58
|
|
|
47
|
-
# --- Optional asset
|
|
59
|
+
# --- Optional asset override ---
|
|
48
60
|
#
|
|
49
|
-
#
|
|
50
|
-
#
|
|
61
|
+
# The snippet template step 3 fills for each skill. Empty string = the
|
|
62
|
+
# bundled default, assets/snippet-format.md. Override it to restyle the free
|
|
63
|
+
# lines or add one (an owner or license line, for example). Scripts parse
|
|
64
|
+
# the rest, so a copy keeps these as they are:
|
|
65
|
+
# - line 1, `[{skill-name} v{version}]|root: {skill_root}{skill-name}/`
|
|
66
|
+
# (for a stack, `[{project}-stack v{version}]|root: ...`): assemble
|
|
67
|
+
# builds each managed-section row from it and leaves out a snippet whose
|
|
68
|
+
# first line differs (skipped_malformed_snippet);
|
|
69
|
+
# - line 2, which starts `|IMPORTANT:` with the skill name as its first
|
|
70
|
+
# word (a single skill's also says `writing {skill-name} code`):
|
|
71
|
+
# skf-validate-output.py checks the start, and rename-skill rewrites the
|
|
72
|
+
# name in each place;
|
|
73
|
+
# - the `|gotchas:` label and its `[CARRIED]` marker, which step 3 reads
|
|
74
|
+
# to carry gotchas forward for one export;
|
|
75
|
+
# - no line that is a bare `|`, which splits rows in the managed section.
|
|
76
|
+
# The quick-start, api and key-types lines, and the stack and integrations
|
|
77
|
+
# lines, are free to change. The managed-section format and the IDE mapping
|
|
78
|
+
# have no override: drop-skill and rename-skill rebuild the same section
|
|
79
|
+
# through the shared helper, so a copy only export read would put them out
|
|
80
|
+
# of step.
|
|
51
81
|
|
|
52
|
-
managed_section_format_path = ""
|
|
53
82
|
snippet_format_path = ""
|
|
@@ -1,14 +1,9 @@
|
|
|
1
1
|
---
|
|
2
2
|
nextStepFile: 'update-context.md'
|
|
3
3
|
snippetFormatData: '{snippetFormatPath}'
|
|
4
|
-
#
|
|
5
|
-
#
|
|
6
|
-
#
|
|
7
|
-
# token count (char-over-four, matching step 5's token report) instead of the
|
|
8
|
-
# in-prompt `words * 1.3` heuristic.
|
|
9
|
-
countTokensProbeOrder:
|
|
10
|
-
- '{project-root}/_bmad/skf/shared/scripts/skf-count-tokens.py'
|
|
11
|
-
- '{project-root}/src/shared/scripts/skf-count-tokens.py'
|
|
4
|
+
# SKILL.md's On Activation resolved {countTokensHelper}, which measures the
|
|
5
|
+
# staged draft in §4, and {manifestOpsHelper}, whose `get` reads the skill's
|
|
6
|
+
# manifest entry in §3a.
|
|
12
7
|
---
|
|
13
8
|
|
|
14
9
|
<!-- Config: communicate in {communication_language}. Generate snippet content in {document_output_language}. -->
|
|
@@ -23,7 +18,8 @@ To generate or update context-snippet.md for the skill in the Vercel-aligned ind
|
|
|
23
18
|
|
|
24
19
|
- Focus only on generating the context-snippet.md content — T1-now only, no T2 annotations
|
|
25
20
|
- If `passive_context: false` was detected in step 1, skip this step entirely
|
|
26
|
-
- **Multi-skill mode:** when step 1 loaded more than one skill (`len(skill_batch) > 1`), iterate sections 2
|
|
21
|
+
- **Multi-skill mode:** when step 1 loaded more than one skill (`len(skill_batch) > 1`), iterate sections 2 to 5 per skill. Each skill has its own prior-gotchas carry-forward state (§2.5): do not share state across skills. §2.7 resolves `{skill_root}`, the snippet's root only, and §2.8 creates the stage folder once for the run (neither depends on the skill). See step 1 §1c.
|
|
22
|
+
- Every HALT names its exit code, `halt_reason` and phase; in headless mode it first emits its envelope as `references/result-envelope.md` states
|
|
27
23
|
|
|
28
24
|
## MANDATORY SEQUENCE
|
|
29
25
|
|
|
@@ -51,53 +47,78 @@ Before generating new snippet content, check for a prior snippet:
|
|
|
51
47
|
4. **Distinguish empty from absent:** If the `|gotchas:` line exists but has no non-whitespace content after the prefix, treat it as **absent** — set `prior_gotchas = null`. Only a non-empty value counts as a prior gotchas line worth carrying forward.
|
|
52
48
|
5. If no prior snippet exists at all, set `prior_gotchas = null` and `prior_gotchas_already_carried = false`.
|
|
53
49
|
|
|
54
|
-
These values will be used as a fallback in
|
|
50
|
+
These values will be used as a fallback in §3a if new gotchas cannot be derived. The `[CARRIED]` marker provides a **hard one-cycle expiry**: gotchas that were already carried once will be dropped on the next carry-forward attempt rather than preserved indefinitely.
|
|
55
51
|
|
|
56
52
|
### 2.7. Resolve Skill Root Path
|
|
57
53
|
|
|
58
|
-
**If `snippet_skill_root_override` is set
|
|
54
|
+
**If `{snippet_skill_root_override}` is set** (by `config.yaml`, or for this run by step 1's snippet-root option (d)): use its value directly as `{skill_root}` and skip the IDE-mapping lookup below. This is the authoring-repo escape hatch, for repos where skills live under a single shared directory (e.g. `skills/`) that does not match any per-IDE skill root. Log: "Using snippet_skill_root_override: `{override}`, bypassing the IDE mapping for the snippet root path."
|
|
59
55
|
|
|
60
56
|
**Otherwise (default):** Using the first entry in `target_context_files` (resolved in step 1), take its `skill_root` value. This is the IDE's actual skill directory (e.g., `.claude/skills/`, `.windsurf/skills/`, `.github/skills/`).
|
|
61
57
|
|
|
62
|
-
Store `{skill_root}` for use in snippet generation
|
|
58
|
+
Store `{skill_root}` for use in snippet generation: it is the snippet's root only, the `root:` path of the context-snippet.md this step stages. It is not a context file's root: step 4 builds each context file's managed section with that target's own skill root, so with `ides` [claude-code, codex] the AGENTS.md rows take `.agents/skills/` while the snippet keeps `.claude/skills/`.
|
|
59
|
+
|
|
60
|
+
### 2.8. Stage Folder
|
|
61
|
+
|
|
62
|
+
Once per run (skip this when `{export_stage_dir}` is already bound, as for the second skill of a batch), create the run's stage folder outside the project and bind `{export_stage_dir}` to the path this prints:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
python3 -c "import tempfile; print(tempfile.mkdtemp(prefix='skf-export-'))"
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
§4 stages each skill's snippet draft there, under `drafts/{skill-name}/`, and step 4 stages each context file's new section there, under `previews/`, so a dry run leaves nothing beside a skill package or a context file. Step 4 deletes the folder on every exit, cancels and halts included.
|
|
63
69
|
|
|
64
70
|
### 3. Generate Snippet Content
|
|
65
71
|
|
|
66
|
-
|
|
72
|
+
#### 3a. Gotchas (Both Skill Types)
|
|
73
|
+
|
|
74
|
+
Derive new gotchas from the T2-future annotations in the evidence report at `{forge_evidence_report}` (breaking changes), async requirements and version-specific behavior. Step 1 §2 bound that path; when it is null, the skill has no evidence report to read.
|
|
75
|
+
|
|
76
|
+
**Detect first-export state before applying carry-forward logic.** The `[CARRIED]` one-cycle expiry is meaningful only on a *re-export*. On a first export, the prior `context-snippet.md` was written by the workflow that built or updated the skill (create-skill, create-stack-skill, quick-skill or update-skill) inside the same forge cycle: those gotchas are freshly derived, not "left over from a previous export." Treating them as carry-forward primes them for premature expiry on the second export.
|
|
77
|
+
|
|
78
|
+
Read the skill's manifest entry: `python3 {manifestOpsHelper} {skills_output_folder} get {skill-name}`. When it returns `not_found`, or an `entry` none of whose `versions` records a `last_exported`, this is a first export: set `is_first_export = true`. Otherwise `is_first_export = false`. The helper returns the entry in the v2 shape whatever is on disk, so a v1 manifest reads the same here as in step 4.
|
|
79
|
+
|
|
80
|
+
Resolve the gotchas line by this decision tree:
|
|
81
|
+
|
|
82
|
+
- **If new gotchas are derived:** Use them (they supersede any prior gotchas). Write as `|gotchas: {pitfall-1}, {pitfall-2}` with no marker.
|
|
83
|
+
- **If NO new gotchas are derived AND `is_first_export == true` AND `prior_gotchas` exists:** Treat the prior gotchas as **freshly derived** by the workflow that wrote them, and write them **without** the `[CARRIED]` marker. (The marker only applies to re-exports.) No warning needed; this is the normal first-export shape.
|
|
84
|
+
- **If NO new gotchas are derived BUT `prior_gotchas` exists AND `is_first_export == false` AND `prior_gotchas_already_carried == false`:** First carry-forward cycle on a re-export: preserve the prior gotchas line, prefixing the value with `[CARRIED]` so the next export can detect that expiry has been reached. Write as `|gotchas: [CARRIED] {prior gotchas content}`. Emit warning: "**Gotchas preserved from prior export (one-cycle carry-forward).** These gotchas will be DROPPED on the next export unless new gotchas are derived or you manually refresh them. Review now if they are still applicable."
|
|
85
|
+
- **If NO new gotchas are derived AND `prior_gotchas` exists AND `prior_gotchas_already_carried == true`:** Expiry reached (re-export only: the first-export branch above takes precedence). Drop the gotchas line entirely. Emit warning: "**Stale gotchas dropped:** the prior gotchas were already carried forward once and cannot be derived from the current evidence report. The snippet now has no gotchas line. If the prior gotchas are still relevant, re-add them to the evidence report's T2-future section and re-run export."
|
|
86
|
+
- **If NO new gotchas derived AND no `prior_gotchas`:** Omit the gotchas line.
|
|
87
|
+
|
|
88
|
+
#### 3b. Single Skills (`skill_type: "single"`)
|
|
67
89
|
|
|
68
90
|
1. Read metadata.json for `version`, `exports` array
|
|
69
91
|
2. Select top exports (up to 10 for Deep tier, 5 otherwise). Append `()` to function names.
|
|
70
92
|
3. Read SKILL.md to extract: heading slugs for `#quick-start` and `#key-types`, inline summary of key types (~10 words)
|
|
71
93
|
4. **Anchor verification (split-body awareness):** For each section anchor (`#quick-start`, `#key-types`), verify the heading exists in SKILL.md. If a `references/` directory exists and `## Full` headings in SKILL.md are absent or stubs (indicating split-body, not a stack skill's structural references), rewrite the anchor to point to the reference file path (e.g., `references/{file}.md#key-types`). If the heading cannot be resolved in either location, omit that anchor line from the snippet.
|
|
72
|
-
5. Derive gotchas from: T2-future annotations in evidence report (breaking changes), async requirements, version-specific behavior.
|
|
73
|
-
|
|
74
|
-
**Detect first-export state before applying carry-forward logic.** The `[CARRIED]` one-cycle expiry is meaningful only on a *re-export*. On a first export, the prior `context-snippet.md` was authored by `create-skill` (or `update-skill`) from the evidence report inside the same forge cycle — those gotchas are freshly derived, not "left over from a previous export." Treating them as carry-forward primes them for premature expiry on the second export.
|
|
75
|
-
|
|
76
|
-
Read `{skills_output_folder}/.export-manifest.json` (the same file step 4 §4a will rewrite). If the skill name is **absent** from `exports`, OR present with no resolvable `last_exported` for any version under `versions`, this is a first export — set `is_first_export = true`. Otherwise `is_first_export = false`. (Step-04 reads the manifest authoritatively for the rebuild; this read is the lightweight probe step 3 needs to choose the right branch below.)
|
|
77
94
|
|
|
78
|
-
|
|
79
|
-
- **If NO new gotchas are derived AND `is_first_export == true` AND `prior_gotchas` exists:** Treat the prior gotchas as **freshly derived** by create-skill/update-skill — write them **without** the `[CARRIED]` marker. (The marker only applies to re-exports.) No warning needed; this is the normal first-export shape.
|
|
80
|
-
- **If NO new gotchas are derived BUT `prior_gotchas` exists AND `is_first_export == false` AND `prior_gotchas_already_carried == false`:** First carry-forward cycle on a re-export — preserve the prior gotchas line, prefixing the value with `[CARRIED]` so the next export can detect that expiry has been reached. Write as `|gotchas: [CARRIED] {prior gotchas content}`. Emit warning: "**Gotchas preserved from prior export (one-cycle carry-forward).** These gotchas will be DROPPED on the next export unless new gotchas are derived or you manually refresh them. Review now if they are still applicable."
|
|
81
|
-
- **If NO new gotchas are derived AND `prior_gotchas` exists AND `prior_gotchas_already_carried == true`:** Expiry reached (re-export only — first-export branch above takes precedence) — drop the gotchas line entirely. Emit warning: "**Stale gotchas dropped** — the prior gotchas were already carried forward once and cannot be derived from the current evidence report. The snippet now has no gotchas line. If the prior gotchas are still relevant, re-add them to the evidence report's T2-future section and re-run export."
|
|
82
|
-
- **If NO new gotchas derived AND no `prior_gotchas`:** Omit the gotchas line.
|
|
95
|
+
Emit the single-skill template from {snippetFormatData} (loaded in §2), filling `api` from the exports selected above (list all if fewer than the limit; omit the line if there are none), `key-types` from the inline summary extracted above, and `gotchas` per the §3a decision tree (omit the line when it resolves to none).
|
|
83
96
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
**For stack skills (`skill_type: "stack"`):**
|
|
97
|
+
#### 3c. Stack Skills (`skill_type: "stack"`)
|
|
87
98
|
|
|
88
99
|
Emit the stack-skill template from {snippetFormatData}, filling `stack` from metadata.json `components` and `integrations` from metadata.json `integrations`.
|
|
89
100
|
|
|
90
|
-
|
|
101
|
+
Stack skills: apply the gotchas decision tree above unchanged, including the first-export branch.
|
|
91
102
|
|
|
92
103
|
### 4. Verify Token Count
|
|
93
104
|
|
|
94
|
-
|
|
105
|
+
Write the generated snippet to `{export_stage_dir}/drafts/{skill-name}/context-snippet.md` with your file-write tool, and measure the draft with `{countTokensHelper}`, the count step 5's token report uses:
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
python3 {countTokensHelper} "{export_stage_dir}/drafts/{skill-name}"
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Bind `{count}` ← the `tokens` value of its `context-snippet.md` row (`len(text)//4`, the SKF-wide convention).
|
|
95
112
|
|
|
96
113
|
- Target: ~80-120 tokens per skill (aspirational for Quick/Forge tiers)
|
|
97
|
-
-
|
|
98
|
-
- If
|
|
114
|
+
- Hard ceiling: 300 tokens (Deep tier may legitimately exceed 120 when gotchas carry load-bearing breaking-change notices)
|
|
115
|
+
- If `{count}` is above 300, trim the description, the exports list or the refs, write the draft again and measure it again, until `{count}` is 300 or below. **Do NOT drop gotchas to fit**: gotchas exist precisely to deliver the "do not rely on training data" signal and are the last thing to cut
|
|
116
|
+
|
|
117
|
+
When the helper exits non-zero, delete the `{export_stage_dir}` folder and HALT (exit code 4, `halt_reason: "context-rebuild-failed"`, phase `generate-snippet §4`): "SKF cannot measure the snippet: {the helper's error}. Re-install SKF and re-run the export."
|
|
118
|
+
|
|
119
|
+
### 5. Preview the Snippet
|
|
99
120
|
|
|
100
|
-
|
|
121
|
+
Nothing is written to a skill package in this step: step 4 copies each measured draft into its package after its [C] gate (§9c), and a dry run never does.
|
|
101
122
|
|
|
102
123
|
**If dry-run mode:**
|
|
103
124
|
|
|
@@ -111,27 +132,14 @@ Estimate the generated snippet's token count with the **char-over-four** convent
|
|
|
111
132
|
|
|
112
133
|
**Estimated tokens:** {count}"
|
|
113
134
|
|
|
114
|
-
Use the §4 char-over-four estimate for `{count}` — nothing is written in dry-run, so the helper has no on-disk snippet to measure. Hold content in context for step 4.
|
|
115
|
-
|
|
116
135
|
**If NOT dry-run:**
|
|
117
136
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
Then confirm the token count authoritatively: resolve `{countTokensHelper}` from `{countTokensProbeOrder}` (first existing path wins) and run it against the written package, reading the `context-snippet.md` row's `tokens` value:
|
|
121
|
-
|
|
122
|
-
```bash
|
|
123
|
-
python3 {countTokensHelper} {resolved_skill_package}
|
|
124
|
-
```
|
|
125
|
-
|
|
126
|
-
Use that value as `{count}` — it matches step 5's token report exactly. If the helper cannot run (no Python/uv), fall back to the §4 char-over-four estimate.
|
|
127
|
-
|
|
128
|
-
"**context-snippet.md written.**
|
|
129
|
-
**Path:** `{resolved_skill_package}/context-snippet.md`
|
|
137
|
+
"**context-snippet.md staged.** Step 4 writes it to `{resolved_skill_package}/context-snippet.md` once its context-update gate passes.
|
|
130
138
|
**Estimated tokens:** {count}"
|
|
131
139
|
|
|
132
140
|
### 6. Proceed to Context Update
|
|
133
141
|
|
|
134
142
|
Display: "**Proceeding to context update...**"
|
|
135
143
|
|
|
136
|
-
Auto-proceed (no user choices): once snippet
|
|
144
|
+
Auto-proceed (no user choices): once each snippet is staged (or generation is skipped via the `passive_context` opt-out), load, read entirely, and execute `{nextStepFile}`.
|
|
137
145
|
|
|
@@ -13,6 +13,8 @@ nextStepFile: 'shared/health-check.md'
|
|
|
13
13
|
|
|
14
14
|
Chain to the shared workflow self-improvement health check at `{nextStepFile}`. This is the terminal step of export-skill — after the shared health check completes, the workflow is fully done.
|
|
15
15
|
|
|
16
|
+
In a headless run summary.md §6 bound `{result_envelope_line}` to the `SKF_EXPORT_RESULT_JSON` line without displaying it: the shared health check displays that line verbatim as the run's last line wherever it stops, so a `claude -p` caller reads the envelope as the final message.
|
|
17
|
+
|
|
16
18
|
## Rules
|
|
17
19
|
|
|
18
20
|
- No user-facing reports, file writes, or result contracts in this step — those belong in step 6
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
<!-- Config: the headless contract of skf-export-skill. Interactive runs do not load it. -->
|
|
2
|
+
|
|
3
|
+
# Invocation Contract
|
|
4
|
+
|
|
5
|
+
The inputs, flags, gates and outputs of `skf-export-skill`, for headless callers and pipelines. `references/result-envelope.md` holds the `SKF_EXPORT_RESULT_JSON` envelope and the exit code of every halt site.
|
|
6
|
+
|
|
7
|
+
| Aspect | Detail |
|
|
8
|
+
|--------|--------|
|
|
9
|
+
| **Inputs** | `skill_name` [one or more, required unless `--all`] |
|
|
10
|
+
| **Flags** | `--headless` / `-H` (auto-resolve all gates); `--all` (export every non-deprecated skill in `.export-manifest.json`); `--context-file <file>` (write only that context file, `CLAUDE.md`, `AGENTS.md` or `.cursorrules`, instead of every file config.yaml `ides` maps to, with the skill root of the first configured IDE that maps to it, else the one the IDE mapping gives that file; any other value halts with exit code 3, `resolution-failure`); `--dry-run` (stage everything but write nothing other than a headless run's scratch run folder, as **Outputs** says: the snippet, context-file and manifest changes are previewed only, no result file is written and no `on_complete` hook runs; the run completes through the terminal step with `status="dry-run"` and `manifest_path: null`) |
|
|
11
|
+
| **Gates** | step 1 §1b, only when config.yaml sets no `snippet_skill_root_override`: the layout question when no earlier export chose a snippet root (headless: [I], the IDE skill folder), or the mismatch gate when an earlier export's root differs from the IDE mapping (headless: checks the disk, and takes (d), the earlier root for this run, when only that folder holds the skills, else (b), the IDE mapping); step 1 §6: one Confirm Gate [C] for the whole batch (headless: [C]); step 4 §3b orphaned context files (headless: keep) and §4c.1 orphaned managed-section rows (headless: preserve); step 4 §8: one Confirm Gate [C] for the whole batch (headless: [C]) |
|
|
12
|
+
| **Outputs** | Updated `.export-manifest.json` (every skill in the batch, also when `passive_context` is off), updated context files (CLAUDE.md/AGENTS.md/.cursorrules), per-skill `context-snippet.md` (written last, after the step-4 gate), per-run result contract `export-skill-result-{YYYYMMDD-HHmmss}.json` and `export-skill-result-latest.json` (none on a dry run); in a headless run, a scratch run folder under `{project-root}/_bmad-output/.skf-run/`, which step 6 deletes (a HARD HALT keeps it) |
|
|
13
|
+
| **Multi-skill mode** | Activated when more than one skill is selected (via `--all`, multi-selection, or multi-argument invocation). See `references/load-skill.md` §1c for the per-step iteration map. |
|
|
14
|
+
| **Headless** | Every gate takes its default action and records it as it decides (SKILL.md Workflow Rules), and the run ends with one `SKF_EXPORT_RESULT_JSON` line: `references/result-envelope.md` |
|
|
15
|
+
| **Exit codes** | 0 on success and on a dry run. Each HARD HALT names its exit code and `halt_reason` where it occurs (3 and `not-skf-output` for a flat skill SKF did not generate, for example); `references/result-envelope.md` maps every halt site to its code |
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
---
|
|
2
2
|
nextStepFile: 'package.md'
|
|
3
|
-
|
|
4
|
-
#
|
|
5
|
-
#
|
|
6
|
-
#
|
|
7
|
-
#
|
|
8
|
-
#
|
|
9
|
-
#
|
|
10
|
-
#
|
|
11
|
-
|
|
12
|
-
- '{project-root}/_bmad/skf/shared/scripts/skf-
|
|
13
|
-
- '{project-root}/src/shared/scripts/skf-
|
|
3
|
+
# SKILL.md's On Activation resolved {manifestOpsHelper},
|
|
4
|
+
# {skillInventoryHelper}, {rebuildManagedSectionsHelper} and
|
|
5
|
+
# {validateOutputHelper}. §2 runs the inventory's `resolve` action to choose
|
|
6
|
+
# the version to export and bind its paths (the Manifest-lag guard included),
|
|
7
|
+
# and runs it with `--skill` before a flat skill moves: only a flat skill
|
|
8
|
+
# whose metadata.json carries an SKF marker (`flat_skf`) is migrated.
|
|
9
|
+
# Resolve `{findTestReportHelper}` to the first existing path. §4b runs its
|
|
10
|
+
# `find` action for the newest finished test report of the version §2 chose.
|
|
11
|
+
findTestReportProbeOrder:
|
|
12
|
+
- '{project-root}/_bmad/skf/shared/scripts/skf-find-test-report.py'
|
|
13
|
+
- '{project-root}/src/shared/scripts/skf-find-test-report.py'
|
|
14
14
|
---
|
|
15
15
|
|
|
16
16
|
<!-- Config: communicate in {communication_language}. -->
|
|
@@ -23,8 +23,9 @@ To load the target skill's artifacts, validate they meet agentskills.io spec com
|
|
|
23
23
|
|
|
24
24
|
## Rules
|
|
25
25
|
|
|
26
|
-
- Focus only on loading, validating, and confirming the skill — this is read-only
|
|
26
|
+
- Focus only on loading, validating, and confirming the skill — this is read-only, except the flat-to-versioned migration in §2
|
|
27
27
|
- Do not write any output files yet (packaging starts in Step 02)
|
|
28
|
+
- Every HALT names its exit code, `halt_reason` and phase; in headless mode it first emits its envelope as `references/result-envelope.md` states
|
|
28
29
|
|
|
29
30
|
## MANDATORY SEQUENCE
|
|
30
31
|
|
|
@@ -32,47 +33,57 @@ To load the target skill's artifacts, validate they meet agentskills.io spec com
|
|
|
32
33
|
|
|
33
34
|
"**Starting skill export...**"
|
|
34
35
|
|
|
35
|
-
Determine the skill(s) to export and any flags
|
|
36
|
+
Determine the skill(s) to export and any flags.
|
|
37
|
+
|
|
38
|
+
**Read the export manifest** on every run, through the helper, which returns it in the v2 shape whatever is on disk (an absent file reads as an empty `exports`), so a manifest that does not parse stops the run here, before any later step reads it:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
python3 {manifestOpsHelper} {skills_output_folder} read
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Use `result.manifest.exports`. On `status: "error"` (the file does not parse), HALT (exit code 3, `halt_reason: "resolution-failure"`, phase `load-skill §1`): "**Export manifest is corrupt** at `{skills_output_folder}/.export-manifest.json`: {error}. Fix or remove the file, then re-run."
|
|
36
45
|
|
|
37
46
|
**Skill Path Discovery (version-aware — see `knowledge/version-paths.md`):**
|
|
38
47
|
- If user provided one or more skill names or paths as arguments, use that list directly
|
|
39
|
-
- If `--all` was passed, build the list from every skill in `
|
|
48
|
+
- If `--all` was passed, build the list from every skill in `result.manifest.exports` whose `versions.{active_version}.status` is not `"deprecated"` (deprecated skills are excluded from all exports; a skill a v1 manifest marks deprecated reads as such through the helper). **First-export fallback:** if the manifest is absent or its `exports` object is empty (a fresh repo with skills on disk but no prior export), do not resolve to an empty set: enumerate skills on disk instead, with the same inventory scan as the no-argument branch below (steps 2-3), which keeps only skills SKF generated. Every disk-discovered skill is non-deprecated by definition, since deprecation status lives only in the manifest.
|
|
40
49
|
- If no explicit skill and no `--all`, then:
|
|
41
|
-
- **Headless guard:** if `{headless_mode}` is true, HALT (exit code 2, `halt_reason: "input-missing"`)
|
|
50
|
+
- **Headless guard:** if `{headless_mode}` is true, HALT (exit code 2, `halt_reason: "input-missing"`, phase `load-skill §1`): a non-interactive run cannot answer the skill-selection menu; the operator must pass an explicit `skill_name` or `--all`.
|
|
42
51
|
- **Interactive:** discover available skills using the export manifest:
|
|
43
|
-
1.
|
|
44
|
-
2.
|
|
45
|
-
3. If neither manifest nor `active` symlink yields results, fall back to flat path: `{skills_output_folder}/{skill-name}/SKILL.md`
|
|
52
|
+
1. List the skill names of `result.manifest.exports`
|
|
53
|
+
2. Run `uv run {skillInventoryHelper} {skills_output_folder}` once. Add every `skills[]` entry whose `skf_skill` is true and whose `flat_skf` is true or `active_version` is not null (a flat SKF skill that §2 migrates, or a versioned skill with an SKF marker and an `active` link). Leave out every other folder. Bind `{not_skf_output}` ← `not_skf_output`; when it is non-empty, display it once: "Skipped (not SKF output): {not_skf_output}".
|
|
46
54
|
- If multiple skills are found, present the list and accept either a single selection or a comma-/space-separated multi-selection (e.g. `1, 2, 3` or `all`)
|
|
47
|
-
- If no skills found, HALT (exit code 3, `halt_reason: "resolution-failure"`): "No skills found in {skills_output_folder}/. Run create-skill first."
|
|
55
|
+
- If no skills found, HALT (exit code 3, `halt_reason: "resolution-failure"`, phase `load-skill §1`): "No skills found in {skills_output_folder}/. Run create-skill first."
|
|
48
56
|
|
|
49
57
|
Store the resolved selection as `skill_batch` — a list of one or more skill names. `len(skill_batch) > 1` activates multi-skill mode (see §1c below).
|
|
50
58
|
|
|
51
59
|
**Flag Parsing:**
|
|
52
60
|
- `--all` flag: Check if provided. When true and no explicit skill list was given, `skill_batch` is the full non-deprecated manifest set — or, when no manifest exists yet, the full on-disk discovery set (see the first-export fallback above).
|
|
53
|
-
- `--context-file` flag: Check if explicitly provided (CLAUDE.md, .cursorrules, or AGENTS.md).
|
|
61
|
+
- `--context-file` flag: Check if explicitly provided (CLAUDE.md, .cursorrules, or AGENTS.md); `references/invocation-contract.md` lists it.
|
|
54
62
|
- `--dry-run` flag: Check if provided. Default: `false`
|
|
55
63
|
|
|
56
64
|
**Context File Resolution:**
|
|
57
65
|
|
|
58
|
-
|
|
66
|
+
Map the `ides` list of `config.yaml` (an absent key is an empty list) to the context files through the helper, which holds the IDE mapping of `shared/data/ide-context-files.json` and its rules: one target per context file with the first configured IDE's skill root, AGENTS.md with `.agents/skills/` for an IDE the mapping does not list (with a warning) and for an empty list (with a note):
|
|
59
67
|
|
|
60
|
-
|
|
68
|
+
```bash
|
|
69
|
+
python3 {rebuildManagedSectionsHelper} resolve-targets --ides "{ides}"
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
`{ides}` is the comma-joined `ides` list. Store `targets` as `target_context_files` (each entry `{context_file, skill_root, ides}`), bind `{other_context_files}` ← `other_context_files` (the known context files no configured IDE maps to, which step 4 §3b checks for a stale section), and display each `warnings[]` and `notes[]` line.
|
|
61
73
|
|
|
62
|
-
|
|
74
|
+
If `--context-file` was passed (CLAUDE.md, .cursorrules or AGENTS.md), run the call again with `--context-file {context-file}` added and store its `targets` as `target_context_files` instead: that file alone, with the skill root of the first configured IDE that maps to it, else the one the mapping gives that file. Drop that file from `{other_context_files}`, and display the call's `notes[]` (it names the configured IDEs this run leaves out).
|
|
63
75
|
|
|
64
|
-
-
|
|
65
|
-
- If mapping produces zero entries (empty ides list and no recognized entries), fall back to `[{context_file: "AGENTS.md", skill_root: ".agents/skills/"}]` with note: "No IDEs configured in config.yaml — defaulting to AGENTS.md with `.agents/skills/`."
|
|
76
|
+
A non-zero exit (an unknown `--context-file` value, or an IDE mapping the helper cannot read) is a HALT (exit code 3, `halt_reason: "resolution-failure"`, phase `load-skill §1`) with the helper's `error`.
|
|
66
77
|
|
|
67
78
|
"**Skill(s):** {skill-batch-list} ({N} total)
|
|
68
79
|
**Context file(s):** {context-file-list} (skill root: {skill-root-list})
|
|
69
80
|
**Dry Run:** {yes/no}"
|
|
70
81
|
|
|
71
|
-
### 1b.
|
|
82
|
+
### 1b. Snippet Root
|
|
72
83
|
|
|
73
|
-
**Skip
|
|
84
|
+
**Skip this if `snippet_skill_root_override` is set in `config.yaml`**: the authoring-repo override already decides every `root:` path (see the override rules in `assets/managed-section-format.md`).
|
|
74
85
|
|
|
75
|
-
**Otherwise:** load `references/preflight-snippet-root-probe.md` and follow
|
|
86
|
+
**Otherwise:** load `references/preflight-snippet-root-probe.md` and follow it. It asks the layout question when no earlier export chose a snippet root, takes the mismatch gate when an earlier export's root differs from the IDE mapping, and states each one's headless default. It returns here on its fast path, after the layout question's [I], or after the mismatch gate's (b) or (d), where (d) binds `{snippet_skill_root_override}` for this run; continue at §1c.
|
|
76
87
|
|
|
77
88
|
### 1c. Multi-skill Mode (when `len(skill_batch) > 1`)
|
|
78
89
|
|
|
@@ -82,18 +93,28 @@ Apply those rules to `config.yaml.ides`, then:
|
|
|
82
93
|
|
|
83
94
|
### 2. Load and Validate Skill Artifacts
|
|
84
95
|
|
|
85
|
-
|
|
96
|
+
The inventory helper chooses the version to export and binds its paths by the Reading Workflows rules of `knowledge/version-paths.md` (the Manifest-lag guard included), so this step never reads the export manifest or the `active` link by hand. Run:
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
uv run {skillInventoryHelper} resolve "{skills_output_folder}" --skill {skill-name} --forge-data-folder "{forge_data_folder}"
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Bind from its `resolve` object `{resolved_version}` ← `chosen_version`, `{resolved_skill_package}` ← `skill_package`, `{forge_version}` ← `forge_version` (the version's forge folder) and `{forge_evidence_report}` ← `paths.evidence_report.path` (that folder's `evidence-report.md`, else the flat copy an older skill keeps, else null), which step 3 derives the gotchas from. Log each `resolve.errors` entry, and `resolve.manifest_error` when it is set, as an Info note, then act on `reason`:
|
|
103
|
+
|
|
104
|
+
1. `manifest-and-link`, `manifest` or `link`: the export manifest or the `active` link names the version, and its package is on disk. Continue.
|
|
105
|
+
2. `manifest-lags-link` (the Manifest-lag guard): the `active` link names a version the manifest has not caught up with, as when a create or update run flipped `active` after the last export (the SS→TS→EX order). Continue with the link's version, and emit the helper's `detail` as an Info note, followed by "Exporting v{resolved_version}: the manifest's active_version advances to it on this export." Step 4 publishes the version in `{resolved_skill_package}/metadata.json`, so the manifest catches up here.
|
|
106
|
+
3. `flat-layout`: fall back to the flat path `{skills_output_folder}/{skill-name}/`, where `SKILL.md` sits at the skill folder root with no version folder yet. Check that SKF generated it before anything moves:
|
|
107
|
+
- Run `uv run {skillInventoryHelper} {skills_output_folder} --skill {skill-name}`, and bind `{group_flat_skf}` ← `skills[0].flat_skf` and `{group_errors}` ← `skills[0].errors`.
|
|
108
|
+
- **`{group_flat_skf}` is true:** if `--dry-run` is set, do not migrate: use the flat folder as the resolved path (the `skill_package` bound above; `{resolved_version}` and `{forge_version}` stay null) and note "would migrate {skill-name} to the versioned layout". Otherwise auto-migrate per `knowledge/version-paths.md` migration rules, then run the `resolve` command above again and bind its values anew: they now name the version folder.
|
|
109
|
+
- **Otherwise** (`{group_flat_skf}` is false, the status is not `ok`, or `skills[]` has no entry): do not migrate. HALT before anything moves, with `halt_reason: "not-skf-output"` and this message: "**`{skill-name}` is not SKF output: nothing was moved.** `{skills_output_folder}/{skill-name}/SKILL.md` has no SKF marker in the `metadata.json` beside it, so SKF will not move or export it. A shared `{skills_output_folder}` is supported: SKF leaves the skills it did not generate alone, so manage `{skill-name}` yourself. Only if `{skills_output_folder}` holds a module's own source rather than skills, set `skills_output_folder` in `{project-root}/_bmad/skf/config.yaml` to a folder of its own, move your SKF skills there and re-run `/skf-setup`." When there is another reason, show it in place of the marker sentence: `{group_errors}` when it is non-empty (for example, the folder is a link, which SKF never moves), or the helper's `error` when the status is not `ok`. HALT with exit code 3 and phase `load-skill §2`.
|
|
110
|
+
4. `missing`, `newest-on-disk`, or the helper stops with `SKILL_NOT_FOUND` or `DIR_NOT_FOUND`: no version named for export is on disk. `newest-on-disk` means version folders exist but neither the export manifest nor a working `active` link names one, and export publishes only a version one of them names. HALT (exit code 3, `halt_reason: "resolution-failure"`, phase `load-skill §2`): "**`{skill-name}` has no version to export.** {the helper's `detail`, or its `error`}. Run create-skill first, or point `{skills_output_folder}/{skill-name}/active` at the version to export, then re-run."
|
|
111
|
+
5. Any other error, or no JSON: HALT (exit code 3, `halt_reason: "resolution-failure"`, phase `load-skill §2`) with the helper's message.
|
|
86
112
|
|
|
87
|
-
|
|
88
|
-
2. **Manifest-lag guard.** If the skill is in the manifest, also read the `active` symlink target at `{skills_output_folder}/{skill-name}/active`. If that symlink resolves to a *different* version than `active_version`, prefer the **symlink target** as `{resolved_version}` and emit an Info note: "manifest active_version {M} lags the active symlink {N} — exporting the symlink target (the just-forged version); the manifest active_version advances to {N} on this export." This is the canonical SS→TS→EX case: create-stack-skill flipped `active` to the new version, but the manifest only advances when *this* export runs. A bare manifest-first resolution would re-export the *previously exported* version, and step 4 §4b/step-5 (`update-context.md`) — which derives the published version from `{resolved_skill_package}/metadata.json` — would then write that stale version straight back as `active_version`, so the forged version could never be published. Resolving to the symlink target here makes this export publish {N} and reconcile the manifest. When the symlink matches `active_version` (or no `active` symlink exists), use `active_version`. See `knowledge/version-paths.md` "Reading Workflows".
|
|
89
|
-
3. If found: resolve to `{skill_package}` = `{skills_output_folder}/{skill-name}/{resolved_version}/{skill-name}/`
|
|
90
|
-
4. If not in manifest: check for `active` symlink at `{skills_output_folder}/{skill-name}/active` — resolve to `{skill_group}/active/{skill-name}/`
|
|
91
|
-
5. If neither: fall back to flat path `{skills_output_folder}/{skill-name}/`. If SKILL.md exists at the flat path, auto-migrate per `knowledge/version-paths.md` migration rules
|
|
92
|
-
6. Store the resolved path as `{resolved_skill_package}` for all subsequent artifact loading
|
|
113
|
+
Every later step reads the skill from `{resolved_skill_package}`.
|
|
93
114
|
|
|
94
115
|
Load all files from `{resolved_skill_package}`:
|
|
95
116
|
|
|
96
|
-
**Required Files (
|
|
117
|
+
**Required Files (the export gate below halts when one is missing):**
|
|
97
118
|
- `SKILL.md` — The main skill document
|
|
98
119
|
- `metadata.json` — Machine-readable skill metadata
|
|
99
120
|
|
|
@@ -101,22 +122,21 @@ Load all files from `{resolved_skill_package}`:
|
|
|
101
122
|
- `references/` — Progressive disclosure directory
|
|
102
123
|
- `context-snippet.md` — Existing snippet (will be regenerated)
|
|
103
124
|
|
|
104
|
-
**Validation (
|
|
125
|
+
**Validation (the export gate):**
|
|
105
126
|
|
|
106
|
-
Run the export gate against the resolved package
|
|
127
|
+
Run the export gate against the resolved package:
|
|
107
128
|
|
|
108
129
|
```bash
|
|
109
130
|
python3 {validateOutputHelper} {resolved_skill_package} --export-gate
|
|
110
131
|
```
|
|
111
132
|
|
|
112
|
-
The script emits one JSON verdict
|
|
113
|
-
|
|
114
|
-
**If the script cannot run** (no `uv`/Python — e.g. claude.ai web): perform the equivalent checks by hand; `python3 {validateOutputHelper} --help` documents exactly what it verifies.
|
|
133
|
+
The script emits one JSON verdict; its docstring lists every check: `SKILL.md` and `metadata.json` present and valid; the required agentskills.io fields and their enums (`confidence_tier` on the scale of the `skill_type`: Quick/Forge/Forge+/Deep for a single skill, T1/T1-low/T2/T3 for a stack, where an older stack's forge tier passes with a low warning); the recommended fields for the `skill_type`, each missing one a low warning; and the SKILL.md Section 7b (`## Scripts & Assets`) cross-reference against the package's `scripts/` and `assets/` files, where a file the section names that is absent on disk is a high issue and a file it does not name a low orphan warning. Read `result` (PASS/FAIL), `export_status` (READY/WARNINGS/NOT_READY), the issue arrays under `validation.metadata.{issues,enum_issues,recommended_missing}` and `validation.crossref_7b.{missing,orphans}`, and `validation.crossref_7b.{heading,heading_line}`, the Section 7b heading the gate matched and its line in SKILL.md. **Retain this JSON as the export verdict**: step 2 (`package.md`) renders its status from it without re-deriving the checks.
|
|
115
134
|
|
|
116
135
|
**If `result` is `FAIL` / `export_status` is `NOT_READY`** (any high-severity issue in `validation.*`):
|
|
117
136
|
"**Export cannot proceed.** Missing or invalid: {list the high-severity issue messages from the script's `validation.metadata.{issues,enum_issues}` and `validation.crossref_7b.missing`}
|
|
118
|
-
|
|
119
|
-
|
|
137
|
+
{when `validation.crossref_7b.missing` is not empty:} Section 7b is the `{validation.crossref_7b.heading}` heading at line {validation.crossref_7b.heading_line} of `{resolved_skill_package}/SKILL.md`.
|
|
138
|
+
Fix each one in the package: add the file Section 7b names or correct its path there, and give `metadata.json` the field or value the message names, or run update-skill or create-skill to rebuild the skill. Then re-run the export."
|
|
139
|
+
Then HALT (exit code 3, `halt_reason: "resolution-failure"`, phase `load-skill §2`).
|
|
120
140
|
|
|
121
141
|
### 3. Read Skill Metadata
|
|
122
142
|
|
|
@@ -126,7 +146,7 @@ Extract from `metadata.json`:
|
|
|
126
146
|
- `source_authority` — `official`, `internal`, or `community`
|
|
127
147
|
- `exports` — Array of exported functions/types
|
|
128
148
|
- `generation_date` — When the skill was last generated
|
|
129
|
-
- `confidence_tier
|
|
149
|
+
- `confidence_tier`: for a single skill, the forge tier it was compiled at (Quick/Forge/Forge+/Deep); for a stack, the dominant confidence tier of its libraries (T1/T1-low/T2/T3), with the forge tier in `forge_tier` (an older stack may hold its forge tier here instead, which the export gate reports as a low warning)
|
|
130
150
|
|
|
131
151
|
**For stack skills, also extract:**
|
|
132
152
|
- `components` — Array of dependencies with versions
|
|
@@ -136,29 +156,29 @@ Extract from `metadata.json`:
|
|
|
136
156
|
|
|
137
157
|
Load `{sidecar_path}/preferences.yaml` (if exists):
|
|
138
158
|
- Check `passive_context` setting
|
|
139
|
-
- If `passive_context: false
|
|
159
|
+
- If `passive_context: false`, note that steps 3 and 4 skip the snippet and the context files; step 4 still records the export in the manifest
|
|
140
160
|
|
|
141
161
|
### 4b. Check Test Report (Quality Gate)
|
|
142
162
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
1. Glob `{forge_data_folder}/{skill_name}/{active_version}/test-report-{skill_name}-*.md` (i.e. `{forge_version}/test-report-{skill_name}-*.md`). Sort matches descending by the parsed ISO-timestamp segment in the filename (`YYYYMMDDTHHMMSSZ` between the skill name and the hash — `sort -r` on the filename works because the timestamp is the first variable component). Take the first match.
|
|
146
|
-
2. If the versioned glob returns nothing, fall back to the same glob at the flat path `{forge_data_folder}/{skill_name}/test-report-{skill_name}-*.md`. Pick the newest by parsed timestamp.
|
|
147
|
-
3. If neither glob returns anything, look for the stable companion `skf-test-skill-result-latest.json` in the same two directories (versioned first, then flat). Read the report path from `outputs[]` per the canonical contract documented at `shared/references/output-contract-schema.md` (resolved by skf-test-skill step 6 §4c) and load that file.
|
|
148
|
-
4. If all three lookups fail, the skill has no test report.
|
|
163
|
+
The shared helper finds the newest finished test report of the version §2 chose. Resolve `{findTestReportHelper}` ← first existing path in `{findTestReportProbeOrder}` and run:
|
|
149
164
|
|
|
150
|
-
|
|
165
|
+
```bash
|
|
166
|
+
uv run {findTestReportHelper} find --forge-data-folder "{forge_data_folder}" --skill-name {skill-name} [--version {resolved_version}]
|
|
167
|
+
```
|
|
151
168
|
|
|
152
|
-
|
|
153
|
-
- If `testResult: fail`: warn: "**Warning:** This skill failed its last test (score: {score}%). Consider running `@Ferris TS` and addressing gaps before export."
|
|
154
|
-
- If `testResult: pass`: note: "Last test: **PASS** ({score}%)"
|
|
155
|
-
- Always surface the actual file picked in the message (e.g. `test-report-my-base-ui-20260507T050917Z-487606-9b2f.md`) — not the no-longer-existent `test-report-{skill_name}.md` — so an operator can navigate to the report from the log.
|
|
169
|
+
Pass `--version` with the `{resolved_version}` §2 chose, never the manifest's `active_version`, which lags a version created or updated since the last export; leave it out when `{resolved_version}` is null (a flat skill in a dry run). Build the message from its JSON (`{score}` reads `n/a` when it is null), and display each `warnings[]` line as it is:
|
|
156
170
|
|
|
157
|
-
|
|
171
|
+
- `status: "found"`: name the report the helper picked, the file name of its `path` (for example `test-report-my-base-ui-20260507T050917Z-487606-9b2f.md`), so an operator can open it from the log, with its verdict by `testResult`:
|
|
172
|
+
- `pass`: note "Last test: **PASS** ({score}%)"
|
|
173
|
+
- `fail`: warn "**Warning:** This skill failed its last test (score: {score}%). Consider running `@Ferris TS` and addressing gaps before export."
|
|
174
|
+
- `pass-with-drift`: warn "**Warning:** This skill passed its last test only with `--allow-workspace-drift` (score: {score}%), against source that differs from its pinned commit. Re-test it against the pinned commit before export."
|
|
175
|
+
- `inconclusive`: warn "**Warning:** This skill's last test was inconclusive (score: {score}%). Review the report before export."
|
|
176
|
+
- no `testResult` (a result file that records no verdict): note "Last test report: no verdict recorded."
|
|
177
|
+
- `status: "not-found"`: warn "**Note:** No test report found for this skill. Consider running `@Ferris TS` before export to verify completeness."
|
|
158
178
|
|
|
159
|
-
-
|
|
179
|
+
If no helper candidate resolves, or the helper exits non-zero, note "**Note:** SKF could not check this skill's test report: {reason}." instead.
|
|
160
180
|
|
|
161
|
-
Continue to step 5 regardless
|
|
181
|
+
Continue to step 5 regardless: this is advisory, not blocking.
|
|
162
182
|
|
|
163
183
|
### 5. Present Skill Summary
|
|
164
184
|
|
|
@@ -195,7 +215,7 @@ Continue to step 5 regardless — this is advisory, not blocking.
|
|
|
195
215
|
|
|
196
216
|
| # | Name | Type | Authority | Tier | Exports | Test |
|
|
197
217
|
|---|------|------|-----------|------|---------|------|
|
|
198
|
-
| 1 | {name-1} | {type} | {authority} | {tier} | {count} | {
|
|
218
|
+
| 1 | {name-1} | {type} | {authority} | {tier} | {count} | {testResult, or none} |
|
|
199
219
|
| 2 | {name-2} | ... | ... | ... | ... | ... |
|
|
200
220
|
| N | {name-N} | ... | ... | ... | ... | ... |
|
|
201
221
|
|
|
@@ -214,7 +234,13 @@ Continue to step 5 regardless — this is advisory, not blocking.
|
|
|
214
234
|
Display: "**Select:** [C] Continue to packaging | [X] Cancel and exit (or type `cancel` / `exit` / `:q`)" (multi-skill mode: the single [C] gate covers the whole batch), then wait for the reply.
|
|
215
235
|
|
|
216
236
|
- **[C]** — proceed with the loaded skill data: load, read entirely, and execute `{nextStepFile}`.
|
|
217
|
-
- **[X]** / `cancel` / `exit` / `:q
|
|
237
|
+
- **[X]** / `cancel` / `exit` / `:q`: display "Cancelled: no packaging or context file writes were performed." and HALT (exit code 6, `halt_reason: "user-cancelled"`, phase `load-skill §6`).
|
|
218
238
|
- **Any other input** — help the user respond, then redisplay this gate.
|
|
219
|
-
- **
|
|
239
|
+
- **GATE [default: C]**: headless, record the decision in the run sink with the command below, log "headless: auto-continue past skill confirmation", then auto-proceed with [C]. If `record` exits non-zero, display its error line and go on: a failed `record` never stops the run.
|
|
240
|
+
|
|
241
|
+
```bash
|
|
242
|
+
uv run {emitEnvelopeHelper} record --workflow skf-export-skill --run-dir "{run_dir}" --decision <<'SKF_JSON'
|
|
243
|
+
{"gate":"load-skill.confirmation","default_action":"C","taken_action":"C","reason":"headless: auto-continue past skill confirmation"}
|
|
244
|
+
SKF_JSON
|
|
245
|
+
```
|
|
220
246
|
|