bmad-module-skill-forge 1.2.0 → 1.4.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 (48) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/docs/_data/pinned.yaml +1 -1
  3. package/docs/skill-model.md +26 -32
  4. package/docs/troubleshooting.md +12 -0
  5. package/docs/workflows.md +87 -15
  6. package/package.json +2 -2
  7. package/src/shared/references/output-contract-schema.md +10 -0
  8. package/src/shared/scripts/schemas/skf-brief-result-envelope.v1.json +58 -0
  9. package/src/shared/scripts/schemas/skill-brief.v1.json +77 -0
  10. package/src/shared/scripts/schemas/workspace-detection.v1.json +44 -0
  11. package/src/shared/scripts/skf-detect-language.py +277 -0
  12. package/src/shared/scripts/skf-detect-workspaces.py +427 -0
  13. package/src/shared/scripts/skf-emit-brief-result-envelope.py +257 -0
  14. package/src/shared/scripts/skf-extract-public-api.py +534 -0
  15. package/src/shared/scripts/skf-forge-tier-rw.py +73 -0
  16. package/src/shared/scripts/skf-recommend-scope-type.py +369 -0
  17. package/src/shared/scripts/skf-render-quick-metadata.py +192 -0
  18. package/src/shared/scripts/skf-resolve-package.py +264 -0
  19. package/src/shared/scripts/skf-validate-brief-inputs.py +293 -0
  20. package/src/shared/scripts/skf-validate-output.py +24 -7
  21. package/src/shared/scripts/skf-write-skill-brief.py +509 -0
  22. package/src/skf-brief-skill/SKILL.md +41 -12
  23. package/src/skf-brief-skill/assets/description-voice-examples.md +19 -0
  24. package/src/skf-brief-skill/assets/scope-templates.md +5 -0
  25. package/src/skf-brief-skill/assets/skill-brief-schema.md +1 -40
  26. package/src/skf-brief-skill/references/draft-checkpoint.md +46 -0
  27. package/src/skf-brief-skill/references/headless-args.md +22 -0
  28. package/src/skf-brief-skill/references/headless-source-authority-detection.md +26 -0
  29. package/src/skf-brief-skill/references/portfolio-similarity-check.md +35 -0
  30. package/src/skf-brief-skill/references/qmd-collection-registration.md +52 -0
  31. package/src/skf-brief-skill/references/version-resolution.md +46 -0
  32. package/src/skf-brief-skill/steps-c/step-01-gather-intent.md +164 -14
  33. package/src/skf-brief-skill/steps-c/step-02-analyze-target.md +118 -50
  34. package/src/skf-brief-skill/steps-c/step-03-scope-definition.md +48 -5
  35. package/src/skf-brief-skill/steps-c/step-04-confirm-brief.md +33 -19
  36. package/src/skf-brief-skill/steps-c/step-05-write-brief.md +93 -97
  37. package/src/skf-brief-skill/steps-c/step-06-health-check.md +11 -2
  38. package/src/skf-quick-skill/SKILL.md +178 -10
  39. package/src/skf-quick-skill/assets/skill-template.md +5 -1
  40. package/src/skf-quick-skill/references/registry-resolution.md +2 -0
  41. package/src/skf-quick-skill/steps-c/step-01-resolve-target.md +84 -16
  42. package/src/skf-quick-skill/steps-c/step-02-ecosystem-check.md +3 -3
  43. package/src/skf-quick-skill/steps-c/step-03-quick-extract.md +86 -43
  44. package/src/skf-quick-skill/steps-c/step-04-compile.md +49 -56
  45. package/src/skf-quick-skill/steps-c/step-05-write-and-validate.md +164 -0
  46. package/src/skf-quick-skill/steps-c/{step-06-write.md → step-06-finalize.md} +15 -7
  47. package/src/skf-quick-skill/steps-c/step-07-health-check.md +5 -3
  48. package/src/skf-quick-skill/steps-c/step-05-validate.md +0 -193
@@ -30,7 +30,7 @@
30
30
  "name": "skill-forge",
31
31
  "source": "./",
32
32
  "description": "Evidence-based agent skills compiler with progressive capability tiers (Quick/Forge/Forge+/Deep).",
33
- "version": "1.2.0",
33
+ "version": "1.4.0",
34
34
  "author": {
35
35
  "name": "Armel"
36
36
  },
@@ -26,7 +26,7 @@
26
26
  # Enforced two ways: (1) release.yaml bumps this line in the same commit
27
27
  # as package.json + marketplace.json on every release; (2) validate-docs-drift.js
28
28
  # cross-checks this value against package.json.version and fails on mismatch.
29
- skf_version: "1.2.0"
29
+ skf_version: "1.4.0"
30
30
 
31
31
  # Path to the oh-my-skills repo, resolved relative to this repo's root.
32
32
  # Override at runtime with the OMS environment variable if oh-my-skills
@@ -25,51 +25,45 @@ Setup detects your installed tools and sets your tier automatically:
25
25
  ```
26
26
 
27
27
  ```
28
- ┌─────────────────────────────┐
29
- FORGE STATUS
30
- └─────────────────────────────┘
28
+ ═══════════════════════════════════════
29
+ FORGE STATUS
30
+ ═══════════════════════════════════════
31
31
 
32
32
  Tier: Deep
33
-
34
- Deep tier active. Full capability unlocked AST-backed code
35
- analysis, GitHub repository exploration, and QMD knowledge search
36
- with cross-repository synthesis. Maximum provenance and intelligence.
33
+ Deep tier active. Full capability unlocked — AST-backed code analysis,
34
+ GitHub repository exploration, and QMD knowledge search with
35
+ cross-repository synthesis. Maximum provenance and intelligence.
37
36
 
38
37
  Tools Detected:
39
- ast-grep 0.42.0
40
- gh 2.89.0
41
- qmd operational (104 docs indexed globally)
42
- ccc 0.2.10 (daemon healthy)
38
+ - ast-grep 0.42.0
39
+ - gh 2.91.0 (2026-04-22)
40
+ - qmd 2.0.1
41
+ - ccc (daemon healthy)
43
42
 
44
43
  QMD Registry:
45
- 0 collection(s) healthy
46
- 39 orphaned collection(s) removed
47
- (empty — collections are created automatically when you run [CS] Create Skill)
44
+ 0 collection(s) healthy
45
+ 23 orphaned collection(s) kept
48
46
 
49
47
  CCC Index:
50
- indexed this run — semantic discovery ready (2 files, 14 chunks)
51
- SKF infrastructure excluded: _bmad, _bmad-output, .claude,
52
- _skf-learn, skills, forge-data
53
-
54
- ┌────────────────────────────────┐
55
- │ Forge ready. Deep tier active. │
56
- └────────────────────────────────┘
57
-
58
- Health Check: Clean run. No workflow issues to report.
48
+ indexed this run — semantic discovery ready (1 file)
59
49
 
60
- Workflow complete.
50
+ Files written this run:
51
+ - forge-tier.yaml — {project-root}/_bmad/_memory/forger-sidecar/forge-tier.yaml
52
+ - .cocoindex_code/settings.yml — {project-root}/.cocoindex_code/settings.yml (6 SKF exclusion patterns merged)
53
+ - .cocoindex_code/ ccc index — 1 file indexed
61
54
 
62
- ---
63
- Forge is live at Deep tier, armel. All four core tools are available, the CCC semantic index is built, and the QMD registry is clean.
55
+ ═══════════════════════════════════════
56
+ Forge ready. Deep tier active.
57
+ ═══════════════════════════════════════
64
58
 
65
- What would you like to forge next? Common starting points:
59
+ Next: try [BS] Brief Skill to scope your first compilation target,
60
+ or [QS] Quick Skill for a fast template-driven path.
61
+ Already have a skill? [AS] Audit Skill drift-checks an existing skill
62
+ against current sources.
66
63
 
67
- - QS fast skill from a GitHub URL or package name
68
- - BS → CS — brief, then compile a skill from source
69
- - AN — analyze a large repo to discover what's worth skilling
70
- - WS — show current lifecycle status
64
+ Health Check: Clean run. No workflow issues to report.
71
65
 
72
- Or chain them: forge (BS CS TS EX), forge-quick (QS TS EX), onboard (AN CS TS EX).
66
+ Workflow complete.
73
67
  ```
74
68
 
75
69
  Don't have ast-grep, cocoindex-code, or QMD yet? No problem — Quick mode works with no additional tools. Optional GitHub CLI improves source access. Install tools later; your tier upgrades automatically.
@@ -9,6 +9,18 @@ If something isn't working, start here. For general setup help see [Getting Star
9
9
 
10
10
  ## Common errors
11
11
 
12
+ ### "Setup cannot proceed: `uv` is not installed"
13
+
14
+ Surfaced by `/skf-setup` On Activation when `uv --version` is missing on `$PATH`. SKF helpers depend on `uv` to auto-resolve their Python dependencies via PEP 723 inline metadata; bare `python3` ignores that metadata and would fail later with `ModuleNotFoundError: No module named 'yaml'`. The probe halts the workflow up-front with one cohesive diagnostic instead of letting five steps each fail individually.
15
+
16
+ **Fix:** install `uv` from <https://docs.astral.sh/uv/getting-started/installation/> and re-run `/skf-setup`. `uv` is documented as a runtime prerequisite in [Getting Started → Prerequisites](../getting-started/#prerequisites-full-reference).
17
+
18
+ ### "Setup cannot proceed: `_bmad/skf/config.yaml` was not found"
19
+
20
+ Surfaced by `/skf-setup` On Activation when the SKF install config is missing — typically because you invoked `/skf-setup` from a directory that is not an SKF-initialised project. The check runs before any file mutation so nothing is written.
21
+
22
+ **Fix:** from the project root, run `npx bmad-module-skill-forge install` (or `npx bmad-method install` and add SKF as a custom module — see [Getting Started → Install](../getting-started/#install)), then re-run `/skf-setup`. If you ARE in the right project but the file was deleted, restore it from version control or re-run the SKF installer. A separate "config.yaml is not valid YAML" diagnostic surfaces the parser error inline if the file exists but is malformed — open the file at the named path and repair the YAML.
23
+
12
24
  ### Forge reports ast-grep is unavailable
13
25
 
14
26
  If setup reports that ast-grep was not detected, install it to unlock the Forge tier: <https://ast-grep.github.io>. Re-run `@Ferris SF` afterward — your tier upgrades automatically.
package/docs/workflows.md CHANGED
@@ -21,6 +21,11 @@ Trigger workflows by typing commands to [Ferris](../agents/). See [Concepts](../
21
21
 
22
22
  **Key Steps:** Detect tools + Determine tier → CCC index check (Forge+) → Write forge-tier.yaml → QMD + CCC registry hygiene (Deep/Forge+) → Status report
23
23
 
24
+ **Flags:**
25
+
26
+ - `--require-tier=<Quick|Forge|Forge+|Deep>` — fail-fast for CI: if the calculated tier does not satisfy the requested tier (tool-prerequisite check, not a name comparison — Deep does NOT subsume Forge+ because Deep does not require ccc), the workflow halts with a "REQUIRED TIER NOT MET" block and exits without chaining to the health check. Pipelines branch on the JSON envelope's `require_tier_satisfied` field.
27
+ - `--headless` / `-H` — see [Headless Mode](#headless-mode) below. For `/skf-setup` specifically, headless mode emits a single-line `SKF_SETUP_RESULT_JSON: {…}` envelope to stdout (schema-locked, includes `tier`, `previous_tier`, `tier_changed`, `tools`, `tools_added`/`removed`, `files_written`, `warnings`, `error`) and SUPPRESSES the human-readable banner — the entire payload pipelines need is on one parseable line.
28
+
24
29
  **Agent:** Ferris (Architect mode)
25
30
 
26
31
  ---
@@ -79,6 +84,19 @@ Trigger workflows by typing commands to [Ferris](../agents/). See [Concepts](../
79
84
 
80
85
  **Key Steps:** Resolve target → Ecosystem check → Quick extract → Compile → Validate → Write
81
86
 
87
+ **Headless / batch flags:**
88
+
89
+ - `--headless` / `-H` — auto-proceed all confirmation gates with documented defaults; emits structured stderr progress events and exit codes (see [Headless Mode](#headless-mode))
90
+ - `--batch <file>` — process N targets from a text file in sequence (one target per line, `#` comments and `language=<lang>` / `scope=<path>` per-line modifiers supported); implies `--headless`
91
+ - `--fail-fast` — only with `--batch`; abort the whole batch on the first per-target failure instead of recording it and proceeding
92
+
93
+ **Per-target overrides** (apply to a single-target run, or globally to every target in `--batch`):
94
+
95
+ - `--description "<string>"` — override the LLM-derived description used in `SKILL.md` frontmatter and `metadata.json`
96
+ - `--exports "name1,name2,..."` — override the extracted export list (comma-separated)
97
+ - `--skip-snippet` — skip `context-snippet.md` generation and write
98
+ - `--no-active-pointer` — skip the active-pointer flip in finalize (deliverables still land in `{skill_package}`)
99
+
82
100
  **Agent:** Ferris (Architect mode)
83
101
 
84
102
  ---
@@ -268,15 +286,15 @@ flowchart TD
268
286
 
269
287
  ## Workflow Categories
270
288
 
271
- | Category | Workflows | Description |
272
- |----------|-----------|-------------|
273
- | Core | SF, BS, CS, US | Setup, brief, create, and update skills |
274
- | Feature | QS, SS, AN | Quick skill, stack skill, and analyze source |
275
- | Quality | AS, TS | Detect skill drift (AS) and verify skill completeness (TS) |
276
- | Architecture Verification | VS, RA | Pre-code architecture feasibility and refinement |
277
- | Management | RS, DS | Rename and drop skill versions with transactional safety |
278
- | Utility | EX | Package and export for consumption |
279
- | In-Agent | WS, KI | WS: show lifecycle position, active briefs, and forge tier; KI: list knowledge fragments (both in-agent, no file-based workflow) |
289
+ | Category | Workflows | Description |
290
+ | ------------------------- | -------------- | -------------------------------------------------------------------------------------------------------------------------------- |
291
+ | Core | SF, BS, CS, US | Setup, brief, create, and update skills |
292
+ | Feature | QS, SS, AN | Quick skill, stack skill, and analyze source |
293
+ | Quality | AS, TS | Detect skill drift (AS) and verify skill completeness (TS) |
294
+ | Architecture Verification | VS, RA | Pre-code architecture feasibility and refinement |
295
+ | Management | RS, DS | Rename and drop skill versions with transactional safety |
296
+ | Utility | EX | Package and export for consumption |
297
+ | In-Agent | WS, KI | WS: show lifecycle position, active briefs, and forge tier; KI: list knowledge fragments (both in-agent, no file-based workflow) |
280
298
 
281
299
  ---
282
300
 
@@ -295,12 +313,12 @@ Instead of running one workflow per session, you can chain multiple workflows in
295
313
 
296
314
  ### Pipeline Aliases
297
315
 
298
- | Alias | Expands To | First Workflow | Required Target |
299
- |-------|-----------|----------------|-----------------|
300
- | `forge` | `BS CS TS EX` | BS | GitHub URL or local path **+** skill name |
301
- | `forge-quick` | `QS TS EX` | QS | GitHub URL **or** package name |
302
- | `onboard` | `AN CS TS EX` | AN | Project path (defaults to current directory) |
303
- | `maintain` | `AS US TS EX` | AS | Existing skill name |
316
+ | Alias | Expands To | First Workflow | Required Target |
317
+ | ------------- | ------------- | -------------- | -------------------------------------------- |
318
+ | `forge` | `BS CS TS EX` | BS | GitHub URL or local path **+** skill name |
319
+ | `forge-quick` | `QS TS EX` | QS | GitHub URL **or** package name |
320
+ | `onboard` | `AN CS TS EX` | AN | Project path (defaults to current directory) |
321
+ | `maintain` | `AS US TS EX` | AS | Existing skill name |
304
322
 
305
323
  **The first workflow's input contract defines what arguments the pipeline needs.** A bare package name works for `forge-quick` (QS resolves packages via the registry) but **not** for `forge` — BS requires both an unambiguous target (URL or path) and a skill name.
306
324
 
@@ -337,6 +355,60 @@ Add `--headless` or `-H` to any workflow command to skip all confirmation gates.
337
355
 
338
356
  You can also set `headless_mode: true` in your forge preferences (`_bmad/_memory/forger-sidecar/preferences.yaml`) to make headless the default for all workflows.
339
357
 
358
+ **Exception — `/skf-setup` headless emits a single-line JSON envelope.** Unlike other workflows, headless `/skf-setup` SUPPRESSES the human-readable status banner entirely and emits exactly one prefixed line on stdout:
359
+
360
+ ```
361
+ SKF_SETUP_RESULT_JSON: {"skf_setup":{"tier":"Deep","previous_tier":"Forge","tier_changed":true,"tools":{...},"tools_added":[...],"tools_removed":[],"config_path":"...","ccc_index":{...},"files_written":[...],"tier_override_active":false,"tier_override_invalid":false,"require_tier_satisfied":null,"warnings":[],"error":null}}
362
+ ```
363
+
364
+ Parent skills and CI pipelines `grep` one line out of the workflow log to learn the outcome — no ASCII-art parsing, no race against the [`forge-tier.yaml`](https://github.com/armelhbobdad/bmad-module-skill-forge/blob/main/src/skf-setup/steps-c/step-02-write-config.md) writer. The envelope schema is versioned at [`src/shared/scripts/schemas/skf-setup-result-envelope.v1.json`](https://github.com/armelhbobdad/bmad-module-skill-forge/blob/main/src/shared/scripts/schemas/skf-setup-result-envelope.v1.json) and asserted against on every emit.
365
+
366
+ **Exception — `/skf-quick-skill` headless emits structured progress + result envelopes.** Headless `/skf-quick-skill` runs are first-class building blocks for batch automators. Three operational contracts beyond per-gate auto-proceed:
367
+
368
+ 1. **Per-step JSON progress events to `stderr`** at each step's entry / exit / HARD HALT — one line per event, no pretty-print:
369
+
370
+ ```
371
+ {"step":3,"name":"quick-extract","status":"start"}
372
+ {"step":3,"name":"quick-extract","status":"done"}
373
+ {"step":1,"name":"resolve-target","status":"halt","exit":3}
374
+ ```
375
+
376
+ `<name>` is the kebab portion of the step filename: `resolve-target`, `ecosystem-check`, `quick-extract`, `compile`, `write-and-validate`, `finalize`, `health-check`.
377
+
378
+ 2. **Structured exit-code map.** Every HARD HALT exits with a stable code so pipelines branch on the failure class without grepping message text:
379
+
380
+ | Code | Meaning |
381
+ | ---- | ------------------- |
382
+ | 0 | success |
383
+ | 3 | resolution-failure |
384
+ | 4 | write-failure |
385
+ | 5 | overwrite-cancelled |
386
+ | 6 | compile-cancelled |
387
+ | 7 | finalize-blocked |
388
+
389
+ 3. **Error-variant result contract on every HARD HALT.** A `SKF_QUICK_SKILL_RESULT_JSON: {…}` envelope is emitted on `stderr` (always) and copied to `{skill_package}/quick-skill-result-latest.json` when the skill package is known (HALTs at step-05 §1 onward). The schema and full population rules live in [`src/skf-quick-skill/SKILL.md`](https://github.com/armelhbobdad/bmad-module-skill-forge/blob/main/src/skf-quick-skill/SKILL.md) § "Result Contract on HARD HALT".
390
+
391
+ **Batch mode (`--batch <file>`).** Drives N targets through the full pipeline (steps 1–7 each) in sequence. Input format: one target per line, `#` comments and blank lines ignored, optional per-line modifiers `language=<lang>` and `scope=<path>`. Per-target output lands in `{skill_package}/` as today; an aggregated summary writes to `{skills_output_folder}/_batch/quick-skill-batch-{ts}.json` (with `quick-skill-batch-latest.json` copy). Per-target boundary events (`{"batch":N,"target":"…","status":"start|done|fail",…}`) and a final `{"batch_summary":true,…}` event extend the per-step event stream above. Full input grammar, summary schema, and exit-code semantics in [`src/skf-quick-skill/SKILL.md`](https://github.com/armelhbobdad/bmad-module-skill-forge/blob/main/src/skf-quick-skill/SKILL.md) § "Batch Mode".
392
+
393
+ **Exception — `/skf-brief-skill` headless emits a final result envelope and supports presets.** Headless `/skf-brief-skill` is a first-class building block for scripted brief generation (e.g. seeding briefs for N SaaS SDKs that share scope/authority defaults). Three operational contracts beyond per-gate auto-proceed:
394
+
395
+ 1. **Pre-supplied inputs replace prompts.** Headless args are consumed at step-01's GATE in place of the interactive menus: `target_repo`, `skill_name`, `target_version`, `language`, `source_type`, `source_authority`, `doc_urls`, `scope_type`, `scripts_intent`, `force`, `preset`. Required-arg shape depends on `source_type` (`target_repo` + `skill_name` for source-backed; `doc_urls` + `skill_name` for `docs-only`). Absent `source_authority` and `scope_type` are NOT guessed — they're resolved by signal-driven detection (`gh api user` vs. repo owner for authority; the 5-rule heuristic ladder for scope). Full grammar in [`src/skf-brief-skill/references/headless-args.md`](https://github.com/armelhbobdad/bmad-module-skill-forge/blob/main/src/skf-brief-skill/references/headless-args.md).
396
+
397
+ 2. **Structured exit-code map.** Every HARD HALT exits with a stable code so pipelines branch on the failure class without grepping message text:
398
+
399
+ | Code | Meaning |
400
+ | ---- | ----------------------------- |
401
+ | 0 | success |
402
+ | 2 | input-missing / input-invalid |
403
+ | 3 | resolution-failure |
404
+ | 4 | write-failure |
405
+ | 5 | overwrite-cancelled |
406
+ | 6 | user-cancelled |
407
+
408
+ 3. **Final result envelope on every terminal exit.** Step-05 emits a single-line `SKF_BRIEF_RESULT_JSON: {…}` envelope on **stdout** before chaining to step-06 on success; every HARD HALT emits the same envelope shape on **stderr** with `status: "error"` and a typed `halt_reason` (`input-missing`, `input-invalid`, `forge-tier-missing`, `target-inaccessible`, `gh-auth-failed`, `write-failed`, `overwrite-cancelled`, `user-cancelled`). Full envelope schema and population rules in [`src/skf-brief-skill/SKILL.md`](https://github.com/armelhbobdad/bmad-module-skill-forge/blob/main/src/skf-brief-skill/SKILL.md) § "Result Contract (Headless)".
409
+
410
+ **Presets (`--preset <name>`).** Loads `{sidecar_path}/brief-presets/{name}.yaml` and merges its keys as defaults at step-01 §8; explicit headless args override preset values. The preset file is YAML containing any subset of the headless args above; unknown fields are ignored with a warning. Useful for repeated patterns — e.g. briefing 5 SaaS SDKs that all share `source_authority=community`, `scope_type=full-library`, `scripts_intent=skip`.
411
+
340
412
  ---
341
413
 
342
414
  ## Terminal Step: Health Check
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/package.json",
3
3
  "name": "bmad-module-skill-forge",
4
- "version": "1.2.0",
4
+ "version": "1.4.0",
5
5
  "description": "BMAD module — Turn code and docs into instructions AI agents can actually follow. Progressive capability tiers (Quick/Forge/Forge+/Deep).",
6
6
  "keywords": [
7
7
  "bmad",
@@ -53,7 +53,7 @@
53
53
  "test:cli": "node test/test-cli-integration.js",
54
54
  "test:install": "node test/test-installation-components.js",
55
55
  "test:knowledge": "node test/test-knowledge-base.js",
56
- "test:python": "uv run --with pytest --with pyyaml pytest test/test-compute-score-contract.py test/test-skf-preflight.py test/test-skf-skill-inventory.py test/test-skf-validate-output.py test/test-skf-validate-frontmatter.py test/test-skf-manifest-ops.py test/test-skf-rebuild-managed-sections.py test/test-skf-severity-classify.py test/test-skf-structural-diff.py test/test-skf-detect-tools.py test/test-skf-forge-tier-rw.py test/test-skf-emit-result-envelope.py test/test-skf-qmd-classify-collections.py test/test-skf-merge-ccc-exclusions.py -v",
56
+ "test:python": "uv run --with pytest --with pyyaml pytest test/test-compute-score-contract.py test/test-skf-preflight.py test/test-skf-skill-inventory.py test/test-skf-validate-output.py test/test-skf-validate-frontmatter.py test/test-skf-manifest-ops.py test/test-skf-rebuild-managed-sections.py test/test-skf-severity-classify.py test/test-skf-structural-diff.py test/test-skf-detect-tools.py test/test-skf-forge-tier-rw.py test/test-skf-emit-result-envelope.py test/test-skf-qmd-classify-collections.py test/test-skf-merge-ccc-exclusions.py test/test-skf-resolve-package.py test/test-skf-extract-public-api.py test/test-skf-render-quick-metadata.py test/test-skf-validate-brief-inputs.py test/test-skf-emit-brief-result-envelope.py test/test-skf-write-skill-brief.py test/test-skf-detect-workspaces.py test/test-skf-recommend-scope-type.py test/test-skf-detect-language.py -v",
57
57
  "test:schemas": "node test/test-agent-schema.js",
58
58
  "test:workflow": "node test/test-workflow-state.js",
59
59
  "validate:refs": "node tools/validate-file-refs.js --strict",
@@ -33,3 +33,13 @@ Each run writes **two files** to `{output_dir}`:
33
33
  Write the per-run record first, then copy it to the `-latest.json` path. If the copy fails, the per-run record still exists — the run is not lost.
34
34
 
35
35
  **Consumers (forger, CI, chained workflows):** read from `{skill-name}-result-latest.json`. Do not enumerate timestamped files unless inspecting prior-run history.
36
+
37
+ ## Available Helpers
38
+
39
+ There is no generic helper that writes the schema above; each skill assembles the JSON in its terminal step today. One specialised helper exists:
40
+
41
+ - **`src/shared/scripts/skf-emit-result-envelope.py`** — `skf-setup`-specific. Writes a different envelope (`SKF_SETUP_RESULT_JSON: {…}`) following the JSON schema at `src/shared/scripts/schemas/skf-setup-result-envelope.v1.json`. Carries setup-specific fields (`tier`, `previous_tier`, `tools`, `ccc_index`, `tier_override_*`, `qmd_status`, etc.) that have no analogue in other workflows. **Do not reuse for non-skf-setup skills.**
42
+
43
+ A generalised emitter (matching this document's schema) is a reasonable future helper when a second consumer materialises with the same shape. For now, skills that write this contract assemble the JSON in their terminal step — the work is small (5–8 fields) and skill-specific summary content benefits from being expressed inline alongside the rest of the step's logic.
44
+
45
+ skf-quick-skill writes both the success-variant contract (`step-06-finalize.md` §3) and the error-variant contract on every HARD HALT (per `SKILL.md` § "Result Contract on HARD HALT") in this hand-assembled style.
@@ -0,0 +1,58 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://github.com/armelhbobdad/bmad-module-skill-forge/src/shared/scripts/schemas/skf-brief-result-envelope.v1.json",
4
+ "title": "SKF_BRIEF_RESULT_JSON envelope (v1)",
5
+ "description": "Single-line JSON document emitted by skf-brief-skill step-05 §4b when {headless_mode} is true, prefixed with the literal 'SKF_BRIEF_RESULT_JSON: '. Pipelines grep one line out of the workflow log to branch on the brief outcome without parsing prose. Schema mirrors the contract in src/skf-brief-skill/SKILL.md Result Contract section.",
6
+ "type": "object",
7
+ "additionalProperties": false,
8
+ "required": ["status", "brief_path", "skill_name", "version", "language", "scope_type", "exit_code", "halt_reason"],
9
+ "properties": {
10
+ "status": {
11
+ "type": "string",
12
+ "enum": ["success", "error"],
13
+ "description": "'success' on the terminal happy path (after step-05 wrote the brief and step-06 returned). 'error' on any HARD HALT."
14
+ },
15
+ "brief_path": {
16
+ "type": ["string", "null"],
17
+ "description": "Absolute path to the written skill-brief.yaml on success. Null when the run errored before any file was written (or when overwrite-cancelled aborted before write)."
18
+ },
19
+ "skill_name": {
20
+ "type": "string",
21
+ "minLength": 1,
22
+ "description": "Brief's skill_name field — present in every envelope (success and error) since it is captured at step-01 §6 before any of the other failure branches."
23
+ },
24
+ "version": {
25
+ "type": ["string", "null"],
26
+ "description": "Resolved brief version (target_version if set, else auto-detected, else '1.0.0'). Null when the run errored before step-05's version-resolution ran."
27
+ },
28
+ "language": {
29
+ "type": ["string", "null"],
30
+ "description": "Detected or user-confirmed primary language. Null when the run errored before step-02's language-detection ran."
31
+ },
32
+ "scope_type": {
33
+ "type": ["string", "null"],
34
+ "enum": ["full-library", "specific-modules", "public-api", "component-library", "reference-app", "docs-only", null],
35
+ "description": "Confirmed scope.type from step-03. Null when the run errored before scope was confirmed."
36
+ },
37
+ "exit_code": {
38
+ "type": "integer",
39
+ "enum": [0, 2, 3, 4, 5, 6],
40
+ "description": "Process exit code matching the SKILL.md Exit Codes table. Derived deterministically from halt_reason: null→0, input-missing/input-invalid→2, forge-tier-missing/target-inaccessible/gh-auth-failed→3, write-failed→4, overwrite-cancelled→5, user-cancelled→6."
41
+ },
42
+ "halt_reason": {
43
+ "type": ["string", "null"],
44
+ "enum": [
45
+ null,
46
+ "input-missing",
47
+ "input-invalid",
48
+ "forge-tier-missing",
49
+ "target-inaccessible",
50
+ "gh-auth-failed",
51
+ "write-failed",
52
+ "overwrite-cancelled",
53
+ "user-cancelled"
54
+ ],
55
+ "description": "Null on success. One of the documented HALT classes on error. Pipelines branch on this to surface the right operator message without grepping the prose error."
56
+ }
57
+ }
58
+ }
@@ -0,0 +1,77 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://github.com/armelhbobdad/bmad-module-skill-forge/src/shared/scripts/schemas/skill-brief.v1.json",
4
+ "title": "skill-brief.yaml (v1)",
5
+ "description": "Canonical schema for the skill-brief.yaml artifact written by skf-brief-skill step-05 and consumed by skf-create-skill, skf-update-skill, skf-audit-skill. Mirrors src/skf-brief-skill/assets/skill-brief-schema.md.",
6
+ "type": "object",
7
+ "required": ["name", "version", "source_repo", "language", "description", "forge_tier", "created", "created_by", "scope"],
8
+ "properties": {
9
+ "name": {
10
+ "type": "string",
11
+ "pattern": "^[a-z0-9]([a-z0-9-]*[a-z0-9])?$",
12
+ "description": "Unique skill identifier (kebab-case)."
13
+ },
14
+ "version": {
15
+ "type": "string",
16
+ "pattern": "^v?\\d+\\.\\d+\\.\\d+([.\\-+][0-9A-Za-z][0-9A-Za-z.\\-+]*)?$",
17
+ "description": "Resolved semver. target_version wins; else auto-detected; else 1.0.0."
18
+ },
19
+ "target_version": {
20
+ "type": "string",
21
+ "pattern": "^v?\\d+\\.\\d+\\.\\d+([.\\-+][0-9A-Za-z][0-9A-Za-z.\\-+]*)?$",
22
+ "description": "User-specified target. When present, MUST equal version."
23
+ },
24
+ "source_type": {
25
+ "type": "string",
26
+ "enum": ["source", "docs-only"]
27
+ },
28
+ "source_repo": {
29
+ "type": "string",
30
+ "minLength": 1,
31
+ "description": "GitHub URL or local path. Required even for docs-only (set to doc site URL)."
32
+ },
33
+ "source_authority": {
34
+ "type": "string",
35
+ "enum": ["official", "community", "internal"]
36
+ },
37
+ "doc_urls": {
38
+ "type": "array",
39
+ "items": {
40
+ "type": "object",
41
+ "required": ["url"],
42
+ "properties": {
43
+ "url": { "type": "string", "minLength": 1 },
44
+ "label": { "type": "string" }
45
+ }
46
+ },
47
+ "minItems": 1,
48
+ "description": "Required when source_type is docs-only; allowed as supplemental for source."
49
+ },
50
+ "language": { "type": "string", "minLength": 1 },
51
+ "description": { "type": "string", "minLength": 1 },
52
+ "forge_tier": {
53
+ "type": "string",
54
+ "enum": ["Quick", "Forge", "Forge+", "Deep"]
55
+ },
56
+ "created": {
57
+ "type": "string",
58
+ "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
59
+ },
60
+ "created_by": { "type": "string", "minLength": 1 },
61
+ "scripts_intent": { "type": "string", "minLength": 1 },
62
+ "assets_intent": { "type": "string", "minLength": 1 },
63
+ "scope": {
64
+ "type": "object",
65
+ "required": ["type", "include", "exclude", "notes"],
66
+ "properties": {
67
+ "type": {
68
+ "type": "string",
69
+ "enum": ["full-library", "specific-modules", "public-api", "component-library", "reference-app", "docs-only"]
70
+ },
71
+ "include": { "type": "array", "items": { "type": "string" } },
72
+ "exclude": { "type": "array", "items": { "type": "string" } },
73
+ "notes": { "type": "string" }
74
+ }
75
+ }
76
+ }
77
+ }
@@ -0,0 +1,44 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://armelhbobdad.github.io/bmad-module-skill-forge/schemas/workspace-detection.v1.json",
4
+ "title": "Workspace Detection Result (v1)",
5
+ "description": "Result envelope returned by skf-detect-workspaces.py. Reports whether the inspected target is a monorepo, which manifest kind drives it, and the list of resolved workspaces.",
6
+ "type": "object",
7
+ "additionalProperties": false,
8
+ "required": ["is_monorepo", "manifest_kind", "workspaces", "warnings"],
9
+ "properties": {
10
+ "is_monorepo": {
11
+ "type": "boolean",
12
+ "description": "True if any detector matched at least one workspace."
13
+ },
14
+ "manifest_kind": {
15
+ "description": "Which detector produced the result. null when is_monorepo is false.",
16
+ "oneOf": [
17
+ {
18
+ "type": "string",
19
+ "enum": ["npm-workspaces", "pnpm-workspaces", "lerna", "cargo-workspace", "python-multi-package", "generic-folders"]
20
+ },
21
+ { "type": "null" }
22
+ ]
23
+ },
24
+ "workspaces": {
25
+ "type": "array",
26
+ "description": "Resolved workspaces. Empty when is_monorepo is false. Each entry has a name, a repository-relative path, and the path to its recognised manifest.",
27
+ "items": {
28
+ "type": "object",
29
+ "additionalProperties": false,
30
+ "required": ["name", "path", "manifest"],
31
+ "properties": {
32
+ "name": { "type": "string", "minLength": 1 },
33
+ "path": { "type": "string", "minLength": 1 },
34
+ "manifest": { "type": "string", "minLength": 1 }
35
+ }
36
+ }
37
+ },
38
+ "warnings": {
39
+ "type": "array",
40
+ "description": "Non-fatal parse warnings encountered during detection (e.g. malformed manifests that the detector skipped).",
41
+ "items": { "type": "string" }
42
+ }
43
+ }
44
+ }