bmad-module-skill-forge 2.2.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 +49 -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 +12 -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 +99 -11
- package/src/shared/scripts/skf-detect-docs.py +694 -2
- 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 +209 -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 +15 -5
- 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 +28 -19
- package/src/skf-create-skill/references/sub/ccc-discover.md +18 -7
- package/src/skf-create-skill/references/sub/fetch-docs.md +106 -59
- 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 -90
- package/src/skf-setup/references/detect-and-tier.md +58 -67
- 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 -679
- 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,12 +1,18 @@
|
|
|
1
1
|
---
|
|
2
2
|
nextStepFile: 'ecosystem-check.md'
|
|
3
|
-
registryResolutionData: '
|
|
3
|
+
registryResolutionData: 'references/registry-resolution.md'
|
|
4
4
|
packageResolverProbeOrder:
|
|
5
5
|
- '{project-root}/_bmad/skf/shared/scripts/skf-resolve-package.py'
|
|
6
6
|
- '{project-root}/src/shared/scripts/skf-resolve-package.py'
|
|
7
|
+
githubProbeProbeOrder:
|
|
8
|
+
- '{project-root}/_bmad/skf/shared/scripts/skf-github-probe.py'
|
|
9
|
+
- '{project-root}/src/shared/scripts/skf-github-probe.py'
|
|
7
10
|
detectLanguageProbeOrder:
|
|
8
11
|
- '{project-root}/_bmad/skf/shared/scripts/skf-detect-language.py'
|
|
9
12
|
- '{project-root}/src/shared/scripts/skf-detect-language.py'
|
|
13
|
+
skillsModuleProbeOrder:
|
|
14
|
+
- '{project-root}/_bmad/skf/shared/scripts/skf-skills-module.py'
|
|
15
|
+
- '{project-root}/src/shared/scripts/skf-skills-module.py'
|
|
10
16
|
---
|
|
11
17
|
|
|
12
18
|
<!-- Config: communicate in {communication_language}. -->
|
|
@@ -21,22 +27,23 @@ To accept a GitHub URL or package name from the user, resolve it to a GitHub rep
|
|
|
21
27
|
|
|
22
28
|
- Focus only on resolving the target to a GitHub repository — do not begin extraction or compilation
|
|
23
29
|
- If resolution fails, hard halt with actionable guidance
|
|
30
|
+
- A HARD HALT prints, after its envelope, this step's `halt` event when `{headless_mode}` is true. Under `--batch` it ends only this target: then return to `references/batch-mode.md` §3, even when the halt reads as the end of the run (`references/halt-contract.md`).
|
|
24
31
|
|
|
25
32
|
## Steps
|
|
26
33
|
|
|
27
34
|
### 1. Accept User Input
|
|
28
35
|
|
|
29
|
-
**Batch mode:**
|
|
36
|
+
**Batch mode:** under `--batch`, `references/batch-mode.md` §2 set `target`, `language_hint` and `scope_hint` from the next pending batch line and printed its `start` event. Skip the prompt below and proceed directly to §1b with those values.
|
|
30
37
|
|
|
31
|
-
**Single-target mode** (default):
|
|
38
|
+
**Single-target mode** (default): when the invocation carried a target, take it, with `--language-hint` as `language_hint` and `--scope-hint` as `scope_hint` when they were passed (SKILL.md On Activation step 4), and go on to §1b without the prompt below, in either mode. Otherwise ask:
|
|
32
39
|
|
|
33
40
|
"**Quick Skill — fastest path to a skill.**
|
|
34
41
|
|
|
35
|
-
Provide a **GitHub URL
|
|
42
|
+
Provide a **GitHub URL**, a **package name** or its **npm, PyPI or crates.io page** and I'll resolve it to source and compile a best-effort SKILL.md.
|
|
36
43
|
|
|
37
|
-
**Target:** (GitHub URL or
|
|
44
|
+
**Target:** (GitHub URL, package name or registry page URL)
|
|
38
45
|
|
|
39
|
-
Examples: `cocoindex`, `@tanstack/query`, `https://github.com/tursodatabase/limbo`, `cognee@0.5.0`
|
|
46
|
+
Examples: `cocoindex`, `@tanstack/react-query`, `requests==2.31.0`, `https://github.com/tursodatabase/limbo`, `cognee@0.5.0`
|
|
40
47
|
|
|
41
48
|
**Optional:**
|
|
42
49
|
- **Language hint:** (if the repo is multi-language)
|
|
@@ -44,60 +51,75 @@ Examples: `cocoindex`, `@tanstack/query`, `https://github.com/tursodatabase/limb
|
|
|
44
51
|
|
|
45
52
|
Or type `cancel` / `exit` / `:q` / `[X]` to leave without writing anything."
|
|
46
53
|
|
|
47
|
-
Wait for user input. **Cancel branch
|
|
54
|
+
Wait for user input. **Cancel branch**: if the user types `cancel`, `exit`, `:q`, `[X]`, or selects `[X] Cancel and exit`, display "Cancelled. No files were written." and HARD HALT with **exit code 6 (user-cancelled)**: stage `{"phase": "resolve-target", "halt_reason": "user-cancelled", "reason": "Cancelled. No files were written.", "skill_package": null}` as `{run_dir}/halt.json` and run `uv run {emitEnvelopeHelper} emit-halt --workflow skf-quick-skill --run-dir "{run_dir}" --target stderr < "{run_dir}/halt.json"` (`references/halt-contract.md`). Cancellation here is non-destructive: no files have been written yet.
|
|
48
55
|
|
|
49
|
-
**GATE [default: use args]
|
|
56
|
+
**GATE [default: use args]**: if `{headless_mode}` and a target (URL or package name) was provided as argument, use it as the target input, with the hint flags, and auto-proceed, log: "headless: using provided target". If no target was provided in headless mode, HARD HALT with **exit code 2 (input-invalid)**: "Headless mode requires a target argument." Stage `{"phase": "resolve-target", "halt_reason": "input-invalid", "reason": "Headless mode requires a target argument.", "skill_package": null}` as `{run_dir}/halt.json` and run `uv run {emitEnvelopeHelper} emit-halt --workflow skf-quick-skill --run-dir "{run_dir}" --target stderr < "{run_dir}/halt.json"`.
|
|
50
57
|
|
|
51
|
-
### 1b. Parse
|
|
58
|
+
### 1b. Parse the Target
|
|
52
59
|
|
|
53
|
-
**
|
|
54
|
-
- **Package/URL:** everything before the last `@`
|
|
55
|
-
- **Target version:** everything after the last `@`
|
|
60
|
+
**Resolve `{packageResolver}`** from `{packageResolverProbeOrder}`; first existing path wins. If no candidate exists, or a call to it prints no JSON on stdout, HARD HALT with **exit code 3 (resolution-failure)**, in interactive mode too: "**The package resolver could not run.** {the call's first stderr line, or with no candidate: SKF's package resolver (`skf-resolve-package.py`) is missing from `{project-root}/_bmad/skf/shared/scripts/`, so re-install SKF.}" Stage `{"phase": "resolve-target", "halt_reason": "resolution-failure", "reason": "The package resolver could not run.", "skill_package": null, "details": {"cause": "<package-resolver-missing, or package-resolver-error after a call that printed no JSON>"}}` as `{run_dir}/halt.json` and run `uv run {emitEnvelopeHelper} emit-halt --workflow skf-quick-skill --run-dir "{run_dir}" --target stderr < "{run_dir}/halt.json"`.
|
|
56
61
|
|
|
57
|
-
|
|
62
|
+
Parse the target. Write it exactly as given on the line between the two markers: the quoted marker hands it to the parser unchanged, quotes, backticks and `$` included.
|
|
58
63
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
64
|
+
```bash
|
|
65
|
+
uv run {packageResolver} parse-target <<'SKF_TARGET'
|
|
66
|
+
{target}
|
|
67
|
+
SKF_TARGET
|
|
68
|
+
```
|
|
62
69
|
|
|
63
|
-
|
|
64
|
-
- Extract org/repo from URL
|
|
65
|
-
- Set `resolved_url` to the GitHub URL
|
|
66
|
-
- Set `repo_name` to the repo name (last path segment)
|
|
67
|
-
- Skip to step 3a (Verify Target Version Tag), then step 4 (Detect Language)
|
|
70
|
+
When the parser's `target_version` is not `null`, store it as `target_version` in the extraction context. A `target_version` overrides auto-detection. A `dist_tag` (an npm dist-tag such as `latest` or `canary`) pins no version: log "`{dist_tag}` pins no version; auto-detecting it". Without a `target_version`, the version is auto-detected.
|
|
68
71
|
|
|
69
|
-
|
|
70
|
-
- Proceed to step 3 (Registry Resolution)
|
|
72
|
+
### 2. Route by Kind
|
|
71
73
|
|
|
72
|
-
|
|
74
|
+
- **`github`**: set `resolved_url` ← `url`, `owner` ← `owner`, `repo` ← `repo` and `repo_name` ← `skill_name`, the name the skill is written under. A `/tree/<ref>/<folder>` URL also gives `ref` and `subdir`: set `source_ref` ← `ref`, and `scope_hint` ← `subdir` when no scope hint was given. Skip to §3a (Verify Target Version Tag), then §4 (Detect Language).
|
|
75
|
+
- **`package`** or **`registry-page`**: proceed to §3 (Registry Resolution) with `package_name`, and with `registry` when it is set.
|
|
76
|
+
- **`other-host`**, **`local-path`** or **`unparsed`**: quick-skill cannot resolve the input to a GitHub repository. Instead of a registry lookup that can only fail, show the redirect for its kind, then, in interactive mode, wait for new input and go back to §1b. Two such inputs still name a package that a web search can place, so they try it first: an `other-host` input written with no scheme, such as the Go module path `go.uber.org/zap` (a Go module proxy serves it, not a registry quick-skill asks), and an `unparsed` Maven coordinate `<group>:<artifact>`, such as `com.google.guava:guava`. Take the input as `package_name` and run the web-search step of §3's `fallthrough` branch; show the redirect only when it finds no GitHub URL.
|
|
73
77
|
|
|
74
|
-
|
|
78
|
+
- **`other-host`**: "**Quick Skill reads GitHub repositories only.** `{url}` is on `{host}`. Paste the project's GitHub URL if it has one, or clone it and run `/skf-brief-skill` on the local clone, then `/skf-create-skill`."
|
|
79
|
+
- **`local-path`**: "**Quick Skill reads GitHub repositories, not local folders.** To make a skill from `{path}`, run `/skf-brief-skill` with that path, then `/skf-create-skill`. Or paste the GitHub URL of its repository."
|
|
80
|
+
- **`unparsed`**: the user typed something like "I want a skill that helps with onboarding" or "build me a brainstorming workflow", or text that is no package name or URL. Redirect with a sibling-skill suggestion:
|
|
75
81
|
|
|
76
|
-
"**This input looks like a description, not a package or URL.** Quick Skill needs a package name (e.g. `lodash`, `@vercel/og`, `requests`) or a GitHub URL (e.g. `https://github.com/lodash/lodash`).
|
|
82
|
+
"**This input looks like a description, not a package or URL.** Quick Skill needs a package name (e.g. `lodash`, `@vercel/og`, `requests==2.31.0`) or a GitHub URL (e.g. `https://github.com/lodash/lodash`).
|
|
77
83
|
|
|
78
|
-
If you are describing a skill you want to **create from scratch** rather than compile from existing source:
|
|
84
|
+
If you are describing a skill you want to **create from scratch** rather than compile from existing source:
|
|
79
85
|
|
|
80
|
-
- Run `/skf-create-skill` with a skill brief
|
|
81
|
-
- Or use `bmad-agent-builder` for an interactive skill design session
|
|
86
|
+
- Run `/skf-create-skill` with a skill brief: the full pipeline, with provenance tracking and AST-verified exports
|
|
87
|
+
- Or use `bmad-workflow-builder` (a workflow or utility skill) or `bmad-agent-builder` (an agent) for an interactive skill design session
|
|
82
88
|
|
|
83
|
-
Otherwise, paste the package name or GitHub URL of the library you want to wrap, and quick-skill will resolve it."
|
|
89
|
+
Otherwise, paste the package name or GitHub URL of the library you want to wrap, and quick-skill will resolve it."
|
|
84
90
|
|
|
85
|
-
**GATE [default: HALT]
|
|
91
|
+
**GATE [default: HALT]**: in headless mode, after the web search above when the input qualifies for it, emit the redirect for the kind and HARD HALT with **exit code 3 (resolution-failure)**: stage `{"phase": "resolve-target", "halt_reason": "resolution-failure", "reason": "<the redirect's first sentence>", "skill_package": null, "details": {"kind": "<kind>"}}` as `{run_dir}/halt.json` and run `uv run {emitEnvelopeHelper} emit-halt --workflow skf-quick-skill --run-dir "{run_dir}" --target stderr < "{run_dir}/halt.json"`.
|
|
86
92
|
|
|
87
93
|
### 3. Registry Resolution
|
|
88
94
|
|
|
89
|
-
Run the shared resolver
|
|
90
|
-
|
|
91
|
-
**Resolve `{packageResolver}`** from `{packageResolverProbeOrder}`; first existing path wins. If no candidate exists, fall back to the LLM walk of {registryResolutionData} for the full chain.
|
|
95
|
+
Run the shared resolver (resolved in §1b), which asks every deterministic registry (npm, PyPI, crates.io):
|
|
92
96
|
|
|
93
97
|
```bash
|
|
94
|
-
|
|
98
|
+
uv run {packageResolver} resolve {package_name} --timeout 10 [--registry {registry}] [--language "{language_hint}"]
|
|
95
99
|
```
|
|
96
100
|
|
|
97
|
-
|
|
101
|
+
Pass `--registry` when §2 set `registry`, and `--language` when a language hint was given: a JavaScript, TypeScript, Python or Rust hint makes the resolver ask that language's registry alone. It prints JSON whose `status` is `ok`, `ambiguous` or `fallthrough` (exit 0, 3 or 1).
|
|
102
|
+
|
|
103
|
+
- **On `status: "ok"`**: set, from the JSON, `resolved_url`, `owner` ← `repo_owner`, `repo` ← `repo_name`, `repo_name` ← `skill_name` and `registry_used`; when `source_subdir` is set and no scope hint was given, set `scope_hint` ← `source_subdir`. Proceed to §3a.
|
|
104
|
+
- **On `status: "ambiguous"`**: another registry answered for the name too, so it may belong to two projects. `resolved_url`, from `registry_used`, is the chain's pick (the first registry, in the order npm, PyPI, crates.io, that gives a GitHub repository), and `also_found_in` lists every other registry that answered. Run the ambiguous-name gate below.
|
|
105
|
+
- **On `status: "fallthrough"`**: no registry gave a GitHub URL. Load {registryResolutionData} and run its web search for `{package_name}`. If found, take that URL as the target and go back to §1b. If web search also returns nothing, HARD HALT below.
|
|
106
|
+
|
|
107
|
+
**Ambiguous-name gate** (on `status: "ambiguous"` only). Offer every candidate: the pick first, then each `also_found_in` entry that has a `resolved_url`, numbered on from 2. `{others}` names each entry without one: `no-github-link` knows the name but gives no GitHub repository, `error` could not be read.
|
|
98
108
|
|
|
99
|
-
|
|
100
|
-
|
|
109
|
+
"**`{package_name}` may name more than one project.**
|
|
110
|
+
|
|
111
|
+
1. {resolved_url}, from `{registry_used}` (the registry chain's pick)
|
|
112
|
+
2. {the next candidate's `resolved_url`}, from `{its registry}`
|
|
113
|
+
|
|
114
|
+
{others}
|
|
115
|
+
|
|
116
|
+
Select: [C] Continue with 1 · [2] to [n] Use that candidate · [U] Use another GitHub URL · [X] Cancel and exit"
|
|
117
|
+
|
|
118
|
+
- **IF C**: log "user accepted the `{registry_used}` resolution of `{package_name}`" and continue as on `status: "ok"`.
|
|
119
|
+
- **IF 2 to n**: continue as on `status: "ok"` with that candidate's entry: its `resolved_url`, `owner` ← its `repo_owner`, `repo` ← its `repo_name`, `registry_used` ← its `registry`, and `scope_hint` ← its `source_subdir` when set and no scope hint was given (`repo_name` stays the package's `skill_name`).
|
|
120
|
+
- **IF U**: ask for the GitHub URL of the project the user means, take it as the target and go back to §1b.
|
|
121
|
+
- **IF X**: display "Cancelled. No files were written." and HARD HALT with **exit code 6 (user-cancelled)**: stage `{"phase": "resolve-target", "halt_reason": "user-cancelled", "reason": "Cancelled. No files were written.", "skill_package": null}` as `{run_dir}/halt.json` and run `uv run {emitEnvelopeHelper} emit-halt --workflow skf-quick-skill --run-dir "{run_dir}" --target stderr < "{run_dir}/halt.json"`.
|
|
122
|
+
- **GATE [default: C]**: in headless mode, keep the chain's pick and never halt. Record the resolver's `warning` (`also_found_in: ...`) with `uv run {emitEnvelopeHelper} record --run-dir "{run_dir}" --warning "{warning}"`, and the decision: stage `{"gate": "resolve-target.ambiguous-package", "default_action": "C", "taken_action": "C", "reason": "headless: kept the {registry_used} pick"}` as `{run_dir}/decision.json` and run `uv run {emitEnvelopeHelper} record --workflow skf-quick-skill --run-dir "{run_dir}" --decision < "{run_dir}/decision.json"`. Then continue as on `status: "ok"`. To build another candidate headlessly, pass its GitHub URL or a language hint for its registry (`language=` on a batch line).
|
|
101
123
|
|
|
102
124
|
**If all methods fail — HARD HALT (exit code 3, resolution-failure):**
|
|
103
125
|
|
|
@@ -110,65 +132,91 @@ Check:
|
|
|
110
132
|
|
|
111
133
|
**Provide the GitHub URL directly to continue.**"
|
|
112
134
|
|
|
113
|
-
In interactive mode, wait for corrected input and loop back to
|
|
135
|
+
In interactive mode, wait for corrected input and loop back to §1b. In headless mode, stage `{"phase": "resolve-target", "halt_reason": "resolution-failure", "reason": "Resolution failed. Could not resolve {package_name} to a GitHub repository.", "skill_package": null}` as `{run_dir}/halt.json` and run `uv run {emitEnvelopeHelper} emit-halt --workflow skf-quick-skill --run-dir "{run_dir}" --target stderr < "{run_dir}/halt.json"`.
|
|
114
136
|
|
|
115
137
|
### 3a. Verify Target Version Tag (when applicable)
|
|
116
138
|
|
|
117
|
-
Skip this section if `target_version` is null (auto-detect path
|
|
139
|
+
Skip this section if `target_version` is null (auto-detect path: the version comes from the manifest read in step 3).
|
|
140
|
+
|
|
141
|
+
When the target carried a version (§1b), verify the tag exists in the resolved repo before extraction. Otherwise step 3 silently reads from the default branch while metadata records the requested version: a quiet provenance bug where the SKILL.md claims version 0.5.0 but the exports actually came from main.
|
|
118
142
|
|
|
119
|
-
|
|
143
|
+
**Resolve `{githubProbe}`** from `{githubProbeProbeOrder}`; first existing path wins. If no candidate exists, halt as when no probe could read the tags (below).
|
|
120
144
|
|
|
121
|
-
|
|
145
|
+
List the repository's tags once, looking for every form a tag gives the version: `0.5.0`, `v0.5.0`, or a monorepo package's `<name>@0.5.0`:
|
|
122
146
|
|
|
123
147
|
```bash
|
|
124
|
-
|
|
125
|
-
|| gh api repos/{owner}/{repo}/git/ref/tags/v{target_version} --silent
|
|
148
|
+
uv run {githubProbe} tags --repo {owner}/{repo} --version {target_version} --name {package_name or repo_name} --limit 5
|
|
126
149
|
```
|
|
127
150
|
|
|
128
|
-
|
|
151
|
+
- **`status: "ok"` with `match` set**: set `source_ref` ← `match`, which replaces a `/tree/` URL's ref. Step 3's ref-aware source reading uses this value to fetch from the tagged commit. Proceed to §4.
|
|
152
|
+
- **`status: "ok"` with `match` null**: the listing lacks the tag. HARD HALT with **exit code 3 (resolution-failure)**:
|
|
129
153
|
|
|
130
|
-
**
|
|
154
|
+
"**Tag `{target_version}` not found in `{owner}/{repo}`.**
|
|
131
155
|
|
|
132
|
-
|
|
156
|
+
The version was parsed from your target but no tag of the resolved repository names it. Quick-skill cannot extract from a version with no commit pointer: the result would be sourced from the default branch but labelled `{target_version}` in metadata.
|
|
133
157
|
|
|
134
|
-
|
|
158
|
+
Tags near this version:
|
|
159
|
+
{the probe's `nearest`, else its `tags`, or "(none: the repo has no tags)"}
|
|
135
160
|
|
|
136
|
-
|
|
137
|
-
{list top 5 from `gh api repos/{owner}/{repo}/tags --paginate=false`, or "(none — repo has no tags; omit @version to auto-detect from default branch)"}
|
|
161
|
+
Re-run with one of these tags, or omit the version to auto-detect from the default branch."
|
|
138
162
|
|
|
139
|
-
|
|
163
|
+
Stage `{"phase": "resolve-target", "halt_reason": "resolution-failure", "reason": "Tag {target_version} not found in {owner}/{repo}.", "skill_package": null, "details": {"requested_version": "{target_version}", "available_tags": [<the tags shown>]}}` as `{run_dir}/halt.json` and run `uv run {emitEnvelopeHelper} emit-halt --workflow skf-quick-skill --run-dir "{run_dir}" --target stderr < "{run_dir}/halt.json"`.
|
|
164
|
+
- **`status: "unavailable"`, any other exit, or no `{githubProbe}` candidate**: nothing could read the repository's tags, so the tag may exist. Do not report it missing. HARD HALT with **exit code 3 (resolution-failure)**: "**Could not check tag `{target_version}` in `{owner}/{repo}`.** {the probe's `message` (on stderr after another exit), or with no candidate: SKF's GitHub probe (`skf-github-probe.py`) is missing from `{project-root}/_bmad/skf/shared/scripts/`, so re-install SKF.} Re-run once GitHub can be read, or omit the version to auto-detect from the default branch." Stage `{"phase": "resolve-target", "halt_reason": "resolution-failure", "reason": "Could not check tag {target_version} in {owner}/{repo}.", "skill_package": null, "details": {"requested_version": "{target_version}", "cause": "<the probe's cause, probe-error after another exit, or github-probe-missing>"}}` as `{run_dir}/halt.json` and run `uv run {emitEnvelopeHelper} emit-halt --workflow skf-quick-skill --run-dir "{run_dir}" --target stderr < "{run_dir}/halt.json"`.
|
|
140
165
|
|
|
141
|
-
|
|
166
|
+
In headless mode, halt at once on either; do not re-prompt.
|
|
142
167
|
|
|
143
168
|
### 4. Detect Language
|
|
144
169
|
|
|
145
|
-
**
|
|
170
|
+
**List the repository's files once**, at the ref step 3 reads. Resolve `{githubProbe}` from `{githubProbeProbeOrder}` (§3a may have resolved it already); first existing path wins. Write the listing into the run folder, where the language helper below and step 3 read it, so no step lists the tree again and no path list passes through the model:
|
|
171
|
+
|
|
172
|
+
```bash
|
|
173
|
+
uv run {githubProbe} tree --repo {owner}/{repo} --ref {source_ref or HEAD} > "{run_dir}/tree.json"
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
The probe reads the tree through gh, and through GitHub's unauthenticated API when gh is missing or logged out, so a public repository needs no login. A `truncated` listing (GitHub cut a very large tree short) is still read.
|
|
177
|
+
|
|
178
|
+
- **`status: "unavailable"`, any other exit, or no `{githubProbe}` candidate**: nothing could list the repository. HARD HALT with **exit code 3 (resolution-failure)**: "**Could not list the files of `{owner}/{repo}`.** {the probe's `message` (on stderr after another exit), or with no candidate: SKF's GitHub probe (`skf-github-probe.py`) is missing from `{project-root}/_bmad/skf/shared/scripts/`, so re-install SKF.}" Stage `{"phase": "resolve-target", "halt_reason": "resolution-failure", "reason": "Could not list the files of {owner}/{repo}.", "skill_package": null, "details": {"ref": "{source_ref or HEAD}", "cause": "<the probe's cause, probe-error after another exit, or github-probe-missing>"}}` as `{run_dir}/halt.json` and run `uv run {emitEnvelopeHelper} emit-halt --workflow skf-quick-skill --run-dir "{run_dir}" --target stderr < "{run_dir}/halt.json"`.
|
|
146
179
|
|
|
147
180
|
Determine primary language:
|
|
148
181
|
|
|
149
|
-
1. **User-provided language hint** (overrides detection)
|
|
182
|
+
1. **User-provided language hint** (overrides detection): set `language` to the hint and `language_resolution` to `hint`, and skip straight to §5. The disambiguation gate below does not run.
|
|
150
183
|
|
|
151
|
-
2. **Delegate the rule walk to `{detectLanguageHelper}
|
|
184
|
+
2. **Delegate the rule walk to `{detectLanguageHelper}`**, resolved from `{detectLanguageProbeOrder}` (first existing path wins). If no candidate exists, or its call below prints no JSON on stdout, HARD HALT with **exit code 3 (resolution-failure)**: "**Could not detect the language of `{repo_name}`.** {the call's first stderr line, or with no candidate: SKF's language detector (`skf-detect-language.py`) is missing from `{project-root}/_bmad/skf/shared/scripts/`, so re-install SKF.} Re-run with `--language-hint <lang>` (a batch line's `language=`) to skip detection." Stage `{"phase": "resolve-target", "halt_reason": "resolution-failure", "reason": "Could not detect the language of {repo_name}.", "skill_package": null, "details": {"cause": "<detect-language-missing, or detect-language-error after a call that printed no JSON>"}}` as `{run_dir}/halt.json` and run `uv run {emitEnvelopeHelper} emit-halt --workflow skf-quick-skill --run-dir "{run_dir}" --target stderr < "{run_dir}/halt.json"`. The helper reads the listing from the file:
|
|
152
185
|
|
|
153
186
|
```bash
|
|
154
|
-
|
|
187
|
+
uv run {detectLanguageHelper} --tree-file "{run_dir}/tree.json"
|
|
155
188
|
```
|
|
156
189
|
|
|
157
|
-
The script returns `{language, confidence, detection_source, detected_languages}
|
|
190
|
+
The script returns `{language, confidence, detection_source, source_language, detected_languages}`: the manifests nearest the tree's root decide (folder depth, then rule order), never one in a non-core or hidden folder while another exists, and with no manifest at the root the nearest one decides at `medium` confidence. `detected_languages` lists the deciding manifests' languages in that ranking, then the languages of the manifests that never decide, then `source_language` (the language most source files are in) when no manifest sits at the root, with `detected_languages[0]` equal to the winning `language`.
|
|
191
|
+
|
|
192
|
+
3. **Auto-pick**: set `language` to the returned `language`. If `detected_languages` is empty (the script recognized no manifest and no source extensions: `language` is `"unknown"`), the repository may still ship agent skills written in Markdown alone, which step 3 documents as a skills module. Resolve `{skillsModuleHelper}` from `{skillsModuleProbeOrder}` and ask it:
|
|
193
|
+
|
|
194
|
+
```bash
|
|
195
|
+
uv run {skillsModuleHelper} sniff --tree-file "{run_dir}/tree.json" [--scope-hint "{scope_hint}"]
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
Pass `--scope-hint` when `scope_hint` is set, as step 3 does, so both steps classify the same folder.
|
|
199
|
+
|
|
200
|
+
- **`skills_module` is true**: set `language` to `markdown` and `language_resolution` to `detected`, keep `detected_languages` empty, and go on to §5.
|
|
201
|
+
- **Otherwise** (or no `{skillsModuleHelper}` candidate): treat it as a zero-match resolution: show the §3 resolution-failure guidance so the user can supply a language hint or a different target, and in headless mode HARD HALT with **exit code 3 (resolution-failure)**: stage `{"phase": "resolve-target", "halt_reason": "resolution-failure", "reason": "No language found in {repo_name}.", "skill_package": null}` as `{run_dir}/halt.json` and run `uv run {emitEnvelopeHelper} emit-halt --workflow skf-quick-skill --run-dir "{run_dir}" --target stderr < "{run_dir}/halt.json"`.
|
|
202
|
+
|
|
203
|
+
4. **Multi-language gate** (`len(detected_languages) > 1`): the helper named more than one language (another manifest's, or the source files' language when no manifest sits at the root). Offer every detected language, the helper's pick first:
|
|
158
204
|
|
|
159
|
-
|
|
205
|
+
"**`{repo_name}` has manifests for multiple languages.**
|
|
160
206
|
|
|
161
|
-
|
|
207
|
+
1. **{language}** (`detected_languages[0]`, the helper's pick)
|
|
208
|
+
2. {detected_languages[1]}
|
|
162
209
|
|
|
163
|
-
|
|
210
|
+
{and so on, one numbered line per entry of `detected_languages`}
|
|
164
211
|
|
|
165
|
-
|
|
212
|
+
Select: [C] Continue with 1 · [2] to [n] Use that language · [A] Abort"
|
|
166
213
|
|
|
167
|
-
|
|
214
|
+
- **IF C**: log "user accepted multi-manifest pick: `{language}`", keep `language` and set `language_resolution: "user-confirmed"`.
|
|
215
|
+
- **IF 2 to n**: set `language` to that entry of `detected_languages`, set `language_resolution: "user-confirmed"` and log "user picked `{language}` of {detected_languages}". `detected_languages` keeps its order.
|
|
216
|
+
- **IF A**: HARD HALT with **exit code 3 (resolution-failure)**: "Aborted to disambiguate language. Re-run with `--language-hint <lang>`." Stage `{"phase": "resolve-target", "halt_reason": "resolution-failure", "reason": "Aborted to disambiguate language.", "skill_package": null, "details": {"detected_languages": [<detected_languages>], "auto_pick": "{language}"}}` as `{run_dir}/halt.json` and run `uv run {emitEnvelopeHelper} emit-halt --workflow skf-quick-skill --run-dir "{run_dir}" --target stderr < "{run_dir}/halt.json"`.
|
|
217
|
+
- **GATE [default: C]**: headless mode auto-proceeds with the helper's pick, sets `language_resolution: "auto-picked-first"`, and records the decision: stage `{"gate": "resolve-target.multi-language", "default_action": "C", "taken_action": "C", "reason": "headless: kept the helper's pick", "evidence": {"detected_languages": [<detected_languages>]}}` as `{run_dir}/decision.json` and run `uv run {emitEnvelopeHelper} record --workflow skf-quick-skill --run-dir "{run_dir}" --decision < "{run_dir}/decision.json"`. To build another of the languages headlessly, pass `--language-hint` (a batch line's `language=`).
|
|
168
218
|
|
|
169
|
-
|
|
170
|
-
- **IF A** — HARD HALT with **exit code 3 (resolution-failure)**: "Aborted to disambiguate language. Re-run with a `language_hint`." Before exiting, emit the error result contract per `references/halt-contract.md` (`phase: "resolve-target"`, `error.code: "resolution-failure"`, `error.details: {detected_languages: [...], auto_pick: "{language}"}`, `skill_package: null`).
|
|
171
|
-
- **GATE [default: C]** — Headless mode auto-proceeds with the manifest-priority pick; record `detected_languages` and `language_resolution: "auto-picked-first"` in the extraction context so the result contract surfaces the ambiguity downstream.
|
|
219
|
+
Keep `language_resolution` and `detected_languages` (the helper's list, empty when a hint set the language) for step 6 §3's summary: `language_resolution` is `hint` when a language hint set the language, `detected` when the helper found no second manifest language (or the listing is a skills module with no code), and the gate's `user-confirmed` or `auto-picked-first` otherwise.
|
|
172
220
|
|
|
173
221
|
### 5. Confirm Resolution
|
|
174
222
|
|
|
@@ -176,6 +224,8 @@ Determine primary language:
|
|
|
176
224
|
|
|
177
225
|
- **Repository:** {resolved_url}
|
|
178
226
|
- **Name:** {repo_name}
|
|
227
|
+
- **Registry:** {registry_used} (omit this line when no registry resolved the target)
|
|
228
|
+
- **Ref:** {source_ref} (omit this line when `source_ref` is not set)
|
|
179
229
|
- **Language:** {language}
|
|
180
230
|
- **Scope:** {scope_hint or 'entire repo'}
|
|
181
231
|
|
|
@@ -183,5 +233,5 @@ Determine primary language:
|
|
|
183
233
|
|
|
184
234
|
### 6. Proceed to Next Step
|
|
185
235
|
|
|
186
|
-
Once the target is resolved to a GitHub repository with confirmed URL, name, and detected language, load and execute {nextStepFile} for the ecosystem check.
|
|
236
|
+
Once the target is resolved to a GitHub repository with confirmed URL, name, and detected language, load and execute {nextStepFile} for the ecosystem check; when `{headless_mode}` is true, print this step's `done` event and step 2's `start` event first (`references/halt-contract.md`).
|
|
187
237
|
|
|
@@ -6,6 +6,15 @@ frontmatterValidatorProbeOrder:
|
|
|
6
6
|
outputValidatorProbeOrder:
|
|
7
7
|
- '{project-root}/_bmad/skf/shared/scripts/skf-validate-output.py'
|
|
8
8
|
- '{project-root}/src/shared/scripts/skf-validate-output.py'
|
|
9
|
+
descriptionGuardProbeOrder:
|
|
10
|
+
- '{project-root}/_bmad/skf/shared/scripts/skf-description-guard.py'
|
|
11
|
+
- '{project-root}/src/shared/scripts/skf-description-guard.py'
|
|
12
|
+
skillInventoryProbeOrder:
|
|
13
|
+
- '{project-root}/_bmad/skf/shared/scripts/skf-skill-inventory.py'
|
|
14
|
+
- '{project-root}/src/shared/scripts/skf-skill-inventory.py'
|
|
15
|
+
atomicWriteProbeOrder:
|
|
16
|
+
- '{project-root}/_bmad/skf/shared/scripts/skf-atomic-write.py'
|
|
17
|
+
- '{project-root}/src/shared/scripts/skf-atomic-write.py'
|
|
9
18
|
---
|
|
10
19
|
|
|
11
20
|
<!-- Config: communicate in {communication_language}. Generated SKILL.md text in {document_output_language}. -->
|
|
@@ -14,44 +23,80 @@ outputValidatorProbeOrder:
|
|
|
14
23
|
|
|
15
24
|
## STEP GOAL:
|
|
16
25
|
|
|
17
|
-
To write the compiled SKILL.md, context-snippet.md, and metadata.json to the versioned skill package, then validate them on disk against the agentskills.io specification at community tier.
|
|
26
|
+
To write the compiled SKILL.md, context-snippet.md, and metadata.json to the versioned skill package, then validate them on disk against the agentskills.io specification at community tier. Validation is advisory: issues are reported but do not block the workflow.
|
|
18
27
|
|
|
19
28
|
## Rules
|
|
20
29
|
|
|
21
30
|
- Write exactly what was compiled — do not modify content during writing or after validation
|
|
22
31
|
- Community-tier validation (lighter than official requirements)
|
|
32
|
+
- A HARD HALT prints, after its envelope, this step's `halt` event when `{headless_mode}` is true. Under `--batch` it ends only this target: then return to `references/batch-mode.md` §3, even when the halt reads as the end of the run (`references/halt-contract.md`).
|
|
23
33
|
|
|
24
34
|
## Steps
|
|
25
35
|
|
|
26
|
-
### 1. Create Output Directory
|
|
36
|
+
### 1. Check Ownership, Then Create Output Directory
|
|
27
37
|
|
|
28
|
-
Resolve `{version}`
|
|
38
|
+
Resolve `{version}` ← the `version` of `{run_dir}/metadata.json`, which step 4 §4 rendered: the version the target pinned, else the manifest's, else `1.0.0`. The version folder and the file's `version` are then one value.
|
|
39
|
+
|
|
40
|
+
**Ownership check.** Run it before creating any directory and before the overwrite prompt below. Resolve `{skillInventoryHelper}` ← first existing path in `{skillInventoryProbeOrder}` and run:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
uv run {skillInventoryHelper} {skills_output_folder} --skill {repo_name} --write-check --write-version {version} --forge-data-folder {forge_data_folder}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
`--forge-data-folder` only tells the helper whether both settings name one folder.
|
|
47
|
+
|
|
48
|
+
Bind `{write_verdict}` ← `write_check.verdict`, `{write_folder}` ← `write_check.folder`, `{write_detail}` ← `write_check.detail`, and `{existing_generator}` ← `write_check.version_generated_by` and `{existing_tier}` ← `write_check.version_confidence_tier` (the build already at `{version}`, each null when none names it). Continue only when the status is `ok` and `{write_verdict}` is `"ok"`: nothing is at the skill folder yet, it holds only what an interrupted run leaves, or SKF generated it and the version is new or SKF's own. Otherwise create nothing and refuse with the first case that applies:
|
|
49
|
+
|
|
50
|
+
- `{write_verdict}` is `"flat-layout"` → `halt_reason: "flat-layout"`: "**`{repo_name}` still uses the flat layout — nothing was written.** A version written beside its root `SKILL.md` would leave a skill SKF can no longer migrate or rename. Run `@Ferris TS {repo_name}` (or US, AS or EX) once to move it into the versioned layout, then re-run."
|
|
51
|
+
- `{write_verdict}` is `"not-skf-output"` → `halt_reason: "not-skf-output"`: "**`{repo_name}` is not SKF output — nothing was written.** `{write_folder}` {write_detail}, so SKF will not write a version there. A shared `{skills_output_folder}` is supported: SKF leaves the skills it did not generate alone, so manage `{repo_name}` yourself, and Quick Skill names a skill after its target, so to create it under another name, brief it with `@Ferris BS` and compile it with `@Ferris CS`. 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`. A version folder with no `metadata.json` can also be one that an interrupted quick-skill run left behind; delete it yourself in that case."
|
|
52
|
+
- The status is not `ok`, or the output has no `write_check` (an older helper: it has no `--write-check` and reports a new skill as `SKILL_NOT_FOUND`) → `halt_reason: "not-skf-output"`: the same message with "SKF could not check it ({the helper's `error`, if any}; re-install SKF if the installed `skf-skill-inventory.py` is out of date)" in place of "`{write_folder}` {write_detail}".
|
|
53
|
+
- When no helper candidate resolves, continue only when nothing exists at `{skill_group}` (no folder, no file, not even a broken link). Otherwise refuse with `halt_reason: "not-skf-output"` and the same message, giving "SKF cannot check who generated `{skill_group}`: `skf-skill-inventory.py` is missing; re-install SKF" in place of "`{write_folder}` {write_detail}".
|
|
54
|
+
|
|
55
|
+
Each refusal is a HARD HALT with **exit code 9 (state-conflict)**: stage `{"phase": "write-and-validate", "halt_reason": "<the halt reason>", "reason": "<the message's first sentence>", "skill_package": null, "details": {"folder": "<the folder the message names>"}}` as `{run_dir}/halt.json` and run `uv run {emitEnvelopeHelper} emit-halt --workflow skf-quick-skill --run-dir "{run_dir}" --target stderr < "{run_dir}/halt.json"`, with no `--result-dir` (`references/halt-contract.md`). This halt writes no result file on disk: `{skill_package}` would sit in a folder SKF did not generate. It is a HALT, not a gate, so it has no headless default.
|
|
56
|
+
|
|
57
|
+
Then create the skill output directories:
|
|
29
58
|
|
|
30
59
|
```
|
|
31
60
|
{skill_group} # {skills_output_folder}/{repo_name}/
|
|
32
61
|
{skill_package} # {skills_output_folder}/{repo_name}/{version}/{repo_name}/
|
|
33
62
|
```
|
|
34
63
|
|
|
35
|
-
If `{skill_package}`
|
|
64
|
+
If `{skill_package}/metadata.json` exists, confirm with user before overwriting:
|
|
65
|
+
|
|
66
|
+
"**Directory `{skill_package}` already exists.** It holds a `{existing_generator}` build ({existing_tier}); overwriting replaces it whole with a community quick skill, and validation results, result contracts, and any manual tweaks from the previous run will not be preserved. Overwrite existing files? [Y/N]" (say "an SKF build" in place of "a `{existing_generator}` build ({existing_tier})" when `{existing_generator}` is null, and leave out " ({existing_tier})" when only `{existing_tier}` is null).
|
|
36
67
|
|
|
37
|
-
|
|
68
|
+
- **If user selects Y:** when `{existing_generator}` is neither `quick-skill` nor null, remove the old package first, so none of its files (create-skill's `references/` and `extraction-rules.yaml`, for example) stays beside the quick skill, and set `{replaced_build}` ← `{existing_generator}` for step 6's summary. The `case` guard removes nothing unless the path is this skill's version package:
|
|
38
69
|
|
|
39
|
-
|
|
40
|
-
|
|
70
|
+
```bash
|
|
71
|
+
case "{skill_package}" in */{repo_name}/{version}/{repo_name}) rm -rf "{skill_package}" && mkdir -p "{skill_package}" ;; esac
|
|
72
|
+
```
|
|
41
73
|
|
|
42
|
-
|
|
74
|
+
Proceed to section 2.
|
|
75
|
+
- **If user selects N:** HARD HALT with **exit code 5 (overwrite-cancelled)**: "Overwrite cancelled. Existing skill preserved. Quick Skill names a skill after its target, so to create it under another name, brief it with `@Ferris BS` and compile it with `@Ferris CS`; or remove the existing directory yourself and re-run." Stage `{"phase": "write-and-validate", "halt_reason": "overwrite-cancelled", "reason": "Overwrite cancelled. Existing skill preserved.", "skill_package": "{skill_package}", "details": {"existing_generator": "{existing_generator}"}}` as `{run_dir}/halt.json` (`existing_generator` null when none names it) and run `uv run {emitEnvelopeHelper} emit-halt --workflow skf-quick-skill --run-dir "{run_dir}" --result-dir "{skill_package}" --target stderr < "{run_dir}/halt.json"`: `{skill_package}` holds `metadata.json`, so the emitter also writes the `-latest.json` envelope there, and consumers that hardcode that path see a deterministic file even on this cancelled run.
|
|
76
|
+
|
|
77
|
+
**GATE [default: Y]** when `{existing_generator}` is `quick-skill` or null: if `{headless_mode}` is true, auto-proceed with Y, log "headless: overwriting existing `{skill_package}`", and record the decision: stage `{"gate": "write-and-validate.overwrite", "default_action": "Y", "taken_action": "Y", "reason": "headless: overwrote the existing package", "evidence": {"skill_package": "{skill_package}"}}` as `{run_dir}/decision.json` and run `uv run {emitEnvelopeHelper} record --workflow skf-quick-skill --run-dir "{run_dir}" --decision < "{run_dir}/decision.json"`.
|
|
78
|
+
|
|
79
|
+
**GATE [default: N]** for any other `{existing_generator}`, so no headless run or batch replaces another workflow's build with a quick skill: if `{headless_mode}` is true, record the decision: stage `{"gate": "write-and-validate.overwrite", "default_action": "N", "taken_action": "N", "reason": "headless: kept the {existing_generator} build", "evidence": {"skill_package": "{skill_package}", "existing_generator": "{existing_generator}"}}` as `{run_dir}/decision.json` and run `uv run {emitEnvelopeHelper} record --workflow skf-quick-skill --run-dir "{run_dir}" --decision < "{run_dir}/decision.json"`, then halt as **If user selects N** does, with the message "**Kept the `{existing_generator}` build at `{skill_package}`.** A headless run never replaces another workflow's build with a quick skill. To replace it, run Quick Skill interactively and answer Y; to keep it, give the quick skill another version (`@Ferris QS <package>@<version>`)." and the `reason` "Kept the {existing_generator} build: a headless run never replaces another workflow's build".
|
|
80
|
+
|
|
81
|
+
A `{skill_package}` without `metadata.json` holds only what an interrupted run leaves (the ownership check refuses anything else), so it is written without asking.
|
|
43
82
|
|
|
44
83
|
### 2. Write Deliverables
|
|
45
84
|
|
|
46
|
-
Write the three compiled artifacts to the skill package so that
|
|
85
|
+
Write the three compiled artifacts to the skill package in this order, `metadata.json` first, so a run interrupted mid-write leaves a package that carries the SKF marker, which the next run's ownership check accepts:
|
|
86
|
+
|
|
87
|
+
1. `{skill_package}/metadata.json`: installed from the file step 4 §4 rendered, never typed again. Resolve `{atomicWriteHelper}` ← first existing path in `{atomicWriteProbeOrder}` and run:
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
uv run {atomicWriteHelper} write --target "{skill_package}/metadata.json" < "{run_dir}/metadata.json"
|
|
91
|
+
```
|
|
47
92
|
|
|
48
|
-
**
|
|
49
|
-
|
|
50
|
-
|
|
93
|
+
It writes the file in place atomically, so an interrupted run never leaves half a `metadata.json`. If no candidate exists, write nothing and HARD HALT with **exit code 3 (resolution-failure)**, in interactive mode too: "**Nothing was written to `{skill_package}`.** SKF's atomic writer (`skf-atomic-write.py`) is missing from `{project-root}/_bmad/skf/shared/scripts/`, so re-install SKF." Stage `{"phase": "write-and-validate", "halt_reason": "resolution-failure", "reason": "Nothing was written: the atomic writer is missing.", "skill_package": "{skill_package}", "details": {"cause": "atomic-writer-missing"}}` as `{run_dir}/halt.json` and run `uv run {emitEnvelopeHelper} emit-halt --workflow skf-quick-skill --run-dir "{run_dir}" --result-dir "{skill_package}" --target stderr < "{run_dir}/halt.json"`, without `--result-dir "{skill_package}"` when no earlier run's `metadata.json` is there (`references/halt-contract.md`).
|
|
94
|
+
2. `{skill_package}/SKILL.md`: the compiled skill document.
|
|
95
|
+
3. `{skill_package}/context-snippet.md`: the compressed context snippet. **Skip this write** if `{overrides.skip_snippet}` was set; the artifact is omitted from `outputs`.
|
|
51
96
|
|
|
52
|
-
Confirm after each write: "Written:
|
|
97
|
+
Confirm after each write: "Written: metadata.json" / "Written: SKILL.md" / "Written: context-snippet.md". When `--skip-snippet` is active, log "Skipped: context-snippet.md (--skip-snippet)" instead of the snippet write confirmation.
|
|
53
98
|
|
|
54
|
-
**If any write fails
|
|
99
|
+
**If any write fails, HARD HALT (exit code 4, write-failure):** stage `{"phase": "write-and-validate", "halt_reason": "write-failure", "reason": "Write failed: could not write <path>.", "skill_package": "{skill_package}", "outputs": {<each file that did write before the failure, as "metadata", "skill_md" or "context_snippet" with its path>}, "details": {"failed_path": "<path>", "error": "<details>"}}` as `{run_dir}/halt.json` and run `uv run {emitEnvelopeHelper} emit-halt --workflow skf-quick-skill --run-dir "{run_dir}" --result-dir "{skill_package}" --target stderr < "{run_dir}/halt.json"`. When `metadata.json` itself failed to write, run it without `--result-dir "{skill_package}"`: the contract writes no result file on disk, because a package holding only result files would read as not SKF output to the next run's ownership check.
|
|
55
100
|
|
|
56
101
|
"**Write failed:** Could not write to `{file_path}`.
|
|
57
102
|
|
|
@@ -67,17 +112,21 @@ Check:
|
|
|
67
112
|
Run: `npx skill-check -h`
|
|
68
113
|
|
|
69
114
|
- If succeeds (returns usage information): Continue to automated validation (section 4)
|
|
70
|
-
- If fails (command not found or error):
|
|
115
|
+
- If fails (command not found or error): skip to the frontmatter validator in section 4, and log "security scan skipped: skill-check unavailable" in the validation results
|
|
71
116
|
|
|
72
117
|
### 4. Validate SKILL.md via skill-check (if available)
|
|
73
118
|
|
|
74
|
-
**If `npx skill-check` is available**, run
|
|
119
|
+
**If `npx skill-check` is available**, run validation and its security scan in one call against the skill package written in section 2. `--fix` can also rewrite the frontmatter `description` the user approved in step 4, which would leave SKILL.md out of step with `metadata.json`, so the call runs inside the description guard. Resolve `{descriptionGuardHelper}` ← first existing path in `{descriptionGuardProbeOrder}`, then run the three commands in order:
|
|
75
120
|
|
|
76
121
|
```bash
|
|
77
|
-
|
|
122
|
+
uv run {descriptionGuardHelper} capture "{skill_package}/SKILL.md" > "{run_dir}/description-guard.json"
|
|
123
|
+
npx skill-check check "{skill_package}" --fix --format json
|
|
124
|
+
uv run {descriptionGuardHelper} verify-restore "{skill_package}/SKILL.md" --captured-file "{run_dir}/description-guard.json"
|
|
78
125
|
```
|
|
79
126
|
|
|
80
|
-
|
|
127
|
+
**Guard outputs.** `capture` stages the approved description in `{run_dir}/description-guard.json` and `verify-restore` reads it there, so it never passes through a shell string. Bind `{guard_restored}` ← `restored` and `{guard_diff_kind}` ← `diff_kind` from `verify-restore`. When `{guard_restored}` is true, the approved description is back in SKILL.md, matching `metadata.json`: record the validation note "description restored after `skill-check --fix` ({guard_diff_kind})", which §6 lists with the auto-fixed issues. `verify-restore` refuses an empty or whitespace-only captured description, and a file it cannot read (exit 1, SKILL.md untouched): re-run it with `--captured-file "{skill_package}/metadata.json"`, whose `description` step 4 rendered, never with an empty value, and if that exits 1 too, record a high-severity issue: the guard could not check the description. When it exits 2 with JSON on stdout (the JSON carries `restore_error`), the restore could not be written, so record a high-severity issue: SKILL.md's description no longer matches `metadata.json`.
|
|
128
|
+
|
|
129
|
+
**If no `{descriptionGuardProbeOrder}` path exists**, never run `--fix` unguarded. Run `npx skill-check check "{skill_package}" --format json` instead, which validates and scans without fixing, and log the validation issue "description guard unavailable (`skf-description-guard.py` missing): skill-check ran without `--fix`".
|
|
81
130
|
|
|
82
131
|
**Parse JSON output** to extract:
|
|
83
132
|
- `scores[].score` — overall score (0-100); match the entry by `relativePath`/`skillId`
|
|
@@ -85,45 +134,35 @@ This validates frontmatter, description, body limits, links, and formatting; run
|
|
|
85
134
|
- `fixed[]` — issues automatically corrected
|
|
86
135
|
- `security[]` (when present) — security findings, recorded as advisory warnings (security issues do not block output)
|
|
87
136
|
|
|
88
|
-
|
|
137
|
+
Bind `{quality_score}` ← that score, and record the remaining diagnostics and security findings as validation issues. `{quality_score}` is null when skill-check did not run.
|
|
89
138
|
|
|
90
|
-
**If skill-check is not available**, run the shared frontmatter validator. Resolve `{frontmatterValidator}` from `{frontmatterValidatorProbeOrder}`; first existing path wins. If no candidate exists,
|
|
139
|
+
**If skill-check is not available**, run the shared frontmatter validator. Resolve `{frontmatterValidator}` from `{frontmatterValidatorProbeOrder}`; first existing path wins. If no candidate exists, nothing can check the frontmatter: HARD HALT with **exit code 3 (resolution-failure)**, in interactive mode too: "**`{skill_package}` was written but not validated.** skill-check is unavailable and SKF's frontmatter validator (`skf-validate-frontmatter.py`) is missing from `{project-root}/_bmad/skf/shared/scripts/`, so re-install SKF, then re-run." Stage `{"phase": "write-and-validate", "halt_reason": "resolution-failure", "reason": "The skill was written but not validated: the frontmatter validator is missing.", "skill_package": "{skill_package}", "outputs": {<each deliverable §2 wrote, as "metadata", "skill_md" or "context_snippet" with its path>}, "details": {"cause": "frontmatter-validator-missing"}}` as `{run_dir}/halt.json` and run `uv run {emitEnvelopeHelper} emit-halt --workflow skf-quick-skill --run-dir "{run_dir}" --result-dir "{skill_package}" --target stderr < "{run_dir}/halt.json"`.
|
|
91
140
|
|
|
92
141
|
```bash
|
|
93
|
-
uv run {frontmatterValidator} {skill_package}/SKILL.md --skill-dir-name {repo_name}
|
|
142
|
+
uv run {frontmatterValidator} "{skill_package}/SKILL.md" --skill-dir-name {repo_name}
|
|
94
143
|
```
|
|
95
144
|
|
|
96
|
-
The validator emits JSON with `status` (`pass`/`fail`), `issues[]` (each with `severity`, `code`, `message`), and `frontmatter` (the parsed name/description).
|
|
145
|
+
The validator emits JSON with `status` (`pass`/`fail`), `issues[]` (each with `severity`, `code`, `message`), and `frontmatter` (the parsed name/description). Record each `issues[]` entry as a validation issue with its reported severity.
|
|
97
146
|
|
|
98
147
|
### 5. Validate Body, Snippet, and Metadata via skf-validate-output.py
|
|
99
148
|
|
|
100
149
|
Run the shared output validator against the on-disk skill package — it performs the body-structure, snippet-format, and metadata-shape checks. Pass `--skip-frontmatter` since §4 has already covered frontmatter.
|
|
101
150
|
|
|
102
|
-
**Resolve `{outputValidator}
|
|
151
|
+
**Resolve `{outputValidator}`** from `{outputValidatorProbeOrder}`; first existing path wins. If no candidate exists, HARD HALT with **exit code 3 (resolution-failure)**, in interactive mode too: "**`{skill_package}` was written but not validated.** SKF's output validator (`skf-validate-output.py`) is missing from `{project-root}/_bmad/skf/shared/scripts/`, so re-install SKF, then re-run." Stage `{"phase": "write-and-validate", "halt_reason": "resolution-failure", "reason": "The skill was written but not validated: the output validator is missing.", "skill_package": "{skill_package}", "outputs": {<each deliverable §2 wrote, as "metadata", "skill_md" or "context_snippet" with its path>}, "details": {"cause": "output-validator-missing"}}` as `{run_dir}/halt.json` and run `uv run {emitEnvelopeHelper} emit-halt --workflow skf-quick-skill --run-dir "{run_dir}" --result-dir "{skill_package}" --target stderr < "{run_dir}/halt.json"`. Otherwise run:
|
|
103
152
|
|
|
104
153
|
```bash
|
|
105
|
-
|
|
154
|
+
uv run {outputValidator} "{skill_package}" --generated-by quick-skill --skip-frontmatter
|
|
106
155
|
```
|
|
107
156
|
|
|
108
157
|
The validator emits JSON with `result` (PASS/FAIL), `validation.skill_md.body[]`, `validation.context_snippet.issues[]`, `validation.metadata.issues[]`, and a severity-bucketed `summary`. Record each issue as a validation issue at its reported severity.
|
|
109
158
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
- **Body structure** — Overview, Description, Key Exports, Usage sections present (medium when missing)
|
|
113
|
-
- **Context snippet** — `[{name} v{version}]|root: ...` first line, `|IMPORTANT:` second line, ~80–120-token length
|
|
114
|
-
- **Metadata** — required string fields (`name`, `version`, `source_authority`, `language`, `generation_date`), `source_repo`, `generated_by`, `confidence_tier`, and `stats` numerics (`exports_documented`, `exports_public_api`, `exports_total`, `public_api_coverage`, `total_coverage`)
|
|
115
|
-
|
|
116
|
-
### 6. Security Scan (covered by §4)
|
|
117
|
-
|
|
118
|
-
Security findings are already collected from the §4 invocation (no separate `npx` round trip needed — `skill-check check ... --fix --format json` runs the security scan by default). If skill-check was unavailable in §3, log "security scan skipped — skill-check unavailable" in validation results.
|
|
119
|
-
|
|
120
|
-
### 7. Report Validation Results
|
|
159
|
+
### 6. Report Validation Results
|
|
121
160
|
|
|
122
161
|
"**Validation complete:**
|
|
123
162
|
|
|
124
163
|
**SKILL.md:** {pass/issues found} (quality score: {score}/100 if skill-check was available)
|
|
125
164
|
{list any issues}
|
|
126
|
-
{list any auto-fixed issues}
|
|
165
|
+
{list any auto-fixed issues, and the §4 description-guard note when the guard restored the description}
|
|
127
166
|
|
|
128
167
|
**context-snippet.md:** {pass/issues found}
|
|
129
168
|
{list any issues}
|
|
@@ -137,13 +176,13 @@ Security findings are already collected from the §4 invocation (no separate `np
|
|
|
137
176
|
**Overall:** {pass / N issues found}
|
|
138
177
|
|
|
139
178
|
{If issues found:}
|
|
140
|
-
These issues are advisory for community-tier skills
|
|
179
|
+
These issues are advisory for community-tier skills: fix them in the written files, or re-run Quick Skill once the source or the hints change.
|
|
141
180
|
|
|
142
181
|
**Proceeding to finalize...**"
|
|
143
182
|
|
|
144
|
-
Set `validation_result` with pass/fail status, quality score, and issues list.
|
|
183
|
+
Set `validation_result` with pass/fail status, quality score, and issues list, and `{validation_issues}` ← `{"skill_md": <n>, "context_snippet": <n>, "metadata": <n>, "security": <n>}`, each `<n>` the number of entries the validators returned for that heading: `skill_md` counts skill-check's `diagnostics[]` (without skill-check, the frontmatter validator's `issues[]`) plus `validation.skill_md.body[]`; `context_snippet` counts `validation.context_snippet.issues[]`; `metadata` counts `validation.metadata.issues[]`; `security` counts skill-check's `security[]`. A check that did not run counts 0, and `fixed[]` and the guard note count nothing. Step 6 §3's summary carries `{quality_score}` and `{validation_issues}`.
|
|
145
184
|
|
|
146
|
-
###
|
|
185
|
+
### 7. Auto-Proceed to Finalize
|
|
147
186
|
|
|
148
|
-
Once deliverables are written to `{skill_package}` and validation is reported (advisory), load and execute {nextStepFile} to finalize.
|
|
187
|
+
Once deliverables are written to `{skill_package}` and validation is reported (advisory), load and execute {nextStepFile} to finalize; when `{headless_mode}` is true, print this step's `done` event and step 6's `start` event first (`references/halt-contract.md`).
|
|
149
188
|
|