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,11 +1,10 @@
|
|
|
1
1
|
---
|
|
2
|
-
tierRulesData: 'references/tier-rules.md'
|
|
3
2
|
nextStepFile: 'health-check.md'
|
|
4
3
|
# `{emitEnvelopeHelper}` = first existing path in `{emitEnvelopeProbeOrder}`;
|
|
5
|
-
# halt if neither exists when
|
|
6
|
-
#
|
|
7
|
-
#
|
|
8
|
-
#
|
|
4
|
+
# halt if neither exists when section 4 emits the envelope. The script is the
|
|
5
|
+
# source of truth for the SKF_SETUP_RESULT_JSON contract: do not render the
|
|
6
|
+
# envelope from prose (LLM schema drift is the bug this script exists to
|
|
7
|
+
# prevent).
|
|
9
8
|
emitEnvelopeProbeOrder:
|
|
10
9
|
- '{project-root}/_bmad/skf/shared/scripts/skf-emit-result-envelope.py'
|
|
11
10
|
- '{project-root}/src/shared/scripts/skf-emit-result-envelope.py'
|
|
@@ -17,196 +16,74 @@ emitEnvelopeProbeOrder:
|
|
|
17
16
|
|
|
18
17
|
## STEP GOAL:
|
|
19
18
|
|
|
20
|
-
|
|
19
|
+
Stage the run's report payload, display the FORGE STATUS banner that `{emitEnvelopeHelper}` renders from it (tier, tools, an upgrade for each tool below its minimum version, tier changes and tool-set deltas on re-runs, and a REQUIRED TIER NOT MET block on a required-tier miss), and (when headless or quiet) emit the schema-locked `SKF_SETUP_RESULT_JSON` envelope from the same payload.
|
|
21
20
|
|
|
22
21
|
## Rules
|
|
23
22
|
|
|
24
23
|
- Focus only on display + envelope emission
|
|
25
|
-
-
|
|
26
|
-
- Do not list tools that are not available
|
|
27
|
-
- Use tier capability descriptions from tier-rules.md
|
|
24
|
+
- The FORGE STATUS lines come from `render-report`: display them (translated when needed), and never compose, add or drop a line yourself
|
|
28
25
|
- Never inline-render the envelope JSON — the script owns the schema; drift breaks pipelines
|
|
29
26
|
- Chains to the local health-check step via `{nextStepFile}` after completion — the user-facing status report is not the terminal step
|
|
27
|
+
- Display messages only when `{quiet_mode}` is false; the one exception is the envelope line section 4 builds, which section 5 displays on a tier miss and the shared health check displays last otherwise
|
|
28
|
+
- When `{quiet_mode}` is true, write no assistant text at all between tool calls: no status, progress or step-transition notes, however brief
|
|
29
|
+
- If section 4 finds no existing path in `emitEnvelopeProbeOrder`, halt with phase `step 4:helper-missing`, `path` set to its first entry, and reason `Setup cannot proceed: skf-emit-result-envelope.py was not found. Reinstall SKF, then re-run /skf-setup.` With no envelope helper to call, display that reason alone as the run's one line (the SKILL.md halt contract)
|
|
30
30
|
|
|
31
31
|
## MANDATORY SEQUENCE
|
|
32
32
|
|
|
33
|
-
### 1.
|
|
33
|
+
### 1. Stage the Report Payload
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
Sections 2 and 4 read the helper outputs the run folder holds (`detect-tools.json`, `ccc-exclusions.json`, `qmd-classify.json`, `qmd-remove.json` and `clean-stale.json`, each when its step ran the helper), take the run's paths from `--project-root`, `--sidecar-path` and `--forge-data-folder` (the folders On Activation bound from preflight), and read one payload file with what neither gives, staged here on every run through a quoted heredoc:
|
|
36
36
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
Tier: {calculated_tier}
|
|
47
|
-
{tier capability description from tier-rules.md}
|
|
48
|
-
|
|
49
|
-
Tools Detected:
|
|
50
|
-
{for each tool that is available, show: tool name — version. ccc exposes no version string, so for ccc show its daemon health instead: ccc — daemon {ccc_daemon} (e.g. "ccc — daemon healthy")}
|
|
51
|
-
{if no tools are available: (none yet — see "Climb to next tier" below)}
|
|
52
|
-
|
|
53
|
-
{if calculated_tier is not Deep:}
|
|
54
|
-
Climb to next tier:
|
|
55
|
-
{if not tools.ast_grep: - Install ast-grep (https://ast-grep.github.io) — unlocks AST-backed code analysis (Forge tier)}
|
|
56
|
-
{if tools.ast_grep and not tools.ccc: - Install cocoindex-code (https://github.com/cocoindex-io/cocoindex-code) — adds semantic-guided precision compilation (Forge+ tier)}
|
|
57
|
-
{if tools.ast_grep and not tools.gh_cli: - Install GitHub CLI (https://cli.github.com) — required for Deep tier (cross-repository synthesis)}
|
|
58
|
-
{if tools.ast_grep and not tools.qmd and qmd_status is "absent": - Install qmd (https://github.com/tobi/qmd) — required for Deep tier (knowledge search)}
|
|
59
|
-
{if tools.ast_grep and not tools.qmd and qmd_status is "daemon_stopped": - Start the qmd daemon (already installed) — run `qmd start` (or your distribution's qmd service command) to unlock Deep tier (knowledge search)}
|
|
60
|
-
{if tools.ccc and ccc_daemon is "error": - The ccc daemon is reporting errors — run `ccc doctor` to diagnose. CCC index will fail until resolved}
|
|
61
|
-
{end if}
|
|
62
|
-
|
|
63
|
-
{if hygiene_result is "completed":}
|
|
64
|
-
QMD Registry:
|
|
65
|
-
{hygiene_healthy} collection(s) healthy
|
|
66
|
-
{if hygiene_orphaned_removed > 0: {hygiene_orphaned_removed} orphaned collection(s) removed}
|
|
67
|
-
{if hygiene_orphaned_kept > 0: {hygiene_orphaned_kept} orphaned collection(s) kept}
|
|
68
|
-
{if hygiene_stale_cleaned > 0: {hygiene_stale_cleaned} stale QMD registry entry/entries cleaned}
|
|
69
|
-
{end if}
|
|
70
|
-
|
|
71
|
-
{if ccc_registry_stale_cleaned > 0:}
|
|
72
|
-
CCC Registry: {ccc_registry_stale_cleaned} stale entry/entries cleaned
|
|
73
|
-
{end if}
|
|
74
|
-
|
|
75
|
-
{if hygiene_result is "completed" and hygiene_healthy is 0:}
|
|
76
|
-
QMD Registry: empty — collections are created automatically when you run /skf-create-skill.
|
|
77
|
-
{end if}
|
|
78
|
-
|
|
79
|
-
{if hygiene_result is "qmd_unavailable":}
|
|
80
|
-
QMD Registry: skipped (qmd unavailable — if the daemon is stopped, `qmd start` restores it).
|
|
81
|
-
{end if}
|
|
82
|
-
|
|
83
|
-
{if tools.ccc is true:}
|
|
84
|
-
CCC Index:
|
|
85
|
-
{if ccc_index_result is "fresh": up to date — semantic discovery ready}
|
|
86
|
-
{if ccc_index_result is "created": indexed this run — semantic discovery ready}
|
|
87
|
-
{if ccc_index_result is "skipped": skipped (--ccc-skip-index) — run `/skf-setup` without --ccc-skip-index to build the index when you're ready}
|
|
88
|
-
{if ccc_index_result is "failed": indexing failed — semantic discovery unavailable this session}
|
|
89
|
-
{end if}
|
|
90
|
-
|
|
91
|
-
Files written this run:
|
|
92
|
-
- forge-tier.yaml — {project-root}/_bmad/_memory/forger-sidecar/forge-tier.yaml
|
|
93
|
-
{if preferences_yaml_created is true:}
|
|
94
|
-
- preferences.yaml — {project-root}/_bmad/_memory/forger-sidecar/preferences.yaml (first-run defaults)
|
|
95
|
-
{end if}
|
|
96
|
-
- {forge_data_folder}/ (directory ensured)
|
|
97
|
-
{if settings_yml_written is true:}
|
|
98
|
-
- .cocoindex_code/settings.yml — {project-root}/.cocoindex_code/settings.yml ({settings_yml_patterns_added} SKF exclusion pattern(s) merged)
|
|
99
|
-
{end if}
|
|
100
|
-
{if ccc_index_result is "created":}
|
|
101
|
-
- .cocoindex_code/ ccc index — {ccc_file_count} files indexed
|
|
102
|
-
{end if}
|
|
103
|
-
|
|
104
|
-
{if tier_override is active:}
|
|
105
|
-
Note: Tier override active (set in preferences.yaml)
|
|
106
|
-
|
|
107
|
-
{if tier_override_invalid is true:}
|
|
108
|
-
Note: tier_override value "{tier_override_invalid_value}" in preferences.yaml is not valid.
|
|
109
|
-
{if tier_override_invalid_suggestion is non-null: Did you mean "{tier_override_invalid_suggestion}"?}
|
|
110
|
-
Valid values are case-sensitive: Quick, Forge, Forge+, Deep. Using detected tier {calculated_tier}.
|
|
111
|
-
|
|
112
|
-
{if tier_override_unsafe is true:}
|
|
113
|
-
Warning: tier_override is forcing {calculated_tier} but the underlying tool prerequisites are not satisfied.
|
|
114
|
-
Missing: {tier_override_unsafe_missing}. The override is honored, but downstream skills that
|
|
115
|
-
rely on the missing tool(s) will fail at runtime. Install the missing tool(s) or remove
|
|
116
|
-
the override from preferences.yaml.
|
|
117
|
-
|
|
118
|
-
{if {previous_tier} is null:}
|
|
119
|
-
Initial detection — {calculated_tier} tier established.
|
|
120
|
-
|
|
121
|
-
{if {tier_changed} is true:}
|
|
122
|
-
{appropriate upgrade/downgrade message from tier-rules.md}
|
|
123
|
-
|
|
124
|
-
{if {tier_changed} is false and {tools_added} is empty and {tools_removed} is empty and {previous_tier} is non-null:}
|
|
125
|
-
{same-tier message from tier-rules.md}
|
|
126
|
-
{if preferences_yaml_created is false and (ccc_index_result is "fresh" or ccc_index_result is "none" or ccc_index_result is "skipped"): Nothing changed — your preferences were left untouched and the index was already current. You're good.}
|
|
127
|
-
|
|
128
|
-
{if {tier_changed} is false and ({tools_added} or {tools_removed} is non-empty) and {previous_tier} is non-null:}
|
|
129
|
-
Tier unchanged: {calculated_tier}.
|
|
130
|
-
{if {tools_added} non-empty:} Newly detected: {comma-separated tool names from tools_added}{if ccc was added and tier is Deep: " — ccc enhances Deep tier transparently."}
|
|
131
|
-
{if {tools_removed} non-empty:} No longer detected: {comma-separated tool names from tools_removed} — re-install to restore those capabilities.
|
|
132
|
-
|
|
133
|
-
═══════════════════════════════════════
|
|
134
|
-
Forge ready. {calculated_tier} tier active.
|
|
135
|
-
═══════════════════════════════════════
|
|
136
|
-
|
|
137
|
-
{if {headless_mode} is false:}
|
|
138
|
-
Next: the fastest start is `@Ferris forge-auto <repo-or-doc-url>` — one command auto-scopes, briefs, compiles, tests at a 90% quality gate, and exports a verified skill with zero configuration. Prefer to scope by hand? `/skf-brief-skill` scopes your first compilation target, or `/skf-quick-skill` is a fast template-driven path. Already have a skill? `/skf-audit-skill` drift-checks an existing skill against current sources.
|
|
37
|
+
```bash
|
|
38
|
+
cat > "{run_dir}/report-context.json" <<'SKF_JSON'
|
|
39
|
+
{
|
|
40
|
+
"orphan_auto_resolution": {orphan_auto_resolution_or_null},
|
|
41
|
+
"customization_resolver_unavailable": {customization_resolver_unavailable},
|
|
42
|
+
"error": null
|
|
43
|
+
}
|
|
44
|
+
SKF_JSON
|
|
139
45
|
```
|
|
140
46
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
### 3. Display Required-Tier Failure Block (when applicable; skip when `{headless_mode}` or `{quiet_mode}` is true)
|
|
47
|
+
Write `{orphan_auto_resolution}` as the JSON object step 3 set (`{"action": "...", "source": "..."}`), or `null` when step 3 set none. `{customization_resolver_unavailable}` is JSON `null` unless SKILL.md On Activation bound it to the resolver's one-line failure reason; it is then that reason as a JSON string, its `"` and `\` escaped, and the envelope warns that the `{project-root}/_bmad/custom/` overrides were not applied. `error` stays `null`: a halt that names a phase never reaches this step, because it displays its own blocked envelope.
|
|
144
48
|
|
|
145
|
-
|
|
49
|
+
### 2. Display Forge Status Report (skip when `{quiet_mode}` is true)
|
|
146
50
|
|
|
147
|
-
|
|
51
|
+
Render the banner from the payload and the run folder:
|
|
148
52
|
|
|
53
|
+
```bash
|
|
54
|
+
uv run {emitEnvelopeHelper} render-report --run-dir "{run_dir}" --project-root "{project-root}" \
|
|
55
|
+
--sidecar-path "{sidecar_path}" --forge-data-folder "{forge_data_folder}" \
|
|
56
|
+
--tier-rules "{skill-root}/references/tier-rules.md" < "{run_dir}/report-context.json"
|
|
149
57
|
```
|
|
150
|
-
═══════════════════════════════════════
|
|
151
|
-
REQUIRED TIER NOT MET
|
|
152
|
-
═══════════════════════════════════════
|
|
153
58
|
|
|
154
|
-
|
|
155
|
-
Detected: {calculated_tier}
|
|
156
|
-
Missing: {require_tier_failure_missing_tools}
|
|
59
|
+
Display its stdout as one code block, so its alignment holds, keeping every line in its order. When `{document_output_language}` is not English, translate the prose and keep paths, commands, flags, tool names and tier names as they are. If the script exits non-zero, or no path in `emitEnvelopeProbeOrder` exists, display one line instead, `FORGE STATUS could not be rendered: <message>`, where `<message>` is the `message` of its stderr JSON, or `skf-emit-result-envelope.py was not found`, and continue: the forge is configured either way.
|
|
157
60
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
```
|
|
61
|
+
### 3. Required-Tier Failure Block (skip when `{quiet_mode}` is true)
|
|
62
|
+
|
|
63
|
+
If section 2 displayed `FORGE STATUS could not be rendered` and `{require_tier_satisfied}` is `false`, display one line: `REQUIRED TIER NOT MET: --require-tier {require_tier}, detected {calculated_tier}, missing <tools>`, where `<tools>` is `{require_tier_failure_missing_tools}` joined with `, `, so the section 5 halt shows its cause. A banner that rendered already ends with the REQUIRED TIER NOT MET block: display nothing more.
|
|
162
64
|
|
|
163
65
|
### 4. Emit Headless JSON Envelope
|
|
164
66
|
|
|
165
|
-
When `{
|
|
67
|
+
When `{quiet_mode}` is `true`, run `{emitEnvelopeHelper}` on the payload section 1 staged; `--run-dir` makes it read the staged helper outputs too, and the three path options give it the run's paths. It emits the single prefixed line `SKF_SETUP_RESULT_JSON: {…}` on stdout. Bind `{setup_envelope_line}` ← that stdout line, and do not display it here. It is the only line a headless or quiet run displays, and in a standalone run it must be the run's final message: `claude -p` prints only the final message, and the health check still runs after this step. Section 5 displays it on a tier miss; otherwise the shared health check displays it when it stops (its §0). Either way it is displayed verbatim as its own line (no code fence, no preface, no commentary), with nothing of setup's after it. When `{pipeline_mode}` is true, control then returns to the forger, which keeps chaining.
|
|
166
68
|
|
|
167
69
|
```bash
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
"previous_tier": {previous_tier_or_null},
|
|
171
|
-
"tools": {tools_dict_from_step_01_or_skf_detect_tools_output},
|
|
172
|
-
"previous_tools": {previous_tools_or_null},
|
|
173
|
-
"config_path": "{project-root}/_bmad/_memory/forger-sidecar/forge-tier.yaml",
|
|
174
|
-
"ccc_index": {
|
|
175
|
-
"status": "{ccc_index_result}",
|
|
176
|
-
"indexed_path": {ccc_indexed_path_or_null},
|
|
177
|
-
"file_count": {ccc_file_count_or_null}
|
|
178
|
-
},
|
|
179
|
-
"files_written": {
|
|
180
|
-
"forge-tier.yaml": true,
|
|
181
|
-
"preferences.yaml": {preferences_yaml_created},
|
|
182
|
-
"settings.yml": {settings_yml_written},
|
|
183
|
-
"ccc_index": {ccc_index_result_was_created}
|
|
184
|
-
},
|
|
185
|
-
"tier_override_active": {tier_override_active},
|
|
186
|
-
"tier_override_invalid": {tier_override_invalid},
|
|
187
|
-
"tier_override_invalid_value": {tier_override_invalid_value_or_null},
|
|
188
|
-
"tier_override_unsafe": {tier_override_unsafe},
|
|
189
|
-
"tier_override_unsafe_missing": {tier_override_unsafe_missing_list},
|
|
190
|
-
"require_tier_satisfied": {require_tier_satisfied_or_null},
|
|
191
|
-
"require_tier_failure_missing": {require_tier_failure_missing_tools_list},
|
|
192
|
-
"qmd_status": "{qmd_status}",
|
|
193
|
-
"ccc_exclusion_warnings": {ccc_exclusion_warnings_list},
|
|
194
|
-
"ccc_registry_stale_removed": {ccc_registry_stale_removed_paths_list},
|
|
195
|
-
"ccc_indexing_failed_reason": {ccc_indexing_failed_reason_or_null},
|
|
196
|
-
"orphan_auto_resolution": {orphan_auto_resolution_or_null},
|
|
197
|
-
"error": {error_object_or_null}
|
|
198
|
-
}' | uv run {emitEnvelopeHelper} emit
|
|
70
|
+
uv run {emitEnvelopeHelper} emit --run-dir "{run_dir}" --project-root "{project-root}" \
|
|
71
|
+
--sidecar-path "{sidecar_path}" --forge-data-folder "{forge_data_folder}" < "{run_dir}/report-context.json"
|
|
199
72
|
```
|
|
200
73
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
**If the script exits non-zero:** the assembled envelope failed schema validation, which means a context flag from an earlier step is malformed. Surface the error to stderr and continue (missing JSON envelope on a headless run is a degraded but non-fatal state — the pipeline observer will see no envelope and treat that as "agent did not complete cleanly").
|
|
74
|
+
**If the script exits non-zero:** a value in the payload or in a staged helper output is malformed: set `{setup_envelope_line}` to the empty string. Display nothing and continue (a missing JSON envelope on a headless or quiet run is a degraded but non-fatal state: the pipeline observer sees no envelope and treats the run as not completed cleanly).
|
|
204
75
|
|
|
205
76
|
### 5. Chain to Health Check
|
|
206
77
|
|
|
207
|
-
After the forge status report
|
|
78
|
+
After the forge status report and any failure block have been displayed (under headless or quiet, once `{setup_envelope_line}` is bound), delete the run folder:
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
rm -f "{run_dir}/detect-tools.json" "{run_dir}/detect-tools.err" "{run_dir}/ccc-exclusions.json" "{run_dir}/write-tools.err" "{run_dir}/forge-data-dir.err" "{run_dir}/qmd-classify.json" "{run_dir}/qmd-remove.json" "{run_dir}/clean-stale.json" "{run_dir}/report-context.json" && rmdir "{run_dir}"
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Then:
|
|
208
85
|
|
|
209
|
-
- If `{require_tier_satisfied}` is `false`, halt the workflow here without chaining to step 5. The tier miss is terminal; `{onCompleteCommand}` does not fire on a failed run.
|
|
210
|
-
- Otherwise the forge is fully configured. If `{onCompleteCommand}` (resolved from `workflow.on_complete` at activation) is non-empty,
|
|
86
|
+
- If `{require_tier_satisfied}` is `false`, halt the workflow here without chaining to step 5. When `{quiet_mode}` is true, display `{setup_envelope_line}` verbatim as the run's final message in a standalone run (nothing when it is empty); when `{pipeline_mode}` is true, control then returns to the forger, which reads the envelope's `tier_failure` status. This halt emits no blocked envelope: the `tier_failure` envelope is its one line. The tier miss is terminal; `{onCompleteCommand}` does not fire on a failed run.
|
|
87
|
+
- Otherwise the forge is fully configured. If `{onCompleteCommand}` (resolved from `workflow.on_complete` at activation) is non-empty, carry out that instruction now: this is the workflow's terminal skill-specific action (for example, notify an onboarding channel); when `{quiet_mode}` is true, display nothing about it. Then load `{nextStepFile}`, read it fully, and execute it; under headless or quiet, the shared health check it chains to ends setup's output with `{setup_envelope_line}`.
|
|
211
88
|
|
|
212
89
|
The health-check step is the true terminal step on success — do not stop after the report on a passing run even though it reads as final. Step 5 in turn delegates to `shared/health-check.md`; after that returns, the setup workflow is fully done.
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# Tier Report Copy
|
|
2
2
|
|
|
3
|
-
The
|
|
3
|
+
The strings the step 4 FORGE STATUS banner shows. `render-report` (`skf-emit-result-envelope.py`) reads the first line under each `###` heading below, without its surrounding double quotes, so keep each string on one line. Tool-detection probes and tier-calculation rules are owned by `skf-detect-tools.py`; this file holds only display copy, never detection or tier logic.
|
|
4
4
|
|
|
5
5
|
## Tier Capability Descriptions
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
Describe what each tier gives, never what it lacks.
|
|
8
8
|
|
|
9
9
|
### Quick Tier
|
|
10
10
|
"Quick tier active. You have fast, template-driven skill generation with package-name resolution. Perfect for getting started quickly."
|
|
@@ -13,15 +13,15 @@ Use these for positive-framing in the report step. Describe what the tier GIVES,
|
|
|
13
13
|
"Forge tier active. You have AST-backed structural code analysis with line-level citations, plus template-driven generation. Every skill instruction traces to verified source code."
|
|
14
14
|
|
|
15
15
|
### Forge+ Tier
|
|
16
|
-
"Forge+ tier active. Semantic-guided precision compilation
|
|
16
|
+
"Forge+ tier active. Semantic-guided precision compilation: cocoindex-code maps the codebase semantically before AST extraction runs. Every skill begins with a ranked discovery pass that surfaces the most relevant source regions, then AST-backed verification gives each export its line-level citation."
|
|
17
17
|
|
|
18
18
|
### Deep Tier
|
|
19
|
-
"Deep tier active. Full capability unlocked
|
|
19
|
+
"Deep tier active. Full capability unlocked: AST-backed code analysis, GitHub repository exploration, and QMD knowledge search with cross-repository synthesis. Maximum provenance and intelligence."
|
|
20
20
|
|
|
21
21
|
## Re-run Tier Change Messages
|
|
22
22
|
|
|
23
23
|
### Upgrade
|
|
24
|
-
"Tier upgraded from {previous} to {current}. {newly available tool(s)} now detected
|
|
24
|
+
"Tier upgraded from {previous} to {current}. {newly available tool(s)} now detected: expanded capabilities unlocked."
|
|
25
25
|
|
|
26
26
|
### Downgrade
|
|
27
27
|
"Tier changed from {previous} to {current}. {tool} no longer detected. Run the tool's installation to restore capabilities."
|
|
@@ -1,17 +1,13 @@
|
|
|
1
1
|
---
|
|
2
2
|
nextStepFile: 'auto-index.md'
|
|
3
3
|
# `{forgeTierRwHelper}` = first existing path in `{forgeTierRwProbeOrder}`;
|
|
4
|
-
# halt if neither exists. The script owns the canonical forge-tier.yaml
|
|
5
|
-
# and the
|
|
6
|
-
# ccc_index_registry / staleness_threshold_hours from being lost on rewrite.
|
|
7
|
-
# Do not fall back to inline YAML emission — a prose-rendered template drifts
|
|
8
|
-
# from the script and silently corrupts downstream skills.
|
|
4
|
+
# halt if neither exists. The script owns the canonical forge-tier.yaml
|
|
5
|
+
# format and keeps the registries a rewrite must not lose.
|
|
9
6
|
forgeTierRwProbeOrder:
|
|
10
7
|
- '{project-root}/_bmad/skf/shared/scripts/skf-forge-tier-rw.py'
|
|
11
8
|
- '{project-root}/src/shared/scripts/skf-forge-tier-rw.py'
|
|
12
|
-
#
|
|
13
|
-
#
|
|
14
|
-
# write halts never reach step 4 — see section 1's blocked-emit protocol).
|
|
9
|
+
# `{emitEnvelopeHelper}` = first existing path in `{emitEnvelopeProbeOrder}`,
|
|
10
|
+
# for the blocked envelope a halt in this step emits under headless or quiet.
|
|
15
11
|
emitEnvelopeProbeOrder:
|
|
16
12
|
- '{project-root}/_bmad/skf/shared/scripts/skf-emit-result-envelope.py'
|
|
17
13
|
- '{project-root}/src/shared/scripts/skf-emit-result-envelope.py'
|
|
@@ -23,74 +19,55 @@ emitEnvelopeProbeOrder:
|
|
|
23
19
|
|
|
24
20
|
## STEP GOAL:
|
|
25
21
|
|
|
26
|
-
Write the detected
|
|
22
|
+
Write the detected tools, the tier and the ccc index state to `{sidecar_path}/forge-tier.yaml` through `{forgeTierRwHelper}`, which reads them from the run folder and keeps the registries and the SKF exclusion record of an existing file, and make sure `{forge_data_folder}/` exists.
|
|
27
23
|
|
|
28
24
|
## Rules
|
|
29
25
|
|
|
30
|
-
-
|
|
31
|
-
-
|
|
32
|
-
-
|
|
33
|
-
-
|
|
26
|
+
- Never inline a YAML template for forge-tier.yaml: the script owns the canonical format
|
|
27
|
+
- Never create or edit `{sidecar_path}/preferences.yaml`: the installer writes it, and activation only reads it
|
|
28
|
+
- File write failures are errors: halt the workflow; under `{quiet_mode}` the blocked envelope is the only output, otherwise report the failure clearly
|
|
29
|
+
- Display messages only when `{quiet_mode}` is false; the one exception is the envelope line a halt displays
|
|
30
|
+
- When `{quiet_mode}` is true, write no assistant text at all between tool calls: no status, progress or step-transition notes, however brief
|
|
31
|
+
- If no path in `forgeTierRwProbeOrder` exists, halt with phase `step 2:helper-missing`, `path` set to its first entry, and reason `Setup cannot proceed: skf-forge-tier-rw.py was not found. Reinstall SKF, then re-run /skf-setup.`
|
|
32
|
+
- Every halt follows the SKILL.md halt contract: when `{quiet_mode}` is true, run `uv run {emitEnvelopeHelper} emit-blocked --phase '<phase>' --reason '<reason>' --path "<path>"`, which builds the payload itself (no `--path` for a halt without one, `--stderr-from` where the halt names it, and `--customization-resolver-unavailable "<reason>"` once SKILL.md On Activation item 6 bound `{customization_resolver_unavailable}` to a reason, escaped as the halt contract says), and display its stdout line verbatim and nothing else (the reason alone if `{emitEnvelopeHelper}` resolves to no path, or the helper exits non-zero or prints no line); otherwise display the reason
|
|
34
33
|
|
|
35
34
|
## MANDATORY SEQUENCE
|
|
36
35
|
|
|
37
36
|
### 1. Write forge-tier.yaml
|
|
38
37
|
|
|
39
|
-
Build the JSON payload from context flags set by step 1 and step 1b. The payload must include `tools`, `tier`, and `ccc_index`; the script handles `tier_detected_at` defaulting to "now" if absent and preserves `qmd_collections`, `ccc_index_registry`, and a user-customized `ccc_index.staleness_threshold_hours` from any existing file.
|
|
40
|
-
|
|
41
|
-
Invoke via `uv run`.
|
|
42
|
-
|
|
43
38
|
```bash
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
"
|
|
47
|
-
"
|
|
48
|
-
"qmd": {qmd},
|
|
49
|
-
"ccc": {ccc},
|
|
50
|
-
"ccc_daemon": {ccc_daemon},
|
|
51
|
-
"security_scan": {security_scan}
|
|
52
|
-
},
|
|
53
|
-
"tier": "{calculated_tier}",
|
|
54
|
-
"ccc_index": {
|
|
55
|
-
"indexed_path": {ccc_indexed_path},
|
|
56
|
-
"last_indexed": {ccc_last_indexed},
|
|
57
|
-
"status": "{ccc_index_result}",
|
|
58
|
-
"file_count": {ccc_file_count},
|
|
59
|
-
"exclude_patterns": {ccc_exclude_patterns}
|
|
60
|
-
}
|
|
61
|
-
}' | uv run {forgeTierRwHelper} write-tools \
|
|
62
|
-
--target "{project-root}/_bmad/_memory/forger-sidecar/forge-tier.yaml"
|
|
39
|
+
uv run {forgeTierRwHelper} write-tools \
|
|
40
|
+
--target "{sidecar_path}/forge-tier.yaml" \
|
|
41
|
+
--detect-from "{run_dir}/detect-tools.json" \
|
|
42
|
+
--ccc-from "{run_dir}/ccc-exclusions.json" 2> "{run_dir}/write-tools.err"
|
|
63
43
|
```
|
|
64
44
|
|
|
65
|
-
The script
|
|
66
|
-
|
|
67
|
-
**Parse the response and set context flags for step 4:**
|
|
68
|
-
|
|
69
|
-
- `{forge_tier_yaml_path}` ← `wrote`
|
|
70
|
-
- `{forge_tier_qmd_collections_count}` ← `preserved_arrays.qmd_collections`
|
|
71
|
-
- `{forge_tier_ccc_registry_count}` ← `preserved_arrays.ccc_index_registry`
|
|
72
|
-
|
|
73
|
-
**If the script exits non-zero**: parse the stderr JSON `{"status":"error","message":...}`, set `{error: {phase: "step 2:write-tools", path: "{project-root}/_bmad/_memory/forger-sidecar/forge-tier.yaml", reason: <message>}}`, and halt the workflow before chaining to step 3. When `{headless_mode}` or `{quiet_mode}` is true, first pipe the same `{phase, reason, path}` payload to `python3 {emitEnvelopeHelper} emit-blocked` so the pipeline sees the blocked envelope before the halt (see `references/report.md` frontmatter for the helper probe order; the subcommand declares zero dependencies).
|
|
45
|
+
The script takes the tools and the tier from step 1's `detect-tools.json`, and the index state and the SKF exclusion record from step 1b's `ccc-exclusions.json`.
|
|
74
46
|
|
|
75
|
-
|
|
47
|
+
**If the script exits non-zero**: halt the workflow before chaining to step 3, with phase `step 2:write-tools`, path `{sidecar_path}/forge-tier.yaml` and as the reason the diagnostic in `{run_dir}/write-tools.err`. When `{quiet_mode}` is true, run the emitter, which reads that diagnostic itself, display its stdout line verbatim, and display nothing else: the envelope's `error` carries the path and reason. If the helper exits non-zero or prints no line, display the reason alone. Otherwise read that file and display the failure with its path and, as the reason, the `message` of its JSON error, else its first line.
|
|
76
48
|
|
|
77
49
|
```bash
|
|
78
|
-
uv run {
|
|
79
|
-
--
|
|
50
|
+
uv run {emitEnvelopeHelper} emit-blocked --phase "step 2:write-tools" --path "{sidecar_path}/forge-tier.yaml" \
|
|
51
|
+
--reason "<message>" --stderr-from "{run_dir}/write-tools.err" \
|
|
52
|
+
[--customization-resolver-unavailable "{customization_resolver_unavailable}"]
|
|
80
53
|
```
|
|
81
54
|
|
|
82
|
-
|
|
55
|
+
In each `emit-blocked` call of this step, keep the bracketed `--customization-resolver-unavailable` only when On Activation item 6 bound `{customization_resolver_unavailable}` to a reason, escaped as the halt contract says; otherwise leave it out.
|
|
83
56
|
|
|
84
|
-
|
|
57
|
+
### 2. Ensure the Forge Data Folder
|
|
85
58
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
59
|
+
```bash
|
|
60
|
+
mkdir -p "{forge_data_folder}" 2> "{run_dir}/forge-data-dir.err"
|
|
61
|
+
```
|
|
89
62
|
|
|
90
|
-
|
|
63
|
+
On non-zero exit, halt as section 1 does, with phase `step 2:forge-data-dir`, path `{forge_data_folder}` and the diagnostic in `{run_dir}/forge-data-dir.err` as the reason (an interactive run reads that file); under `{quiet_mode}`:
|
|
91
64
|
|
|
92
|
-
|
|
65
|
+
```bash
|
|
66
|
+
uv run {emitEnvelopeHelper} emit-blocked --phase "step 2:forge-data-dir" --path "{forge_data_folder}" \
|
|
67
|
+
--reason "<message>" --stderr-from "{run_dir}/forge-data-dir.err" \
|
|
68
|
+
[--customization-resolver-unavailable "{customization_resolver_unavailable}"]
|
|
69
|
+
```
|
|
93
70
|
|
|
94
|
-
###
|
|
71
|
+
### 3. Auto-Proceed
|
|
95
72
|
|
|
96
|
-
|
|
73
|
+
Once forge-tier.yaml is written, load `{nextStepFile}`, read it fully, and execute it.
|
|
@@ -12,7 +12,9 @@ Verifies that a skill is complete enough to be useful to an AI agent by checking
|
|
|
12
12
|
## Conventions
|
|
13
13
|
|
|
14
14
|
- Bare paths (e.g. `references/<name>.md`) resolve from the skill root.
|
|
15
|
-
-
|
|
15
|
+
- **Module-level path exception:** bare paths beginning with `knowledge/` or `shared/` resolve from the SKF module root (`{project-root}/_bmad/skf/` installed, `src/` in dev), not the skill root; e.g. `shared/references/output-contract-schema.md` and `shared/health-check.md`.
|
|
16
|
+
- **Sibling skills:** a path that names another SKF skill's folder (`skf-<name>/...`) resolves from the SKF module root, and that skill must be installed with this one. The coherence and migration rules cite `skf-create-skill/assets/skill-sections.md` and `skf-create-stack-skill/references/compose-mode-rules.md`.
|
|
17
|
+
- `references/` holds prompt content carved out of SKILL.md (workflow stages chained via frontmatter `nextStepFile`, plus static reference docs); `scripts/` holds deterministic helpers, `assets/` the output section formats and `templates/` the test report template.
|
|
16
18
|
- `{skill-root}` resolves to this skill's installed directory (where `customize.toml` lives, if present).
|
|
17
19
|
- `{project-root}`-prefixed paths resolve from the project working directory.
|
|
18
20
|
- `{skill-name}` resolves to the skill directory's basename.
|
|
@@ -29,7 +31,11 @@ These rules apply to every step in this workflow:
|
|
|
29
31
|
- Only load one step file at a time — never preload future steps
|
|
30
32
|
- Update `stepsCompleted` in output file frontmatter before loading next step
|
|
31
33
|
- Always communicate in `{communication_language}`
|
|
32
|
-
-
|
|
34
|
+
- No stage waits for an answer in headless mode: the one question, the skill name, halts `input-missing` there
|
|
35
|
+
- Every HARD HALT names its `halt_reason` and phase and carries exit code 1 (`exit_code` in its envelope); in headless mode it prints its envelope through the shared emitter, as each stage's **Halt envelope** paragraph shows
|
|
36
|
+
- Once `references/init.md` §6a has taken the run lock, every HALT after it first releases the lock, whatever the release prints (it never removes another run's lock): from `{project-root}`, run `uv run {runLockHelper} release --lock "{forge_version}/.test-skill.lock" --owner "{run_owner}"`.
|
|
37
|
+
- The report is `{report_file}`: init.md §6c creates it as `.skf-test-report-{skill_name}-{run_id}.md`, and it takes its public name `test-report-{skill_name}-{run_id}.md` only once report.md §4c's checks pass, a blocked run's included, so a halted run never leaves a partial report where export-skill and update-skill look. The steps read the verdict inputs (`threshold`, `toolingStatus`, `workspaceDrift`, `testResult`) from its frontmatter, never from memory
|
|
38
|
+
- Run state (the scripts' files, the emitter's payloads) lives in `{run_dir}`: report.md §7 deletes it, a HALT keeps it
|
|
33
39
|
|
|
34
40
|
## Stages
|
|
35
41
|
|
|
@@ -42,49 +48,12 @@ These rules apply to every step in this workflow:
|
|
|
42
48
|
| 4b | External Validators | references/external-validators.md | Yes |
|
|
43
49
|
| 4c | Hard Gate | references/step-hard-gate.md | Yes |
|
|
44
50
|
| 5 | Score | references/score.md | Yes |
|
|
45
|
-
| 6 | Report | references/report.md |
|
|
51
|
+
| 6 | Report | references/report.md | Yes |
|
|
46
52
|
| 7 | Workflow Health Check | references/health-check.md | Yes |
|
|
47
53
|
|
|
48
54
|
## Invocation Contract
|
|
49
55
|
|
|
50
|
-
|
|
51
|
-
|--------|--------|
|
|
52
|
-
| **Inputs** | skill_name [required]; optional flags: `--allow-workspace-drift`, `--no-discovery` (skip the report step's Discovery Testing block), `--no-health-check` (skip §7 health-check dispatch), `--tier=<Quick\|Forge\|Forge+\|Deep>` (bypass forge-tier.yaml sidecar requirement), `--threshold=<N>` (override pass threshold; CLI wins over per-pipeline defaults and `workflow.default_threshold` scalar) |
|
|
53
|
-
| **Gates** | step 6: Confirm Gate [C] |
|
|
54
|
-
| **Outputs** | per-run `test-report-{skill_name}-{run_id}.md` with completeness score and result (PASS/FAIL); per-run `skf-test-skill-result-{run_id}.json` and `skf-test-skill-result-latest.json` written atomically under `{forge_version}/`; `evidence-report-fallback.md` written under `{forge_version}/` when threshold fallback occurs (score between 80% and target threshold) — downstream consumers (export-skill, update-skill `--from-test-report`) glob `test-report-{skill_name}-*.md` and pick newest by parsed ISO timestamp |
|
|
55
|
-
| **Headless** | All gates auto-resolve with default action when `{headless_mode}` is true |
|
|
56
|
-
| **Exit codes** | See "Exit Codes" below |
|
|
57
|
-
|
|
58
|
-
## Exit Codes
|
|
59
|
-
|
|
60
|
-
Every terminal state in this workflow exits with a stable code so headless automators can branch on the verdict (and any HARD HALT) without grepping message text:
|
|
61
|
-
|
|
62
|
-
| Code | Meaning | Raised by |
|
|
63
|
-
| ---- | -------------------- | ------------------------------------------------------------------------------------------ |
|
|
64
|
-
| 0 | success / PASS | step 6 §6b — `testResult: 'pass'` (after the result contract is written in §4c) |
|
|
65
|
-
| 1 | error (HARD HALT) | infrastructure / precondition HALT in step 1 or step 6 before a verdict exists — see the "Result Contract" `halt_reason` set (the hard gate uses code 2) |
|
|
66
|
-
| 2 | fail / FAIL | step 4c §3 — hard gate blocked (`halt_reason: "hard-gate-blocked"`); step 6 §6b — `testResult: 'fail'` (after the result contract is written in §4c) |
|
|
67
|
-
| 3 | inconclusive | step 6 §6b — `testResult: 'inconclusive'` (distinct from fail so orchestrators can route to manual-review queues) |
|
|
68
|
-
| 4 | pass-with-drift | step 6 §6b — `testResult: 'pass-with-drift'` (distinct from clean pass — `--allow-workspace-drift` was in effect; re-test against the pinned commit and refuse export — exit 0 would wrongly signal a clean pass) |
|
|
69
|
-
|
|
70
|
-
## Result Contract (Headless)
|
|
71
|
-
|
|
72
|
-
When `{headless_mode}` is true, step 6 emits a single-line JSON envelope on **stdout** before chaining to step 7, and every HALT the Exit Codes table above marks with a non-zero code emits the same envelope shape on **stderr** with `status: "error"` and the `halt_reason` naming the failure, so a headless orchestrator branches on the reason without grepping prose:
|
|
73
|
-
|
|
74
|
-
```
|
|
75
|
-
SKF_TEST_RESULT_JSON: {"status":"success|error","skill_name":"…","verdict":"PASS|FAIL|INCONCLUSIVE|pass-with-drift","score":N,"threshold":N,"report_path":"…|null","next_workflow":"export-skill|update-skill|null","exit_code":0,"halt_reason":null,"threshold_fallback":true,"original_threshold":90}
|
|
76
|
-
```
|
|
77
|
-
|
|
78
|
-
`status` is `"success"` on the terminal happy path (PASS / FAIL / INCONCLUSIVE / pass-with-drift — the workflow completed), `"error"` on an emitted HARD HALT. `verdict` is the canonical result string (`null` on an infrastructure error halt). `next_workflow` is `"export-skill"` only when `verdict == "PASS"`; `"update-skill"` for `FAIL` or `pass-with-drift`; `null` for `INCONCLUSIVE` and error halts. `halt_reason` is `null` on the terminal path or one of the emitted strings: `"target-inaccessible"`, `"forge-tier-missing"`, `"workspace-drift"`, `"another-run-active"`, `"frontmatter-invalid"` (init HALTs), `"atomic-writer-missing"`, `"step-completeness-violation"`, `"report-anchor-missing"`, `"health-check-missing"` (report HALTs), or `"hard-gate-blocked"` (step 4c). `exit_code` is the code the Exit Codes table above assigns to the reached terminal state or HALT. Step 1 §3 frontmatter-validation now emits the `"frontmatter-invalid"` stderr envelope (see init.md §3c) and is branchable. Only the coverage/coherence analysis aborts print a diagnostic and exit non-zero **without** this envelope — they are the sole remaining outcomes outside the branchable set. When threshold fallback occurred, the envelope includes `"threshold_fallback":true` and `"original_threshold":N`; these fields are omitted when no fallback occurred.
|
|
79
|
-
|
|
80
|
-
The same payload is persisted to disk by step 6 §4c (atomic write) at two locations under `{forge_version}/`:
|
|
81
|
-
|
|
82
|
-
| Path | Purpose |
|
|
83
|
-
| --------------------------------------------- | -------------------------------------------------------------------------- |
|
|
84
|
-
| `skf-test-skill-result-{run_id}.json` | Per-run record. `{run_id}` carries UTC timestamp + PID + random suffix. |
|
|
85
|
-
| `skf-test-skill-result-latest.json` | Latest copy — stable path for pipeline consumers (copy, not symlink). |
|
|
86
|
-
|
|
87
|
-
The on-disk payload is the richer form: it adds `outputs[]` (report-path entries), `summary` (`score`, `threshold`, `result`, `testMode`, `activeCategories[]`, `inconclusiveReasons[]` when present, `threshold_fallback`, `original_threshold`, `evidence_report_path` when threshold fallback occurred), `runId`, and `healthCheckDispatched`. The stdout envelope is the compact subset documented above.
|
|
56
|
+
Headless callers: the full argument set (`Inputs`), the outputs, the exit codes and the `SKF_TEST_RESULT_JSON` result envelope live in `references/invocation-contract.md`. Interactive runs do not need it.
|
|
88
57
|
|
|
89
58
|
## On Activation
|
|
90
59
|
|
|
@@ -92,33 +61,24 @@ The on-disk payload is the richer form: it adds `outputs[]` (report-path entries
|
|
|
92
61
|
- `project_name`, `user_name`, `communication_language`, `document_output_language`
|
|
93
62
|
- `skills_output_folder`, `forge_data_folder`, `sidecar_path`
|
|
94
63
|
|
|
95
|
-
2. **Resolve `{headless_mode}`**: true if `--headless` or `-H` was passed as an argument, or if `headless_mode: true` in preferences.yaml
|
|
64
|
+
2. **Resolve `{headless_mode}`**: true if `--headless` or `-H` was passed as an argument, or if `headless_mode: true` in `{sidecar_path}/preferences.yaml`. Default: false.
|
|
96
65
|
|
|
97
66
|
3. **Resolve workflow customization.** Run:
|
|
98
67
|
|
|
99
68
|
```bash
|
|
100
|
-
|
|
101
|
-
--skill {skill-root} --key workflow
|
|
69
|
+
uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --project-root {project-root} --key workflow
|
|
102
70
|
```
|
|
103
71
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
- `{skill-root}/customize.toml` — bundled defaults
|
|
107
|
-
- `_bmad/custom/<skill-name>.toml` under `{project-root}` — team overrides (committed)
|
|
108
|
-
- `_bmad/custom/<skill-name>.user.toml` under `{project-root}` — personal overrides (gitignored)
|
|
109
|
-
|
|
110
|
-
If the script fails or is missing, fall back to reading `{skill-root}/customize.toml` directly — the bundled defaults are an empty string for each path scalar.
|
|
72
|
+
It merges the bundled `{skill-root}/customize.toml` with `{project-root}/_bmad/custom/skf-test-skill.toml` (team overrides, committed) and `.user.toml` (personal overrides, gitignored). When it exits non-zero, prints no JSON or is missing, print one line, `[activation/warn] customization_resolver_unavailable: <reason>` (`<reason>`: its first stderr line, `not found` when the script is missing, `no JSON` when it printed none). If the resolver cannot run, read `{skill-root}/customize.toml` alone and use its bundled defaults: the `{project-root}/_bmad/custom/` overrides do not apply to this run. In that case keep the reason as `{customization_resolver_unavailable}`: report.md §4c hands it to the result as a warning.
|
|
111
73
|
|
|
112
|
-
Apply the
|
|
74
|
+
Apply the scalar fallbacks now so stage files don't have to repeat the conditional logic. For each scalar, if the merged value is empty or absent, use the bundled default:
|
|
113
75
|
|
|
114
76
|
- `{testReportTemplatePath}` ← `workflow.test_report_template_path` if non-empty, else `templates/test-report-template.md`
|
|
115
|
-
- `{
|
|
116
|
-
- `{scoringRulesPath}` ← `workflow.scoring_rules_path` if non-empty, else `references/scoring-rules.md`
|
|
117
|
-
- `{defaultThreshold}` ← `workflow.default_threshold` if non-empty/non-null, else `80`. CLI `--threshold=<N>` wins over per-pipeline defaults (from init.md §1b) which win over this scalar at the usage site in `references/score.md`.
|
|
77
|
+
- `{defaultThreshold}` ← `workflow.default_threshold` if non-empty/non-null, else `80`. init.md §1b resolves the precedence (CLI, then per-pipeline default, then this scalar) once and writes `threshold` and `thresholdSource` into the report frontmatter, which score.md §1 reads.
|
|
118
78
|
- `{onCompleteCommand}` ← `workflow.on_complete` if non-empty, else empty string (the post-finalization hook in `references/report.md` is then a no-op).
|
|
119
79
|
|
|
120
|
-
Stash all
|
|
80
|
+
Stash all three as workflow-context variables that stage files reference directly, with no conditional at the usage site. The scoring rules, the Gap Severity table and the output formats are not overridable: scripts own the scoring and the hard gate reads the table, so a house-style copy could change what blocks export.
|
|
121
81
|
|
|
122
|
-
**Apply the array surfaces** (not silent no-ops): run `workflow.activation_steps_prepend` in order now; treat each `workflow.persistent_facts` entry as standing context for the run (`file:`-prefixed entries load their file/glob contents as facts
|
|
82
|
+
**Apply the array surfaces** (not silent no-ops): run `workflow.activation_steps_prepend` in order now; treat each `workflow.persistent_facts` entry as standing context for the run (`file:`-prefixed entries load their file/glob contents as facts: the bundled default loads every `project-context.md` under `{project-root}`; an entry prefixed `!` drops each earlier entry it names and loads nothing itself, so an override's `"!file:{project-root}/**/project-context.md"` turns that default off); then run `workflow.activation_steps_append` after activation.
|
|
123
83
|
|
|
124
84
|
4. Load, read the full file, and then execute `references/init.md` to begin the workflow.
|