bmad-module-skill-forge 1.4.1 → 1.5.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 +0 -8
- package/docs/_data/pinned.yaml +1 -1
- package/docs/_internal/STABILITY.md +1 -1
- package/docs/architecture.md +2 -2
- package/docs/examples.md +1 -1
- package/docs/workflows.md +5 -5
- package/package.json +2 -2
- package/src/README.md +1 -1
- package/src/knowledge/ccc-bridge.md +12 -12
- package/src/knowledge/qmd-registry.md +5 -5
- package/src/shared/health-check.md +5 -5
- package/src/shared/references/description-guard-protocol.md +100 -0
- package/src/shared/references/output-contract-schema.md +1 -1
- package/src/shared/scripts/schemas/skf-brief-result-envelope.v1.json +6 -6
- package/src/shared/scripts/schemas/skf-setup-result-envelope.v1.json +9 -3
- package/src/shared/scripts/schemas/skf-update-result-envelope.v1.json +149 -0
- package/src/shared/scripts/schemas/skill-brief.v1.json +22 -2
- package/src/shared/scripts/skf-build-change-manifest.py +420 -0
- package/src/shared/scripts/skf-check-workspace-drift.py +321 -0
- package/src/shared/scripts/skf-compare-file-hashes.py +357 -0
- package/src/shared/scripts/skf-description-guard.py +359 -0
- package/src/shared/scripts/skf-detect-language.py +2 -2
- package/src/shared/scripts/skf-detect-scripts-assets.py +613 -0
- package/src/shared/scripts/skf-detect-tools.py +97 -8
- package/src/shared/scripts/skf-detect-workspaces.py +1 -1
- package/src/shared/scripts/skf-disqualify-candidates.py +576 -0
- package/src/shared/scripts/skf-emit-brief-result-envelope.py +3 -3
- package/src/shared/scripts/skf-emit-result-envelope.py +93 -9
- package/src/shared/scripts/skf-enumerate-stack-skills.py +514 -0
- package/src/shared/scripts/skf-forge-tier-rw.py +11 -11
- package/src/shared/scripts/skf-hash-content.py +284 -0
- package/src/shared/scripts/skf-load-provenance.py +295 -0
- package/src/shared/scripts/skf-merge-ccc-exclusions.py +34 -4
- package/src/shared/scripts/skf-pair-intersect.py +250 -0
- package/src/shared/scripts/skf-provenance-gap-dispatch.py +433 -0
- package/src/shared/scripts/skf-qmd-classify-collections.py +42 -8
- package/src/shared/scripts/skf-recommend-scope-type.py +2 -2
- package/src/shared/scripts/skf-render-quick-metadata.py +2 -2
- package/src/shared/scripts/skf-resolve-authoritative-files.py +504 -0
- package/src/shared/scripts/skf-scan-manifests.py +738 -0
- package/src/shared/scripts/skf-scan-skill-md-structure.py +375 -0
- package/src/shared/scripts/skf-update-active-symlink.py +315 -0
- package/src/shared/scripts/skf-validate-brief-inputs.py +5 -5
- package/src/shared/scripts/skf-validate-brief-schema.py +348 -0
- package/src/shared/scripts/skf-write-skill-brief.py +61 -5
- package/src/skf-analyze-source/SKILL.md +69 -16
- package/src/skf-analyze-source/assets/skill-brief-schema.md +1 -1
- package/src/skf-analyze-source/customize.toml +55 -0
- package/src/skf-analyze-source/{steps-c/step-01b-continue.md → references/continue.md} +12 -12
- package/src/skf-analyze-source/{steps-c/step-06-generate-briefs.md → references/generate-briefs.md} +29 -10
- package/src/skf-analyze-source/{steps-c/step-07-health-check.md → references/health-check.md} +5 -3
- package/src/skf-analyze-source/{steps-c/step-03-identify-units.md → references/identify-units.md} +44 -14
- package/src/skf-analyze-source/{steps-c/step-01-init.md → references/init.md} +27 -6
- package/src/skf-analyze-source/{steps-c/step-04-map-and-detect.md → references/map-and-detect.md} +52 -25
- package/src/skf-analyze-source/{steps-c/step-05-recommend.md → references/recommend.md} +15 -8
- package/src/skf-analyze-source/{steps-c/step-02-scan-project.md → references/scan-project.md} +12 -10
- package/src/skf-analyze-source/references/unit-detection-heuristics.md +2 -0
- package/src/skf-analyze-source/templates/analysis-report-template.md +6 -6
- package/src/skf-audit-skill/SKILL.md +66 -15
- package/src/skf-audit-skill/assets/drift-report-template.md +6 -5
- package/src/skf-audit-skill/customize.toml +49 -0
- package/src/skf-audit-skill/{steps-c/step-07-health-check.md → references/health-check.md} +5 -3
- package/src/skf-audit-skill/{steps-c/step-01-init.md → references/init.md} +57 -19
- package/src/skf-audit-skill/{steps-c/step-02-re-index.md → references/re-index.md} +11 -11
- package/src/skf-audit-skill/{steps-c/step-06-report.md → references/report.md} +25 -7
- package/src/skf-audit-skill/{steps-c/step-04-semantic-diff.md → references/semantic-diff.md} +6 -6
- package/src/skf-audit-skill/{steps-c/step-05-severity-classify.md → references/severity-classify.md} +5 -5
- package/src/skf-audit-skill/references/severity-rules.md +2 -0
- package/src/skf-audit-skill/{steps-c/step-03-structural-diff.md → references/structural-diff.md} +29 -17
- package/src/skf-brief-skill/SKILL.md +48 -18
- package/src/skf-brief-skill/assets/description-voice-examples.md +1 -1
- package/src/skf-brief-skill/assets/skill-brief-schema.md +32 -2
- package/src/skf-brief-skill/customize.toml +44 -0
- package/src/skf-brief-skill/{steps-c/step-02-analyze-target.md → references/analyze-target.md} +5 -5
- package/src/skf-brief-skill/{steps-c/step-04-confirm-brief.md → references/confirm-brief.md} +13 -10
- package/src/skf-brief-skill/references/draft-checkpoint.md +4 -4
- package/src/skf-brief-skill/{steps-c/step-01-gather-intent.md → references/gather-intent.md} +24 -24
- package/src/skf-brief-skill/references/headless-args.md +9 -9
- package/src/skf-brief-skill/references/headless-source-authority-detection.md +1 -1
- package/src/skf-brief-skill/{steps-c/step-06-health-check.md → references/health-check.md} +4 -2
- package/src/skf-brief-skill/references/portfolio-similarity-check.md +2 -2
- package/src/skf-brief-skill/references/qmd-collection-registration.md +1 -1
- package/src/skf-brief-skill/{steps-c/step-03-scope-definition.md → references/scope-definition.md} +19 -16
- package/src/skf-brief-skill/references/version-resolution.md +2 -2
- package/src/skf-brief-skill/{steps-c/step-05-write-brief.md → references/write-brief.md} +11 -10
- package/src/skf-create-skill/SKILL.md +25 -19
- package/src/skf-create-skill/assets/compile-assembly-rules.md +3 -3
- package/src/skf-create-skill/assets/skill-sections.md +5 -5
- package/src/skf-create-skill/assets/tessl-dismissal-rules.md +11 -11
- package/src/skf-create-skill/customize.toml +35 -0
- package/src/skf-create-skill/references/authoritative-files-protocol.md +142 -0
- package/src/skf-create-skill/{steps-c/step-05-compile.md → references/compile.md} +16 -16
- package/src/skf-create-skill/{steps-c/step-03d-component-extraction.md → references/component-extraction.md} +16 -16
- package/src/skf-create-skill/{steps-c/step-02-ecosystem-check.md → references/ecosystem-check.md} +4 -4
- package/src/skf-create-skill/{steps-c/step-04-enrich.md → references/enrich.md} +3 -3
- package/src/skf-create-skill/{steps-c/step-03-extract.md → references/extract.md} +52 -120
- package/src/skf-create-skill/references/extraction-patterns.md +8 -8
- package/src/skf-create-skill/{steps-c/step-07-generate-artifacts.md → references/generate-artifacts.md} +11 -11
- package/src/skf-create-skill/{steps-c/step-09-health-check.md → references/health-check.md} +4 -2
- package/src/skf-create-skill/{steps-c/step-01-load-brief.md → references/load-brief.md} +40 -32
- package/src/skf-create-skill/{steps-c/step-08-report.md → references/report.md} +8 -8
- package/src/skf-create-skill/references/source-resolution-protocols.md +6 -6
- package/src/skf-create-skill/{steps-c/sub/step-02b-ccc-discover.md → references/sub/ccc-discover.md} +5 -5
- package/src/skf-create-skill/{steps-c/sub/step-03c-fetch-docs.md → references/sub/fetch-docs.md} +28 -12
- package/src/skf-create-skill/{steps-c/sub/step-03b-fetch-temporal.md → references/sub/fetch-temporal.md} +81 -50
- package/src/skf-create-skill/{steps-c/step-06-validate.md → references/validate.md} +46 -26
- package/src/skf-create-stack-skill/SKILL.md +76 -17
- package/src/skf-create-stack-skill/assets/provenance-map-schema.md +102 -0
- package/src/skf-create-stack-skill/assets/stack-skill-template.md +1 -1
- package/src/skf-create-stack-skill/customize.toml +46 -0
- package/src/skf-create-stack-skill/{steps-c/step-06-compile-stack.md → references/compile-stack.md} +6 -5
- package/src/skf-create-stack-skill/references/compose-mode-rules.md +3 -1
- package/src/skf-create-stack-skill/{steps-c/step-05-detect-integrations.md → references/detect-integrations.md} +32 -11
- package/src/skf-create-stack-skill/{steps-c/step-02-detect-manifests.md → references/detect-manifests.md} +28 -28
- package/src/skf-create-stack-skill/{steps-c/step-07-generate-output.md → references/generate-output.md} +11 -85
- package/src/skf-create-stack-skill/{steps-c/step-10-health-check.md → references/health-check.md} +4 -2
- package/src/skf-create-stack-skill/{steps-c/step-01-init.md → references/init.md} +70 -4
- package/src/skf-create-stack-skill/references/integration-patterns.md +2 -0
- package/src/skf-create-stack-skill/references/manifest-patterns.md +2 -0
- package/src/skf-create-stack-skill/{steps-c/step-04-parallel-extract.md → references/parallel-extract.md} +40 -17
- package/src/skf-create-stack-skill/{steps-c/step-03-rank-and-confirm.md → references/rank-and-confirm.md} +5 -4
- package/src/skf-create-stack-skill/{steps-c/step-09-report.md → references/report.md} +3 -3
- package/src/skf-create-stack-skill/{steps-c/step-08-validate.md → references/validate.md} +6 -6
- package/src/skf-drop-skill/SKILL.md +84 -12
- package/src/skf-drop-skill/customize.toml +57 -0
- package/src/skf-drop-skill/{steps-c/step-02-execute.md → references/execute.md} +49 -34
- package/src/skf-drop-skill/{steps-c/step-04-health-check.md → references/health-check.md} +6 -4
- package/src/skf-drop-skill/{steps-c/step-03-report.md → references/report.md} +13 -5
- package/src/skf-drop-skill/{steps-c/step-01-select.md → references/select.md} +63 -15
- package/src/skf-export-skill/SKILL.md +85 -16
- package/src/skf-export-skill/assets/managed-section-format.md +3 -3
- package/src/skf-export-skill/assets/snippet-format.md +2 -2
- package/src/skf-export-skill/customize.toml +49 -0
- package/src/skf-export-skill/{steps-c/step-03-generate-snippet.md → references/generate-snippet.md} +11 -11
- package/src/skf-export-skill/{steps-c/step-07-health-check.md → references/health-check.md} +6 -4
- package/src/skf-export-skill/{steps-c/step-01-load-skill.md → references/load-skill.md} +11 -49
- package/src/skf-export-skill/references/manifest-rebuild.md +68 -0
- package/src/skf-export-skill/references/multi-skill-mode.md +38 -0
- package/src/skf-export-skill/references/orphan-context-detection.md +75 -0
- package/src/skf-export-skill/references/orphan-row-detection.md +102 -0
- package/src/skf-export-skill/{steps-c/step-02-package.md → references/package.md} +7 -7
- package/src/skf-export-skill/references/preflight-snippet-root-probe.md +74 -0
- package/src/skf-export-skill/{steps-c/step-06-summary.md → references/summary.md} +20 -8
- package/src/skf-export-skill/{steps-c/step-05-token-report.md → references/token-report.md} +5 -5
- package/src/skf-export-skill/{steps-c/step-04-update-context.md → references/update-context.md} +109 -113
- package/src/skf-quick-skill/SKILL.md +63 -123
- package/src/skf-quick-skill/customize.toml +44 -0
- package/src/skf-quick-skill/references/batch-mode.md +102 -0
- package/src/skf-quick-skill/{steps-c/step-04-compile.md → references/compile.md} +10 -10
- package/src/skf-quick-skill/{steps-c/step-02-ecosystem-check.md → references/ecosystem-check.md} +5 -5
- package/src/skf-quick-skill/{steps-c/step-06-finalize.md → references/finalize.md} +7 -7
- package/src/skf-quick-skill/{steps-c/step-07-health-check.md → references/health-check.md} +3 -3
- package/src/skf-quick-skill/{steps-c/step-03-quick-extract.md → references/quick-extract.md} +5 -5
- package/src/skf-quick-skill/references/registry-resolution.md +2 -0
- package/src/skf-quick-skill/{steps-c/step-01-resolve-target.md → references/resolve-target.md} +14 -10
- package/src/skf-quick-skill/{steps-c/step-05-write-and-validate.md → references/write-and-validate.md} +4 -4
- package/src/skf-refine-architecture/SKILL.md +86 -16
- package/src/skf-refine-architecture/customize.toml +49 -0
- package/src/skf-refine-architecture/{steps-c/step-05-compile.md → references/compile.md} +4 -4
- package/src/skf-refine-architecture/{steps-c/step-02-gap-analysis.md → references/gap-analysis.md} +5 -5
- package/src/skf-refine-architecture/{steps-c/step-07-health-check.md → references/health-check.md} +6 -4
- package/src/skf-refine-architecture/{steps-c/step-04-improvements.md → references/improvements.md} +5 -5
- package/src/skf-refine-architecture/references/init.md +144 -0
- package/src/skf-refine-architecture/{steps-c/step-03-issue-detection.md → references/issue-detection.md} +5 -5
- package/src/skf-refine-architecture/references/refinement-rules.md +2 -0
- package/src/skf-refine-architecture/{steps-c/step-06-report.md → references/report.md} +14 -5
- package/src/skf-rename-skill/SKILL.md +82 -12
- package/src/skf-rename-skill/customize.toml +52 -0
- package/src/skf-rename-skill/{steps-c/step-02-execute.md → references/execute.md} +94 -99
- package/src/skf-rename-skill/references/health-check.md +30 -0
- package/src/skf-rename-skill/references/rebuild-context.md +110 -0
- package/src/skf-rename-skill/{steps-c/step-03-report.md → references/report.md} +13 -5
- package/src/skf-rename-skill/{steps-c/step-01-select.md → references/select.md} +59 -20
- package/src/skf-setup/SKILL.md +35 -35
- package/src/skf-setup/customize.toml +33 -0
- package/src/skf-setup/{steps-c/step-03-auto-index.md → references/auto-index.md} +10 -18
- package/src/skf-setup/{steps-c/step-01b-ccc-index.md → references/ccc-index.md} +16 -31
- package/src/skf-setup/{steps-c/step-01-detect-and-tier.md → references/detect-and-tier.md} +23 -10
- package/src/skf-setup/{steps-c/step-05-health-check.md → references/health-check.md} +1 -1
- package/src/skf-setup/{steps-c/step-04-report.md → references/report.md} +21 -19
- package/src/skf-setup/references/tier-rules.md +1 -1
- package/src/skf-setup/{steps-c/step-02-write-config.md → references/write-config.md} +14 -13
- package/src/skf-test-skill/SKILL.md +77 -15
- package/src/skf-test-skill/customize.toml +54 -0
- package/src/skf-test-skill/{steps-c/step-04-coherence-check.md → references/coherence-check.md} +28 -71
- package/src/skf-test-skill/{steps-c/step-03-coverage-check.md → references/coverage-check.md} +16 -39
- package/src/skf-test-skill/{steps-c/step-02-detect-mode.md → references/detect-mode.md} +4 -26
- package/src/skf-test-skill/{steps-c/step-04b-external-validators.md → references/external-validators.md} +6 -28
- package/src/skf-test-skill/references/health-check.md +14 -0
- package/src/skf-test-skill/{steps-c/step-01-init.md → references/init.md} +21 -37
- package/src/skf-test-skill/references/migration-section-rules.md +4 -2
- package/src/skf-test-skill/{steps-c/step-06-report.md → references/report.md} +41 -51
- package/src/skf-test-skill/{steps-c/step-05-score.md → references/score.md} +26 -43
- package/src/skf-test-skill/references/scoring-rules.md +8 -6
- package/src/skf-test-skill/references/source-access-protocol.md +7 -5
- package/src/skf-test-skill/scripts/compute-score.py +88 -17
- package/src/skf-test-skill/templates/test-report-template.md +13 -13
- package/src/skf-update-skill/SKILL.md +23 -14
- package/src/skf-update-skill/customize.toml +44 -0
- package/src/skf-update-skill/{steps-c/step-02-detect-changes.md → references/detect-changes.md} +176 -68
- package/src/skf-update-skill/references/health-check.md +32 -0
- package/src/skf-update-skill/{steps-c/step-01-init.md → references/init.md} +56 -8
- package/src/skf-update-skill/references/manual-section-rules.md +4 -0
- package/src/skf-update-skill/references/merge-conflict-rules.md +4 -0
- package/src/skf-update-skill/{steps-c/step-04-merge.md → references/merge.md} +8 -8
- package/src/skf-update-skill/{steps-c/step-03-re-extract.md → references/re-extract.md} +53 -44
- package/src/skf-update-skill/references/remote-source-resolution.md +5 -1
- package/src/skf-update-skill/references/report.md +214 -0
- package/src/skf-update-skill/{steps-c/step-05-validate.md → references/validate.md} +5 -5
- package/src/skf-update-skill/{steps-c/step-06-write.md → references/write.md} +73 -51
- package/src/skf-verify-stack/SKILL.md +89 -17
- package/src/skf-verify-stack/assets/feasibility-report-template.md +4 -4
- package/src/skf-verify-stack/customize.toml +50 -0
- package/src/skf-verify-stack/references/coverage-patterns.md +2 -2
- package/src/skf-verify-stack/{steps-c/step-02-coverage.md → references/coverage.md} +7 -7
- package/src/skf-verify-stack/{steps-c/step-07-health-check.md → references/health-check.md} +7 -5
- package/src/skf-verify-stack/references/init.md +166 -0
- package/src/skf-verify-stack/references/integration-verification-rules.md +1 -1
- package/src/skf-verify-stack/{steps-c/step-03-integrations.md → references/integrations.md} +12 -12
- package/src/skf-verify-stack/{steps-c/step-06-report.md → references/report.md} +22 -41
- package/src/skf-verify-stack/{steps-c/step-04-requirements.md → references/requirements.md} +7 -7
- package/src/skf-verify-stack/{steps-c/step-05-synthesize.md → references/synthesize.md} +8 -8
- package/tools/validate-docs-drift.js +1 -1
- package/src/skf-refine-architecture/steps-c/step-01-init.md +0 -136
- package/src/skf-rename-skill/steps-c/step-04-health-check.md +0 -22
- package/src/skf-test-skill/steps-c/step-07-health-check.md +0 -25
- package/src/skf-update-skill/steps-c/step-07-report.md +0 -148
- package/src/skf-update-skill/steps-c/step-08-health-check.md +0 -22
- package/src/skf-verify-stack/steps-c/step-01-init.md +0 -178
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
---
|
|
2
|
+
# Static reference loaded by execute.md §7. The carve removes ~70
|
|
3
|
+
# lines of context-rebuild loop logic from the main execute.md so
|
|
4
|
+
# the §1–§6 + §8–§10 critical-path stays tight; §7 itself is always
|
|
5
|
+
# reached on the success path so this file loads on every successful
|
|
6
|
+
# rename, but the rollback paths (§4–§6 failure jumps) skip §7
|
|
7
|
+
# entirely and never load this reference.
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
<!-- Config: communicate in {communication_language}. Render the rebuilt-files report in {document_output_language}. -->
|
|
11
|
+
|
|
12
|
+
# Rename: Rebuild Context Files (per-IDE managed-section sweep)
|
|
13
|
+
|
|
14
|
+
## Purpose
|
|
15
|
+
|
|
16
|
+
After §6 re-keys the manifest from `{old_name}` to `{new_name}`, every IDE's context file (`CLAUDE.md`, `.cursorrules`, `AGENTS.md`, etc.) still contains the old name in its managed-section snippet rows. This step rewrites each one in-place via the surgical between-marker swap so the on-disk managed sections reflect the new name.
|
|
17
|
+
|
|
18
|
+
Loaded by `execute.md` §7 once `manifest_updated == true` (§6 succeeded) and the rollback paths in §4–§6 were not taken.
|
|
19
|
+
|
|
20
|
+
## Resolve target_context_files
|
|
21
|
+
|
|
22
|
+
Load the `ides` list from `config.yaml`. The installer writes IDE identifiers — these must be mapped to context files and skill roots using the "IDE → Context File Mapping" table in `{managedSectionLogic}`:
|
|
23
|
+
|
|
24
|
+
1. For each entry in `config.yaml.ides`, look up its `context_file` and `skill_root` from the mapping table.
|
|
25
|
+
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 AGENTS.md`.
|
|
26
|
+
3. Deduplicate by `context_file` — when multiple IDEs map to the same context file, use the first configured IDE's `skill_root`.
|
|
27
|
+
4. If `config.yaml.ides` is absent or the mapping yields an empty list, fall back to `[{context_file: "AGENTS.md", skill_root: ".agents/skills/"}]` and emit a note: `No IDEs configured in config.yaml — defaulting to AGENTS.md`.
|
|
28
|
+
|
|
29
|
+
Store the result as `target_context_files`.
|
|
30
|
+
|
|
31
|
+
## Per-file loop
|
|
32
|
+
|
|
33
|
+
For each entry in `target_context_files`:
|
|
34
|
+
|
|
35
|
+
### 1. Resolve target file
|
|
36
|
+
|
|
37
|
+
Resolve the absolute path at `{context_file}`.
|
|
38
|
+
|
|
39
|
+
### 2. Read the current file
|
|
40
|
+
|
|
41
|
+
- If the file does not exist, skip this context file (nothing to rebuild — the file will be re-created the next time export-skill runs).
|
|
42
|
+
- If the file exists but contains no `<!-- SKF:BEGIN -->` marker, skip this context file (no managed section to rewrite).
|
|
43
|
+
- If the file contains `<!-- SKF:BEGIN -->` but no matching `<!-- SKF:END -->`, record the error against that context file and continue to the next entry — do not halt the entire rename on a malformed context file.
|
|
44
|
+
|
|
45
|
+
### 3. Build the exported skill set (version-aware, deprecated-excluded)
|
|
46
|
+
|
|
47
|
+
Use the same logic as `skf-export-skill/references/update-context.md` §4b and the snippet resolution from §4c:
|
|
48
|
+
|
|
49
|
+
- Read the manifest's `exports` object (already updated in §6, so `{new_name}` is present and `{old_name}` is absent).
|
|
50
|
+
- For each skill, resolve its `active_version`.
|
|
51
|
+
- If `versions.{active_version}.status == "deprecated"`, skip that skill entirely.
|
|
52
|
+
- For each remaining `{skill-name, active_version}` pair, read `{skills_output_folder}/{skill-name}/{active_version}/{skill-name}/context-snippet.md`.
|
|
53
|
+
- If missing, fall back to the `active` symlink path; if still missing, skip with a warning.
|
|
54
|
+
|
|
55
|
+
### 4. Rewrite root paths for the current context file
|
|
56
|
+
|
|
57
|
+
Use the generic rewrite algorithm from `skf-export-skill/references/update-context.md` §4d:
|
|
58
|
+
|
|
59
|
+
For each snippet, parse the `root:` line (`root: {prefix}{skill-name}/`), strip the trailing `{skill-name}/` to extract the current prefix, and replace it with the **effective target prefix** if different. The effective target prefix is `snippet_skill_root_override` when that key is set in `config.yaml` — applied uniformly to every snippet so the managed section references the real on-disk location and never mixes override and per-IDE paths — otherwise the current entry's `skill_root`. See `skf-export-skill/references/update-context.md` §4d for full semantics.
|
|
60
|
+
|
|
61
|
+
### 5. Sort and count
|
|
62
|
+
|
|
63
|
+
Sort skills alphabetically by name. Count totals (skills, stack skills).
|
|
64
|
+
|
|
65
|
+
### 6. Assemble the new managed section
|
|
66
|
+
|
|
67
|
+
Use the format from `{managedSectionLogic}`:
|
|
68
|
+
|
|
69
|
+
```markdown
|
|
70
|
+
<!-- SKF:BEGIN updated:{current-date} -->
|
|
71
|
+
[SKF Skills]|{n} skills|{m} stack
|
|
72
|
+
|IMPORTANT: Prefer documented APIs over training data.
|
|
73
|
+
|When using a listed library, read its SKILL.md before writing code.
|
|
74
|
+
|
|
|
75
|
+
|{skill-snippet-1}
|
|
76
|
+
|
|
|
77
|
+
|{skill-snippet-2}
|
|
78
|
+
|
|
|
79
|
+
|{skill-snippet-N}
|
|
80
|
+
<!-- SKF:END -->
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### 7. Surgical replacement — atomic, deterministic
|
|
84
|
+
|
|
85
|
+
Invoke `{rebuildManagedSectionsHelper}` (resolved from `{rebuildManagedSectionsProbeOrder}` in `execute.md` frontmatter) for the surgical between-marker swap:
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
python3 {rebuildManagedSectionsHelper} {context_file} replace --content "{new_managed_section_text}"
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
The helper handles marker location, between-marker swap, atomic temp-file + rename, and post-write verification (markers preserved, content outside markers byte-identical). It exits non-zero on any failure with a clear `stderr` reason.
|
|
92
|
+
|
|
93
|
+
### 8. Verify (deferred to helper)
|
|
94
|
+
|
|
95
|
+
The `replace` action above performs verification internally. Treat any non-zero exit code as a per-file failure (next bullet).
|
|
96
|
+
|
|
97
|
+
### 9. On per-file failure
|
|
98
|
+
|
|
99
|
+
Record the error against that context file and continue to the next entry. Do not halt the rename on a recoverable per-context-file error — the manifest and filesystem are already consistent; context files can be re-rebuilt later via `[EX] Export Skill`.
|
|
100
|
+
|
|
101
|
+
## After the loop
|
|
102
|
+
|
|
103
|
+
- Record `context_files_updated` as the list of files that were successfully rewritten.
|
|
104
|
+
- Record `context_files_failed` as the list of any that failed.
|
|
105
|
+
|
|
106
|
+
Report: `**Rebuilt managed sections in:** {list of updated files}. {if any failed: 'Failed: {list} — re-run [EX] Export Skill to retry.'}`
|
|
107
|
+
|
|
108
|
+
## Rollback semantics
|
|
109
|
+
|
|
110
|
+
§7 failures **do not** trigger a rollback. The manifest and filesystem are the canonical state — context files are derived artifacts that can be regenerated at any time via `[EX] Export Skill`. The rename is considered successful as soon as §6 lands, even if §7 partially or fully fails to rewrite context files.
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
---
|
|
2
|
-
nextStepFile: '
|
|
2
|
+
nextStepFile: 'health-check.md'
|
|
3
3
|
---
|
|
4
4
|
|
|
5
|
+
<!-- Config: communicate in {communication_language}. Render the report block in {document_output_language}. -->
|
|
6
|
+
|
|
5
7
|
# Step 3: Report Rename Results
|
|
6
8
|
|
|
7
9
|
## STEP GOAL:
|
|
@@ -10,15 +12,13 @@ Present a clear, final summary of what the rename workflow changed — old and n
|
|
|
10
12
|
|
|
11
13
|
## Rules
|
|
12
14
|
|
|
13
|
-
- Focus only on reporting results stored in context by step
|
|
15
|
+
- Focus only on reporting results stored in context by step 2 — do not re-execute any part of the rename
|
|
14
16
|
- Do not hide verification warnings, context file rebuild failures, or deletion errors
|
|
15
17
|
- Present next-steps guidance so the user knows which downstream workflows to run
|
|
16
18
|
- Chains to the local health-check step via `{nextStepFile}` after completion — the user-facing report is NOT the terminal step
|
|
17
19
|
|
|
18
20
|
## MANDATORY SEQUENCE
|
|
19
21
|
|
|
20
|
-
**CRITICAL:** Follow this sequence exactly.
|
|
21
|
-
|
|
22
22
|
### 1. Render the Report
|
|
23
23
|
|
|
24
24
|
Display the following block, filling in values from context:
|
|
@@ -71,7 +71,15 @@ Informational: the old name still appears in SKILL.md body text (prose only, non
|
|
|
71
71
|
|
|
72
72
|
### Result Contract
|
|
73
73
|
|
|
74
|
-
Write the result contract per `shared/references/output-contract-schema.md`: the per-run record at `{skills_output_folder}/{new_name}/rename-skill-result-{
|
|
74
|
+
Write the result contract per `shared/references/output-contract-schema.md`: the per-run record at `{skills_output_folder}/{new_name}/rename-skill-result-{timestamp}.json` (reuse the activation-stored `{timestamp}`, resolution to seconds) and a copy at `{skills_output_folder}/{new_name}/rename-skill-result-latest.json` (stable path for pipeline consumers — copy, not symlink). Include all updated file paths (SKILL.md, metadata.json, context-snippet.md, provenance-map.json) in `outputs`; include `old_name`, `new_name`, and `versions_renamed` in `summary`.
|
|
75
|
+
|
|
76
|
+
When `{headless_mode}` is true, also emit the single-line envelope on **stdout** before chaining to step 4 (matches the SKILL.md "Result Contract (Headless)" shape):
|
|
77
|
+
|
|
78
|
+
```
|
|
79
|
+
SKF_RENAME_SKILL_RESULT_JSON: {"status":"success","old_name":"{old_name}","new_name":"{new_name}","versions_renamed":{affected_versions},"manifest_rekeyed":{manifest_rekeyed},"context_files_updated":{context_files_updated},"exit_code":0,"halt_reason":null}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Substitute `{affected_versions}` and `{context_files_updated}` as JSON arrays; `manifest_rekeyed` is the boolean from step 2's context.
|
|
75
83
|
|
|
76
84
|
### 2. Chain to Health Check
|
|
77
85
|
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
---
|
|
2
|
-
nextStepFile: '
|
|
2
|
+
nextStepFile: 'execute.md'
|
|
3
3
|
versionPathsKnowledge: 'knowledge/version-paths.md'
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
+
<!-- Config: communicate in {communication_language}. -->
|
|
7
|
+
|
|
6
8
|
# Step 1: Select Rename Target
|
|
7
9
|
|
|
8
10
|
## STEP GOAL:
|
|
9
11
|
|
|
10
|
-
Identify the skill the user wants to rename, validate the new name against the agentskills.io spec (kebab-case, length, uniqueness), warn about source authority implications, enumerate every version that will be touched, and obtain explicit user confirmation before any filesystem operation is scheduled. Every selection decision is stored in context so step
|
|
12
|
+
Identify the skill the user wants to rename, validate the new name against the agentskills.io spec (kebab-case, length, uniqueness), warn about source authority implications, enumerate every version that will be touched, and obtain explicit user confirmation before any filesystem operation is scheduled. Every selection decision is stored in context so step 2 can execute the rename transactionally.
|
|
11
13
|
|
|
12
14
|
## Rules
|
|
13
15
|
|
|
@@ -18,8 +20,6 @@ Identify the skill the user wants to rename, validate the new name against the a
|
|
|
18
20
|
|
|
19
21
|
## MANDATORY SEQUENCE
|
|
20
22
|
|
|
21
|
-
**CRITICAL:** Follow this sequence exactly. Do not skip, reorder, or improvise unless user explicitly requests a change.
|
|
22
|
-
|
|
23
23
|
### 1. Load Knowledge
|
|
24
24
|
|
|
25
25
|
Read `{versionPathsKnowledge}` completely and extract:
|
|
@@ -28,19 +28,19 @@ Read `{versionPathsKnowledge}` completely and extract:
|
|
|
28
28
|
- Export manifest v2 schema (`schema_version`, `exports`, `active_version`, `versions` map, `status` field values)
|
|
29
29
|
- The Rename section under "Skill Management Operations" — the complete list of 9 locations that must be updated coherently
|
|
30
30
|
|
|
31
|
-
You will use these templates and rules to build directory paths, enumerate affected versions, and plan the transactional rename in step
|
|
31
|
+
You will use these templates and rules to build directory paths, enumerate affected versions, and plan the transactional rename in step 2.
|
|
32
32
|
|
|
33
33
|
### 2. Read Export Manifest
|
|
34
34
|
|
|
35
35
|
Load `{skills_output_folder}/.export-manifest.json` if it exists.
|
|
36
36
|
|
|
37
|
-
**If the file is missing or empty:** Treat as an empty manifest — proceed to section 3 and rely entirely on the on-disk directory scan. Drafted or never-exported skills can still be renamed. Store `manifest_exists = false` for later use in step
|
|
37
|
+
**If the file is missing or empty:** Treat as an empty manifest — proceed to section 3 and rely entirely on the on-disk directory scan. Drafted or never-exported skills can still be renamed. Store `manifest_exists = false` for later use in step 2 (section 6 will not attempt to update a manifest that does not exist).
|
|
38
38
|
|
|
39
|
-
**If the file exists but contains no `exports` entries:** Same handling — proceed to section 3 with the directory scan. Store `manifest_exists = true` so step
|
|
39
|
+
**If the file exists but contains no `exports` entries:** Same handling — proceed to section 3 with the directory scan. Store `manifest_exists = true` so step 2 still touches the (empty) manifest on write.
|
|
40
40
|
|
|
41
41
|
**If the file exists with entries:** Parse JSON and verify `schema_version` is `"2"`. If the manifest is v1 (no `schema_version` field), note this but continue — treat every entry as having a single active version derived from its current state. Store `manifest_exists = true`.
|
|
42
42
|
|
|
43
|
-
**Hard halt condition:** If the file exists but is malformed (not valid JSON), halt with: "**Export manifest is corrupt** at `{skills_output_folder}/.export-manifest.json` — fix or remove the file before renaming."
|
|
43
|
+
**Hard halt condition:** If the file exists but is malformed (not valid JSON), halt with: "**Export manifest is corrupt** at `{skills_output_folder}/.export-manifest.json` — fix or remove the file before renaming." HALT (exit code 3, `halt_reason: "manifest-corrupt"`). In headless mode, emit the error envelope per SKILL.md "Result Contract (Headless)" with `old_name: null`, `new_name: null`.
|
|
44
44
|
|
|
45
45
|
### 3. List Available Skills
|
|
46
46
|
|
|
@@ -54,7 +54,7 @@ For each skill in the manifest's `exports` (if `manifest_exists` and entries exi
|
|
|
54
54
|
|
|
55
55
|
Also scan `{skills_output_folder}/` for any top-level directories that are NOT present in the manifest's `exports` object. Record these as "(not in manifest)" — they represent draft or orphaned skills that the rename workflow can also handle. When the manifest is missing or empty, every on-disk skill appears in this category.
|
|
56
56
|
|
|
57
|
-
**If the combined list is empty** (no manifest entries AND no on-disk skill directories): halt with "**Rename Skill — nothing to rename.** No skills found in `{skills_output_folder}/`. Run `[CS] Create Skill` first."
|
|
57
|
+
**If the combined list is empty** (no manifest entries AND no on-disk skill directories): halt with "**Rename Skill — nothing to rename.** No skills found in `{skills_output_folder}/`. Run `[CS] Create Skill` first." HALT (exit code 3, `halt_reason: "nothing-to-rename"`). In headless mode, emit the error envelope with `old_name: null`, `new_name: null`.
|
|
58
58
|
|
|
59
59
|
Display the combined list:
|
|
60
60
|
|
|
@@ -70,20 +70,55 @@ Available skills:
|
|
|
70
70
|
### 4. Ask Which Skill
|
|
71
71
|
|
|
72
72
|
"**Which skill would you like to rename?**
|
|
73
|
-
Enter the skill name or its number from the list above."
|
|
73
|
+
Enter the skill name or its number from the list above, or `cancel` / `exit` / `:q` to abort."
|
|
74
74
|
|
|
75
|
-
Wait for user input. Accept either the numeric index or the skill name (exact match). **GATE [default: use args]** — If `{headless_mode}` and old skill name was provided as argument: select that skill and auto-proceed. If not provided, HALT: "headless mode requires old_name argument."
|
|
75
|
+
Wait for user input. Accept either the numeric index or the skill name (exact match). **GATE [default: use args]** — If `{headless_mode}` and old skill name was provided as argument: select that skill and auto-proceed. If not provided, HALT (exit code 2, `halt_reason: "input-missing"`): "headless mode requires old_name argument." In headless, emit the error envelope.
|
|
76
76
|
|
|
77
|
-
|
|
77
|
+
- If the user enters `cancel`, `exit`, `[X]`, `q`, or `:q`: Display "Cancelled — no changes were made." and HALT (exit code 6, `halt_reason: "user-cancelled"`).
|
|
78
|
+
- **If the user's input does not match any listed skill:** Re-display the list and ask again.
|
|
78
79
|
|
|
79
80
|
Store the selection as `old_name`.
|
|
80
81
|
|
|
82
|
+
### 4b. Concurrency Guard
|
|
83
|
+
|
|
84
|
+
Two concurrent rename runs against the same `old_name` would corrupt state mid-copy: one would `rm -rf` the other's freshly-staged new directories, or both would race on the manifest re-key. The lock below catches the common accidental-double-invoke case. It is a **best-effort PID-file guard**, not a held flock — the LLM-driven workflow spans many turn boundaries and no single bash invocation can hold flock across them.
|
|
85
|
+
|
|
86
|
+
**Mirror this exactly so the guard works the same way every run:**
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
LOCK={forge_data_folder}/{old_name}/.skf-rename.lock
|
|
90
|
+
mkdir -p "$(dirname "$LOCK")"
|
|
91
|
+
|
|
92
|
+
if [ -f "$LOCK" ]; then
|
|
93
|
+
HELD_PID=$(head -n1 "$LOCK" 2>/dev/null | awk '{print $1}')
|
|
94
|
+
if [ -n "$HELD_PID" ] && kill -0 "$HELD_PID" 2>/dev/null; then
|
|
95
|
+
echo "skf-rename-skill: another rename is in progress (pid=$HELD_PID, started $(awk 'NR==2' "$LOCK" 2>/dev/null))"
|
|
96
|
+
exit 1
|
|
97
|
+
fi
|
|
98
|
+
echo "skf-rename-skill: clearing stale lock from pid=$HELD_PID"
|
|
99
|
+
fi
|
|
100
|
+
|
|
101
|
+
printf '%s\n%s\n' "$$" "$(date -u +%Y-%m-%dT%H:%M:%SZ)" > "$LOCK"
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
**Halt protocol on live-PID collision:**
|
|
105
|
+
|
|
106
|
+
- Display: `"**Another rename is in progress.** The skill {old_name} is locked by pid={HELD_PID} (started {timestamp from line 2 of the lock file}). Wait for that run to finish, or — if you know that pid is no longer running — delete {LOCK} manually and re-run."`
|
|
107
|
+
- HALT (exit code 5, `halt_reason: "halted-for-concurrent-run"`). In `{headless_mode}`, emit the error envelope per SKILL.md "Result Contract (Headless)" with `old_name: "{old_name}"`, `new_name: null`. **No `headless_decisions[]` entry** — this is a hard halt before any gate fires.
|
|
108
|
+
|
|
109
|
+
**Release contract:**
|
|
110
|
+
|
|
111
|
+
- The terminal health-check step (step 4) deletes the lock as its final action.
|
|
112
|
+
- **Every halted-for-\* path in this workflow must delete the lock before exiting** — otherwise the next attempt would see a stale lock from this run. The lock-release is a single `rm -f "$LOCK"` per halt site.
|
|
113
|
+
|
|
81
114
|
### 5. Ask for New Name
|
|
82
115
|
|
|
83
116
|
"**What is the new name for this skill?**
|
|
84
|
-
The new name must be kebab-case: lowercase alphanumeric with hyphens, 1-64 characters, matching the regex `^[a-z][a-z0-9-]*[a-z0-9]$` (single-character names may be a single lowercase letter or digit)."
|
|
117
|
+
The new name must be kebab-case: lowercase alphanumeric with hyphens, 1-64 characters, matching the regex `^[a-z][a-z0-9-]*[a-z0-9]$` (single-character names may be a single lowercase letter or digit). Or type `cancel` / `exit` / `:q` to abort."
|
|
85
118
|
|
|
86
|
-
Wait for user input. Trim whitespace. **GATE [default: use args]** — If `{headless_mode}` and new_name was provided as argument: use it and auto-proceed through validation. If not provided, HALT: "headless mode requires new_name argument."
|
|
119
|
+
Wait for user input. Trim whitespace. **GATE [default: use args]** — If `{headless_mode}` and new_name was provided as argument: use it and auto-proceed through validation. If not provided, release the lock and HALT (exit code 2, `halt_reason: "input-missing"`): "headless mode requires new_name argument." In headless, emit the error envelope.
|
|
120
|
+
|
|
121
|
+
- If the user enters `cancel`, `exit`, `[X]`, `q`, or `:q`: release the lock (`rm -f {forge_data_folder}/{old_name}/.skf-rename.lock`), display "Cancelled — no changes were made.", and HALT (exit code 6, `halt_reason: "user-cancelled"`).
|
|
87
122
|
|
|
88
123
|
Apply the following validations in order:
|
|
89
124
|
|
|
@@ -106,7 +141,7 @@ Apply the following validations in order:
|
|
|
106
141
|
|
|
107
142
|
If any collision is detected:
|
|
108
143
|
"**Name collision.** `{new-name}` already exists at: {list the colliding locations}. Pick a different name."
|
|
109
|
-
Re-ask.
|
|
144
|
+
Re-ask. In headless mode, instead of re-asking, release the lock and HALT (exit code 5, `halt_reason: "name-collision"`) and emit the error envelope.
|
|
110
145
|
|
|
111
146
|
Only after all four validations pass, store the input as `new_name`.
|
|
112
147
|
|
|
@@ -129,11 +164,13 @@ registry will still get the original name. Rename is a LOCAL operation only —
|
|
|
129
164
|
does not rename anything at the registry.
|
|
130
165
|
```
|
|
131
166
|
|
|
132
|
-
Ask: "**Continue anyway?** [Y/N]"
|
|
167
|
+
Ask: "**Continue anyway?** [Y/N] (or `cancel` / `exit` / `:q` to abort)"
|
|
133
168
|
|
|
134
169
|
Wait for response.
|
|
135
|
-
- **If `N`** or
|
|
136
|
-
- **If `Y`** → proceed.
|
|
170
|
+
- **If `N`** (or `cancel` / `exit` / `[X]` / `:q`) → release the lock (`rm -f {forge_data_folder}/{old_name}/.skf-rename.lock`), display "**Cancelled.** No changes were made.", HALT (exit code 6, `halt_reason: "user-cancelled"`).
|
|
171
|
+
- **If `Y`** → proceed. Set `source_authority_override = true`.
|
|
172
|
+
|
|
173
|
+
**Headless behavior:** If `{headless_mode}` is true AND `{forceSourceAuthorityInHeadless}` is `"true"`, auto-proceed and record `{gate: "source-authority", default_action: "halt", taken_action: "proceed", reason: "force_source_authority_in_headless override"}` in `headless_decisions[]`. Otherwise, release the lock and HALT (exit code 5, `halt_reason: "source-authority-blocked"`) and emit the error envelope — the safe default protects against silent registry-divergence on `published`-tagged skills.
|
|
137
174
|
|
|
138
175
|
**If `source_authority` is absent, or any value other than `"official"`:** skip the warning and proceed.
|
|
139
176
|
|
|
@@ -192,13 +229,15 @@ Proceed? [Y/N]
|
|
|
192
229
|
|
|
193
230
|
Wait for explicit user response.
|
|
194
231
|
|
|
232
|
+
**If `--dry-run` was passed**: skip the Y/N prompt entirely. Release the lock (`rm -f {forge_data_folder}/{old_name}/.skf-rename.lock`), display "**[DRY RUN] No changes were made — preview above shows what would be renamed.**", and emit the success envelope per SKILL.md "Result Contract (Headless)" with `status: "dry-run"`, the resolved `old_name`, `new_name`, and `versions_renamed: {affected_versions}`, then HALT (exit code 0). No copy, no manifest re-key, no delete.
|
|
233
|
+
|
|
195
234
|
- **If `Y`** → proceed to section 9
|
|
196
|
-
- **If `N`** → "**Cancelled.** No changes were made." HALT the
|
|
235
|
+
- **If `N`** (or `cancel` / `exit` / `[X]` / `:q`) → release the lock (`rm -f {forge_data_folder}/{old_name}/.skf-rename.lock`), display "**Cancelled.** No changes were made.", HALT (exit code 6, `halt_reason: "user-cancelled"`). In headless mode, emit the error envelope per SKILL.md "Result Contract (Headless)" with the resolved `old_name` and `new_name`.
|
|
197
236
|
- **Any other input** → re-display the confirmation and ask again
|
|
198
237
|
|
|
199
238
|
### 9. Store Decisions in Context
|
|
200
239
|
|
|
201
|
-
Store the following decisions in workflow context for step
|
|
240
|
+
Store the following decisions in workflow context for step 2:
|
|
202
241
|
|
|
203
242
|
- `old_name` — the current skill name
|
|
204
243
|
- `new_name` — the validated new name
|
package/src/skf-setup/SKILL.md
CHANGED
|
@@ -1,13 +1,21 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: skf-setup
|
|
3
|
-
description: Initialize forge environment, detect tools, and set capability tier (Quick/Forge/Forge+/Deep). Use when the user requests to "set up" or "initialize the forge.
|
|
3
|
+
description: Initialize forge environment, detect tools, and set capability tier (Quick/Forge/Forge+/Deep). Use when the user requests to "set up" or "initialize the forge".
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Setup Forge
|
|
7
7
|
|
|
8
8
|
## Overview
|
|
9
9
|
|
|
10
|
-
Initializes the forge environment by detecting available tools, determining the capability tier (Quick/Forge/Forge+/Deep), and writing persistent configuration to `{project-root}/_bmad/_memory/forger-sidecar/`. When `ccc` (cocoindex-code) is available, also augments `.cocoindex_code/settings.yml` with SKF exclusion patterns and creates or refreshes the project's semantic-search index. On Deep tier, reconciles the QMD collection registry; whenever ccc is available, reconciles the CCC index registry as well. The workflow is autonomous with one optional gate — orphaned QMD collection removal in step 3 (Deep tier only; default action: Keep) — which auto-resolves
|
|
10
|
+
Initializes the forge environment by detecting available tools, determining the capability tier (Quick/Forge/Forge+/Deep), and writing persistent configuration to `{project-root}/_bmad/_memory/forger-sidecar/`. When `ccc` (cocoindex-code) is available, also augments `.cocoindex_code/settings.yml` with SKF exclusion patterns and creates or refreshes the project's semantic-search index. On Deep tier, reconciles the QMD collection registry; whenever ccc is available, reconciles the CCC index registry as well. The workflow is autonomous with one optional gate — orphaned QMD collection removal in step 3 (Deep tier only; default action: Keep) — which auto-resolves non-interactively when `{headless_mode}` is true or when `--orphan-action=<keep|remove>` is passed.
|
|
11
|
+
|
|
12
|
+
## Conventions
|
|
13
|
+
|
|
14
|
+
- Bare paths (e.g. `references/<name>.md`) resolve from the skill root.
|
|
15
|
+
- `references/` holds prompt content carved out of SKILL.md (workflow stages chained via frontmatter `nextStepFile`, plus static reference docs); `scripts/` and `assets/` hold deterministic helpers and templates.
|
|
16
|
+
- `{skill-root}` resolves to this skill's installed directory (where `customize.toml` lives, if present).
|
|
17
|
+
- `{project-root}`-prefixed paths resolve from the project working directory.
|
|
18
|
+
- `{skill-name}` resolves to the skill directory's basename.
|
|
11
19
|
|
|
12
20
|
## Role
|
|
13
21
|
|
|
@@ -15,56 +23,48 @@ You are a system executor performing environment resolution. Run each step in se
|
|
|
15
23
|
|
|
16
24
|
## Workflow Rules
|
|
17
25
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
-
|
|
21
|
-
-
|
|
22
|
-
- Follow the mandatory sequence in each step exactly — do not skip, reorder, or optimize
|
|
23
|
-
- Only load one step file at a time — never preload future steps
|
|
24
|
-
- Always communicate in `{communication_language}`
|
|
25
|
-
- If `{headless_mode}` is true, auto-proceed through confirmation gates with their default action and log each auto-decision
|
|
26
|
+
- One optional gate (step 3 orphan-removal prompt; default: Keep). Every other step auto-proceeds.
|
|
27
|
+
- Only load one step file at a time — never preload future steps.
|
|
28
|
+
- Communicate in `{communication_language}`.
|
|
29
|
+
- If `{headless_mode}` is true, or if `{orphan_action}` is non-null, auto-resolve the gate non-interactively and log the decision.
|
|
26
30
|
|
|
27
31
|
## Stages
|
|
28
32
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
|
32
|
-
|
|
33
|
-
|
|
|
34
|
-
|
|
|
35
|
-
|
|
|
36
|
-
|
|
|
33
|
+
All stages auto-proceed except the optional orphan-removal gate in step 3.
|
|
34
|
+
|
|
35
|
+
| # | Step | File |
|
|
36
|
+
|---|------|------|
|
|
37
|
+
| 1 | Detect Tools & Set Tier | references/detect-and-tier.md |
|
|
38
|
+
| 1b | CCC Index (only when ccc is available) | references/ccc-index.md |
|
|
39
|
+
| 2 | Write Config | references/write-config.md |
|
|
40
|
+
| 3 | QMD + CCC Registry Hygiene | references/auto-index.md |
|
|
41
|
+
| 4 | Report | references/report.md |
|
|
42
|
+
| 5 | Workflow Health Check | references/health-check.md |
|
|
37
43
|
|
|
38
44
|
## Invocation Contract
|
|
39
45
|
|
|
40
46
|
| Aspect | Detail |
|
|
41
47
|
|--------|--------|
|
|
42
48
|
| **Inputs** | (none) |
|
|
43
|
-
| **Flags** | `--headless` / `-H` (skip prompts, auto-resolve gates to defaults); `--require-tier=<Quick\|Forge\|Forge+\|Deep>` (halt with failure if calculated tier does not satisfy the requirement) |
|
|
44
|
-
| **Gates** | One optional: orphaned QMD collection removal (step 3, Deep tier only; default: Keep) |
|
|
49
|
+
| **Flags** | `--headless` / `-H` (skip prompts, auto-resolve gates to defaults); `--require-tier=<Quick\|Forge\|Forge+\|Deep>` (halt with failure if calculated tier does not satisfy the requirement); `--orphan-action=<keep\|remove>` (resolve the orphan-removal gate non-interactively, even outside `--headless`); `--ccc-skip-index` (skip CCC indexing; envelope `ccc_index.status` becomes `"skipped"`); `--quiet` (suppress the human-readable FORGE STATUS banner — pipelines and expert re-runners get the envelope only) |
|
|
50
|
+
| **Gates** | One optional: orphaned QMD collection removal (step 3, Deep tier only; default: Keep, or whatever `--orphan-action` set) |
|
|
45
51
|
| **Outputs** | `forger-sidecar/forge-tier.yaml`, `forger-sidecar/preferences.yaml`, `{forge_data_folder}/`; when ccc is available, `.cocoindex_code/settings.yml` (exclusion patterns merged) and the project ccc index |
|
|
46
|
-
| **Headless** | All gates auto-resolve with default action when `{headless_mode}` is true. step
|
|
47
|
-
| **Failure modes** | `--require-tier` not satisfied →
|
|
52
|
+
| **Headless** | All gates auto-resolve with default action when `{headless_mode}` is true. Under `--headless` or `--quiet`, step 4 emits a single-line `SKF_SETUP_RESULT_JSON: {…}` envelope as the only stdout line — the FORGE STATUS banner is suppressed. Branch on the envelope's top-level `status` field (one of `success`, `tier_failure`, `write_failure`, `blocked`) — `skf-emit-result-envelope.py` derives it from the payload, so pipelines never compose it from `require_tier_satisfied` + `error`. Schema in `references/report.md` §4. |
|
|
53
|
+
| **Failure modes** | `--require-tier` not satisfied → status becomes `tier_failure`, the envelope sets `"require_tier_satisfied": false`, and the workflow halts before step 5 (interactive runs also print a "REQUIRED TIER NOT MET" block). |
|
|
48
54
|
| **Exit codes** | The workflow runs as an LLM-driven sequence rather than a CLI process, so "exit code" describes the agent's terminal state for a calling pipeline that reads `SKF_SETUP_RESULT_JSON`. **0 — success** (no JSON `error` field, all writes completed, `require_tier_satisfied` is `true` or `null`). **1 — required-tier failure** (`require_tier_satisfied` is `false`; envelope still emitted with full state for diagnosis). **2 — write failure** (forge-tier.yaml or preferences.yaml could not be written; envelope `error` field names the path and reason). Pipelines should branch on the JSON `require_tier_satisfied` and `error` fields rather than process exit codes. |
|
|
49
55
|
|
|
50
56
|
## On Activation
|
|
51
57
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
"**Setup cannot proceed: `uv` is not installed.** SKF helpers depend on `uv` to auto-resolve their Python dependencies. Install it from <https://docs.astral.sh/uv/getting-started/installation/> and re-run `/skf-setup`. (See the Prerequisites section in <https://docs.astral.sh/uv/getting-started/installation/> or the SKF docs at `docs/getting-started.md` for details.)"
|
|
55
|
-
|
|
56
|
-
2. Load config from `{project-root}/_bmad/skf/config.yaml` and resolve:
|
|
57
|
-
- `project_name` (from installer-generated config.yaml, not module.yaml), `output_folder`, `user_name`, `communication_language`, `document_output_language`
|
|
58
|
-
- `skills_output_folder`, `forge_data_folder`, `sidecar_path`
|
|
58
|
+
> **Halt contract for headless/quiet runs.** Any halt below MUST first emit a blocked envelope when `{headless_mode}` or `{quiet_mode}` is true, before printing the human diagnostic. Pipe `{"phase":"<phase>","reason":"<reason>","path":"<path>"}` to `python3 <helper> emit-blocked` where `<helper>` is the first existing path of `{project-root}/_bmad/skf/shared/scripts/skf-emit-result-envelope.py` then `{project-root}/src/shared/scripts/skf-emit-result-envelope.py`. The `emit-blocked` subcommand declares zero dependencies (no `uv`, no `pyyaml`), so it works even when `uv` itself is the thing that's missing.
|
|
59
59
|
|
|
60
|
-
|
|
60
|
+
1. **Parse invocation flags FIRST** (so every halt below knows whether to emit an envelope): `{headless_mode}` (true on `--headless` / `-H`), `{require_tier}` (`--require-tier=<Quick|Forge|Forge+|Deep>`, case-sensitive; null if absent or unparseable), `{orphan_action}` (`--orphan-action=<keep|remove>`; null if absent), `{ccc_skip_index}` (true on `--ccc-skip-index`), `{quiet_mode}` (true on `--quiet`).
|
|
61
61
|
|
|
62
|
-
|
|
62
|
+
2. **Probe `uv` runtime.** Run `uv --version`. Every step invokes shared Python helpers via `uv run` (PEP 723 inline metadata auto-resolves `pyyaml`). If `uv` is missing, halt with phase `on-activation:uv-missing` and the human diagnostic:
|
|
63
63
|
|
|
64
|
-
|
|
64
|
+
"**Setup cannot proceed: `uv` is not installed.** SKF helpers depend on `uv` to auto-resolve their Python dependencies. Install it from <https://docs.astral.sh/uv/getting-started/installation/> and re-run `/skf-setup`."
|
|
65
65
|
|
|
66
|
-
3. **
|
|
66
|
+
3. **Load config** from `{project-root}/_bmad/skf/config.yaml` and resolve `project_name`, `output_folder`, `user_name`, `communication_language`, `document_output_language`, `skills_output_folder`, `forge_data_folder`, `sidecar_path`. Halt with phase `on-activation:config-missing` if the file does not exist, or `on-activation:config-malformed` if the YAML is invalid, with the matching human diagnostic.
|
|
67
67
|
|
|
68
|
-
4. **
|
|
68
|
+
4. **Reconcile `{headless_mode}`** with `preferences.yaml`: OR the parsed flag with `headless_mode: true` from the YAML.
|
|
69
69
|
|
|
70
|
-
5.
|
|
70
|
+
5. Execute `references/detect-and-tier.md`.
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# DO NOT EDIT -- overwritten on every update.
|
|
2
|
+
#
|
|
3
|
+
# Workflow customization surface for skf-setup.
|
|
4
|
+
|
|
5
|
+
[workflow]
|
|
6
|
+
|
|
7
|
+
# --- Configurable below. Overrides merge per BMad structural rules: ---
|
|
8
|
+
# scalars: override wins • arrays (persistent_facts, activation_steps_*): append
|
|
9
|
+
# arrays-of-tables with `code`/`id`: replace matching items, append new ones.
|
|
10
|
+
|
|
11
|
+
# Steps to run before the standard activation (uv probe, config load).
|
|
12
|
+
# Overrides append. Use for org-wide pre-flight checks (auth, network,
|
|
13
|
+
# compliance) that must precede any forge setup work.
|
|
14
|
+
|
|
15
|
+
activation_steps_prepend = []
|
|
16
|
+
|
|
17
|
+
# Steps to run after activation but before the first stage executes.
|
|
18
|
+
# Overrides append. Use for context loads or banner customization that
|
|
19
|
+
# should run once activation completes successfully.
|
|
20
|
+
|
|
21
|
+
activation_steps_append = []
|
|
22
|
+
|
|
23
|
+
# Persistent facts the workflow keeps in mind for the whole run
|
|
24
|
+
# (standards, compliance constraints, stylistic guardrails). Overrides
|
|
25
|
+
# append.
|
|
26
|
+
#
|
|
27
|
+
# Each entry is either:
|
|
28
|
+
# - a literal sentence, e.g. "Forge writes must be reproducible in CI."
|
|
29
|
+
# - a file reference prefixed with `file:`, e.g.
|
|
30
|
+
# "file:{project-root}/docs/forge-policy.md" (globs supported; file
|
|
31
|
+
# contents are loaded and treated as facts).
|
|
32
|
+
|
|
33
|
+
persistent_facts = []
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
nextStepFile: '
|
|
2
|
+
nextStepFile: 'report.md'
|
|
3
3
|
# Resolve `{qmdClassifyHelper}` and `{forgeTierRwHelper}` by probing the
|
|
4
4
|
# corresponding `*ProbeOrder` arrays (installed SKF module path first, src/
|
|
5
5
|
# dev-checkout fallback); first existing path wins. HALT if neither resolves
|
|
@@ -35,7 +35,7 @@ For Quick and Forge tiers, skip silently and proceed (QMD is not available; ccc
|
|
|
35
35
|
|
|
36
36
|
### 1. Check Tier
|
|
37
37
|
|
|
38
|
-
Read `{calculated_tier}` and `{ccc}` from context (set by step
|
|
38
|
+
Read `{calculated_tier}` and `{ccc}` from context (set by step 1).
|
|
39
39
|
|
|
40
40
|
**If `{calculated_tier}` is Quick or Forge AND `{ccc}` is false:** No registry hygiene needed. Set `{hygiene_result: "skipped", hygiene_healthy: 0, hygiene_orphaned_removed: 0, hygiene_orphaned_kept: 0, hygiene_stale_cleaned: 0, ccc_registry_stale_cleaned: 0, ccc_registry_stale_removed_paths: []}`. Proceed directly to section 5 (Auto-Proceed) — no output, no messaging.
|
|
41
41
|
|
|
@@ -47,31 +47,23 @@ Read `{calculated_tier}` and `{ccc}` from context (set by step-01).
|
|
|
47
47
|
|
|
48
48
|
### 2. Classify Live QMD Collections vs Registry
|
|
49
49
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
```bash
|
|
53
|
-
qmd collection list
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
Parse the output into a comma-separated string of collection names and store as `{live_collections}` (raw — including any foreign collections owned by other tools sharing the QMD daemon; the classifier filters them out).
|
|
57
|
-
|
|
58
|
-
**Error handling:** If `qmd collection list` fails (daemon down, daemon errors), set `{hygiene_result: "qmd_unavailable", hygiene_healthy: 0, hygiene_orphaned_removed: 0, hygiene_orphaned_kept: 0, hygiene_stale_cleaned: 0}`, log the error, and skip directly to section 4 (which will still run the ccc-prune branch if `{ccc}` is true).
|
|
59
|
-
|
|
60
|
-
Run the classifier. Invoke via `uv run` so the script's PEP 723 PyYAML dependency resolves automatically (`docs/getting-started.md` documents uv as the runtime prereq for exactly this); bare `python3` would `ModuleNotFoundError` on a fresh interpreter.
|
|
50
|
+
Run the classifier — it owns the `qmd collection list` invocation and stdout parsing. Invoke via `uv run`:
|
|
61
51
|
|
|
62
52
|
```bash
|
|
63
53
|
uv run {qmdClassifyHelper} \
|
|
64
|
-
--live-names "{live_collections}" \
|
|
65
54
|
--registry-from-yaml "{project-root}/_bmad/_memory/forger-sidecar/forge-tier.yaml"
|
|
66
55
|
```
|
|
67
56
|
|
|
68
|
-
The script (see `src/shared/scripts/skf-qmd-classify-collections.py` docstring for the full schema) applies the forge-namespace suffix filter (`-brief | -temporal | -docs | -extraction`)
|
|
57
|
+
The script (see `src/shared/scripts/skf-qmd-classify-collections.py` docstring for the full schema) invokes `qmd collection list` itself, applies the forge-namespace suffix filter (`-brief | -temporal | -docs | -extraction`) before classifying, and exits non-zero with an error message on stderr if the daemon is down. Collections owned by unrelated tools are silently excluded from the orphan / healthy / stale sets and counted under `foreign_filtered_count` for telemetry only. This is the PR #244 incident protection: foreign collections never enter any classification that could lead to data loss.
|
|
58
|
+
|
|
59
|
+
**Error handling:** If the script exits non-zero, set `{hygiene_result: "qmd_unavailable", hygiene_healthy: 0, hygiene_orphaned_removed: 0, hygiene_orphaned_kept: 0, hygiene_stale_cleaned: 0}` and skip directly to section 4 (which will still run the ccc-prune branch if `{ccc}` is true).
|
|
69
60
|
|
|
70
61
|
**Parse the JSON output and set context flags:**
|
|
71
62
|
|
|
72
63
|
- `{hygiene_healthy}` ← `len(healthy)`
|
|
73
64
|
- `{orphaned_collections}` ← `orphaned` (the list — used in section 3)
|
|
74
65
|
- `{stale_collections}` ← `stale` (the list — used in section 4)
|
|
66
|
+
- `{live_collections}` ← comma-join of `live_names` (used in §4's clean-stale invocation; the script owns the raw set, the prompt only forwards it)
|
|
75
67
|
- `{foreign_filtered_count}` ← `foreign_filtered_count`
|
|
76
68
|
|
|
77
69
|
Set `{hygiene_result: "completed"}`.
|
|
@@ -80,7 +72,7 @@ Set `{hygiene_result: "completed"}`.
|
|
|
80
72
|
|
|
81
73
|
**If `{orphaned_collections}` is empty:** Set `{hygiene_orphaned_removed: 0, hygiene_orphaned_kept: 0}` and skip to section 4.
|
|
82
74
|
|
|
83
|
-
**
|
|
75
|
+
**Non-interactive resolution.** If `{orphan_action}` is non-null, resolve the gate without prompting using that value: log `"Auto-decision (--orphan-action={value}): kept|removed {len(orphaned_collections)} orphaned forge collection(s)"`. If `{orphan_action}` is `"keep"`, set `{hygiene_orphaned_removed: 0, hygiene_orphaned_kept: len(orphaned_collections)}` and skip to section 4. If `"remove"`, fall through to the removal block below (still no user prompt). Independently, if `{headless_mode}` is true and `{orphan_action}` is null, auto-resolve to the default **Keep** with the equivalent log line and skip to section 4. The two paths compose: `--orphan-action` overrides the headless default; `--headless` without `--orphan-action` keeps backward-compatible behavior.
|
|
84
76
|
|
|
85
77
|
**If `{headless_mode}` is false**, display to the user:
|
|
86
78
|
|
|
@@ -118,11 +110,11 @@ uv run {forgeTierRwHelper} clean-stale \
|
|
|
118
110
|
|
|
119
111
|
The script reads the registry, computes set-difference operations (qmd: registry − live; ccc: filter where `path` does not exist on disk), and atomically rewrites forge-tier.yaml only when something actually changed (mtime preserved on idempotent re-runs). The CI ephemeral-mount caveat for ccc-registry pruning is logged in the script's WARNING message (per PR #248).
|
|
120
112
|
|
|
121
|
-
**Parse the JSON output and set context flags for step
|
|
113
|
+
**Parse the JSON output and set context flags for step 4:**
|
|
122
114
|
|
|
123
115
|
- `{hygiene_stale_cleaned}` ← `len(qmd_removed)`
|
|
124
116
|
- `{ccc_registry_stale_cleaned}` ← `len(ccc_removed)`
|
|
125
|
-
- `{ccc_registry_stale_removed_paths}` ← `ccc_removed` (the list — step
|
|
117
|
+
- `{ccc_registry_stale_removed_paths}` ← `ccc_removed` (the list — step 4 folds individual paths into envelope warnings)
|
|
126
118
|
|
|
127
119
|
If `{hygiene_stale_cleaned}` > 0, display: "**Cleaned {hygiene_stale_cleaned} stale QMD registry entry/entries** (collection no longer exists in QMD)."
|
|
128
120
|
|