bmad-module-skill-forge 2.2.0 → 4.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 +143 -18
- package/docs/verifying-a-skill.md +87 -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 +3 -3
- 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 +31 -59
- 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 +233 -64
- package/src/shared/scripts/skf-build-change-manifest.py +2753 -28
- 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 +772 -0
- package/src/shared/scripts/skf-comention-pairs.py +1333 -123
- package/src/shared/scripts/skf-compare-file-hashes.py +267 -105
- 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 +21 -3
- 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 +197 -55
- 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 +5247 -96
- package/src/shared/scripts/skf-extraction-inventory.py +1280 -0
- package/src/shared/scripts/skf-extraction-snapshot.py +664 -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 +469 -205
- package/src/shared/scripts/skf-github-fetch.py +365 -0
- package/src/shared/scripts/skf-github-probe.py +700 -0
- package/src/shared/scripts/skf-hash-content.py +180 -20
- package/src/shared/scripts/skf-language-corpora.py +1 -1
- package/src/shared/scripts/skf-load-provenance.py +161 -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 +143 -20
- 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 +176 -28
- package/src/shared/scripts/skf-promote-staged.py +430 -0
- package/src/shared/scripts/skf-provenance-gap-dispatch.py +64 -8
- 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 +155 -14
- 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 +787 -121
- package/src/shared/scripts/skf-tessl-review.py +706 -0
- package/src/shared/scripts/skf-update-active-symlink.py +120 -67
- 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 +23 -2
- 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 +3945 -152
- package/src/shared/scripts/skf-write-skill-brief.py +406 -25
- 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 +28 -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/health-check.md +2 -0
- package/src/skf-audit-skill/references/init.md +149 -210
- package/src/skf-audit-skill/references/re-index.md +103 -110
- package/src/skf-audit-skill/references/report.md +96 -33
- package/src/skf-audit-skill/references/semantic-diff.md +34 -25
- 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 +80 -90
- package/src/skf-audit-skill/references/upstream-checkout.md +77 -0
- package/src/skf-audit-skill/scripts/render-drift-tables.py +712 -0
- package/src/skf-brief-skill/SKILL.md +37 -26
- package/src/skf-brief-skill/assets/description-voice-examples.md +1 -1
- package/src/skf-brief-skill/assets/scope-templates.md +18 -25
- package/src/skf-brief-skill/assets/skill-brief-schema.md +30 -23
- package/src/skf-brief-skill/customize.toml +48 -20
- package/src/skf-brief-skill/references/analyze-target.md +144 -127
- package/src/skf-brief-skill/references/confirm-brief.md +11 -9
- 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 +26 -100
- package/src/skf-brief-skill/references/step-auto-validate.md +20 -121
- package/src/skf-brief-skill/references/version-resolution.md +7 -10
- 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 +11 -8
- package/src/skf-create-skill/assets/skill-sections.md +21 -11
- package/src/skf-create-skill/customize.toml +20 -8
- package/src/skf-create-skill/references/authoritative-files-protocol.md +36 -58
- 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 +119 -70
- 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 +37 -0
- package/src/skf-create-skill/references/extract.md +204 -162
- package/src/skf-create-skill/references/extraction-patterns-by-hand.md +141 -0
- package/src/skf-create-skill/references/extraction-patterns-tracing.md +11 -11
- package/src/skf-create-skill/references/extraction-patterns.md +588 -201
- 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 +37 -57
- package/src/skf-create-skill/references/source-resolution-protocols.md +58 -169
- 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 +83 -146
- package/src/skf-drop-skill/references/health-check.md +2 -0
- 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 +122 -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 +209 -264
- 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 +164 -91
- 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 +164 -142
- package/src/skf-test-skill/references/score.md +80 -107
- package/src/skf-test-skill/references/scoring-rules.md +42 -155
- package/src/skf-test-skill/references/source-access-protocol.md +18 -94
- 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 +380 -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 +1666 -0
- package/src/skf-test-skill/scripts/hard-gate.py +203 -0
- package/src/skf-test-skill/scripts/load-coverage-inputs.py +1198 -0
- package/src/skf-test-skill/scripts/locate-export-segments.py +835 -0
- package/src/skf-test-skill/scripts/reconcile-coverage.py +547 -79
- package/src/skf-test-skill/scripts/score-signatures.py +479 -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 +133 -56
- 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 +253 -223
- 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 +254 -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 +182 -49
- package/src/skf-update-skill/references/re-extract.md +53 -262
- package/src/skf-update-skill/references/report.md +102 -35
- package/src/skf-update-skill/references/write.md +357 -155
- package/src/skf-update-skill/scripts/skf-new-file-diff.py +183 -46
- 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
|
@@ -117,7 +117,7 @@ Indexed pipe-delimited format for CLAUDE.md managed section (~80-120 tokens per
|
|
|
117
117
|
"tool_versions": {
|
|
118
118
|
"ast_grep": "{version-or-null}",
|
|
119
119
|
"qmd": "{version-or-null}",
|
|
120
|
-
"skf": "{
|
|
120
|
+
"skf": "{installed-skf-version-or-unknown}"
|
|
121
121
|
},
|
|
122
122
|
"confidence_distribution": {
|
|
123
123
|
"t1": 0,
|
|
@@ -134,7 +134,7 @@ Indexed pipe-delimited format for CLAUDE.md managed section (~80-120 tokens per
|
|
|
134
134
|
"total_coverage": 0.0,
|
|
135
135
|
"scripts_count": 0,
|
|
136
136
|
"assets_count": 0
|
|
137
|
-
// "effective_denominator": 0 // optional
|
|
137
|
+
// "effective_denominator": 0 // optional: emitted when compile.md §4 passes it (counts.effective_denominator_decision.store and a stratified scope.notes); test-skill uses this as the coverage denominator when present.
|
|
138
138
|
},
|
|
139
139
|
// scripts[] and assets[] — include ONLY when inventories are non-empty; omit entirely otherwise
|
|
140
140
|
// "scripts": [{ "file": "scripts/{name}", "purpose": "{description}", "source_file": "{source-path}", "confidence": "T1-low" }],
|
|
@@ -144,7 +144,7 @@ Indexed pipe-delimited format for CLAUDE.md managed section (~80-120 tokens per
|
|
|
144
144
|
// detected_via "brief_doc_urls" = docs-only skills: the brief's doc_urls (plus subpages step 3c fetched), hashed by `skf-detect-docs.py hash-urls`
|
|
145
145
|
"generated_by": "{quick-skill|create-skill}",
|
|
146
146
|
"dependencies": [],
|
|
147
|
-
"compatibility": "
|
|
147
|
+
"compatibility": ""
|
|
148
148
|
}
|
|
149
149
|
```
|
|
150
150
|
|
|
@@ -194,7 +194,7 @@ Each reference file includes:
|
|
|
194
194
|
"source_line": 42,
|
|
195
195
|
"confidence": "T1",
|
|
196
196
|
"extraction_method": "ast-grep",
|
|
197
|
-
"ast_node_type": "
|
|
197
|
+
"ast_node_type": "export_statement",
|
|
198
198
|
"signature_source": "T1"
|
|
199
199
|
}
|
|
200
200
|
],
|
|
@@ -203,7 +203,7 @@ Each reference file includes:
|
|
|
203
203
|
"libraries": ["lib-a", "lib-b"],
|
|
204
204
|
"pattern_type": "provider-consumer",
|
|
205
205
|
"detection_method": "co-import grep|architecture_co_mention|inferred_from_shared_domain",
|
|
206
|
-
"co_import_files": [{"
|
|
206
|
+
"co_import_files": [{"path": "src/app.ts", "line_a": 5, "line_b": 7}],
|
|
207
207
|
"confidence": "T1|T2|T3"
|
|
208
208
|
}
|
|
209
209
|
],
|
|
@@ -270,9 +270,9 @@ t2_future_count: {N}
|
|
|
270
270
|
**Source:** {repo} @ {commit}
|
|
271
271
|
|
|
272
272
|
## Tool Versions
|
|
273
|
-
- ast-grep: {
|
|
274
|
-
- QMD: {
|
|
275
|
-
- SKF: {
|
|
273
|
+
- ast-grep: {tool_versions.ast_grep}
|
|
274
|
+
- QMD: {tool_versions.qmd}
|
|
275
|
+
- SKF: {tool_versions.skf}
|
|
276
276
|
|
|
277
277
|
## Extraction Summary
|
|
278
278
|
- Files scanned: {count}
|
|
@@ -282,10 +282,13 @@ t2_future_count: {N}
|
|
|
282
282
|
## Validation Results
|
|
283
283
|
- Schema: {pass/fail} (quality score: {score}/100)
|
|
284
284
|
- Frontmatter: {pass/fail}
|
|
285
|
-
- Body: {pass/fail} {
|
|
285
|
+
- Body: {pass/fail} {body split applied if applicable}
|
|
286
286
|
- Security: {pass/warn/skipped}
|
|
287
|
-
-
|
|
287
|
+
- Description angle brackets: {none | re-sanitized ({count} substitutions) | not checked — no description}
|
|
288
|
+
- Tessl Review: {tessl_summary}
|
|
288
289
|
- Metadata: {pass/fail}
|
|
290
|
+
- Provenance labels: {pass | relabeled {N} to match extraction_method: {export names}}{; WARN, no node kind found: {export names}}
|
|
291
|
+
- Provenance lines: {pass | findings | fixed {N} source lines, {M} citation prefixes and {K} node kinds | not run: verifier missing | not run: verifier error}{; second run: verifier error}{; unverified, no definition line found: {export names}}{; WARN: {each line, citation or node-kind warning §7a lists}}{; source lines not checked: no local source tree}{; node kinds not checked: no ast-grep CLI | unrecognized ast-grep}{; node kinds unchecked: {export name (reason) for each node_kinds_unchecked item}}{; node kinds skipped: {N} in files ast-grep has no language for}
|
|
289
292
|
|
|
290
293
|
## Quality Score Breakdown
|
|
291
294
|
- Frontmatter (30%): {score} | Description (30%): {score} | Body (20%): {score} | Links (10%): {score} | File (10%): {score}
|
|
@@ -301,8 +304,15 @@ t2_future_count: {N}
|
|
|
301
304
|
|
|
302
305
|
## Remaining Warnings
|
|
303
306
|
- {any warnings from extraction or validation}
|
|
307
|
+
|
|
308
|
+
## Tessl Review
|
|
309
|
+
- Result: {tessl_summary}
|
|
310
|
+
- Workspace: {tessl_workspace or —} · tessl {tessl_version or —} · Run: {tessl_run_id or —}
|
|
311
|
+
- Validation findings: {each {tessl_validation} finding as `name (status): message`, or "none"}
|
|
312
|
+
- Description suggestions (to act on one, edit the description in the brief and re-run create-skill): {each of {tessl_description_suggestions}, or "none"}
|
|
313
|
+
- Content suggestions (advisory, not applied): {each of {tessl_content_suggestions} with its `(not applicable: <rule-id>)` mark, or "none"}
|
|
304
314
|
```
|
|
305
315
|
|
|
306
316
|
**Frontmatter — pinned detection contract:** the `t2_future_count` field is the authoritative forward-looking-annotation count for downstream gate checks (e.g. skf-test-skill §2b migration-section rule). Emit **always**, even when 0 — omission is indistinguishable from "no T2-future data" and silently flips the gate into Case 2/3 for a Case-1 skill. `generated` and `forge_tier` mirror the narrative header for consumers that read only the frontmatter. Downstream gate rules parse `t2_future_count` from frontmatter, not prose — prose drift (heading renames, alternate phrasings like "forward-looking annotations") silently breaks grep-based detection.
|
|
307
317
|
|
|
308
|
-
**Description Guard slot:** populated by step 6 §0 (create-skill) and §0 (update-skill) when the guard protocol fires. `Restored: true` indicates that an external tool (typically `skill-check --fix` or `split-body`) rewrote the frontmatter `description` and the guard restored the pre-tool value. When `Restored: false`, leave `Triggering tool`, `Original description preserved`, and `Notes` as
|
|
318
|
+
**Description Guard slot:** populated by step 6 §0 (create-skill) and §0 (update-skill) when the guard protocol fires. `Restored: true` indicates that an external tool (typically `skill-check --fix`, create-skill's `skf-shard-body.py` body split or update-skill's `split-body`) rewrote the frontmatter `description` and the guard restored the pre-tool value. When `Restored: false`, leave `Triggering tool`, `Original description preserved`, and `Notes` as the no-fire dash the template above shows. When `Restored: true`, fill all four fields: tool name, whether the original was successfully written back, and a one-sentence note describing what the tool had changed (e.g., "replaced with generic summary", "truncated at 80 chars", "angle-bracket tokens re-introduced"). Downstream test-skill assertions can grep for `Restored: true` to detect unintended tool rewrites without parsing free-form warning prose.
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# DO NOT EDIT -- overwritten on every update.
|
|
2
2
|
#
|
|
3
3
|
# Workflow customization surface for skf-create-skill.
|
|
4
|
-
# Team overrides: _bmad/custom/skf-create-skill.toml
|
|
5
|
-
# Personal overrides: _bmad/custom/skf-create-skill.user.toml
|
|
4
|
+
# Team overrides: {project-root}/_bmad/custom/skf-create-skill.toml
|
|
5
|
+
# Personal overrides: {project-root}/_bmad/custom/skf-create-skill.user.toml
|
|
6
6
|
|
|
7
7
|
[workflow]
|
|
8
8
|
|
|
@@ -23,7 +23,7 @@ activation_steps_prepend = []
|
|
|
23
23
|
activation_steps_append = []
|
|
24
24
|
|
|
25
25
|
# Persistent facts the workflow keeps in mind for the whole run
|
|
26
|
-
# (extraction style, compilation guardrails
|
|
26
|
+
# (extraction style, compilation guardrails).
|
|
27
27
|
# Overrides append.
|
|
28
28
|
#
|
|
29
29
|
# Each entry is either:
|
|
@@ -31,17 +31,29 @@ activation_steps_append = []
|
|
|
31
31
|
# - a file reference prefixed with `file:`, e.g.
|
|
32
32
|
# "file:{project-root}/docs/create-policy.md" (globs supported; file
|
|
33
33
|
# contents are loaded and treated as facts).
|
|
34
|
+
#
|
|
35
|
+
# The bundled entry below loads every project-context.md under
|
|
36
|
+
# {project-root} (the BMad project context) as facts for each brief.
|
|
37
|
+
# Overrides append, so no override can delete it. To drop it, add the same
|
|
38
|
+
# entry with a leading `!` in {project-root}/_bmad/custom/skf-create-skill.toml:
|
|
39
|
+
# persistent_facts = ["!file:{project-root}/**/project-context.md"]
|
|
40
|
+
# The workflow then skips both (SKILL.md On Activation step 3); a `!` entry
|
|
41
|
+
# drops any entry it names this way.
|
|
34
42
|
|
|
35
43
|
persistent_facts = [
|
|
36
44
|
"file:{project-root}/**/project-context.md",
|
|
37
45
|
]
|
|
38
46
|
|
|
39
|
-
# Pipeline-integration hook invoked
|
|
40
|
-
#
|
|
47
|
+
# Pipeline-integration hook invoked by step 8 (report) once a brief's result
|
|
48
|
+
# contract is written, after its compilation report. The value is a shell
|
|
49
|
+
# command, run from {project-root}, not an agent instruction: a shell cannot
|
|
50
|
+
# run a skill such as test-skill or export-skill. It is called as:
|
|
41
51
|
# <on_complete> --result-path=<{forge_version}/create-skill-result-latest.json>
|
|
42
|
-
#
|
|
43
|
-
#
|
|
44
|
-
#
|
|
52
|
+
# Under --batch it runs once per brief, each time with that brief's result
|
|
53
|
+
# file; a brief that halts, or whose result file was not written, gets no
|
|
54
|
+
# call. Useful for a Slack or email notifier, dashboard ingest, a CI script
|
|
55
|
+
# or a git-add wrapper. A failure is reported on its own line and never
|
|
56
|
+
# fails the brief.
|
|
45
57
|
#
|
|
46
58
|
# Empty string = no-op (default).
|
|
47
59
|
|
|
@@ -2,28 +2,28 @@
|
|
|
2
2
|
|
|
3
3
|
## Overview
|
|
4
4
|
|
|
5
|
-
Loaded on demand when step 3's `### 2a. Discovered Authoritative Files Protocol` sub-step runs.
|
|
5
|
+
Loaded on demand when step 3's `### 2a. Discovered Authoritative Files Protocol` sub-step runs, after `### 2b. Resolve Source Access` has resolved the source to a local tree.
|
|
6
6
|
|
|
7
7
|
**Skip this protocol entirely if `source_type: "docs-only"`** — there is no source tree to scan.
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
**Skip it too when `source_root` is still a remote URL** (a Quick-tier remote source, which §2b never clones, or a remote source §2b could not read into a tree): step 3 §2a's remote source guard skips the scan with a notice, because the helper below walks a local directory and refuses a URL.
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
Once §2b has resolved source access, scan the resolved source tree (the local source, or the private tree §2b read a remote one into) for **authoritative AI documentation files** that the brief's scope filters excluded. Project authors increasingly add files specifically written to steer AI assistants (`llms.txt`, `AGENTS.md`, `.cursorrules`, etc.), and these files often contain the **canonical** install command, quick-start, or architecture summary: information that nowhere else in the source tree provides. A brief authored from a scan of `src/**` will frequently exclude these files without the author realizing they exist.
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
This protocol detects such files, prompts the user, and records the decision in the brief so future runs (re-create, update, audit) honor it.
|
|
14
14
|
|
|
15
15
|
## Procedure
|
|
16
16
|
|
|
17
|
-
1. **Resolve, scan, classify, and load previews in one call.**
|
|
17
|
+
1. **Resolve, scan, classify, and load previews in one call.** Resolve `{resolveAuthoritativeFilesHelper}` ← first existing path in `{resolveAuthoritativeFilesProbeOrder}` (step 3's frontmatter); if neither exists, **HARD HALT** (exit code 3, `helper-missing`, phase `extract`; stage `{run_dir}/halt.json` per the Workflow Rules and run `uv run {emitEnvelopeHelper} emit-halt --workflow skf-create-skill --run-dir "{run_dir}" --target stderr < "{run_dir}/halt.json"`): "Cannot scan for authoritative files: skf-resolve-authoritative-files.py is missing. Re-install SKF, then re-run create-skill." The helper walks the tree, classifies each candidate and hashes it:
|
|
18
18
|
|
|
19
19
|
```bash
|
|
20
20
|
uv run {resolveAuthoritativeFilesHelper} resolve \
|
|
21
|
-
--source-root {source_root} \
|
|
22
|
-
--brief {
|
|
21
|
+
--source-root "{source_root}" \
|
|
22
|
+
--brief "{brief_path}" \
|
|
23
23
|
[--preview-lines 20]
|
|
24
24
|
```
|
|
25
25
|
|
|
26
|
-
The helper emits one envelope with three buckets:
|
|
26
|
+
`{source_root}` is the local tree §2b resolved: the local source, or the private tree of a remote one, and `{brief_path}` the `skill-brief.yaml` step 1 loaded. The helper emits one envelope with three buckets:
|
|
27
27
|
|
|
28
28
|
```json
|
|
29
29
|
{
|
|
@@ -47,17 +47,18 @@ This protocol detects such files, prompts the user, and records the decision in
|
|
|
47
47
|
{"path": "...", "heuristic": "...", "size_bytes": N,
|
|
48
48
|
"line_count": N, "content_hash": "sha256:...",
|
|
49
49
|
"preview": "<first N lines>",
|
|
50
|
-
"excluded_by_pattern": "<glob>"|"not matched by any scope.include"
|
|
50
|
+
"excluded_by_pattern": "<glob>"|"not matched by any scope.include",
|
|
51
|
+
"prior_action": null|"deferred-headless"}
|
|
51
52
|
]
|
|
52
53
|
}
|
|
53
54
|
```
|
|
54
55
|
|
|
55
56
|
2. **Apply the helper's classification:**
|
|
56
57
|
|
|
57
|
-
- **`already_in_scope[]
|
|
58
|
+
- **`already_in_scope[]`**: the file is in scope and not skipped. Append the record to in-context `promoted_docs[]`, and remove the path from §2's filtered file list when §2 built one. No prompt: authoritative docs must never reach §4 code extraction even when scope.include matches.
|
|
58
59
|
- **`pre_decided[]` with `prior_action: "promoted"`** — amendment says promoted; **append to `promoted_docs[]`** using the helper-supplied hash/size/lines. Deterministic replay path.
|
|
59
60
|
- **`pre_decided[]` with `prior_action: "skipped"`** — user previously declined. Do nothing. Move on.
|
|
60
|
-
- **`unresolved[]
|
|
61
|
+
- **`unresolved[]`**: proceed to step 3 below (user prompt). A `prior_action` of `deferred-headless` means an earlier headless run met the file and left the decision to the next interactive run.
|
|
61
62
|
|
|
62
63
|
3. **Prompt.** Present each `unresolved[]` candidate to the user. Use the helper's `preview`, `size_bytes`, `line_count`, and `excluded_by_pattern` fields verbatim so the prompt reports facts rather than recomputing them:
|
|
63
64
|
|
|
@@ -79,64 +80,41 @@ This protocol detects such files, prompts the user, and records the decision in
|
|
|
79
80
|
[U] Update — halt this run and return to skf-brief-skill to refine scope
|
|
80
81
|
```
|
|
81
82
|
|
|
82
|
-
4. **
|
|
83
|
+
4. **GATE [default: defer]**: in headless mode (`{headless_mode}` is true), promote nothing and decline nothing: whether a file enters scope is a person's decision, so this run leaves every `unresolved[]` candidate out of extraction and defers it to the next interactive run, which asks. For each candidate:
|
|
84
|
+
- Record one auto-decision per path, per the Workflow Rules: stage `{"step": "extract", "gate": "authoritative-file:{path}", "decision": "deferred-headless", "rationale": "headless mode: no person to decide whether {path} enters the scope", "timestamp": "{ISO}"}` as `{run_dir}/decision.json` and run `uv run {emitEnvelopeHelper} record --workflow skf-create-skill --run-dir "{run_dir}" --decision < "{run_dir}/decision.json"`. The path in the gate keeps several candidates from collapsing into one row.
|
|
85
|
+
- When its `prior_action` is null, record the deferral in the brief with step 5's **Write the decision** call, with one amendment per such candidate: `action: "deferred-headless"`, `reason: "headless: no person to decide; the next interactive run asks"`, `heuristic: {basename}`, `date: {today ISO}`, `workflow: "skf-create-skill"`. The helper keeps a `deferred-headless` path in `unresolved[]`, never in `pre_decided[]`. A candidate whose `prior_action` is already `deferred-headless` is not written again.
|
|
83
86
|
|
|
84
87
|
5. **Apply decision:**
|
|
85
88
|
|
|
89
|
+
**Write the decision** to the brief at once, so a crashed run still leaves it recorded and a re-run replays it instead of asking again. Resolve `{writeSkillBriefHelper}` ← first existing path in `{writeSkillBriefProbeOrder}` and, from `{project-root}`, run `amend`: it reads the brief again, appends the paths in `include` to `scope.include` and the entries in `amendments` to `scope.amendments`, refuses an amendment that breaks the brief schema, keeps the previous brief as `{brief_path}.bak` and writes the new one atomically:
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
uv run {writeSkillBriefHelper} amend --target "{brief_path}" <<'SKF_BRIEF_DECISION'
|
|
93
|
+
{"include": ["{path}"], "amendments": [{"path": "{path}", "action": "promoted|skipped|deferred-headless", "reason": "{reason}", "heuristic": "{basename}", "date": "{today ISO}", "workflow": "skf-create-skill"}]}
|
|
94
|
+
SKF_BRIEF_DECISION
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Pass `include` for a promoted path only. The helper appends it only when `scope.include` is not empty: an empty include already covers every file, and appending one path would narrow the scope to it; the `promoted` amendment replays the decision either way, through the helper's `pre_decided[]`. When the command exits non-zero or no path resolves, warn "The decision on `{path}` was not saved to the brief ({its stderr}): the next run asks again." and continue.
|
|
98
|
+
|
|
86
99
|
- **[P] Promote:**
|
|
87
|
-
1. **Do not
|
|
88
|
-
2.
|
|
89
|
-
3.
|
|
90
|
-
4. **Write the amended brief back to disk immediately** at `{forge_data_folder}/{skill_name}/skill-brief.yaml`. Immediate write (not deferred to step 7) ensures a crashed run still leaves the amendment recorded. Preserve all other brief fields and formatting. **Use atomic write + backup:** before writing, copy the original brief to `{forge_data_folder}/{skill_name}/skill-brief.yaml.bak` (overwriting any prior `.bak` — the most recent pre-amendment snapshot is the useful one). Then pipe the amended YAML through the shared atomic writer so a crash mid-write cannot corrupt the brief:
|
|
91
|
-
|
|
92
|
-
```bash
|
|
93
|
-
# 1. Backup
|
|
94
|
-
cp {forge_data_folder}/{skill_name}/skill-brief.yaml \
|
|
95
|
-
{forge_data_folder}/{skill_name}/skill-brief.yaml.bak
|
|
96
|
-
|
|
97
|
-
# 2. Atomic write (stdin → tmp → fsync → rename)
|
|
98
|
-
cat <<'AMENDED_YAML' | python3 {atomicWriteHelper} write \
|
|
99
|
-
--target {forge_data_folder}/{skill_name}/skill-brief.yaml
|
|
100
|
-
{amended brief YAML}
|
|
101
|
-
AMENDED_YAML
|
|
102
|
-
```
|
|
103
|
-
|
|
104
|
-
The helper stages into `{brief}.skf-tmp`, fsyncs, then `os.replace()`s — readers never see a half-written brief.
|
|
105
|
-
5. Display: "**Promoted `{path}`** — tracked as documentation file, amendment recorded."
|
|
100
|
+
1. **Do not hand the path to §4.** Authoritative documentation files are not code: the AST extraction pipeline would silently produce no exports (ghost entries). Add the path to a new in-context list `promoted_docs[]` with `{path, heuristic, size_bytes, line_count, content_hash}`, taking the values the helper reported, and remove it from §2's filtered file list when §2 built one.
|
|
101
|
+
2. **Write the decision** with `include: ["{path}"]` and an amendment with `action: "promoted"`, `reason`: the user's one-sentence reason, else "authoritative AI docs, matched heuristic {basename}".
|
|
102
|
+
3. Display: "**Promoted `{path}`**: tracked as documentation file, amendment recorded."
|
|
106
103
|
|
|
107
104
|
- **[S] Skip:**
|
|
108
|
-
1.
|
|
109
|
-
2.
|
|
110
|
-
3.
|
|
111
|
-
4. Display: "**Skipped `{path}`** — decision recorded in amendments."
|
|
105
|
+
1. Leave `scope.include` and `scope.exclude` as they are.
|
|
106
|
+
2. **Write the decision** with no `include` and an amendment with `action: "skipped"`, `reason`: the user's reason, else "user declined promotion at create-skill §2a".
|
|
107
|
+
3. Display: "**Skipped `{path}`**: decision recorded in amendments."
|
|
112
108
|
|
|
113
109
|
- **[U] Update:**
|
|
114
|
-
1.
|
|
115
|
-
2.
|
|
116
|
-
3. Exit with status `halted-for-brief-refinement`.
|
|
110
|
+
1. When `{source_tree}` is set, first run `uv run {sourceTreeHelper} close --tree "{source_tree}"` from `{project-root}` and go on whatever it prints: the scan read the tree §2b made, and nothing reads it after this halt.
|
|
111
|
+
2. **HARD HALT** (exit code 6, `halted-for-brief-refinement`, phase `extract`; stage `{run_dir}/halt.json` per the Workflow Rules and run `uv run {emitEnvelopeHelper} emit-halt --workflow skf-create-skill --run-dir "{run_dir}" --target stderr < "{run_dir}/halt.json"`): "**Halting create-skill.** Re-run `skf-brief-skill` to refine the scope filters for `{skill_name}`, then re-run `skf-create-skill`. Decisions for previously prompted candidates were already persisted to the brief; the current candidate was not written."
|
|
117
112
|
|
|
118
113
|
6. **Summary.** After all candidates are resolved (or none were found), display a one-line summary:
|
|
119
114
|
|
|
120
|
-
- `"Authoritative files scan: {N} candidates, {P} promoted, {S} skipped, {A} pre-decided from amendments."`
|
|
115
|
+
- `"Authoritative files scan: {N} candidates, {P} promoted, {S} skipped, {D} left for an interactive run, {A} pre-decided from amendments."`
|
|
121
116
|
- If N = 0: `"Authoritative files scan: no candidates."`
|
|
122
117
|
|
|
123
|
-
**Record for evidence report:** `authoritative_files_scan: {candidates: N, promoted: P, skipped: S, pre_decided: A, decisions: [{path, action, heuristic, reason}]}`
|
|
124
|
-
|
|
125
|
-
## How promoted docs reach the provenance map
|
|
126
|
-
|
|
127
|
-
Promoted docs do not flow through §4 code extraction. Instead:
|
|
128
|
-
|
|
129
|
-
1. §2a populates the in-context `promoted_docs[]` list with content hashes.
|
|
130
|
-
2. **Step-05 §6** (provenance-map assembly) reads `promoted_docs[]` and emits one `file_entries[]` entry per promoted doc with `file_type: "doc"`, `extraction_method: "promoted-authoritative"`, `confidence: "T1-low"`, and the pre-computed `content_hash`.
|
|
131
|
-
3. **Step-07 §2** does not copy doc files into the skill package (unlike scripts and assets). The source file remains at its original path; only the provenance map tracks it. Future audit and update workflows compare against this tracking entry via content hash — no file copy is required because the intent is drift detection on the *source*, not bundling documentation into the skill output.
|
|
132
|
-
|
|
133
|
-
**Re-running `skf-create-skill`** reads the amended brief. Files with `action: "promoted"` amendments already appear in `scope.include`, but §2a still runs — it detects the file is in scope AND has an existing amendment, and takes the "pre-decided" silent path. The `promoted_docs[]` list is rebuilt on each run by scanning amendments with `action: "promoted"` (this is the deterministic replay path).
|
|
134
|
-
|
|
135
|
-
## Downstream workflow consumption
|
|
136
|
-
|
|
137
|
-
Zero code changes required in consumer workflows:
|
|
138
|
-
|
|
139
|
-
- **`skf-update-skill`** reads `provenance-map.json`. Promoted docs appear as `file_entries[]` entries. Update-skill Category D (script/asset file changes) iterates `file_entries` and compares content hashes — this works identically for `file_type: "doc"` entries, giving drift detection for free.
|
|
140
|
-
- **`skf-audit-skill`** scans files from `provenance-map.json`. The re-index builds its list from `entries[].source_file ∪ file_entries[].source_file`, so promoted doc paths are naturally included in the audit scan.
|
|
118
|
+
**Record for evidence report:** `authoritative_files_scan: {candidates: N, promoted: P, skipped: S, deferred: D, pre_decided: A, decisions: [{path, action, heuristic, reason}]}`. Step 3 §5 writes it and `promoted_docs[]` into the extraction inventory, and step 5 writes it into `evidence-report.md`.
|
|
141
119
|
|
|
142
|
-
|
|
120
|
+
When step 3 §2a's remote source guard skipped the scan, the record is `authoritative_files_scan: {not_scanned: "remote source not cloned"}` instead (its own key, apart from the `skipped` count of candidates above), and step 6 lists that skip under the evidence report's Remaining Warnings.
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
---
|
|
2
|
+
nextStepFile: 'load-brief.md'
|
|
3
|
+
healthCheckStepFile: 'health-check.md'
|
|
4
|
+
# Resolve `{quickBatchHelper}` to the first existing path. It keeps the
|
|
5
|
+
# batch on disk: §1 starts it, §2 hands out each brief, §3 records how each
|
|
6
|
+
# one ended and §4 ends the batch. If neither path exists, §1 halts before
|
|
7
|
+
# any brief compiles.
|
|
8
|
+
quickBatchProbeOrder:
|
|
9
|
+
- '{project-root}/_bmad/skf/shared/scripts/skf-quick-batch.py'
|
|
10
|
+
- '{project-root}/src/shared/scripts/skf-quick-batch.py'
|
|
11
|
+
# HARD HALT helper (Execution).
|
|
12
|
+
emitEnvelopeProbeOrder:
|
|
13
|
+
- '{project-root}/_bmad/skf/shared/scripts/skf-emit-result-envelope.py'
|
|
14
|
+
- '{project-root}/src/shared/scripts/skf-emit-result-envelope.py'
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
<!-- Config: communicate in {communication_language}. -->
|
|
18
|
+
|
|
19
|
+
# Batch Mode
|
|
20
|
+
|
|
21
|
+
With `--batch`, create-skill compiles every brief the paths after the flag name, one after another: each path is a `skill-brief.yaml`, or a folder whose `skill-brief.yaml` files (at any depth, hidden folders left out) are compiled; with no path, the briefs under `{forge_data_folder}`. `skf-quick-batch.py` keeps the batch in its run folder, never only in context: it checks every brief with the brief schema validator before the first one compiles, hands out each brief in turn, records how each one ended, and computes the counts, the status and the exit code. A HARD HALT ends its brief, not the batch.
|
|
22
|
+
|
|
23
|
+
## Execution
|
|
24
|
+
|
|
25
|
+
Resolve `{quickBatchHelper}` ← the first existing path in `{quickBatchProbeOrder}`, and `{emitEnvelopeHelper}`, which every HARD HALT here emits through, ← the first existing path in `{emitEnvelopeProbeOrder}` when it is not bound. The helper names the batch run folder, `{batch_dir}`, after the briefs: the same briefs always get the same folder, so a batch a session ended mid-way is found again (run `--batch` with the same briefs and it goes on with the brief it was working on, which compiles again from the start), and a batch of other briefs, from another terminal, never touches it. After a compaction, `{batch_dir}` is the parent folder of the brief's `{run_dir}`, and §1's `start` run again with the same briefs prints it without changing the batch.
|
|
26
|
+
|
|
27
|
+
### 1. Start the Batch
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
uv run {quickBatchHelper} start --briefs {batch_paths} --run-root "{project-root}/_bmad-output/.skf-run"
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
`{batch_paths}` is each path given to `--batch`, quoted, or `"{forge_data_folder}"` when none was given. The helper finds the briefs and checks each one, and records each brief the validator refuses as failed, with its `halt_reason` (`brief-missing`, `brief-malformed` or `brief-invalid`) and the validator's first message, before any brief compiles; a brief whose `name` an earlier brief already has is refused the same way (`brief-invalid`), since both would compile into one skill folder. Bind `{batch_dir}` ← its `batch_dir`. When On Activation step 3 kept a `{customization_resolver_unavailable}` reason, write `customization_resolver_unavailable: {customization_resolver_unavailable}` to `{batch_dir}/resolver-warning.txt` with a file write, never `echo`: load-brief.md §0 records it in each brief's sink, after a compaction too. Display the plan: "**Batch:** {targets_total} briefs, {targets_total minus the `rejected` count} to compile." and, for each `rejected` entry, "Not compiled: `{target}`: {message}". When `resumed` is true, add "Resuming the batch: {recorded} briefs already ended."
|
|
34
|
+
|
|
35
|
+
If it exits non-zero, no brief compiles: the `halt_reason` of its stderr JSON names the halt. Display "**The batch cannot start:** {its `message`, or: skf-quick-batch.py is missing, re-install SKF}", and stop:
|
|
36
|
+
|
|
37
|
+
- `brief-missing`, no brief under the paths: **HARD HALT** (exit code 2, `brief-missing`, phase `batch-mode`; emit with nothing to stage in, below).
|
|
38
|
+
- `helper-missing`, the validator cannot load, or no path in `{quickBatchProbeOrder}` exists: **HARD HALT** (exit code 3, `helper-missing`, phase `batch-mode`; emit with nothing to stage in, below).
|
|
39
|
+
- `write-failed`, the batch folder cannot be written, or holds an unfinished batch of other briefs, which start never deletes: **HARD HALT** (exit code 4, `write-failed`, phase `batch-mode`; emit with nothing to stage in, below).
|
|
40
|
+
|
|
41
|
+
No run folder holds a payload yet, so the halt's envelope comes from the command alone. Every halt of this file emits this way, with the reason it gives:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
uv run {emitEnvelopeHelper} emit-halt --workflow skf-create-skill --target stderr <<'SKF_JSON'
|
|
45
|
+
{"phase": "batch-mode", "halt_reason": "<the halt_reason>", "reason": "The batch cannot start: <that message, one line>", "summary": {"halt_reason": "<the halt_reason>", "evidence_report": null}}
|
|
46
|
+
SKF_JSON
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### 2. Take the Next Brief
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
uv run {quickBatchHelper} next --run-dir "{batch_dir}"
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
- **`"status": "next"`**: display the `start` event the helper printed on stderr. Bind `{run_dir}` ← its `run_dir`, the brief's own run folder, created empty, and `{brief_path}` ← its `target`. Nothing else carries over from the previous brief: its source, tree, extraction, staged skill and summary values all start empty. Then load, read in full and execute `{nextStepFile}`: steps 1 to 8 run for this brief.
|
|
56
|
+
- **`"status": "record"`**: brief `batch` ended, its payload staged, before §3 recorded it (a compaction came between its envelope and §3): go to §3 with that `batch`, never compiling it again.
|
|
57
|
+
- **`"status": "done"`**: no brief is pending. Go to §4.
|
|
58
|
+
|
|
59
|
+
If it exits non-zero (the brief's run folder cannot be created, or the batch file is gone or unreadable), the batch cannot go on: display "**The batch stopped:** {its `message`}" and **HARD HALT** (exit code 4, `write-failed`, phase `batch-mode`; emit with nothing to stage in, as §1 does, with the reason "The batch stopped: <its message>").
|
|
60
|
+
|
|
61
|
+
### 3. Record the Brief
|
|
62
|
+
|
|
63
|
+
Every brief ends here: step 8 §6 sends a finished brief here, and every HARD HALT of steps 1 to 7 returns here after its envelope (each stage's Rules say so). Control returns here even when the step that ended the brief reads as the end of the run. Record it:
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
uv run {quickBatchHelper} record --run-dir "{batch_dir}" --batch {batch} --target stderr
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
`{batch}` is the number §2's `next` printed. The helper reads how the brief ended from what its run folder staged for the emitter (`halt.json`, or step 8's `result-context.json`), appends the outcome to the batch file, removes the run folder of a brief that finished (a halted brief keeps its folder for a look), and prints the brief's `done` or `fail` event on stderr: display it verbatim. Then go back to §2. If it exits non-zero, its `message` names what is missing: stage the payload the brief ended with and record again, once. If it exits non-zero a second time (the batch file cannot be written, or a `halt_reason` maps to no exit code), the outcome cannot be kept: display "**The batch stopped:** {its `message`}" and **HARD HALT** (exit code 4, `write-failed`, phase `batch-mode`; emit with nothing to stage in, as §1 does, with the reason "The batch stopped: <its message>").
|
|
70
|
+
|
|
71
|
+
### 4. Batch Summary
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
uv run {quickBatchHelper} summarize --run-dir "{batch_dir}" --output-dir "{skills_output_folder}/_batch" --target stderr
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
The helper counts the briefs, sets the batch status and exit code, writes the summary to `{skills_output_folder}/_batch/create-skill-batch-{YYYYMMDD-HHmmss}.json` and its `create-skill-batch-latest.json` copy (`skill`, `mode`, `status`, `timestamp`, `input_briefs`, `targets_total`, `succeeded`, `failed`, `fail_fast_triggered`, `exit_code`, and `results[]`, one per brief with its `batch`, `target`, `status`, `exit_code`, `skill_package` and `error_code`), removes the batch run folder when no brief failed, and prints the `batch_summary` event on stderr: display it verbatim, then "Batch complete: {succeeded} of {targets_total} briefs compiled." and, when `failed` is above 0, the `target` and `error_code` of each failed `results[]` entry of the summary file.
|
|
78
|
+
|
|
79
|
+
Then load, read in full and execute `{healthCheckStepFile}`: the health check runs once per batch, here. The batch ends with the event's `exit_code`: 0 when every brief finished, else the highest exit code among the briefs that failed.
|
|
80
|
+
|
|
81
|
+
If `summarize` exits non-zero (a brief is still pending, or the batch file is gone or unreadable), the health check does not run: display "**The batch stopped:** {its `message`}" and **HARD HALT** (exit code 4, `write-failed`, phase `batch-mode`; emit with nothing to stage in, as §1 does, with the reason "The batch stopped: <its message>"). The summary files may be missing then, but each brief's own result contract is in its `{forge_version}`.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# CCC Index Check
|
|
2
|
+
|
|
3
|
+
Step 3 §2b (deferred ccc discovery on SKF's workspace clone) and step 7 §6b (the index the skill registers) load this file after they run `ccc index`. It waits for a running pass, checks that the source language was indexed, and repairs the index settings when it was not. The caller binds:
|
|
4
|
+
|
|
5
|
+
- `{ccc_root}`: the folder the index belongs to. ccc takes no path argument, so every ccc command below runs as `cd "{ccc_root}" && ccc ...`.
|
|
6
|
+
- `{ccc_settings_owner}`: `skf` when `{ccc_root}` is SKF's workspace clone of a remote source, whose `settings.yml` SKF edits only through `{mergeCccExclusionsHelper}`; `user` when `{ccc_root}` is the user's own source folder, whose `settings.yml` SKF never edits.
|
|
7
|
+
|
|
8
|
+
`{mergeCccExclusionsHelper}` is the first existing path in the caller's `mergeCccExclusionsProbeOrder`; run it from `{project-root}`.
|
|
9
|
+
|
|
10
|
+
## 1. Wait for the Pass
|
|
11
|
+
|
|
12
|
+
Run `cd "{ccc_root}" && ccc status`. If it prints an `Indexing in progress:` line, a pass is still running and the counts below it are not final: run `cd "{ccc_root}" && ccc index` again, which waits for the running pass to finish and then makes a quick incremental pass, then run `ccc status` again. If the line is still there after 3 such runs, return **index unverified** to the caller and skip §2 and §3.
|
|
13
|
+
|
|
14
|
+
## 2. Check the Languages
|
|
15
|
+
|
|
16
|
+
Once the line is gone, read the `Languages:` breakdown: a non-zero `Chunks`/`Files` total is not sufficient. Confirm the source's primary language (`{brief.language}`) reports a non-trivial chunk count. An index dominated by `markdown`/config chunks with the source language absent or near-zero means the source code was never indexed, and searches over it return nothing useful. When the source language is there, return **verified**.
|
|
17
|
+
|
|
18
|
+
## 3. Repair
|
|
19
|
+
|
|
20
|
+
When the source language is absent, apply these repairs in order, stopping at the first one after which `Languages:` shows the source language:
|
|
21
|
+
|
|
22
|
+
1. **No project of its own:** `{ccc_root}/.cocoindex_code/settings.yml` is missing and the `Project:` line of `ccc status` names another folder, so ccc indexed an enclosing project. With `{ccc_settings_owner}` `skf`, run `uv run {mergeCccExclusionsHelper} --clone-root "{ccc_root}"`: it runs `ccc init -f` there and adds the standard build and dependency exclusions. With `user`, run `cd "{ccc_root}" && ccc init -f`. Then run `ccc index`, then run `ccc status` and check `Languages:` again.
|
|
23
|
+
2. **Language not included:** ccc indexes only the file types listed in `include_patterns`, and its default list leaves some languages out (Elixir's `.ex`, for example). Take the extensions of the `{brief.language}` files in step 3's §2 filtered file list, at most 3.
|
|
24
|
+
- `skf`: run `uv run {mergeCccExclusionsHelper} --clone-root "{ccc_root}" --include-ext {ext}`, with one `--include-ext` per extension. It appends a single-quoted `- '**/*.{ext}'` item for each extension no `include_patterns` entry matches (`includes_added_list`) and lists the extensions an entry already matches (`includes_covered_list`). On a file with no `include_patterns` list it adds nothing and says so in `warnings`, since a list written from scratch replaces ccc's default file types: display that `{ccc_root}/.cocoindex_code/settings.yml` has no `include_patterns` list to add the `{brief.language}` file types to, and return **degraded**. When `includes_covered_list` holds every extension, the files are excluded rather than left out of `include_patterns`: skip this repair and display which `exclude_patterns` entry covers the `{brief.language}` source files (`**/build` covers a package under `src/build/`, for example). Otherwise display "Added {includes_added_list} to include_patterns in {ccc_root}/.cocoindex_code/settings.yml so ccc indexes {brief.language} files.", run a plain `cd "{ccc_root}" && ccc index`, then run `ccc status` and check `Languages:` again.
|
|
25
|
+
- `user`: the settings belong to the user's project, so do not edit them. Keep the extensions that no `include_patterns` entry matches. If there are none, the files are excluded rather than left out of `include_patterns`: display which `exclude_patterns` entry covers the `{brief.language}` source files. Otherwise display that ccc did not index `{brief.language}` files, and the exact lines to add under `include_patterns` in `{ccc_root}/.cocoindex_code/settings.yml`, one single-quoted `- '**/*.{ext}'` line per extension (YAML reads an unquoted leading `*` as an alias, and ccc then fails to load the file), followed by a plain `ccc index`.
|
|
26
|
+
|
|
27
|
+
A plain `ccc index` is enough after any `settings.yml` edit; nothing needs deleting first. Do not run `ccc reset`: it deletes only the index databases and keeps `settings.yml`, so it cannot repair the settings, a `ccc index` right after it can fail and leave the project with no index, and run from a folder without its own `settings.yml` it deletes the enclosing project's index. If the source language is still missing after these repairs, return **degraded** to the caller.
|