bmad-module-skill-forge 1.9.0 → 2.0.1
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/.nvmrc +1 -1
- package/README.md +10 -5
- package/docs/_data/pinned.yaml +2 -2
- package/docs/agents.md +11 -2
- package/docs/architecture.md +5 -4
- package/docs/bmad-synergy.md +30 -7
- package/docs/campaign.md +172 -0
- package/docs/examples.md +7 -3
- package/docs/forge-auto.md +90 -0
- package/docs/getting-started.md +9 -0
- package/docs/how-it-works.md +6 -4
- package/docs/index.md +4 -3
- package/docs/skill-model.md +1 -1
- package/docs/troubleshooting.md +17 -1
- package/docs/verifying-a-skill.md +2 -2
- package/docs/why-skf.md +1 -1
- package/docs/workflows.md +64 -24
- package/package.json +2 -2
- package/src/knowledge/skill-lifecycle.md +1 -1
- package/src/module-help.csv +4 -3
- package/src/shared/data/language-corpora.json +32 -0
- package/src/shared/references/pipeline-contracts.md +6 -3
- package/src/shared/scripts/schemas/skill-brief.v1.json +6 -1
- package/src/shared/scripts/skf-comention-pairs.py +350 -0
- package/src/shared/scripts/skf-count-tokens.py +222 -0
- package/src/shared/scripts/skf-derive-assembly-shape.py +107 -0
- package/src/shared/scripts/skf-detect-docs.py +240 -4
- package/src/shared/scripts/skf-detect-language.py +82 -3
- package/src/shared/scripts/skf-detect-tools.py +105 -2
- package/src/shared/scripts/skf-emit-result-envelope.py +17 -0
- package/src/shared/scripts/skf-enumerate-stack-skills.py +111 -2
- package/src/shared/scripts/skf-extract-public-api.py +53 -0
- package/src/shared/scripts/skf-find-cycles.py +246 -0
- package/src/shared/scripts/skf-hash-content.py +487 -2
- package/src/shared/scripts/skf-language-corpora.py +100 -0
- package/src/shared/scripts/skf-manifest-ops.py +67 -1
- package/src/shared/scripts/skf-merge-doc-urls.py +244 -0
- package/src/shared/scripts/skf-preapply.py +1 -1
- package/src/shared/scripts/skf-rebuild-managed-sections.py +180 -0
- package/src/shared/scripts/skf-recommend-scope-type.py +1 -2
- package/src/shared/scripts/skf-render-metadata-stats.py +499 -0
- package/src/shared/scripts/skf-rewrite-skill-name.py +308 -0
- package/src/shared/scripts/skf-shape-detect.py +576 -25
- package/src/shared/scripts/skf-shard-body.py +461 -0
- package/src/shared/scripts/skf-skill-inventory.py +139 -3
- package/src/shared/scripts/skf-structural-diff.py +307 -67
- package/src/shared/scripts/skf-validate-brief-schema.py +41 -6
- package/src/shared/scripts/skf-validate-feasibility-report.py +234 -0
- package/src/shared/scripts/skf-validate-frontmatter.py +17 -12
- package/src/shared/scripts/skf-validate-output.py +443 -10
- package/src/shared/scripts/skf-validate-pins.py +3 -3
- package/src/shared/scripts/skf-verify-no-trace.py +214 -0
- package/src/shared/scripts/skf-verify-provenance-completeness.py +439 -0
- package/src/shared/scripts/skf-write-skill-brief.py +21 -5
- package/src/skf-analyze-source/SKILL.md +17 -32
- package/src/skf-analyze-source/assets/skill-brief-schema.md +1 -1
- package/src/skf-analyze-source/customize.toml +2 -0
- package/src/skf-analyze-source/references/auto-docs-only.md +116 -0
- package/src/skf-analyze-source/references/continue.md +8 -13
- package/src/skf-analyze-source/references/generate-briefs.md +28 -12
- package/src/skf-analyze-source/references/headless-contract.md +33 -0
- package/src/skf-analyze-source/references/health-check.md +1 -2
- package/src/skf-analyze-source/references/identify-units.md +25 -36
- package/src/skf-analyze-source/references/init.md +12 -25
- package/src/skf-analyze-source/references/map-and-detect.md +8 -20
- package/src/skf-analyze-source/references/recommend.md +4 -14
- package/src/skf-analyze-source/references/scan-project.md +3 -11
- package/src/skf-analyze-source/references/step-auto-scope.md +211 -197
- package/src/skf-analyze-source/references/step-shape-detect.md +20 -13
- package/src/skf-analyze-source/references/unit-detection-heuristics.md +2 -2
- package/src/skf-audit-skill/SKILL.md +9 -6
- package/src/skf-audit-skill/customize.toml +2 -0
- package/src/skf-audit-skill/references/init.md +58 -32
- package/src/skf-audit-skill/references/re-index.md +15 -34
- package/src/skf-audit-skill/references/report.md +11 -58
- package/src/skf-audit-skill/references/semantic-diff.md +4 -22
- package/src/skf-audit-skill/references/severity-classify.md +53 -87
- package/src/skf-audit-skill/references/step-doc-drift.md +49 -19
- package/src/skf-audit-skill/references/structural-diff.md +43 -68
- package/src/skf-brief-skill/SKILL.md +7 -36
- package/src/skf-brief-skill/assets/scope-templates.md +1 -1
- package/src/skf-brief-skill/assets/skill-brief-schema.md +1 -1
- package/src/skf-brief-skill/customize.toml +14 -0
- package/src/skf-brief-skill/references/analyze-target.md +13 -18
- package/src/skf-brief-skill/references/confirm-brief.md +2 -15
- package/src/skf-brief-skill/references/draft-checkpoint.md +8 -8
- package/src/skf-brief-skill/references/gather-intent.md +27 -24
- package/src/skf-brief-skill/references/headless-args.md +1 -1
- package/src/skf-brief-skill/references/health-check.md +1 -22
- package/src/skf-brief-skill/references/invocation-contract.md +37 -0
- package/src/skf-brief-skill/references/scope-definition.md +6 -15
- package/src/skf-brief-skill/references/step-auto-brief.md +22 -9
- package/src/skf-brief-skill/references/step-auto-validate.md +3 -7
- package/src/skf-brief-skill/references/version-resolution.md +1 -1
- package/src/skf-brief-skill/references/write-brief.md +19 -13
- package/src/skf-campaign/SKILL.md +121 -0
- package/src/skf-campaign/assets/campaign-state-schema.json +191 -0
- package/src/skf-campaign/customize.toml +75 -0
- package/src/skf-campaign/manifest.yaml +15 -0
- package/src/skf-campaign/references/campaign-contracts.md +67 -0
- package/src/skf-campaign/references/campaign-directive-spec.md +32 -0
- package/src/skf-campaign/references/health-check.md +35 -0
- package/src/skf-campaign/references/step-01-setup.md +121 -0
- package/src/skf-campaign/references/step-02-strategy.md +102 -0
- package/src/skf-campaign/references/step-03-pins.md +56 -0
- package/src/skf-campaign/references/step-04-provenance.md +63 -0
- package/src/skf-campaign/references/step-05-skill-loop.md +103 -0
- package/src/skf-campaign/references/step-06-batch.md +88 -0
- package/src/skf-campaign/references/step-07-capstone.md +63 -0
- package/src/skf-campaign/references/step-08-verify.md +75 -0
- package/src/skf-campaign/references/step-09-refine.md +83 -0
- package/src/skf-campaign/references/step-10-export.md +106 -0
- package/src/skf-campaign/references/step-11-maintenance.md +84 -0
- package/src/skf-campaign/references/step-resume.md +115 -0
- package/src/skf-campaign/scripts/.gitkeep +0 -0
- package/src/skf-campaign/scripts/campaign-deps.py +244 -0
- package/src/skf-campaign/scripts/campaign-parse-manifest.py +119 -0
- package/src/skf-campaign/scripts/campaign-provenance.py +247 -0
- package/src/skf-campaign/scripts/campaign-render-batch.py +199 -0
- package/src/skf-campaign/scripts/campaign-render-kickoff.py +158 -0
- package/src/skf-campaign/scripts/campaign-report.py +249 -0
- package/src/skf-campaign/scripts/campaign-status.py +162 -0
- package/src/skf-campaign/scripts/campaign-validate-pins.py +174 -0
- package/src/skf-campaign/scripts/campaign-validate-state.py +207 -0
- package/src/skf-campaign/templates/campaign-brief-template.yaml +34 -0
- package/src/skf-campaign/templates/campaign-report-template.md +54 -0
- package/src/skf-campaign/templates/kickoff-template.md +48 -0
- package/src/skf-create-skill/SKILL.md +15 -4
- package/src/skf-create-skill/assets/compile-assembly-rules.md +35 -34
- package/src/skf-create-skill/assets/skill-sections.md +9 -100
- package/src/skf-create-skill/assets/tessl-dismissal-rules.md +4 -13
- package/src/skf-create-skill/customize.toml +13 -0
- package/src/skf-create-skill/references/authoritative-files-protocol.md +7 -7
- package/src/skf-create-skill/references/compile.md +37 -47
- package/src/skf-create-skill/references/component-extraction.md +8 -35
- package/src/skf-create-skill/references/ecosystem-check.md +9 -25
- package/src/skf-create-skill/references/enrich.md +4 -17
- package/src/skf-create-skill/references/extract.md +20 -27
- package/src/skf-create-skill/references/extraction-patterns-tracing.md +1 -1
- package/src/skf-create-skill/references/extraction-patterns.md +10 -8
- package/src/skf-create-skill/references/generate-artifacts.md +20 -25
- package/src/skf-create-skill/references/health-check.md +2 -2
- package/src/skf-create-skill/references/load-brief.md +16 -18
- package/src/skf-create-skill/references/report.md +27 -14
- package/src/skf-create-skill/references/source-resolution-protocols.md +4 -4
- package/src/skf-create-skill/references/step-auto-shard.md +52 -25
- package/src/skf-create-skill/references/step-doc-rot.md +33 -15
- package/src/skf-create-skill/references/step-doc-sources.md +13 -4
- package/src/skf-create-skill/references/sub/ccc-discover.md +2 -13
- package/src/skf-create-skill/references/sub/fetch-docs.md +33 -46
- package/src/skf-create-skill/references/sub/fetch-temporal.md +5 -20
- package/src/skf-create-skill/references/tier-degradation-rules.md +6 -8
- package/src/skf-create-skill/references/validate.md +69 -29
- package/src/skf-create-skill/scripts/scan-doc-rot.py +245 -0
- package/src/skf-create-stack-skill/SKILL.md +15 -9
- package/src/skf-create-stack-skill/assets/provenance-map-schema.md +1 -1
- package/src/skf-create-stack-skill/customize.toml +10 -0
- package/src/skf-create-stack-skill/references/compile-stack.md +7 -8
- package/src/skf-create-stack-skill/references/compose-mode-rules.md +2 -13
- package/src/skf-create-stack-skill/references/detect-integrations.md +49 -54
- package/src/skf-create-stack-skill/references/detect-manifests.md +37 -30
- package/src/skf-create-stack-skill/references/generate-output.md +24 -75
- package/src/skf-create-stack-skill/references/init.md +9 -81
- package/src/skf-create-stack-skill/references/manifest-patterns.md +5 -35
- package/src/skf-create-stack-skill/references/parallel-extract.md +12 -27
- package/src/skf-create-stack-skill/references/rank-and-confirm.md +6 -6
- package/src/skf-create-stack-skill/references/report.md +27 -62
- package/src/skf-create-stack-skill/references/validate.md +35 -31
- package/src/skf-drop-skill/SKILL.md +20 -23
- package/src/skf-drop-skill/customize.toml +10 -0
- package/src/skf-drop-skill/references/execute.md +67 -36
- package/src/skf-drop-skill/references/headless-contract.md +18 -0
- package/src/skf-drop-skill/references/health-check.md +1 -13
- package/src/skf-drop-skill/references/report.md +44 -10
- package/src/skf-drop-skill/references/select.md +93 -48
- package/src/skf-drop-skill/scripts/dir-sizes.py +116 -0
- package/src/skf-export-skill/SKILL.md +17 -14
- package/src/skf-export-skill/assets/managed-section-format.md +2 -5
- package/src/skf-export-skill/customize.toml +10 -6
- package/src/skf-export-skill/references/generate-snippet.md +21 -35
- package/src/skf-export-skill/references/load-skill.md +44 -42
- package/src/skf-export-skill/references/multi-skill-mode.md +1 -1
- package/src/skf-export-skill/references/orphan-context-detection.md +11 -3
- package/src/skf-export-skill/references/package.md +27 -33
- package/src/skf-export-skill/references/preflight-snippet-root-probe.md +24 -5
- package/src/skf-export-skill/references/result-envelope.md +28 -0
- package/src/skf-export-skill/references/summary.md +11 -5
- package/src/skf-export-skill/references/token-report.md +42 -24
- package/src/skf-export-skill/references/update-context.md +32 -33
- package/src/skf-forger/SKILL.md +32 -39
- package/src/skf-forger/references/pipeline-mode.md +34 -0
- package/src/skf-forger/scripts/parse-pipeline.py +270 -0
- package/src/skf-quick-skill/SKILL.md +10 -60
- package/src/skf-quick-skill/customize.toml +9 -0
- package/src/skf-quick-skill/references/batch-mode.md +6 -4
- package/src/skf-quick-skill/references/compile.md +15 -52
- package/src/skf-quick-skill/references/ecosystem-check.md +5 -20
- package/src/skf-quick-skill/references/finalize.md +12 -6
- package/src/skf-quick-skill/references/halt-contract.md +54 -0
- package/src/skf-quick-skill/references/health-check.md +3 -4
- package/src/skf-quick-skill/references/quick-extract.md +7 -18
- package/src/skf-quick-skill/references/registry-resolution.md +1 -23
- package/src/skf-quick-skill/references/resolve-target.md +27 -34
- package/src/skf-quick-skill/references/write-and-validate.md +10 -25
- package/src/skf-refine-architecture/SKILL.md +16 -8
- package/src/skf-refine-architecture/customize.toml +9 -0
- package/src/skf-refine-architecture/references/compile.md +10 -8
- package/src/skf-refine-architecture/references/gap-analysis.md +21 -50
- package/src/skf-refine-architecture/references/health-check.md +1 -1
- package/src/skf-refine-architecture/references/improvements.md +9 -25
- package/src/skf-refine-architecture/references/init.md +9 -16
- package/src/skf-refine-architecture/references/issue-detection.md +10 -25
- package/src/skf-refine-architecture/references/refinement-rules.md +4 -16
- package/src/skf-refine-architecture/references/report.md +14 -11
- package/src/skf-rename-skill/SKILL.md +11 -21
- package/src/skf-rename-skill/customize.toml +10 -0
- package/src/skf-rename-skill/references/execute.md +112 -82
- package/src/skf-rename-skill/references/exit-codes.md +12 -0
- package/src/skf-rename-skill/references/report.md +16 -8
- package/src/skf-rename-skill/references/select.md +69 -42
- package/src/skf-rename-skill/scripts/skf-validate-rename-name.py +161 -0
- package/src/skf-setup/SKILL.md +21 -13
- package/src/skf-setup/customize.toml +10 -0
- package/src/skf-setup/references/auto-index.md +11 -10
- package/src/skf-setup/references/ccc-index.md +14 -15
- package/src/skf-setup/references/detect-and-tier.md +10 -8
- package/src/skf-setup/references/report.md +26 -32
- package/src/skf-setup/references/tier-rules.md +2 -32
- package/src/skf-setup/references/write-config.md +9 -10
- package/src/skf-test-skill/SKILL.md +10 -8
- package/src/skf-test-skill/customize.toml +2 -0
- package/src/skf-test-skill/references/coherence-check.md +19 -31
- package/src/skf-test-skill/references/coverage-check.md +111 -67
- package/src/skf-test-skill/references/detect-mode.md +10 -41
- package/src/skf-test-skill/references/external-validators.md +11 -19
- package/src/skf-test-skill/references/init.md +39 -21
- package/src/skf-test-skill/references/migration-section-rules.md +4 -4
- package/src/skf-test-skill/references/report.md +60 -40
- package/src/skf-test-skill/references/score.md +32 -64
- package/src/skf-test-skill/references/scoring-rules.md +6 -62
- package/src/skf-test-skill/references/source-access-protocol.md +15 -5
- package/src/skf-test-skill/references/step-hard-gate.md +1 -3
- package/src/skf-test-skill/scripts/aggregate-coherence.py +276 -0
- package/src/skf-test-skill/scripts/check-metadata-coherence.py +359 -0
- package/src/skf-test-skill/scripts/combine-external-scores.py +190 -0
- package/src/skf-test-skill/scripts/compute-score.py +135 -4
- package/src/skf-test-skill/scripts/reconcile-coverage.py +327 -0
- package/src/skf-test-skill/scripts/validate-inventory.py +251 -0
- package/src/skf-test-skill/scripts/verify-declared-numerator.py +192 -0
- package/src/skf-update-skill/SKILL.md +17 -5
- package/src/skf-update-skill/customize.toml +11 -6
- package/src/skf-update-skill/references/detect-changes.md +48 -36
- package/src/skf-update-skill/references/health-check.md +5 -11
- package/src/skf-update-skill/references/init.md +40 -32
- package/src/skf-update-skill/references/manual-section-rules.md +1 -2
- package/src/skf-update-skill/references/merge-conflict-rules.md +1 -52
- package/src/skf-update-skill/references/merge.md +13 -57
- package/src/skf-update-skill/references/re-extract.md +27 -25
- package/src/skf-update-skill/references/report.md +14 -7
- package/src/skf-update-skill/references/validate.md +32 -30
- package/src/skf-update-skill/references/write.md +86 -51
- package/src/skf-update-skill/scripts/skf-new-file-diff.py +167 -0
- package/src/skf-verify-stack/SKILL.md +11 -21
- package/src/skf-verify-stack/customize.toml +12 -3
- package/src/skf-verify-stack/references/coverage-patterns.md +1 -29
- package/src/skf-verify-stack/references/coverage.md +21 -10
- package/src/skf-verify-stack/references/exit-codes.md +14 -0
- package/src/skf-verify-stack/references/health-check.md +1 -1
- package/src/skf-verify-stack/references/init.md +20 -25
- package/src/skf-verify-stack/references/integration-verification-rules.md +10 -19
- package/src/skf-verify-stack/references/integrations.md +44 -49
- package/src/skf-verify-stack/references/report.md +28 -34
- package/src/skf-verify-stack/references/requirements.md +3 -3
- package/src/skf-verify-stack/references/synthesize.md +36 -39
- package/src/skf-verify-stack/scripts/skf-coverage-tally.py +196 -0
- package/src/skf-verify-stack/scripts/skf-report-delta.py +256 -0
- package/src/skf-verify-stack/scripts/skf-verdict-rollup.py +258 -0
- package/tools/cli/lib/ui.js +3 -2
- package/docs/deepwiki.md +0 -89
- package/src/skf-rename-skill/references/rebuild-context.md +0 -110
|
@@ -25,68 +25,17 @@ Display the final summary of the forged stack skill with confidence distribution
|
|
|
25
25
|
|
|
26
26
|
## MANDATORY SEQUENCE
|
|
27
27
|
|
|
28
|
-
### 1.
|
|
28
|
+
### 1. Report the Forge Result
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
Surface the forge result to the console, leading with the win:
|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
- **Headline:** stack `{project_name}-stack` — `{lib_count}` libraries, `{integration_count}` integration patterns, forge tier `{tier}`.
|
|
33
|
+
- **Confidence distribution:** the T1 / T1-low / T2 counts (T1 = AST-verified structural extraction, T1-low = source-reading inference, T2 = QMD-enriched temporal context). **In compose-mode**, note the tiers are inherited from the source skills — they reflect the extraction method used when those skills were originally generated, not the current compose run.
|
|
34
|
+
- **Output files:** the `{skill_package}` deliverables (SKILL.md, context-snippet.md with `{token_estimate}` tokens, metadata.json, `references/` per-library files, and `references/integrations/` pair files when integrations exist), the `{forge_version}` workspace (provenance-map.json, evidence-report.md), and the `{skill_group}/active -> {version}` symlink.
|
|
35
|
+
- **Validation:** all checks passed, or `{warning_count}` finding(s) each with its description.
|
|
36
|
+
- **Warnings — only if `workflow_warnings[]` is non-empty:** the accumulated entries rendered as `[{step}/{severity}] {code}: {message}`. `workflow_warnings[]` (defined in SKILL.md's *Workflow state contract*) is the single sink surfacing every warning pushed during the run; if it is empty, omit this section.
|
|
33
37
|
|
|
34
|
-
### 2.
|
|
35
|
-
|
|
36
|
-
"**Confidence distribution:**
|
|
37
|
-
|
|
38
|
-
| Tier | Count | Description |
|
|
39
|
-
|------|-------|-------------|
|
|
40
|
-
| T1 | {count} | AST-verified structural extraction |
|
|
41
|
-
| T1-low | {count} | Source reading inference |
|
|
42
|
-
| T2 | {count} | QMD-enriched temporal context |
|
|
43
|
-
|
|
44
|
-
{IF compose_mode:}
|
|
45
|
-
*Note: Confidence tiers above are inherited from source skills — they reflect the extraction method used when those skills were originally generated, not the current compose run.*
|
|
46
|
-
{END IF}"
|
|
47
|
-
|
|
48
|
-
### 3. Display Output File Summary
|
|
49
|
-
|
|
50
|
-
"**Output files:**
|
|
51
|
-
|
|
52
|
-
**Deliverables** (`{skill_package}`):
|
|
53
|
-
- SKILL.md — Integration patterns, library summaries, conventions
|
|
54
|
-
- context-snippet.md — Compressed stack index ({token_estimate} tokens)
|
|
55
|
-
- metadata.json — Skill metadata and library registry
|
|
56
|
-
- references/ — {lib_count} per-library reference files
|
|
57
|
-
{If integrations:} - references/integrations/ — {pair_count} integration pair files
|
|
58
|
-
|
|
59
|
-
**Workspace** (`{forge_version}`):
|
|
60
|
-
- provenance-map.json — Extraction source tracking
|
|
61
|
-
- evidence-report.md — Evidence and confidence breakdown
|
|
62
|
-
|
|
63
|
-
**Symlink:** `{skill_group}/active` -> `{version}`"
|
|
64
|
-
|
|
65
|
-
### 4. Display Validation Summary
|
|
66
|
-
|
|
67
|
-
**If validation passed with no findings:**
|
|
68
|
-
|
|
69
|
-
"**Validation:** All checks passed"
|
|
70
|
-
|
|
71
|
-
**If validation had findings:**
|
|
72
|
-
|
|
73
|
-
"**Validation:** {warning_count} warning(s) found
|
|
74
|
-
{For each finding:}
|
|
75
|
-
- ⚠ {description}"
|
|
76
|
-
|
|
77
|
-
### 5. Display Warnings (Conditional)
|
|
78
|
-
|
|
79
|
-
Read from the `workflow_warnings[]` accumulator defined in the Workflow Rules of `SKILL.md` (M4). Every step that emitted a warning during this run pushed a structured entry there — this section is the single sink that surfaces them.
|
|
80
|
-
|
|
81
|
-
**Only display if `workflow_warnings[]` is non-empty:**
|
|
82
|
-
|
|
83
|
-
"**Warnings:**
|
|
84
|
-
{For each entry in workflow_warnings[]:}
|
|
85
|
-
- [{step}/{severity}] {code}: {message}"
|
|
86
|
-
|
|
87
|
-
**If `workflow_warnings[]` is empty:** Skip this section entirely.
|
|
88
|
-
|
|
89
|
-
### 6. Recommend Next Workflows
|
|
38
|
+
### 2. Recommend Next Workflows
|
|
90
39
|
|
|
91
40
|
"**Next steps:**
|
|
92
41
|
- **[TS] test-skill** — Validate the stack skill against its own assertions
|
|
@@ -94,7 +43,7 @@ Read from the `workflow_warnings[]` accumulator defined in the Workflow Rules of
|
|
|
94
43
|
|
|
95
44
|
- **[VS] verify-stack** — Validate the stack's integration feasibility against your architecture document{IF compose_mode:} (re-run to confirm feasibility after any architecture changes from **[RA] refine-architecture**){END IF}"
|
|
96
45
|
|
|
97
|
-
###
|
|
46
|
+
### 2b. Result Contract
|
|
98
47
|
|
|
99
48
|
Write the result contract per `shared/references/output-contract-schema.md` using the shared atomic writer. Two artifacts — both written via `skf-atomic-write.py write`:
|
|
100
49
|
|
|
@@ -122,7 +71,23 @@ Include `SKILL.md`, `context-snippet.md`, and `metadata.json` paths in `outputs`
|
|
|
122
71
|
|
|
123
72
|
If either atomic write fails, log the error, leave any prior `-latest.json` untouched, and continue — the report is advisory and should not block the health-check chain.
|
|
124
73
|
|
|
125
|
-
|
|
74
|
+
**Headless success envelope.** When `{headless_mode}` is true, emit the single-line result envelope on **stdout** (the success counterpart to the error envelopes every HARD HALT emits on stderr) before chaining to step 10. `skill_package` is the absolute path to the committed package; `stack_libraries` is the included library names:
|
|
75
|
+
|
|
76
|
+
```
|
|
77
|
+
SKF_STACK_RESULT_JSON: {"status":"success","skill_package":"{skill_package}","skill_name":"{project_name}-stack","stack_libraries":["<lib>", "..."],"mode":"{code|compose}","exit_code":0,"halt_reason":null}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### 2c. Post-Completion Hook (optional)
|
|
81
|
+
|
|
82
|
+
If `{onCompleteCommand}` (resolved at SKILL.md On Activation §3 from `workflow.on_complete`) is non-empty, invoke it now — after the result contract (§2b) is written, before chaining to health-check:
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
{onCompleteCommand}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Run it with a bounded timeout (default 60s). On success, continue. On non-zero exit, timeout, or any failure, append the reason to `workflow_warnings[]` (e.g. `on_complete — failed (exit {N}): {stderr_first_line}`) and continue. **The hook must never fail the workflow** — it is integration glue (catalog registration, downstream pipeline notify) orthogonal to the forged stack. When `{onCompleteCommand}` is empty (bundled default), skip this section entirely.
|
|
89
|
+
|
|
90
|
+
### 3. Chain to Health Check
|
|
126
91
|
|
|
127
|
-
|
|
92
|
+
After the report sections above are handled, load, read the full file, and execute `{nextStepFile}`. The health-check step is the true terminal step — do not stop here even though the report reads as final.
|
|
128
93
|
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
---
|
|
2
2
|
nextStepFile: 'report.md'
|
|
3
|
-
|
|
3
|
+
outputValidatorProbeOrder:
|
|
4
|
+
- '{project-root}/_bmad/skf/shared/scripts/skf-validate-output.py'
|
|
5
|
+
- '{project-root}/src/shared/scripts/skf-validate-output.py'
|
|
4
6
|
---
|
|
5
7
|
|
|
6
8
|
<!-- Config: communicate in {communication_language}. Artifact text in {document_output_language}. -->
|
|
@@ -20,12 +22,25 @@ Validate all written output files against their expected structure and verify co
|
|
|
20
22
|
|
|
21
23
|
### 1. Verify File Existence
|
|
22
24
|
|
|
23
|
-
|
|
25
|
+
Run the shared deterministic output validator once against the committed package — it checks the three core deliverable files' existence, SKILL.md frontmatter, and context-snippet format/token in a single call, so this step consumes its JSON rather than re-deriving those by hand. Resolve `{outputValidator}` from `{outputValidatorProbeOrder}` (first existing path wins). If neither candidate exists, log a WARNING (`"output validator unavailable — skf-validate-output.py missing"`) and fall back to the manual file/frontmatter/snippet checks below.
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
python3 {outputValidator} {skill_package} --generated-by create-stack-skill --skill-type stack
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Consume from its JSON:
|
|
32
|
+
|
|
33
|
+
- `files_found` — existence of `SKILL.md` / `context-snippet.md` / `metadata.json` (the three core deliverable rows below).
|
|
34
|
+
- `validation.skill_md.frontmatter` — feeds the frontmatter check in §3 (manual-fallback path).
|
|
35
|
+
- `validation.context_snippet.issues` — feeds §8.
|
|
36
|
+
- `validation.stack_counts` — the stack count-equalities, derived deterministically from disk + metadata by the `--skill-type stack` pass: `issues[]` (each `{severity, field, message}`, one per mismatch of `library_count` / `integration_count` / `confidence_distribution`; empty when all agree) and `observed` (`library_count_meta`, `ref_file_count`, `integration_count_meta`, `pair_file_count`, `confidence_sum`). Feeds the count rows in §5 and the confidence-sum row in §7 — do not re-count files or re-sum the distribution by hand.
|
|
37
|
+
|
|
38
|
+
**Under `--skill-type stack`, `validation.skill_md.body` and `validation.metadata` are emitted as `{"skipped": ...}` markers** — the *individual-skill* schema (which looks for `## Overview` / `Description` / `Key Exports` / `Usage` sections and a `source_repo` field) does not apply to a stack package, so the validator skips those passes and runs `validation.stack_counts` instead. Stack-shaped body structure and the remaining (non-count) metadata fields are checked in §4 / §5.
|
|
39
|
+
|
|
40
|
+
Then confirm the remaining files the validator does not cover:
|
|
24
41
|
|
|
25
42
|
**Deliverables** (`{skill_package}`):
|
|
26
|
-
- [ ] SKILL.md
|
|
27
|
-
- [ ] context-snippet.md
|
|
28
|
-
- [ ] metadata.json
|
|
43
|
+
- [ ] SKILL.md · context-snippet.md · metadata.json — from `files_found` above
|
|
29
44
|
- [ ] references/ directory with per-library files
|
|
30
45
|
- [ ] references/integrations/ directory with pair files (if integrations detected)
|
|
31
46
|
|
|
@@ -36,7 +51,7 @@ Check that all expected files exist from written_files[]:
|
|
|
36
51
|
**Symlink:**
|
|
37
52
|
- [ ] `{skill_group}/active` exists and resolves to `{version}`
|
|
38
53
|
|
|
39
|
-
Record any missing files as **ERROR** findings.
|
|
54
|
+
Record any missing files (from `files_found` or the manual rows) as **ERROR** findings.
|
|
40
55
|
|
|
41
56
|
### 2. Check Tool Availability
|
|
42
57
|
|
|
@@ -57,21 +72,15 @@ timeout 10s npx --no-install skill-check -h
|
|
|
57
72
|
|
|
58
73
|
This validates frontmatter, description, body limits, links, formatting — and auto-fixes deterministic issues. Parse JSON for `scores[].score` (match the entry by `relativePath`/`skillId`; falls back to a top-level `qualityScore` on older skill-check builds), `diagnostics[]`, `fixed[]`.
|
|
59
74
|
|
|
60
|
-
**Post-fix provenance drift guard (S15):** If `fixed[]` is non-empty, `skill-check --fix` has modified `SKILL.md` after step 7 wrote it.
|
|
75
|
+
**Post-fix provenance drift guard (S15):** If `fixed[]` is non-empty, `skill-check --fix` has modified `SKILL.md` after step 7 wrote it — so the `metadata.json` hashes/provenance recorded against the pre-fix body may now be stale. Emit a **WARNING** finding listing each auto-fix (`"skill-check --fix modified SKILL.md: {fix_description} — metadata.json hashes/provenance may be out of date"`) rather than silently accepting the fixes, so the drift is surfaced. If the caller wants authoritative metadata, they should re-run the workflow.
|
|
61
76
|
|
|
62
|
-
**If `body.max_lines` reported**, prefer selective split: extract only the largest Tier 2 section(s) to `references/`, keeping Tier 1 content inline (inline passive context achieves 100% task accuracy vs 79% for on-demand retrieval). For a stack capstone the canonical split is the catalog (`Library Reference Index` + `Per-Library Summaries`) → `references/stack-catalog.md`, leaving an inline pointer (see `{
|
|
77
|
+
**If `body.max_lines` reported**, prefer selective split: extract only the largest Tier 2 section(s) to `references/`, keeping Tier 1 content inline (inline passive context achieves 100% task accuracy vs 79% for on-demand retrieval). For a stack capstone the canonical split is the catalog (`Library Reference Index` + `Per-Library Summaries`) → `references/stack-catalog.md`, leaving an inline pointer (see `{stackSkillTemplatePath}` "Sizing Guidance"). This is the **intended** large-stack layout, not a violation: §4 below accepts the pointer form, so clearing the skill-check body ERROR this way does not also trip the structure check. Fall back to `npx skill-check split-body <skill-dir> --write` if not feasible. Verify any in-SKILL.md anchor links (e.g. to the catalog/pointer or other moved sections) still resolve after the split. Then re-validate.
|
|
63
78
|
|
|
64
|
-
**If unavailable**,
|
|
65
|
-
- [ ] Frontmatter present with `---` delimiters
|
|
66
|
-
- [ ] `name` — present, non-empty, lowercase alphanumeric + hyphens, 1-64 chars, matches `{project_name}-stack`
|
|
67
|
-
- [ ] `description` — present, non-empty, 1-1024 characters
|
|
68
|
-
- [ ] No unknown fields — only `name`, `description`, `license`, `compatibility`, `metadata`, `allowed-tools` permitted
|
|
69
|
-
|
|
70
|
-
Record frontmatter violations as **WARNING** findings. Invalid frontmatter will fail `npx skills add` and `npx skill-check check`.
|
|
79
|
+
**If unavailable**, do not hand-walk the frontmatter — use `validation.skill_md.frontmatter` from the §1 output-validator run, which checks delimiters, `name` format + directory match (`{project_name}-stack`), `description` presence/length, and unknown fields against the agentskills.io allow-set. Record each reported issue at its severity as a **WARNING** finding. (If the output validator was *also* unavailable in §1, fall back to the manual checklist: `---` delimiters; `name` lowercase-alphanumeric-plus-hyphens 1-64 chars matching `{project_name}-stack`; `description` present and 1-1024 chars; only `name`/`description`/`license`/`compatibility`/`metadata`/`allowed-tools` permitted.) Invalid frontmatter will fail `npx skills add` and `npx skill-check check`.
|
|
71
80
|
|
|
72
81
|
### 4. Validate SKILL.md Body Structure
|
|
73
82
|
|
|
74
|
-
Load `{
|
|
83
|
+
Load `{stackSkillTemplatePath}` and verify SKILL.md contains expected sections:
|
|
75
84
|
|
|
76
85
|
- [ ] Header with project name, library count, integration count, forge tier
|
|
77
86
|
- [ ] Integration Patterns section (before per-library summaries)
|
|
@@ -93,11 +102,12 @@ Parse metadata.json and verify required fields:
|
|
|
93
102
|
- [ ] `version` and `generation_date` present
|
|
94
103
|
- [ ] `forge_tier` is present and matches the forge tier from step 01 (`Quick|Forge|Forge+|Deep`)
|
|
95
104
|
- [ ] `confidence_tier` is present and is exactly one of `T1|T1-low|T2|T3` — the dominant T-code computed from `confidence_distribution` (pick the tier with the highest count; ties resolve to the weaker tier: T1-low > T1, T2 > T1-low, T3 > T2 for tie-break so the reported tier never overstates confidence)
|
|
96
|
-
- [ ] `library_count` matches actual reference files; `integration_count` matches pair files
|
|
97
105
|
- [ ] `libraries` array present and non-empty
|
|
98
106
|
- [ ] `confidence_distribution` object present with `t1`, `t1_low`, `t2`, `t3` keys (lowercase, matching template definition)
|
|
99
107
|
|
|
100
|
-
|
|
108
|
+
**Count equalities (library / integration)** — do NOT re-count files here; take them from `validation.stack_counts` in the §1 output-validator run (invoked with `--skill-type stack`), which derived them deterministically from disk. The `library_count` vs per-library reference files and `integration_count` vs integration pair files checks surface as `field: "library_count"` / `field: "integration_count"` entries in `validation.stack_counts.issues[]` (absent when they agree); echo the exact numbers from `validation.stack_counts.observed` (`library_count_meta` / `ref_file_count`, `integration_count_meta` / `pair_file_count`). The `confidence_distribution`-sum equality is covered in §7.
|
|
109
|
+
|
|
110
|
+
Record each `validation.stack_counts.issues[]` count entry (`library_count` / `integration_count`) and any other mismatch above as **WARNING** findings.
|
|
101
111
|
|
|
102
112
|
### 6. Validate Reference File Completeness
|
|
103
113
|
|
|
@@ -113,17 +123,17 @@ Scan all output files for confidence tier coverage:
|
|
|
113
123
|
|
|
114
124
|
- [ ] SKILL.md: each per-library summary and integration pair entry has a confidence label
|
|
115
125
|
- [ ] Reference files: each has a confidence label in its header
|
|
116
|
-
- [ ] metadata.json: confidence_distribution sums
|
|
126
|
+
- [ ] metadata.json: `confidence_distribution` sums to `library_count` — take this from the §1 output-validator run (`--skill-type stack`): the `field: "confidence_distribution"` entry in `validation.stack_counts.issues[]` is present only on mismatch, with `validation.stack_counts.observed.confidence_sum` vs `library_count_meta` for the exact numbers. Do not re-sum the distribution by hand.
|
|
117
127
|
|
|
118
|
-
Record missing tier labels as **WARNING** findings.
|
|
128
|
+
Record missing tier labels and any `validation.stack_counts` `confidence_distribution` issue as **WARNING** findings.
|
|
119
129
|
|
|
120
130
|
### 8. Validate context-snippet.md
|
|
121
131
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
-
|
|
132
|
+
Take the first-line format, `|IMPORTANT:` second-line, and token-estimate checks from `validation.context_snippet.issues` returned by the §1 output-validator run — it performs the line-1 `[name vVersion]|root:` pattern match, the line-2 check, and the `len(content)//4` token estimate deterministically, so this step does not recompute them. Record each reported issue as a **WARNING** finding.
|
|
133
|
+
|
|
134
|
+
Then verify the two stack-specific rows the generic validator does not cover:
|
|
125
135
|
- [ ] Stack and integrations lines present
|
|
126
|
-
- [ ]
|
|
136
|
+
- [ ] Token estimate lands near the ~80-120 design target from step 7 §5 (the validator flags only its wider <40 / >200 bounds; an ~80-150 snippet with an overflow-strategy `workflow_warning` is expected, not a defect)
|
|
127
137
|
|
|
128
138
|
Record format violations as **WARNING** findings.
|
|
129
139
|
|
|
@@ -137,13 +147,7 @@ Record security findings as advisory **WARNING** findings — they do not block
|
|
|
137
147
|
|
|
138
148
|
### 10. Display Validation Results
|
|
139
149
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
"**Validation complete — all checks passed.** Files: {count}/{count} present. SKILL.md structure valid. metadata.json fields verified. {lib_count} library + {pair_count} integration files verified. Confidence tiers: complete coverage. **Proceeding to summary report...**"
|
|
143
|
-
|
|
144
|
-
**If warnings found:**
|
|
145
|
-
|
|
146
|
-
"**Validation complete with {warning_count} finding(s).** Findings: {list each: severity, description, file_path}. Files: {present}/{expected} present. Warnings: {count}. Errors: {count}. {If errors: Note missing files may indicate a write failure in step 07.} **Proceeding to summary report...**"
|
|
150
|
+
Report the validation outcome. If all checks passed, state so and name what was verified: file presence (`{count}/{count}`), SKILL.md structure, metadata.json fields, the `{lib_count}` library + `{pair_count}` integration reference files, and complete confidence-tier coverage. If there were findings, report the `{warning_count}` finding(s) — each with severity, description, and file path — plus files present/expected and warning/error counts; when errors include missing files, note this may indicate a write failure in step 07.
|
|
147
151
|
|
|
148
152
|
### 11. Auto-Proceed to Next Step
|
|
149
153
|
|
|
@@ -7,7 +7,7 @@ description: Drop a specific skill version or an entire skill — soft (deprecat
|
|
|
7
7
|
|
|
8
8
|
## Overview
|
|
9
9
|
|
|
10
|
-
Drops a specific skill version or an entire skill, either as a soft deprecation (manifest-only, files retained) or a hard purge (files deleted). Ensures platform context files are rebuilt to exclude dropped versions.
|
|
10
|
+
Drops a specific skill version or an entire skill, either as a soft deprecation (manifest-only, files retained) or a hard purge (files deleted). Ensures platform context files are rebuilt to exclude dropped versions. In interactive mode every destructive action requires explicit user confirmation — nothing is deleted silently; headless runs auto-resolve the gates with their default action and log each auto-decision. The export manifest is the source of truth; the filesystem is updated to match.
|
|
11
11
|
|
|
12
12
|
## Conventions
|
|
13
13
|
|
|
@@ -21,13 +21,13 @@ Drops a specific skill version or an entire skill, either as a soft deprecation
|
|
|
21
21
|
|
|
22
22
|
## Role
|
|
23
23
|
|
|
24
|
-
You are Ferris in Management mode — a destructive operation specialist who enforces safety guards. You treat every drop as potentially irreversible and
|
|
24
|
+
You are Ferris in Management mode — a destructive operation specialist who enforces safety guards. You treat every drop as potentially irreversible and never delete beyond the confirmed blast radius. You protect the active version, keep the export manifest consistent with on-disk state, and ensure downstream platform context files are rebuilt.
|
|
25
25
|
|
|
26
26
|
## Workflow Rules
|
|
27
27
|
|
|
28
28
|
These rules apply to every step in this workflow:
|
|
29
29
|
|
|
30
|
-
- Never delete files without
|
|
30
|
+
- Never delete files in purge mode without clearing the §10 confirmation gate (auto-resolved with its default in headless)
|
|
31
31
|
- Never drop an active version when other non-deprecated versions exist — enforce the active version guard
|
|
32
32
|
- Only load one step file at a time — never preload future steps
|
|
33
33
|
- If any instruction references a subprocess or tool you lack, achieve the outcome in your main context thread
|
|
@@ -52,31 +52,25 @@ These rules apply to every step in this workflow:
|
|
|
52
52
|
| **Flags** | `--headless` / `-H` (auto-resolve all gates); `--dry-run` (run selection + display the §10 confirmation block, then exit with `status="dry-run"` — no manifest mutation, no file deletion). Useful for "show me what this would touch before I commit." |
|
|
53
53
|
| **Gates** | step 1: Input Gate [use args], Confirm Gate [Y] |
|
|
54
54
|
| **Outputs** | Updated manifest, rebuilt context files, (purge: deleted directories), `drop-skill-result-{timestamp}.json` and `drop-skill-result-latest.json` |
|
|
55
|
-
| **Headless** |
|
|
55
|
+
| **Headless** | Gates auto-resolve with their default action (see Workflow Rules). When `forbid_purge_in_headless` is `"true"` in `customize.toml` AND the effective drop mode is `"purge"` (defined in On-Activation §4 — explicit `mode=purge` or `default_mode` purge), §4 HALTs with exit code 6 (`halt_reason: "headless-purge-forbidden"`) before any work begins. |
|
|
56
56
|
| **Exit codes** | See "Exit Codes" below |
|
|
57
57
|
|
|
58
58
|
## Exit Codes
|
|
59
59
|
|
|
60
|
-
Every
|
|
60
|
+
Every hard HALT exits with a stable code so headless automators branch on the failure class without grepping message text. The `Raised by` column names the HALT class per code; the authoritative per-site declarations (with exact `halt_reason`) live in the step files.
|
|
61
61
|
|
|
62
|
-
| Code | Meaning | Raised by
|
|
63
|
-
| ---- | -------------------- |
|
|
64
|
-
| 0 | success | step 4 (terminal)
|
|
65
|
-
| 2 | input-missing / input-invalid | step 1
|
|
66
|
-
| 3 | resolution-failure | step 1
|
|
67
|
-
| 4 | write-failure | On-Activation
|
|
68
|
-
| 5 | state-conflict | step 1
|
|
69
|
-
| 6 | user-cancelled |
|
|
62
|
+
| Code | Meaning | Raised by (class) |
|
|
63
|
+
| ---- | -------------------- | ----------------- |
|
|
64
|
+
| 0 | success | step 4 (terminal) |
|
|
65
|
+
| 2 | input-missing / input-invalid | step 1 headless input gates — missing or unmatched `skill_name`, `version`, or `--mode` value (§4 / §6 / §8) |
|
|
66
|
+
| 3 | resolution-failure | step 1 manifest/skill-list resolution (§2 corrupt manifest, §3 nothing to drop) |
|
|
67
|
+
| 4 | write-failure | On-Activation write probe; step 2 manifest write / context rebuild / full-purge failure |
|
|
68
|
+
| 5 | state-conflict | step 1 active-version guard (§7) |
|
|
69
|
+
| 6 | user-cancelled | any interactive cancel or confirm-gate `[N]`; On-Activation headless-purge guard |
|
|
70
70
|
|
|
71
71
|
## Result Contract (Headless)
|
|
72
72
|
|
|
73
|
-
When `{headless_mode}` is true, step 3 emits a single-line
|
|
74
|
-
|
|
75
|
-
```
|
|
76
|
-
SKF_DROP_SKILL_RESULT_JSON: {"status":"success|error|dry-run","skill":"…|null","drop_mode":"…|null","versions_affected":[],"files_deleted":[],"manifest_updated":false,"exit_code":0,"halt_reason":null}
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
`status` is `"success"` on the terminal happy path, `"dry-run"` when `--dry-run` was set and the workflow exited before §11 stores decisions, `"error"` on any HALT. `halt_reason` is one of: `null` (success), `"input-missing"`, `"input-invalid"`, `"manifest-corrupt"`, `"nothing-to-drop"`, `"active-version-guard-refused"`, `"headless-purge-forbidden"`, `"manifest-write-failed"`, `"context-rebuild-failed"`, `"delete-failed"`, `"write-failed"`, `"user-cancelled"`. `exit_code` matches the table above.
|
|
73
|
+
When `{headless_mode}` is true, step 3 emits a single-line `SKF_DROP_SKILL_RESULT_JSON:` envelope on **stdout**; every HARD HALT emits the same shape on **stderr** with `status: "error"`. The template, `status`/`halt_reason` semantics, `exit_code` (per the Exit Codes table above), and full enum live in `references/headless-contract.md` — the emitting stages load it directly, so an error path never depends on this file.
|
|
80
74
|
|
|
81
75
|
## On Activation
|
|
82
76
|
|
|
@@ -103,14 +97,17 @@ SKF_DROP_SKILL_RESULT_JSON: {"status":"success|error|dry-run","skill":"…|null"
|
|
|
103
97
|
|
|
104
98
|
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 scalar.
|
|
105
99
|
|
|
106
|
-
Apply the scalar fallback now so stage files don't have to repeat the conditional logic. For each of the
|
|
100
|
+
Apply the scalar fallback now so stage files don't have to repeat the conditional logic. For each of the five scalars, if the merged value is empty or absent, the bundled default applies:
|
|
107
101
|
|
|
108
102
|
- `{defaultMode}` ← `workflow.default_mode` (empty = always prompt; `"deprecate"` or `"purge"` = skip §8 Ask Mode)
|
|
109
103
|
- `{forbidPurgeInHeadless}` ← `workflow.forbid_purge_in_headless` (empty or non-`"true"` = no guard)
|
|
110
104
|
- `{unknownIdeDefaultContextFile}` ← `workflow.unknown_ide_default_context_file` if non-empty, else `AGENTS.md`
|
|
111
105
|
- `{unknownIdeDefaultSkillRoot}` ← `workflow.unknown_ide_default_skill_root` if non-empty, else `.agents/skills/`
|
|
106
|
+
- `{onCompleteCommand}` ← `workflow.on_complete` if non-empty, else empty (no-op — step 3 skips the post-drop hook entirely)
|
|
107
|
+
|
|
108
|
+
Stash all five as workflow-context variables. Stage files reference them directly — no conditional at the usage site.
|
|
112
109
|
|
|
113
|
-
|
|
110
|
+
Also apply the array surfaces: run `workflow.activation_steps_prepend` now, keep `workflow.persistent_facts` as standing context (`file:` entries load their contents), then run `workflow.activation_steps_append` after.
|
|
114
111
|
|
|
115
112
|
4. **Pre-flight write probe + headless-purge guard.**
|
|
116
113
|
|
|
@@ -124,6 +121,6 @@ SKF_DROP_SKILL_RESULT_JSON: {"status":"success|error|dry-run","skill":"…|null"
|
|
|
124
121
|
|
|
125
122
|
On any non-zero exit: HALT (exit code 4, `halt_reason: "write-failed"`). In headless mode, emit the error envelope per **Result Contract (Headless)** with `skill: null` and `drop_mode: null` (neither is resolved yet at activation time).
|
|
126
123
|
|
|
127
|
-
Second, enforce the headless-purge guard. If `{headless_mode}` is true AND `{forbidPurgeInHeadless}` is `"true"` AND the
|
|
124
|
+
Second, enforce the headless-purge guard. First compute the **effective drop mode**: it is `"purge"` when the parsed `mode` arg is `"purge"`, OR when no `mode` arg was passed AND `{defaultMode}` (resolved in §3) is `"purge"` — a purge reached via `default_mode` is still an unattended irreversible purge and must be caught here, not only an explicit `--mode purge`. If `{headless_mode}` is true AND `{forbidPurgeInHeadless}` is `"true"` AND the effective drop mode is `"purge"`: HALT with exit code 6 and `halt_reason: "headless-purge-forbidden"`, emit the error envelope, and exit immediately. The operator must re-run with an explicit `mode=deprecate` (an explicit arg overrides `default_mode`) or set `forbid_purge_in_headless = ""` (or omit the override entirely) to proceed.
|
|
128
125
|
|
|
129
126
|
5. Load, read the full file, and then execute `references/select.md` to begin the workflow.
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
# DO NOT EDIT -- overwritten on every update.
|
|
2
2
|
#
|
|
3
3
|
# Workflow customization surface for skf-drop-skill.
|
|
4
|
+
# Team overrides: {project-root}/_bmad/custom/skf-drop-skill.toml
|
|
5
|
+
# Personal overrides: {project-root}/_bmad/custom/skf-drop-skill.user.toml
|
|
4
6
|
|
|
5
7
|
[workflow]
|
|
6
8
|
|
|
@@ -34,6 +36,14 @@ persistent_facts = [
|
|
|
34
36
|
"file:{project-root}/**/project-context.md",
|
|
35
37
|
]
|
|
36
38
|
|
|
39
|
+
# Optional post-drop hook. When non-empty, invoked with
|
|
40
|
+
# `--result-path=<path>` after the drop-skill result JSON is finalized
|
|
41
|
+
# (references/report.md). Failures are logged to workflow_warnings[] but
|
|
42
|
+
# never fail the workflow — useful for audit-log emit, a notifier, or a
|
|
43
|
+
# ticket-tracker integration after an irreversible purge.
|
|
44
|
+
|
|
45
|
+
on_complete = ""
|
|
46
|
+
|
|
37
47
|
# --- Optional safety + default scalars ---
|
|
38
48
|
#
|
|
39
49
|
# Default drop mode. Empty string = always prompt the user at §8 Ask Mode.
|
|
@@ -18,6 +18,23 @@ manifestOpsProbeOrder:
|
|
|
18
18
|
rebuildManagedSectionsProbeOrder:
|
|
19
19
|
- '{project-root}/_bmad/skf/shared/scripts/skf-rebuild-managed-sections.py'
|
|
20
20
|
- '{project-root}/src/shared/scripts/skf-rebuild-managed-sections.py'
|
|
21
|
+
# Resolve `{updateActiveSymlinkHelper}` similarly. §4 uses it (update
|
|
22
|
+
# action) to atomically repoint `{skill_group}/active` after a version-level
|
|
23
|
+
# purge deletes the version the symlink pointed at — the helper does a
|
|
24
|
+
# temp-symlink + os.replace flip so concurrent readers never see a missing
|
|
25
|
+
# link. Matches skf-update-skill/references/write.md and
|
|
26
|
+
# skf-rename-skill/references/execute.md. HALT if neither candidate exists.
|
|
27
|
+
updateActiveSymlinkProbeOrder:
|
|
28
|
+
- '{project-root}/_bmad/skf/shared/scripts/skf-update-active-symlink.py'
|
|
29
|
+
- '{project-root}/src/shared/scripts/skf-update-active-symlink.py'
|
|
30
|
+
# Standalone single-line result-envelope contract emitted at every headless
|
|
31
|
+
# HALT in this step. Loaded in §1 so no error path depends on SKILL.md
|
|
32
|
+
# remaining in context under compaction.
|
|
33
|
+
headlessContract: 'headless-contract.md'
|
|
34
|
+
# Deterministic recursive byte sizing + human formatting for `disk_freed`
|
|
35
|
+
# (§4). Bundled with this skill; the same helper backs select.md §9b's
|
|
36
|
+
# blast-radius preview, so gate and report agree on the method.
|
|
37
|
+
dirSizesHelper: 'scripts/dir-sizes.py'
|
|
21
38
|
---
|
|
22
39
|
|
|
23
40
|
<!-- Config: communicate in {communication_language}. -->
|
|
@@ -43,6 +60,8 @@ Read `{versionPathsKnowledge}` again and confirm the templates and management op
|
|
|
43
60
|
|
|
44
61
|
Also read `{managedSectionLogic}` for the format template, the four-case logic, and the skill index rebuild rules that will be reused in section 3.
|
|
45
62
|
|
|
63
|
+
If `{headless_mode}` is true, also read `{headlessContract}` now — it defines the single-line result envelope the error paths below emit, so the shape is in context even if SKILL.md was compacted out.
|
|
64
|
+
|
|
46
65
|
### 2. Update Export Manifest
|
|
47
66
|
|
|
48
67
|
**If `target_in_manifest == false`** (draft skill discovered only by on-disk scan): Skip this section entirely. There is no manifest entry to deprecate or delete. Set `manifest_updated = false` and proceed directly to section 3. Step-01 forced `drop_mode = "purge"` and `is_skill_level = true` in this case, so the subsequent sections will hard-delete the on-disk directories without any manifest interaction.
|
|
@@ -75,7 +94,7 @@ Set context flag `manifest_updated = true`.
|
|
|
75
94
|
|
|
76
95
|
- Do not proceed to section 3
|
|
77
96
|
- Report: "**Manifest update failed:** {captured stderr}. No files were deleted and platform context files were not rebuilt. The manifest is in its pre-drop state — rerun the workflow once the underlying issue is resolved."
|
|
78
|
-
- Store `manifest_updated = false` and jump to section 6. In headless mode, emit the error envelope per
|
|
97
|
+
- Store `manifest_updated = false` and jump to section 6. In headless mode, emit the error envelope per `{headlessContract}` with `halt_reason: "manifest-write-failed"` and exit code 4.
|
|
79
98
|
|
|
80
99
|
### 3. Rebuild Context Files
|
|
81
100
|
|
|
@@ -84,9 +103,9 @@ Load the `ides` list from `config.yaml`. The installer writes IDE identifiers
|
|
|
84
103
|
**Resolve `target_context_files`** using the canonical mapping table in `{managedSectionLogic}`:
|
|
85
104
|
|
|
86
105
|
1. For each entry in `config.yaml.ides`, look up its `context_file` and `skill_root` from the mapping table
|
|
87
|
-
2. For any entry not found in the table, default to AGENTS.md / `.agents/skills/` and emit a warning: "Unknown IDE '{value}' in config.yaml — defaulting to
|
|
106
|
+
2. For any entry not found in the table, default to `{unknownIdeDefaultContextFile}` / `{unknownIdeDefaultSkillRoot}` (resolved at SKILL.md On Activation §3 from `workflow.unknown_ide_default_*`, bundled defaults `AGENTS.md` / `.agents/skills/`) and emit a warning: "Unknown IDE '{value}' in config.yaml — defaulting to {unknownIdeDefaultContextFile}"
|
|
88
107
|
3. Deduplicate by `context_file` — when multiple IDEs map to the same context file, use the first configured IDE's `skill_root`
|
|
89
|
-
4. If `config.yaml.ides` is absent or the mapping yields an empty list, fall back to `[{context_file: "
|
|
108
|
+
4. If `config.yaml.ides` is absent or the mapping yields an empty list, fall back to `[{context_file: "{unknownIdeDefaultContextFile}", skill_root: "{unknownIdeDefaultSkillRoot}"}]` and emit a note: "No IDEs configured in config.yaml — defaulting to {unknownIdeDefaultContextFile}"
|
|
90
109
|
|
|
91
110
|
Store the result as `target_context_files` for this section.
|
|
92
111
|
|
|
@@ -152,37 +171,62 @@ Report: "**Rebuilt managed sections in:** {list of updated files}. {if any faile
|
|
|
152
171
|
|
|
153
172
|
### 4. Delete Files (Purge Mode Only)
|
|
154
173
|
|
|
155
|
-
**If `drop_mode != "purge"`**, skip this section entirely. Set `files_deleted = []
|
|
174
|
+
**If `drop_mode != "purge"`**, skip this section entirely. Set `files_deleted = []`, `disk_freed = "N/A (soft drop)"`, `delete_failures = []`, and `purge_status = "success"`, then jump to section 5.
|
|
156
175
|
|
|
157
176
|
**If `drop_mode == "purge"`:**
|
|
158
177
|
|
|
159
|
-
1. Initialize `files_deleted = []` and `
|
|
178
|
+
1. Initialize `files_deleted = []` and `delete_failures = []` (paths whose deletion was attempted but did not succeed).
|
|
179
|
+
|
|
180
|
+
2. **Measure sizes before deleting anything.** Run the sizing helper once over `affected_directories` so each path's byte size is captured while it still exists:
|
|
181
|
+
|
|
182
|
+
```bash
|
|
183
|
+
uv run {dirSizesHelper} sizes {each path in affected_directories, space-separated}
|
|
184
|
+
```
|
|
160
185
|
|
|
161
|
-
|
|
186
|
+
Keep each `result.paths[].bytes` as `path_bytes[{path}]`; a path reported `exists: false` is already gone. If the helper is unavailable, fall back to `du -sb` per existing path.
|
|
187
|
+
|
|
188
|
+
3. For each directory path in `affected_directories`:
|
|
162
189
|
a. Verify the path is inside either `{skills_output_folder}` or `{forge_data_folder}` (defense in depth against accidental deletion of unrelated paths)
|
|
163
190
|
b. If the directory does not exist, record it as "(already absent)" and continue
|
|
164
|
-
c.
|
|
165
|
-
d.
|
|
166
|
-
e.
|
|
167
|
-
f. Append the path to `files_deleted` and add its byte size to `bytes_freed`
|
|
191
|
+
c. Delete the directory recursively
|
|
192
|
+
d. Verify deletion succeeded (the path no longer exists)
|
|
193
|
+
e. Append the path to `files_deleted`
|
|
168
194
|
|
|
169
|
-
|
|
195
|
+
4. **Version-level purge, single version:**
|
|
170
196
|
- `{skills_output_folder}/{target_skill}/{version}/` is deleted, but `{skills_output_folder}/{target_skill}/` remains (it still contains other versions or the `active` symlink)
|
|
171
|
-
- If the `active` symlink pointed to the just-deleted version, update or remove it
|
|
172
|
-
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
197
|
+
- If the `active` symlink pointed to the just-deleted version, update or remove it. The version directory is already gone at this point, so a symlink problem never claims `delete-failed` — record it and continue (`verification_errors`) so the report surfaces the manual repair rather than masking a successful purge.
|
|
198
|
+
- **Other non-deprecated versions remain** for `{target_skill}`: resolve `{new_active_version}` = the version the manifest now lists as `active_version` for `{target_skill}` (if that one is deprecated, the newest non-deprecated version in its `versions` map). Repoint `active` to it atomically through the shared helper rather than a hand-rolled `ln` — resolve `{updateActiveSymlinkHelper}` from `{updateActiveSymlinkProbeOrder}` (first existing path wins), then:
|
|
199
|
+
```bash
|
|
200
|
+
python3 {updateActiveSymlinkHelper} update \
|
|
201
|
+
--skill-group {skills_output_folder}/{target_skill} \
|
|
202
|
+
--version {new_active_version}
|
|
203
|
+
```
|
|
204
|
+
The helper does a temp-symlink + `os.replace` flip, so a concurrent reader never sees a missing `active`. Record a `mismatch`/`missing-target` exit (code 2), or a missing helper (no probe candidate), in `verification_errors` with the manual fix (`ln -sfn {new_active_version} {skills_output_folder}/{target_skill}/active`) and continue.
|
|
205
|
+
- **No non-deprecated versions remain** (reachable only when dropping the sole surviving version, permitted in step 1 because no other non-deprecated versions existed): remove the now-dangling `active` symlink with a single atomic unlink of the link itself — `rm {skills_output_folder}/{target_skill}/active` (unlink removes only the symlink, never its target, and is atomic). A single unlink has one correct outcome and no intermediate state, so it stays in-prompt (the helper has no removal action).
|
|
206
|
+
|
|
207
|
+
5. **Skill-level purge:**
|
|
176
208
|
- `{skills_output_folder}/{target_skill}/` and `{forge_data_folder}/{target_skill}/` are deleted in full — the `active` symlink disappears with the parent directory
|
|
177
209
|
|
|
178
|
-
|
|
210
|
+
6. Sum the sizes of the paths in `files_deleted` and format one human-readable label through the helper — do not add or round in-prompt:
|
|
211
|
+
|
|
212
|
+
```bash
|
|
213
|
+
uv run {dirSizesHelper} humanize {path_bytes[p] for each p in files_deleted, space-separated}
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
Store `result.total_human` as `disk_freed` (e.g. `"4.2 MB"`; `"0 B"` when nothing was deleted).
|
|
179
217
|
|
|
180
|
-
**On deletion error:**
|
|
218
|
+
**On deletion error (per path):**
|
|
181
219
|
|
|
182
|
-
-
|
|
183
|
-
- Continue attempting the remaining paths — partial purge is still better than no purge
|
|
220
|
+
- Append the path and its error message to `delete_failures`
|
|
221
|
+
- Continue attempting the remaining paths — a partial purge is still better than no purge
|
|
184
222
|
- Report all failures at the end of this section
|
|
185
223
|
|
|
224
|
+
**After the loop — classify the deletion outcome.** Let `attempted` be the number of paths in `affected_directories` that existed on disk (i.e. were not recorded as "(already absent)"):
|
|
225
|
+
|
|
226
|
+
- **Full purge failure** — `attempted > 0` AND every attempted path is in `delete_failures` (nothing was deleted): the purge accomplished none of its destructive intent, so it must NOT report success. HALT (exit code 4, `halt_reason: "delete-failed"`): "**Purge failed** — none of the {attempted} target director(ies) could be deleted: {list each path with its error}. The manifest and context files were already updated in sections 2–3; the on-disk files remain and can be removed manually (`rm -rf {path}`)." In headless mode, emit the error envelope per `{headlessContract}` with the resolved `skill`, `drop_mode`, `versions_affected`, `files_deleted: []`, and `manifest_updated` from section 2. Do not proceed to section 5.
|
|
227
|
+
- **Partial purge failure** — `delete_failures` is non-empty but at least one path was deleted: keep record-and-continue. Set `purge_status = "partial"` so step 3's on-disk result record reflects it (the `output-contract-schema.md` `status` enum supports `"partial"`); proceed to section 5. The headless single-line envelope has no `"partial"` value in its enum, so it stays `"success"` while `context_files_failed`/`verification_errors`/the report surface the unfreed paths.
|
|
228
|
+
- **No failures** — `delete_failures` is empty: set `purge_status = "success"` and proceed to section 5.
|
|
229
|
+
|
|
186
230
|
### 5. Verify Final State
|
|
187
231
|
|
|
188
232
|
Run these verification checks:
|
|
@@ -203,6 +247,8 @@ Store the following for step 3:
|
|
|
203
247
|
|
|
204
248
|
- `files_deleted` — list of directory paths actually deleted (purge mode) or `[]` (soft drop)
|
|
205
249
|
- `disk_freed` — human-readable size (purge mode) or `"N/A (soft drop)"`
|
|
250
|
+
- `delete_failures` — list of `{path, error}` for paths whose deletion was attempted but failed (empty if none; a *full* purge failure already HALTed in section 4 and never reaches this step)
|
|
251
|
+
- `purge_status` — `"success"`, `"partial"` (some paths failed to delete), or `"success"` for soft drops; step 3 maps this to the on-disk result record's `status` field
|
|
206
252
|
- `manifest_updated` — boolean (true if section 2 succeeded)
|
|
207
253
|
- `context_files_updated` — list of successfully rebuilt files
|
|
208
254
|
- `context_files_failed` — list of files that failed to rebuild (empty if none)
|
|
@@ -210,20 +256,5 @@ Store the following for step 3:
|
|
|
210
256
|
|
|
211
257
|
### 7. Load Next Step
|
|
212
258
|
|
|
213
|
-
Load, read the full file, and then execute
|
|
214
|
-
|
|
215
|
-
## Error Handling Summary
|
|
216
|
-
|
|
217
|
-
If any stage fails, record which stage failed and provide recovery guidance in the final report:
|
|
218
|
-
|
|
219
|
-
| Failed Stage | Recovery Guidance |
|
|
220
|
-
|--------------|-------------------|
|
|
221
|
-
| Manifest update | "Manifest is in pre-drop state. Re-run the workflow once the underlying I/O issue is resolved. No files were deleted." |
|
|
222
|
-
| Context file rebuild | "Manifest is already updated. Re-run `[EX] Export Skill` against any still-valid skill to regenerate the affected managed sections, or rerun the drop workflow." |
|
|
223
|
-
| File deletion (purge) | "Manifest and context files are consistent. Remaining directories listed in the report can be deleted manually: `rm -rf {path}`." |
|
|
224
|
-
| Verification | "Execution completed but post-write checks found drift. See the report for specific paths requiring manual review." |
|
|
225
|
-
|
|
226
|
-
## CRITICAL STEP COMPLETION NOTE
|
|
227
|
-
|
|
228
|
-
ONLY WHEN all execution stages have been attempted (manifest update, context rebuild, file deletion in purge mode, verification) and results have been stored in context, will you then load and read fully `{nextStepFile}` to generate the final report.
|
|
259
|
+
The report in `{nextStepFile}` renders from the results stored in §6, so chain to it only after every execution stage above has been attempted and its outcome stored. Load, read the full file, and then execute it.
|
|
229
260
|
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Headless Result Envelope
|
|
2
|
+
|
|
3
|
+
The single-line JSON contract every headless run of skf-drop-skill emits. It stands alone: the stages that emit it load this file directly, so an error path never depends on any other file staying in context under compaction.
|
|
4
|
+
|
|
5
|
+
When `{headless_mode}` is true, step 3 emits this envelope on **stdout** before chaining to step 4; every HARD HALT emits the same shape on **stderr** with `status: "error"`:
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
SKF_DROP_SKILL_RESULT_JSON: {"status":"success|error|dry-run","skill":"…|null","drop_mode":"…|null","versions_affected":[],"files_deleted":[],"manifest_updated":false,"exit_code":0,"halt_reason":null}
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Field rules:
|
|
12
|
+
|
|
13
|
+
- `status` — `"success"` on the terminal happy path, `"dry-run"` when `--dry-run` was set and the workflow exited at the confirmation gate before any mutation, `"error"` on any HALT.
|
|
14
|
+
- `halt_reason` — `null` on success/dry-run; otherwise one of `"input-missing"`, `"input-invalid"`, `"manifest-corrupt"`, `"nothing-to-drop"`, `"active-version-guard-refused"`, `"headless-purge-forbidden"`, `"manifest-write-failed"`, `"context-rebuild-failed"`, `"delete-failed"`, `"write-failed"`, `"user-cancelled"`.
|
|
15
|
+
- `exit_code` — the stable numeric code the emitting HALT specifies (`0` on success/dry-run).
|
|
16
|
+
- `skill` / `drop_mode` / `versions_affected` / `files_deleted` / `manifest_updated` — the discriminating values the emit site supplies; any key not yet resolved at that point takes the default shown in the template (`null`, `[]`, or `false`).
|
|
17
|
+
|
|
18
|
+
Each emit site supplies its own `exit_code`, `halt_reason`, and whichever discriminating fields are known at that point; all other keys default as shown.
|
|
@@ -9,16 +9,4 @@ nextStepFile: 'shared/health-check.md'
|
|
|
9
9
|
|
|
10
10
|
# Step 4: Workflow Health Check
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
Chain to the shared workflow self-improvement health check at `{nextStepFile}`. This is the terminal step of drop-skill — after the shared health check completes, the workflow is fully done.
|
|
15
|
-
|
|
16
|
-
## Rules
|
|
17
|
-
|
|
18
|
-
- No user-facing reports, file writes, or result contracts in this step — those belong in step 3
|
|
19
|
-
- Delegate directly to `{nextStepFile}` with no additional commentary
|
|
20
|
-
- Do not attempt any other action between loading this step and executing `{nextStepFile}`
|
|
21
|
-
|
|
22
|
-
## MANDATORY SEQUENCE
|
|
23
|
-
|
|
24
|
-
Load `{nextStepFile}`, read it fully, then execute it.
|
|
12
|
+
This is the terminal step of drop-skill. Load `{nextStepFile}`, read it fully, then execute it — do nothing else here (no user-facing reports, file writes, or result contracts; those were step 3). After the shared health check completes, the workflow is done.
|