$npx -y skills add armelhbobdad/bmad-module-skill-forge --skill skf-campaignCampaign orchestration — multi-library skill production with dependency tracking, file-based state, and resume. Use when the user asks to "run a campaign" or "orchestrate skills.
| 1 | # Campaign |
| 2 | |
| 3 | ## Overview |
| 4 | |
| 5 | Orchestrates the production of 15+ skills across multiple sessions by driving them through the full SKF pipeline (brief, generate, compile, test, export) in dependency order. Campaign sits atop the pipeline ladder: it sequences the workflows that produce skills rather than producing artifacts itself. File-based state (`_campaign-state.yaml`) survives context death, enabling resume from any point. |
| 6 | |
| 7 | ## Conventions |
| 8 | |
| 9 | - Bare paths (e.g. `references/step-01-setup.md`) resolve from the skill root. |
| 10 | - `references/` holds the stage-chained step files plus reference specs (e.g. the `_campaign-directive.md` contract at `references/campaign-directive-spec.md`); `templates/`, `scripts/`, and `assets/` hold templates, deterministic helpers, and the state schema. |
| 11 | - `{skill-root}` resolves to this skill's installed directory (where `customize.toml` lives). |
| 12 | - `{project-root}`-prefixed paths resolve from the project working directory. |
| 13 | - `{skill-name}` resolves to the skill directory's basename. |
| 14 | |
| 15 | ## Role |
| 16 | |
| 17 | You are a campaign orchestrator operating in Ferris's Management mode. You sequence workflows, track per-skill state, enforce quality gates, and ensure every skill reaches its target tier — while the individual pipeline workflows handle the actual artifact production. |
| 18 | |
| 19 | ## On Activation |
| 20 | |
| 21 | Run these steps once, in order, before dispatching to Mode Routing. |
| 22 | |
| 23 | 1. **Load config.** Read `{project-root}/_bmad/skf/config.yaml` and `{sidecar_path}/preferences.yaml` in one batched message (independent files). From config resolve `project_name`, `user_name`, `communication_language`, `document_output_language`, `skills_output_folder`, `forge_data_folder`, `sidecar_path`. From preferences resolve `headless_mode` (default false). If the config file is missing, fall back to `forge_data_folder = forge-data`. |
| 24 | |
| 25 | 2. **Resolve `{headless_mode}`** — true if `--headless` or `-H` was passed as an argument, or if `headless_mode: true` in `preferences.yaml`. Default: false. |
| 26 | |
| 27 | 3. **Resolve workflow customization.** Run: |
| 28 | |
| 29 | ```bash |
| 30 | python3 {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key workflow |
| 31 | ``` |
| 32 | |
| 33 | The script merges three layers (scalars override, arrays append): |
| 34 | |
| 35 | - `{skill-root}/customize.toml` — bundled defaults |
| 36 | - `_bmad/custom/<skill-name>.toml` under `{project-root}` — team overrides (committed) |
| 37 | - `_bmad/custom/<skill-name>.user.toml` under `{project-root}` — personal overrides (gitignored) |
| 38 | |
| 39 | If it fails or is missing, fall back to `{skill-root}/customize.toml` directly. Resolve each scalar now (so step files never repeat the conditional) and stash as workflow-context variables: |
| 40 | |
| 41 | - `{campaignWorkspacePath}` ← `workflow.campaign_workspace_path` if non-empty, else `{forge_data_folder}/_campaign` |
| 42 | - `{qualityGateHard}` / `{qualityGateSoftTarget}` / `{qualityGateSoftFallback}` ← the `quality_gate_*` scalars (defaults `zero-critical-high` / `90` / `80`) |
| 43 | - `{reportTemplatePath}` ← `workflow.report_template_path` if non-empty, else `templates/campaign-report-template.md` |
| 44 | - `{kickoffTemplatePath}` ← `workflow.kickoff_template_path` if non-empty, else `templates/kickoff-template.md` |
| 45 | - `{briefTemplatePath}` ← `workflow.brief_template_path` if non-empty, else `templates/campaign-brief-template.yaml` |
| 46 | - `{onComplete}` ← `workflow.on_complete` (empty = no-op) |
| 47 | |
| 48 | Load `workflow.persistent_facts` (literal sentences and `file:` references, globs expanded) and keep them in mind for the whole campaign — they are injected into every per-skill kickoff. Run any `activation_steps_prepend` before step 1 and any `activation_steps_append` after this step. |
| 49 | |
| 50 | 4. **Parse CLI overrides** into the workflow context: |
| 51 | |
| 52 | | Flag | Effect | |
| 53 | | --- | --- | |
| 54 | | `--headless` / `-H` | Force `{headless_mode} = true` (see step 2). | |
| 55 | | `--brief <file>` | Seed step-01 targets from a `campaign-brief.yaml` instead of interactive prompts. Implies `--headless`. | |
| 56 | | `--manifest <file>` | Seed step-01 targets from a plain-text `name,repo_url,tier,pin` manifest. Implies `--headless`. | |
| 57 | | `--from <skill>` | Resume override — see Mode Routing. | |
| 58 | |
| 59 | If `--brief` or `--manifest` is set, force `{headless_mode} = true` (log "headless: coerced by --brief/--manifest" if it was false). |
| 60 | |
| 61 | **`--manifest` format:** one `name,repo_url,tier,pin` target per line (empty `pin` = latest); a trailing `;dep1,dep2` segment sets `depends_on`; blank and `#` lines are skipped. A malformed line HALTs step-01 with the offending line numbers — never a partial target set. |
| 62 | |
| 63 | 5. **Dispatch** per Mode Routing below. |
| 64 | |
| 65 | ## Workflow Rules |
| 66 | |
| 67 | These rules apply to every step in this workflow: |
| 68 | |
| 69 | - State-first — write state to disk before chaining to the next step or workflow |
| 70 | - Read-backup-modify-write for all stat |