bmad-module-skill-forge 1.8.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (136) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/README.md +10 -5
  3. package/docs/_data/pinned.yaml +2 -2
  4. package/docs/agents.md +11 -2
  5. package/docs/architecture.md +5 -4
  6. package/docs/bmad-synergy.md +42 -3
  7. package/docs/campaign.md +172 -0
  8. package/docs/examples.md +7 -3
  9. package/docs/forge-auto.md +90 -0
  10. package/docs/getting-started.md +9 -0
  11. package/docs/how-it-works.md +6 -4
  12. package/docs/index.md +4 -3
  13. package/docs/skill-model.md +1 -1
  14. package/docs/troubleshooting.md +17 -1
  15. package/docs/verifying-a-skill.md +9 -3
  16. package/docs/why-skf.md +1 -1
  17. package/docs/workflows.md +73 -27
  18. package/package.json +2 -2
  19. package/src/module-help.csv +2 -1
  20. package/src/shared/_known-workarounds.yaml +155 -0
  21. package/src/shared/data/language-corpora.json +32 -0
  22. package/src/shared/references/pipeline-contracts.md +14 -2
  23. package/src/shared/scripts/schemas/skf-brief-result-envelope.v1.json +6 -1
  24. package/src/shared/scripts/schemas/skill-brief.v1.json +6 -1
  25. package/src/shared/scripts/skf-derive-assembly-shape.py +107 -0
  26. package/src/shared/scripts/skf-detect-docs.py +417 -0
  27. package/src/shared/scripts/skf-detect-language.py +5 -3
  28. package/src/shared/scripts/skf-emit-brief-result-envelope.py +12 -1
  29. package/src/shared/scripts/skf-emit-result-envelope.py +17 -0
  30. package/src/shared/scripts/skf-extract-public-api.py +53 -0
  31. package/src/shared/scripts/skf-language-corpora.py +100 -0
  32. package/src/shared/scripts/skf-merge-doc-urls.py +244 -0
  33. package/src/shared/scripts/skf-preapply.py +192 -0
  34. package/src/shared/scripts/skf-shape-detect.py +1114 -0
  35. package/src/shared/scripts/skf-validate-brief-schema.py +2 -5
  36. package/src/shared/scripts/skf-validate-pins.py +368 -0
  37. package/src/shared/scripts/skf-write-skill-brief.py +21 -5
  38. package/src/skf-analyze-source/SKILL.md +26 -20
  39. package/src/skf-analyze-source/assets/skill-brief-schema.md +1 -1
  40. package/src/skf-analyze-source/references/init.md +30 -0
  41. package/src/skf-analyze-source/references/step-auto-scope.md +677 -0
  42. package/src/skf-analyze-source/references/step-shape-detect.md +86 -0
  43. package/src/skf-audit-skill/SKILL.md +1 -0
  44. package/src/skf-audit-skill/assets/drift-report-template.md +6 -0
  45. package/src/skf-audit-skill/references/init.md +1 -1
  46. package/src/skf-audit-skill/references/report.md +4 -0
  47. package/src/skf-audit-skill/references/severity-classify.md +1 -1
  48. package/src/skf-audit-skill/references/step-doc-drift.md +147 -0
  49. package/src/skf-brief-skill/SKILL.md +7 -3
  50. package/src/skf-brief-skill/assets/skill-brief-schema.md +1 -1
  51. package/src/skf-brief-skill/references/analyze-target.md +7 -4
  52. package/src/skf-brief-skill/references/confirm-brief.md +0 -1
  53. package/src/skf-brief-skill/references/gather-intent.md +22 -2
  54. package/src/skf-brief-skill/references/scope-definition.md +2 -1
  55. package/src/skf-brief-skill/references/step-auto-brief.md +188 -0
  56. package/src/skf-brief-skill/references/step-auto-validate.md +209 -0
  57. package/src/skf-brief-skill/references/write-brief.md +2 -3
  58. package/src/skf-campaign/SKILL.md +190 -0
  59. package/src/skf-campaign/assets/campaign-state-schema.json +191 -0
  60. package/src/skf-campaign/customize.toml +73 -0
  61. package/src/skf-campaign/manifest.yaml +11 -0
  62. package/src/skf-campaign/references/campaign-directive-spec.md +121 -0
  63. package/src/skf-campaign/references/health-check.md +35 -0
  64. package/src/skf-campaign/references/step-01-setup.md +122 -0
  65. package/src/skf-campaign/references/step-02-strategy.md +97 -0
  66. package/src/skf-campaign/references/step-03-pins.md +56 -0
  67. package/src/skf-campaign/references/step-04-provenance.md +63 -0
  68. package/src/skf-campaign/references/step-05-skill-loop.md +103 -0
  69. package/src/skf-campaign/references/step-06-batch.md +87 -0
  70. package/src/skf-campaign/references/step-07-capstone.md +63 -0
  71. package/src/skf-campaign/references/step-08-verify.md +75 -0
  72. package/src/skf-campaign/references/step-09-refine.md +83 -0
  73. package/src/skf-campaign/references/step-10-export.md +106 -0
  74. package/src/skf-campaign/references/step-11-maintenance.md +84 -0
  75. package/src/skf-campaign/references/step-resume.md +114 -0
  76. package/src/skf-campaign/scripts/.gitkeep +0 -0
  77. package/src/skf-campaign/scripts/campaign-deps.py +235 -0
  78. package/src/skf-campaign/scripts/campaign-parse-manifest.py +119 -0
  79. package/src/skf-campaign/scripts/campaign-provenance.py +247 -0
  80. package/src/skf-campaign/scripts/campaign-render-kickoff.py +158 -0
  81. package/src/skf-campaign/scripts/campaign-report.py +249 -0
  82. package/src/skf-campaign/scripts/campaign-validate-pins.py +174 -0
  83. package/src/skf-campaign/scripts/campaign-validate-state.py +207 -0
  84. package/src/skf-campaign/templates/campaign-brief-template.yaml +34 -0
  85. package/src/skf-campaign/templates/campaign-report-template.md +54 -0
  86. package/src/skf-campaign/templates/kickoff-template.md +48 -0
  87. package/src/skf-create-skill/SKILL.md +4 -1
  88. package/src/skf-create-skill/assets/compile-assembly-rules.md +22 -0
  89. package/src/skf-create-skill/assets/skill-sections.md +2 -0
  90. package/src/skf-create-skill/references/compile.md +5 -2
  91. package/src/skf-create-skill/references/extract.md +9 -1
  92. package/src/skf-create-skill/references/extraction-patterns.md +3 -1
  93. package/src/skf-create-skill/references/generate-artifacts.md +11 -2
  94. package/src/skf-create-skill/references/health-check.md +2 -2
  95. package/src/skf-create-skill/references/report.md +17 -1
  96. package/src/skf-create-skill/references/source-resolution-protocols.md +1 -1
  97. package/src/skf-create-skill/references/step-auto-shard.md +110 -0
  98. package/src/skf-create-skill/references/step-doc-rot.md +109 -0
  99. package/src/skf-create-skill/references/step-doc-sources.md +123 -0
  100. package/src/skf-create-skill/references/sub/fetch-docs.md +29 -0
  101. package/src/skf-create-skill/references/validate.md +12 -3
  102. package/src/skf-drop-skill/SKILL.md +2 -2
  103. package/src/skf-drop-skill/references/execute.md +20 -9
  104. package/src/skf-drop-skill/references/report.md +2 -0
  105. package/src/skf-drop-skill/references/select.md +7 -2
  106. package/src/skf-forger/SKILL.md +15 -4
  107. package/src/skf-refine-architecture/SKILL.md +2 -1
  108. package/src/skf-refine-architecture/references/compile.md +1 -1
  109. package/src/skf-refine-architecture/references/report.md +1 -1
  110. package/src/skf-rename-skill/SKILL.md +2 -2
  111. package/src/skf-rename-skill/references/execute.md +5 -4
  112. package/src/skf-rename-skill/references/rebuild-context.md +2 -2
  113. package/src/skf-rename-skill/references/select.md +3 -3
  114. package/src/skf-setup/SKILL.md +1 -1
  115. package/src/skf-setup/references/auto-index.md +3 -1
  116. package/src/skf-setup/references/detect-and-tier.md +4 -0
  117. package/src/skf-setup/references/report.md +4 -1
  118. package/src/skf-setup/references/tier-rules.md +1 -1
  119. package/src/skf-test-skill/SKILL.md +8 -7
  120. package/src/skf-test-skill/customize.toml +2 -1
  121. package/src/skf-test-skill/references/coverage-check.md +10 -0
  122. package/src/skf-test-skill/references/external-validators.md +1 -1
  123. package/src/skf-test-skill/references/init.md +16 -1
  124. package/src/skf-test-skill/references/report.md +5 -1
  125. package/src/skf-test-skill/references/score.md +95 -6
  126. package/src/skf-test-skill/references/source-access-protocol.md +13 -3
  127. package/src/skf-test-skill/references/step-hard-gate.md +73 -0
  128. package/src/skf-test-skill/scripts/compute-score.py +4 -3
  129. package/src/skf-test-skill/templates/test-report-template.md +1 -0
  130. package/src/skf-update-skill/customize.toml +0 -9
  131. package/src/skf-update-skill/references/detect-changes.md +33 -3
  132. package/src/skf-update-skill/references/health-check.md +2 -2
  133. package/src/skf-update-skill/references/init.md +1 -0
  134. package/src/skf-update-skill/references/re-extract.md +15 -1
  135. package/src/skf-verify-stack/references/report.md +1 -1
  136. package/tools/cli/lib/ui.js +3 -2
@@ -0,0 +1,191 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "title": "campaign-state",
4
+ "description": "Schema for _campaign-state.yaml — single source of truth for campaign orchestration state",
5
+ "type": "object",
6
+ "required": ["campaign", "skills", "dependency_graph"],
7
+ "additionalProperties": false,
8
+ "properties": {
9
+ "campaign": {
10
+ "type": "object",
11
+ "required": ["name", "started_at", "last_updated", "current_stage", "quality_gate", "health_findings_queue"],
12
+ "additionalProperties": false,
13
+ "properties": {
14
+ "name": {
15
+ "type": "string"
16
+ },
17
+ "started_at": {
18
+ "type": "string",
19
+ "format": "date-time"
20
+ },
21
+ "last_updated": {
22
+ "type": "string",
23
+ "format": "date-time"
24
+ },
25
+ "current_stage": {
26
+ "type": "integer",
27
+ "minimum": 0,
28
+ "maximum": 10
29
+ },
30
+ "directive_path": {
31
+ "type": "string"
32
+ },
33
+ "quality_gate": {
34
+ "type": "object",
35
+ "required": ["hard", "soft_target", "soft_fallback"],
36
+ "additionalProperties": false,
37
+ "properties": {
38
+ "hard": {
39
+ "type": "string"
40
+ },
41
+ "soft_target": {
42
+ "type": "number"
43
+ },
44
+ "soft_fallback": {
45
+ "type": "number"
46
+ }
47
+ }
48
+ },
49
+ "health_findings_queue": {
50
+ "type": "string",
51
+ "enum": ["local", "improvement"]
52
+ },
53
+ "architecture_doc_path": {
54
+ "type": ["string", "null"],
55
+ "description": "Path to the architecture document consumed by the verify (Stage 7) and refine (Stage 8) stages. Sourced at setup; null when the campaign runs no verification."
56
+ },
57
+ "capstone": {
58
+ "type": ["object", "null"],
59
+ "additionalProperties": false,
60
+ "description": "Capstone (stack) outcome composed from all completed campaign skills (Tier A and Tier B). Campaign-level summary; the composed skill itself lives at skill_path.",
61
+ "properties": {
62
+ "skill_path": {
63
+ "type": ["string", "null"]
64
+ },
65
+ "quality_score": {
66
+ "type": ["number", "null"]
67
+ },
68
+ "verified": {
69
+ "type": ["boolean", "null"]
70
+ },
71
+ "completed_at": {
72
+ "type": ["string", "null"],
73
+ "format": "date-time"
74
+ }
75
+ }
76
+ },
77
+ "verification": {
78
+ "type": ["object", "null"],
79
+ "additionalProperties": false,
80
+ "description": "Stage 7 verify-stack summary. Detailed findings live in the external report at report_path.",
81
+ "properties": {
82
+ "report_path": {
83
+ "type": ["string", "null"]
84
+ },
85
+ "overall_verdict": {
86
+ "type": ["string", "null"],
87
+ "enum": ["Verified", "Plausible", "Risky", "Blocked", null]
88
+ },
89
+ "coverage_percentage": {
90
+ "type": ["number", "null"]
91
+ },
92
+ "recommendation_count": {
93
+ "type": ["integer", "null"]
94
+ }
95
+ }
96
+ },
97
+ "refinement": {
98
+ "type": ["object", "null"],
99
+ "additionalProperties": false,
100
+ "description": "Stage 8 refine-architecture summary. The refined document lives at refined_path.",
101
+ "properties": {
102
+ "refined_path": {
103
+ "type": ["string", "null"]
104
+ },
105
+ "gap_count": {
106
+ "type": ["integer", "null"]
107
+ },
108
+ "issue_count": {
109
+ "type": ["integer", "null"]
110
+ },
111
+ "improvement_count": {
112
+ "type": ["integer", "null"]
113
+ }
114
+ }
115
+ }
116
+ }
117
+ },
118
+ "skills": {
119
+ "type": "array",
120
+ "items": {
121
+ "type": "object",
122
+ "required": ["name", "status", "tier"],
123
+ "additionalProperties": false,
124
+ "properties": {
125
+ "name": {
126
+ "type": "string"
127
+ },
128
+ "status": {
129
+ "type": "string",
130
+ "enum": ["pending", "active", "completed", "failed", "skipped"]
131
+ },
132
+ "depends_on": {
133
+ "type": "array",
134
+ "items": {
135
+ "type": "string"
136
+ }
137
+ },
138
+ "tier": {
139
+ "type": "string",
140
+ "enum": ["A", "B"]
141
+ },
142
+ "pin": {
143
+ "type": ["string", "null"]
144
+ },
145
+ "brief_path": {
146
+ "type": ["string", "null"]
147
+ },
148
+ "skill_path": {
149
+ "type": ["string", "null"]
150
+ },
151
+ "quality_score": {
152
+ "type": ["number", "null"]
153
+ },
154
+ "workarounds_applied": {
155
+ "type": "array",
156
+ "items": {
157
+ "type": "string"
158
+ }
159
+ },
160
+ "started_at": {
161
+ "type": ["string", "null"],
162
+ "format": "date-time"
163
+ },
164
+ "completed_at": {
165
+ "type": ["string", "null"],
166
+ "format": "date-time"
167
+ },
168
+ "commit_sha": {
169
+ "type": ["string", "null"]
170
+ }
171
+ }
172
+ }
173
+ },
174
+ "dependency_graph": {
175
+ "type": "object",
176
+ "required": ["execution_order", "circular_deps_detected"],
177
+ "additionalProperties": false,
178
+ "properties": {
179
+ "execution_order": {
180
+ "type": "array",
181
+ "items": {
182
+ "type": "string"
183
+ }
184
+ },
185
+ "circular_deps_detected": {
186
+ "type": "boolean"
187
+ }
188
+ }
189
+ }
190
+ }
191
+ }
@@ -0,0 +1,73 @@
1
+ # DO NOT EDIT -- overwritten on every update.
2
+ #
3
+ # Workflow customization surface for skf-campaign.
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 (config load, customization
12
+ # resolve). Overrides append. Use for org-wide pre-flight checks (auth,
13
+ # network, compliance) that must precede any orchestration 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 campaign
24
+ # (house style, naming conventions, quality guardrails). These are injected
25
+ # into every per-skill kickoff, so project-scoped house facts propagate to
26
+ # the whole campaign. Overrides append.
27
+ #
28
+ # Each entry is either:
29
+ # - a literal sentence, e.g. "All skills must cite their upstream source."
30
+ # - a file reference prefixed with `file:`, e.g.
31
+ # "file:{project-root}/docs/skill-style.md" (globs supported; file
32
+ # contents are loaded and treated as facts).
33
+
34
+ persistent_facts = [
35
+ "file:{project-root}/**/project-context.md",
36
+ ]
37
+
38
+ # --- Workspace path ---
39
+ #
40
+ # Where the campaign keeps its state, backup, brief, batch input, archive,
41
+ # and decision log. Empty string = use the bundled default
42
+ # `{forge_data_folder}/_campaign`. Override to relocate campaign artifacts
43
+ # (e.g. a shared volume) without editing every step file. Resolved once in
44
+ # On Activation as {campaignWorkspacePath}.
45
+
46
+ campaign_workspace_path = ""
47
+
48
+ # --- Quality gate ---
49
+ #
50
+ # Campaign-wide quality bar applied to every skill. Scalars override the
51
+ # bundled defaults; the per-campaign brief and any directive `## Quality
52
+ # Overrides` still take precedence at runtime. Override here to change the
53
+ # org-wide default without forking the skill.
54
+
55
+ quality_gate_hard = "zero-critical-high"
56
+ quality_gate_soft_target = 90
57
+ quality_gate_soft_fallback = 80
58
+
59
+ # --- Optional template overrides ---
60
+ #
61
+ # Lift the canonical template paths so orgs can substitute house-style copies
62
+ # without forking the skill. Empty string = use the bundled default under
63
+ # `templates/`.
64
+
65
+ report_template_path = ""
66
+ kickoff_template_path = ""
67
+ brief_template_path = ""
68
+
69
+ # Optional post-completion hook. When non-empty, the workflow invokes:
70
+ # <on_complete> --report-path=<path-to-campaign-report.md>
71
+ # after the campaign report is finalized (step-11). Failures are logged to
72
+ # the decision log but never fail the campaign. Empty = no-op.
73
+ on_complete = ""
@@ -0,0 +1,11 @@
1
+ code: CA
2
+ name: skf-campaign
3
+ description: "Campaign orchestration — multi-library skill production with dependency tracking"
4
+ version: "2.0.0"
5
+ trigger: campaign
6
+ parent_module: skf
7
+
8
+ config:
9
+ state_file: "_campaign-state.yaml"
10
+ backup_file: "_campaign-state.yaml.bak"
11
+ directive_file: "_campaign-directive.md"
@@ -0,0 +1,121 @@
1
+ ---
2
+ stateFile: '{campaignWorkspacePath}/_campaign-state.yaml'
3
+ directiveFile: '_campaign-directive.md'
4
+ ---
5
+
6
+ # Campaign Directive Specification
7
+
8
+ This is the **canonical contract** for the campaign directive. SKILL.md and the
9
+ step files' "Read Directive" sections defer to it rather than re-specifying the
10
+ format — when a step loads `campaign.directive_path`, it applies the contents
11
+ per the sections below.
12
+
13
+ ## Purpose
14
+
15
+ The campaign directive (`_campaign-directive.md`) is a file-based standing directive that provides campaign-wide policy persisting across context boundaries. It is:
16
+
17
+ - **Human-readable** — plain markdown, editable with any text editor
18
+ - **Auditable** — version-controllable alongside campaign artifacts
19
+ - **Context-boundary safe** — re-read from disk at each stage transition, with no dependency on LLM memory (NFR-2)
20
+
21
+ The directive allows the operator to adjust campaign-wide policy without editing the state file or relying on LLM memory.
22
+
23
+ ## File Format
24
+
25
+ - **Encoding:** UTF-8 markdown
26
+ - **Frontmatter:** not required (plain content is sufficient)
27
+ - **Location:** the path specified by `campaign.directive_path` in the campaign state file
28
+ - **Default filename:** `_campaign-directive.md` (configured in `manifest.yaml` as `config.directive_file`)
29
+
30
+ ## Recognized Sections
31
+
32
+ All sections are optional. The directive may contain any combination of these, or none at all.
33
+
34
+ ### `## Quality Overrides`
35
+
36
+ Operator adjustments to quality gates for specific skills or the entire campaign.
37
+
38
+ Example:
39
+ ```markdown
40
+ ## Quality Overrides
41
+
42
+ - Accept 85% for library-x due to incomplete upstream docs
43
+ - Lower soft gate to 70% for experimental-sdk (early-stage repo)
44
+ ```
45
+
46
+ ### `## Skip List`
47
+
48
+ Skills to skip during processing, with rationale.
49
+
50
+ Example:
51
+ ```markdown
52
+ ## Skip List
53
+
54
+ - Skip library-y — upstream repo is in maintenance mode
55
+ - Skip legacy-tool — will be removed in next sprint
56
+ ```
57
+
58
+ ### `## Pipeline Flags`
59
+
60
+ Per-skill or campaign-wide pipeline modifiers.
61
+
62
+ Example:
63
+ ```markdown
64
+ ## Pipeline Flags
65
+
66
+ - Use `--pin main` for all unpinned skills
67
+ - Force forge-auto mode for large-repo-z
68
+ ```
69
+
70
+ ### `## Notes`
71
+
72
+ Free-form operator context for the LLM agent processing the campaign.
73
+
74
+ Example:
75
+ ```markdown
76
+ ## Notes
77
+
78
+ Focus on documentation quality this run — the team is preparing for an external audit.
79
+ Prioritize skills that feed into the public API layer.
80
+ ```
81
+
82
+ ## Unrecognized Sections
83
+
84
+ Any section heading not listed above is treated as general guidance. The LLM agent reads and applies judgment based on the content. This allows operators to add ad-hoc context without modifying the specification.
85
+
86
+ ## Read Contract
87
+
88
+ The directive is read from the path stored in `campaign.directive_path` (in the campaign state file) at stage entry. Every step that loads state and performs actionable processing checks for and applies the directive.
89
+
90
+ Steps that read the directive:
91
+ - **step-02-strategy** — applies directive contents as campaign-wide context for strategy processing (e.g. `## Notes` visible while reviewing the computed order; the order itself is computed deterministically by `campaign-deps.py`)
92
+ - **step-05-skill-loop** — directive populates `{{directive_content}}` in kickoff template and provides campaign-wide context for all skill processing
93
+ - **step-06-batch** — operator may want skip/quality overrides for Tier B batch processing
94
+ - **step-08-verify** — operator may want to influence verification focus areas
95
+ - **step-09-refine** — operator may want to guide refinement priorities
96
+ - **step-10-export** — operator may want to exclude specific skills from export
97
+
98
+ Steps that do NOT read the directive:
99
+ - **step-01-setup** — creates the state file; `directive_path` is collected as input, not read
100
+ - **step-03-pins** — pin validation is deterministic (Python script); directive cannot influence gh API calls
101
+ - **step-04-provenance** — repo access verification is deterministic; directive cannot influence commit SHA recording
102
+ - **step-07-capstone** — SS compose-mode is mechanical aggregation; no operator policy applies
103
+ - **step-11-maintenance** — report generation is templated; health check is autonomous
104
+ - **step-resume** — routing step, not a processing step
105
+
106
+ ## Absence Behavior
107
+
108
+ - If `campaign.directive_path` is not set in the state file: no error, proceed with defaults
109
+ - If `campaign.directive_path` is set but the file does not exist at that path: no error, proceed with defaults
110
+ - The directive is always optional — a campaign runs identically without one
111
+
112
+ ## Modification Contract
113
+
114
+ The operator may edit the directive file at any time between stages. The next stage that reads the directive will pick up the updated version. There is no caching — the directive is always read fresh from disk at stage entry.
115
+
116
+ ## Lifecycle
117
+
118
+ 1. **Created:** before or during Stage 0 (setup) — the operator provides the file path, or it defaults to `_campaign-directive.md`
119
+ 2. **Read:** at each stage entry by applicable steps (see Read Contract above)
120
+ 3. **Modified:** at any time between stages by the operator
121
+ 4. **Consumed:** by the LLM agent as campaign-wide context influencing processing decisions
@@ -0,0 +1,35 @@
1
+ ---
2
+ # Note: `shared/health-check.md` resolves relative to the SKF module root
3
+ # ({project-root}/_bmad/skf/ when installed, {project-root}/src/ during
4
+ # development), NOT relative to this step file.
5
+ nextStepFile: 'shared/health-check.md'
6
+ stateFile: '{campaignWorkspacePath}/_campaign-state.yaml'
7
+ ---
8
+
9
+ <!-- Config: communicate in {communication_language}. -->
10
+
11
+ # Workflow Health Check
12
+
13
+ ## STEP GOAL:
14
+
15
+ Apply the operator's findings-routing consent, then chain to the shared workflow self-improvement health check at `{nextStepFile}`. This is the terminal step of skf-campaign — after the shared health check completes, the workflow is fully done.
16
+
17
+ ## Rules
18
+
19
+ - No user-facing reports, file writes, or result contracts in this step — those belong in step 11.
20
+ - The ONLY processing permitted here is reading the routing preference (below) and carrying it into `{nextStepFile}`; otherwise delegate directly with no additional commentary.
21
+
22
+ ## MANDATORY SEQUENCE
23
+
24
+ ### 1. Apply findings-routing consent
25
+
26
+ Read `campaign.health_findings_queue` from `{stateFile}` and carry it into the shared health check as the operator's **already-decided** routing consent (so the shared step does not re-prompt, satisfying its "explicit opt-in" requirement for non-bug findings):
27
+
28
+ - `"improvement"` — the operator opted in at setup: route this campaign's friction/gap findings to the shared improvement queue (the shared step's opt-in is pre-satisfied; do not re-prompt).
29
+ - `"local"` (default) — keep findings in the local queue only; do not submit to the shared queue.
30
+
31
+ If the state file is unreadable, default to `"local"` (never submit without consent).
32
+
33
+ ### 2. Delegate
34
+
35
+ Load `{nextStepFile}`, read it fully, then execute it — applying the routing consent from step 1.
@@ -0,0 +1,122 @@
1
+ ---
2
+ nextStepFile: 'step-02-strategy.md'
3
+ stateSchemaFile: 'assets/campaign-state-schema.json'
4
+ stateFile: '{campaignWorkspacePath}/_campaign-state.yaml'
5
+ briefFile: '{campaignWorkspacePath}/campaign-brief.yaml'
6
+ templateFile: '{briefTemplatePath}'
7
+ validateScript: 'scripts/campaign-validate-state.py'
8
+ manifestScript: 'scripts/campaign-parse-manifest.py'
9
+ ---
10
+
11
+ <!-- Config: communicate in {communication_language}. -->
12
+
13
+ # Setup
14
+
15
+ ## STEP GOAL:
16
+
17
+ Collect campaign inputs from the operator, create the initial `_campaign-state.yaml`, and generate `campaign-brief.yaml` so the campaign has a persistent starting point that survives context death.
18
+
19
+ This is the only step that creates the state file (it does not yet exist). All subsequent steps use **read-backup-modify-write** per the State Contract in SKILL.md.
20
+
21
+ ## RULES
22
+
23
+ - This step creates the state file — there is no existing state to read or back up.
24
+ - Validate the written state with `uv run {validateScript} --state-file {stateFile}` before generating the brief. HALT (exit code 3, `invalid-state`) on non-zero, surfacing the script's `errors[]`.
25
+ - If `{headless_mode}` is true, draw inputs from `--brief`/`--manifest` (On Activation step 4) and auto-proceed through confirmation gates with the default action, logging each auto-decision to the decision log.
26
+
27
+ ## TASKS
28
+
29
+ ### §1 — Collect Inputs
30
+
31
+ Accept from the operator (or, in headless mode, from the `--brief`/`--manifest` source parsed in On Activation):
32
+
33
+ - `campaign_name` — string identifier for this campaign run
34
+ - Target libraries — each entry requires:
35
+ - `name` — skill name
36
+ - `repo_url` — source repository URL
37
+ - `tier` — `"A"` (full pipeline) or `"B"` (batch)
38
+ - `pin` — version pin (string) or `null` for latest
39
+ - `depends_on` — array of skill names this target depends on (may be empty)
40
+ - `directive_path` (optional) — path to a `_campaign-directive.md` file with operator directives (contract: `references/campaign-directive-spec.md`)
41
+ - `architecture_doc_path` (optional) — path to the architecture document the verify (Stage 7) and refine (Stage 8) stages consume. If omitted here, those stages discover it at runtime (`docs/architecture.md`, then `_bmad-output/planning-artifacts/architecture.md`). Capturing it now persists the choice across resume and avoids re-prompting.
42
+
43
+ When seeding from `--manifest`, parse it deterministically: `uv run {manifestScript} <manifest-file>`. If the result's `errors[]` is non-empty (exit 1), HALT listing the offending line numbers — never run a partial target set. When seeding from `--brief`, read the existing `campaign-brief.yaml` directly.
44
+
45
+ If no targets can be collected (empty interactive input or empty `--brief`/`--manifest`), HALT with guidance — a campaign needs at least one target.
46
+
47
+ ### §2 — Health Queue Preference
48
+
49
+ Default to `"local"` (project-local findings queue). Present the opt-in prompt:
50
+
51
+ > Send anonymized quality findings to the shared improvement queue? [y/N]
52
+
53
+ - **y** — set `health_findings_queue` to `"improvement"`
54
+ - **N** (default) — keep `health_findings_queue` as `"local"`
55
+
56
+ In headless mode: auto-select `"local"` (N) and log the auto-decision.
57
+
58
+ ### §3 — Build State Object
59
+
60
+ Construct `_campaign-state.yaml` in memory from collected inputs. Use the campaign-wide quality gate resolved in On Activation: `{qualityGateHard}` / `{qualityGateSoftTarget}` / `{qualityGateSoftFallback}`. Note: `repo_url` (collected in §1) is NOT part of the state schema — it belongs in the brief only (§5). The state schema enforces `additionalProperties: false`, so including it would fail validation.
61
+
62
+ ```yaml
63
+ campaign:
64
+ name: "{campaign_name}"
65
+ started_at: "{current_iso8601_with_tz}"
66
+ last_updated: "{current_iso8601_with_tz}"
67
+ current_stage: 0
68
+ directive_path: "{directive_path or omit if not provided}"
69
+ architecture_doc_path: "{architecture_doc_path or omit if not provided}"
70
+ quality_gate:
71
+ hard: "{qualityGateHard}"
72
+ soft_target: {qualityGateSoftTarget}
73
+ soft_fallback: {qualityGateSoftFallback}
74
+ health_findings_queue: "{local or improvement}"
75
+ skills:
76
+ # One entry per target:
77
+ - name: "{target.name}"
78
+ status: "pending"
79
+ depends_on: [] # from target.depends_on
80
+ tier: "{target.tier}"
81
+ pin: null # from target.pin
82
+ brief_path: null # populated in step-05 once BS produces the skill's brief
83
+ skill_path: null
84
+ quality_score: null
85
+ workarounds_applied: []
86
+ started_at: null
87
+ completed_at: null
88
+ dependency_graph:
89
+ execution_order: [] # populated by step-02-strategy
90
+ circular_deps_detected: false
91
+ ```
92
+
93
+ ### §4 — Write + Validate State
94
+
95
+ 1. Ensure the directory `{campaignWorkspacePath}/` exists (create if missing).
96
+ 2. Write the constructed state to `{stateFile}`. This is the initial creation — no `.bak` is needed for the first write; all subsequent steps use read-backup-modify-write.
97
+ 3. Run `uv run {validateScript} --state-file {stateFile}`. On non-zero (invalid), **HALT** (exit 3) with the script's `errors[]` — do not proceed to brief generation with an invalid state file.
98
+
99
+ ### §5 — Generate Brief
100
+
101
+ Populate `{templateFile}` with collected inputs and write to `{briefFile}`. Fill in:
102
+
103
+ - `campaign_name` — from collected input
104
+ - `created_at` — current ISO-8601 timestamp with timezone
105
+ - `targets` — array of target entries with `name`, `repo_url`, `tier`, `pin`, `depends_on`
106
+ - `quality_gate` — `{qualityGateHard}` / `{qualityGateSoftTarget}` / `{qualityGateSoftFallback}`
107
+ - `health_findings_queue` — from the §2 preference decision
108
+ - `architecture_doc_path` — from collected input, or empty string if not provided
109
+ - `notes` — operator-provided context, or empty string
110
+
111
+ The brief is a machine-readable snapshot enabling fresh-context resume (FR-35).
112
+
113
+ ## OUTPUT
114
+
115
+ Confirm state file creation and brief generation. Display summary:
116
+
117
+ - Campaign name
118
+ - Number of targets
119
+ - Tier distribution (count of A vs B)
120
+ - Health queue setting
121
+
122
+ Chain to `{nextStepFile}`.
@@ -0,0 +1,97 @@
1
+ ---
2
+ nextStepFile: 'step-03-pins.md'
3
+ stateSchemaFile: 'assets/campaign-state-schema.json'
4
+ stateFile: '{campaignWorkspacePath}/_campaign-state.yaml'
5
+ backupFile: '{campaignWorkspacePath}/_campaign-state.yaml.bak'
6
+ depsScript: 'scripts/campaign-deps.py'
7
+ validateScript: 'scripts/campaign-validate-state.py'
8
+ ---
9
+
10
+ <!-- Config: communicate in {communication_language}. -->
11
+
12
+ # Strategy
13
+
14
+ ## STEP GOAL:
15
+
16
+ Compute the execution order from dependency edges, detect circular dependencies, and present a human-readable strategy view to the operator so the campaign plan is visible before execution begins.
17
+
18
+ ## RULES
19
+
20
+ - This step uses the **read-backup-modify-write** pattern (state file exists from step-01).
21
+ - Validate state on load via `uv run {validateScript} --state-file {stateFile}`; HALT (exit 3) on non-zero.
22
+ - Write `execution_order` and `circular_deps_detected` to `dependency_graph`.
23
+ - Update `campaign.current_stage` to `1`.
24
+ - Update `campaign.last_updated` to current ISO-8601 with timezone on every write.
25
+ - If `{headless_mode}` is true, auto-proceed through confirmation gates with the default action and log each auto-decision.
26
+
27
+ ## TASKS
28
+
29
+ ### §1 — Read + Validate State
30
+
31
+ Load `{stateFile}`. Run `uv run {validateScript} --state-file {stateFile}`; on non-zero, HALT (exit 3) with the script's `errors[]`.
32
+
33
+ ### §2 — Backup State
34
+
35
+ Copy `{stateFile}` to `{backupFile}` before any modification.
36
+
37
+ ### §3 — Read Directive
38
+
39
+ If `campaign.directive_path` is set in state, load the file at that path and apply its contents as campaign-wide context for this stage's processing, per the directive contract in `references/campaign-directive-spec.md`. If the file is not found, continue without error (directive is optional).
40
+
41
+ ### §4 — Compute Execution Order
42
+
43
+ Run the deterministic topological sort — do not hand-compute it:
44
+
45
+ ```
46
+ uv run {depsScript} --compute --state-file {stateFile}
47
+ ```
48
+
49
+ Parse the JSON output: `execution_order` (the ordered skill names — Kahn's sort with Tier A placed before Tier B within a dependency level), `circular_deps_detected` (bool), and `cycle_participants` (the unplaced skills when a cycle exists, else null). Exit code 1 from the script signals a cycle or a dangling dependency reference; exit code 2 signals a state/parse error — surface either and HALT.
50
+
51
+ ### §5 — Handle Circular Dependencies
52
+
53
+ If `circular_deps_detected` is `true`, HALT (exit code 4, `circular-deps`) with a clear error listing `cycle_participants` and their mutual `depends_on` edges. Do NOT proceed — circular dependencies make execution order impossible.
54
+
55
+ ### §6 — Write State
56
+
57
+ Set `dependency_graph.execution_order` to the computed order. Set `dependency_graph.circular_deps_detected` to the detection result. Set `campaign.current_stage` to `1`. Set `campaign.last_updated` to current ISO-8601 with timezone. Write to `{stateFile}`.
58
+
59
+ ### §7 — Present Strategy View
60
+
61
+ Display a human-readable strategy summary to the operator (not written to a file — display only):
62
+
63
+ ```
64
+ CAMPAIGN STRATEGY: {campaign_name}
65
+
66
+ EXECUTION ORDER:
67
+ 1. {skill_name} [Tier {tier}] {pin or "latest"}
68
+ 2. {skill_name} [Tier {tier}] {pin or "latest"} ← depends on: {dep1, dep2}
69
+ ...
70
+
71
+ DEPENDENCY MAP:
72
+ {skill_a} → {skill_b}, {skill_c}
73
+ {skill_d} → (no dependencies)
74
+ ...
75
+
76
+ QUALITY GATE:
77
+ Hard gate: {quality_gate.hard}
78
+ Soft target: {quality_gate.soft_target}%
79
+ Soft fallback: {quality_gate.soft_fallback}%
80
+
81
+ TIER DISTRIBUTION:
82
+ Tier A (full pipeline): {count}
83
+ Tier B (QS batch): {count}
84
+ ```
85
+
86
+ ### §8 — Plan Confirmation Gate
87
+
88
+ The strategy view is the last review surface before a potentially long, mostly-unattended run begins. Present a confirmation gate:
89
+
90
+ - `[P]roceed` — begin execution (chain to `{nextStepFile}`).
91
+ - `[C]ancel` — stop now with exit code 12 (`user-cancelled`); state is intact and resumable. To change targets, edit the campaign brief (`{campaignWorkspacePath}/campaign-brief.yaml`) or re-run `campaign` (overwrite), then start again.
92
+
93
+ **HALT and wait for operator input.** In headless mode, auto-proceed with `[P]` and log "headless: auto-proceed past plan-confirmation gate" to the decision log.
94
+
95
+ ## OUTPUT
96
+
97
+ Confirm strategy computed, display the strategy view, and resolve the §8 gate. Chain to `{nextStepFile}`.