bmad-module-skill-forge 1.3.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 (31) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/docs/_data/pinned.yaml +1 -1
  3. package/docs/workflows.md +34 -15
  4. package/package.json +2 -2
  5. package/src/shared/scripts/schemas/skf-brief-result-envelope.v1.json +58 -0
  6. package/src/shared/scripts/schemas/skill-brief.v1.json +77 -0
  7. package/src/shared/scripts/schemas/workspace-detection.v1.json +44 -0
  8. package/src/shared/scripts/skf-detect-language.py +277 -0
  9. package/src/shared/scripts/skf-detect-workspaces.py +427 -0
  10. package/src/shared/scripts/skf-emit-brief-result-envelope.py +257 -0
  11. package/src/shared/scripts/skf-extract-public-api.py +29 -0
  12. package/src/shared/scripts/skf-forge-tier-rw.py +73 -0
  13. package/src/shared/scripts/skf-recommend-scope-type.py +369 -0
  14. package/src/shared/scripts/skf-validate-brief-inputs.py +293 -0
  15. package/src/shared/scripts/skf-write-skill-brief.py +509 -0
  16. package/src/skf-brief-skill/SKILL.md +41 -12
  17. package/src/skf-brief-skill/assets/description-voice-examples.md +19 -0
  18. package/src/skf-brief-skill/assets/scope-templates.md +5 -0
  19. package/src/skf-brief-skill/assets/skill-brief-schema.md +1 -40
  20. package/src/skf-brief-skill/references/draft-checkpoint.md +46 -0
  21. package/src/skf-brief-skill/references/headless-args.md +22 -0
  22. package/src/skf-brief-skill/references/headless-source-authority-detection.md +26 -0
  23. package/src/skf-brief-skill/references/portfolio-similarity-check.md +35 -0
  24. package/src/skf-brief-skill/references/qmd-collection-registration.md +52 -0
  25. package/src/skf-brief-skill/references/version-resolution.md +46 -0
  26. package/src/skf-brief-skill/steps-c/step-01-gather-intent.md +164 -14
  27. package/src/skf-brief-skill/steps-c/step-02-analyze-target.md +118 -50
  28. package/src/skf-brief-skill/steps-c/step-03-scope-definition.md +48 -5
  29. package/src/skf-brief-skill/steps-c/step-04-confirm-brief.md +33 -19
  30. package/src/skf-brief-skill/steps-c/step-05-write-brief.md +93 -97
  31. package/src/skf-brief-skill/steps-c/step-06-health-check.md +11 -2
@@ -1,6 +1,12 @@
1
1
  ---
2
2
  briefSchemaFile: 'assets/skill-brief-schema.md'
3
+ versionResolutionFile: 'references/version-resolution.md'
4
+ qmdRegistrationFile: 'references/qmd-collection-registration.md'
3
5
  nextStepFile: './step-06-health-check.md'
6
+ writeSkillBriefScript: '{project-root}/src/shared/scripts/skf-write-skill-brief.py'
7
+ emitBriefEnvelopeScript: '{project-root}/src/shared/scripts/skf-emit-brief-result-envelope.py'
8
+ forgeTierRwScript: '{project-root}/src/shared/scripts/skf-forge-tier-rw.py'
9
+ forgeTierFile: '{sidecar_path}/forge-tier.yaml'
4
10
  ---
5
11
 
6
12
  # Step 5: Write Brief
@@ -15,145 +21,136 @@ To generate the complete skill-brief.yaml from the approved brief data and write
15
21
  - Do not change any field values without user request — the brief was already approved
16
22
  - Create the output directory if it doesn't exist
17
23
  - Chains to the local health-check step via `{nextStepFile}` after completion — the user-facing success summary is NOT the terminal step
24
+ - All user-facing output in `{communication_language}`; written artifact (`description`, `notes`) in `{document_output_language}`
25
+ - **Determinism delegation:** YAML rendering, version-precedence, atomic write, the headless result envelope, and the QMD-collection registry mutation are all delegated to shared SKF scripts. The LLM's job in this step is to assemble inputs, branch on script results, and surface user-facing prose — not to render YAML, JSON envelopes, or YAML-mutation diffs in the model.
18
26
 
19
27
  ## MANDATORY SEQUENCE
20
28
 
21
29
  **CRITICAL:** Follow this sequence exactly. Do not skip, reorder, or improvise unless user explicitly requests a change.
22
30
 
23
- ### 1. Load Schema Template
31
+ ### 1. Reference the Schema (LLM context only)
24
32
 
25
- Load `{briefSchemaFile}` to reference the YAML template structure.
33
+ `{briefSchemaFile}` and `{versionResolutionFile}` document the brief contract for human readers. The deterministic enforcement of that contract lives in `{writeSkillBriefScript}` and its JSON Schema artifact at `src/shared/scripts/schemas/skill-brief.v1.json`. Load `{briefSchemaFile}` only if you need to explain a specific field to the user during inline adjustments — otherwise skip the read; the script is the source of truth.
26
34
 
27
- ### 2. Create Output Directory
35
+ ### 2. Resolve Output Path
28
36
 
29
- Create the directory `{forge_data_folder}/{skill-name}/` if it doesn't already exist.
37
+ Resolve the target write path:
38
+ - Primary: `{forge_data_folder}/{skill-name}/skill-brief.yaml`
39
+ - Fallback (when `{forge_data_folder}` is not set or doesn't exist): `{output_folder}/forge-data/{skill-name}/skill-brief.yaml` and inform user "**Note:** forge_data_folder not configured. Writing to {output_folder}/forge-data/{skill-name}/ instead."
30
40
 
31
- If `{forge_data_folder}` is not set or doesn't exist:
32
- - Fall back to `{output_folder}/forge-data/{skill-name}/`
33
- - Inform user: "**Note:** forge_data_folder not configured. Writing to {output_folder}/forge-data/{skill-name}/ instead."
41
+ The script's atomic-write helper creates parent directories as needed (`mkdir -p`) no separate mkdir call required.
34
42
 
35
- ### 3. Generate skill-brief.yaml
43
+ ### 2b. Existing Brief — Overwrite Policy
36
44
 
37
- **Resolve the `version` field before generating the YAML:**
45
+ Before writing, check whether the resolved target path already exists.
38
46
 
39
- - If `target_version` was set in step 01 (the user explicitly asked for a specific version), use `target_version` as the value of the `version` field. This is the authoritative version for create-skill.
40
- - Otherwise, use the auto-detected source version from step 02, or `1.0.0` if none was detected.
47
+ **Interactive (`{headless_mode}` is false):**
41
48
 
42
- `target_version` and `version` must never carry different values in the written brief. When the user provided a `target_version`, also include it as a separate `target_version` field so downstream tooling can distinguish "user-requested" from "auto-detected" without re-deriving the provenance — but its value must be identical to `version`.
49
+ If the file exists, present:
43
50
 
44
- Generate the YAML file using the approved field values and the schema template:
51
+ "**An existing brief was found at `{path}`.**
52
+ Overwrite it with the brief you just approved? [Y/N]"
45
53
 
46
- ```yaml
47
- ---
48
- name: "{approved skill name}"
49
- version: "{resolved version — target_version if set, else detected source version, else 1.0.0}"
50
- source_type: "{source or docs-only}"
51
- source_repo: "{approved source repo or doc site URL}"
52
- language: "{approved language}"
53
- description: "{approved description}"
54
- forge_tier: "{approved forge tier}"
55
- created: "{current date}"
56
- created_by: "{user_name}"
57
- scope:
58
- type: "{approved scope type}"
59
- include:
60
- - "{approved include patterns}"
61
- exclude:
62
- - "{approved exclude patterns}"
63
- notes: "{approved scope notes or empty string}"
64
- ---
65
- ```
54
+ - **[Y]** Overwrite — proceed to §3.
55
+ - **[N]** Cancel — emit a single-line stderr log `brief-skill: overwrite-cancelled at {path}` and HALT with exit code 5 (do not chain to step-06; the run produced no new artifact).
66
56
 
67
- **Conditional optional field inclusion:**
57
+ **Headless (`{headless_mode}` is true):**
68
58
 
69
- **If `target_version` was set in step 01:**
70
- Include the `target_version` field in the generated YAML — its value MUST be identical to the `version` field above:
71
- ```yaml
72
- target_version: "{target_version — same value as version}"
73
- ```
59
+ If the file exists:
74
60
 
75
- **If `source_type: "docs-only"` OR supplemental `doc_urls` were collected:**
76
- Include the `doc_urls` array (uncommented) in the generated YAML:
77
- ```yaml
78
- doc_urls:
79
- - url: "{documentation URL}"
80
- label: "{page label}"
81
- ```
82
- When `source_type: "docs-only"`: `doc_urls` is required (at least one entry), `source_repo` may be set to the doc site URL for reference or omitted.
61
+ - If `force` was supplied as a headless argument: log `"headless: force-overwriting existing brief at {path}"` and proceed to §3.
62
+ - Otherwise: emit the error envelope per §4b with `halt_reason: "overwrite-cancelled"`, then HALT with exit code 5.
83
63
 
84
- **If `scripts_intent` was collected and is not the default `"detect"`:**
85
- Include the `scripts_intent` field (uncommented):
86
- ```yaml
87
- scripts_intent: "{none or description}"
88
- ```
64
+ If the file does not exist, proceed normally.
65
+
66
+ ### 3. Write the Brief
89
67
 
90
- **If `assets_intent` was collected and is not the default `"detect"`:**
91
- Include the `assets_intent` field (uncommented):
92
- ```yaml
93
- assets_intent: "{none or description}"
68
+ Assemble the brief context as a **flat** JSON object — every approved value is a top-level key, scope is split across four `scope_*` keys instead of nested, and every optional field is passed as `null` when not set rather than conditionally omitted. This eliminates the "decide what to omit" cognitive load that previously made this the most expensive HALT-typo site in the workflow:
69
+
70
+ ```json
71
+ {
72
+ "name": "{approved skill name}",
73
+ "target_version": "{target_version from step 01, or null}",
74
+ "detected_version": "{auto-detected version from step 02, or null}",
75
+ "source_type": "{source or docs-only}",
76
+ "source_repo": "{approved source repo or doc site URL}",
77
+ "language": "{approved language}",
78
+ "description": "{approved description}",
79
+ "forge_tier": "{Quick|Forge|Forge+|Deep}",
80
+ "created": "{current ISO date YYYY-MM-DD}",
81
+ "created_by": "{user_name}",
82
+ "scope_type": "{approved scope type}",
83
+ "scope_include": ["{approved include patterns}"],
84
+ "scope_exclude": ["{approved exclude patterns}"],
85
+ "scope_notes": "{approved scope notes or empty string}",
86
+ "doc_urls": null | [{"url": "...", "label": "..."}],
87
+ "scripts_intent": null | "{detect|none|free-text}",
88
+ "assets_intent": null | "{detect|none|free-text}",
89
+ "source_authority": null | "{official|community|internal}"
90
+ }
94
91
  ```
95
92
 
96
- **Always include** `source_authority` (default: `"community"`, forced to `"community"` when `source_type: "docs-only"`):
97
- ```yaml
98
- source_authority: "{official|community|internal}"
93
+ Pipe it into the writer script with the `--from-flat` flag:
94
+
95
+ ```bash
96
+ echo '<context-json>' | uv run {writeSkillBriefScript} write --target {resolved-target-path} --from-flat
99
97
  ```
100
98
 
101
- ### 4. Write the File
99
+ The script translates flat → nested internally, drops the null optional fields, and runs the same schema validation and atomic write as before — pass every key always, the writer decides what reaches the YAML.
102
100
 
103
- Write the generated YAML to `{forge_data_folder}/{skill-name}/skill-brief.yaml`.
101
+ The script:
102
+ - Validates the context against `src/shared/scripts/schemas/skill-brief.v1.json`
103
+ - Applies the version-precedence rule from `{versionResolutionFile}`
104
+ - Enforces the `target_version == version` invariant (refuses to write a brief that violates it)
105
+ - Renders YAML in canonical key order (byte-stable across runs)
106
+ - Atomically writes the file via temp + fsync + rename (no half-written file ever visible)
107
+ - Emits a JSON success envelope on stdout: `{"status":"ok","brief_path":"…","version":"…","bytes":…,"warnings":[…]}`
104
108
 
105
- If write fails: **HALT** "**Error:** Failed to write skill-brief.yaml. Please check that the directory is writable and try again."
109
+ **On script failure (non-zero exit):**
110
+ - Exit 1 (validation/invariant): The error JSON on stderr names the offending field. This indicates a context-assembly bug, not a user error — surface the message to the user, log it, then HALT.
111
+ - Interactive: **HALT** — display the error JSON's `message` field.
112
+ - Headless: emit the error envelope per §4b with `halt_reason: "input-invalid"`, then `exit 2`.
113
+ - Exit 2 (I/O failure): The atomic write failed (target unwritable, disk full, etc.).
114
+ - Interactive: **HALT** — "**Error:** Failed to write skill-brief.yaml. Check that the directory is writable and try again."
115
+ - Headless: emit the error envelope per §4b with `halt_reason: "write-failed"`, then `exit 4`.
106
116
 
107
- ### 5. QMD Collection Registration (Deep Tier Only)
117
+ **On success:** capture `brief_path` and `version` from the response envelope — both are needed for §4b and §6.
108
118
 
109
- **IF forge tier is Deep AND QMD tool is available:**
119
+ **Draft cleanup.** After a successful write, remove `{forge_data_folder}/{skill-name}/.brief-draft.json` if it exists (`rm -f` — silent on absent). The draft was a step-01 §7 checkpoint covering the in-flight workflow window; once the brief is written it is no longer meaningful. In headless mode this rm is a no-op (drafts are only written interactively).
110
120
 
111
- Index the skill brief into a QMD collection so that portfolio-level searches can find existing briefs and avoid duplicate skill creation across large monorepos.
121
+ ### 4b. Headless Result Envelope (Canonical)
112
122
 
113
- **Collection creation:**
123
+ This section is the canonical envelope-emission reference for the workflow. Every headless emission — the success terminal here and every HARD HALT in step-01/02/05 — uses this contract. Remote sites point here instead of restating it.
124
+
125
+ **Success (this call site only — emitted from §3 directly):**
114
126
 
115
- Create a QMD collection targeting only the brief file:
116
127
  ```bash
117
- qmd collection add {forge_data_folder}/{skill-name} --name {skill-name}-brief --mask "skill-brief.yaml"
118
- qmd embed
128
+ echo '{"status":"success","brief_path":"<from §3 response>","skill_name":"<name>","version":"<from §3 response>","language":"<language>","scope_type":"<scope.type>","halt_reason":null}' | \
129
+ uv run {emitBriefEnvelopeScript} emit
119
130
  ```
120
131
 
121
- If collection already exists (re-briefing): remove and recreate for atomic replace:
132
+ **Error (used by every HARD HALT site):**
133
+
122
134
  ```bash
123
- qmd collection remove {skill-name}-brief
124
- qmd collection add {forge_data_folder}/{skill-name} --name {skill-name}-brief --mask "skill-brief.yaml"
125
- qmd embed
135
+ echo '{"status":"error","skill_name":"<name>","halt_reason":"<reason>"}' | \
136
+ uv run {emitBriefEnvelopeScript} emit --target stderr
126
137
  ```
127
138
 
128
- **Embed verification:**
139
+ When the HALT fires before `skill_name` has been resolved (step-01 §1 pre-flight write probe, step-01 §8 input-missing on a malformed args bundle), pass the partially-gathered value or the literal `"unknown"` — the script accepts any non-empty string at this position.
129
140
 
130
- After `qmd embed` completes, verify the collection was embedded:
131
- - Run `qmd status` or `qmd collection list` and confirm `{skill-name}-brief` shows document count > 0
132
- - If verification succeeds: proceed to registry update normally
133
- - If verification fails: log warning "QMD embed verification failed for {skill-name}-brief — collection may not be searchable yet", still proceed to registry update but add `status: "pending"` field to the registry entry
141
+ The script derives `exit_code` 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 [interactive-only — headless never raises this]), validates against `src/shared/scripts/schemas/skf-brief-result-envelope.v1.json`, and prints the prefixed `SKF_BRIEF_RESULT_JSON: {…}` line.
134
142
 
135
- **Registry update:**
143
+ The script enforces the success/error halt_reason invariant (success requires null halt_reason; error requires non-null). The `user-cancelled` halt_reason is accepted for completeness (interactive `[X]` Cancel sites in step-01/03/04) but never appears on the headless code path.
136
144
 
137
- Read `{sidecar_path}/forge-tier.yaml` and update the `qmd_collections` array.
145
+ Invocation sites (each pointed at this block, not duplicated): step-01 §1 (write-failed pre-resolution), step-01 §8 (input-missing/input-invalid GATE), step-05 §2b (overwrite-cancelled), step-05 §3 (input-invalid/write-failed from script). Step-01 §1 forge-tier-missing and step-02 §1 (target-inaccessible/gh-auth-failed) currently HALT without emitting an envelope — pre-existing gaps tracked separately, not addressed by this canonicalization.
138
146
 
139
- If an entry with `name: "{skill-name}-brief"` already exists, replace it. Otherwise, append:
147
+ When `{headless_mode}` is false, skip this section silently — no envelope is emitted.
140
148
 
141
- ```yaml
142
- - name: "{skill-name}-brief"
143
- type: "brief"
144
- source_workflow: "brief-skill"
145
- skill_name: "{skill-name}"
146
- created_at: "{current ISO date}"
147
- # status: "pending" # Added only when embed verification fails
148
- ```
149
-
150
- Write the updated forge-tier.yaml.
149
+ ### 5. QMD Collection Registration (Deep Tier Only)
151
150
 
152
- **Error handling:**
153
- - If QMD collection creation fails: log the error. Do NOT fail the workflow — the brief file was already written successfully.
154
- - If forge-tier.yaml update fails: log the error, continue.
151
+ **IF forge tier is Deep AND QMD tool is available:** load `{qmdRegistrationFile}` and follow the procedure there to index the brief into a QMD collection and update the forge-tier registry.
155
152
 
156
- **IF forge tier is NOT Deep:** Skip this section silently. No messaging.
153
+ **IF forge tier is NOT Deep OR QMD is not available:** skip this section silently — do not load `{qmdRegistrationFile}`. No messaging.
157
154
 
158
155
  ### 6. Display Success Summary
159
156
 
@@ -161,7 +158,7 @@ Write the updated forge-tier.yaml.
161
158
 
162
159
  ---
163
160
 
164
- **File:** `{forge_data_folder}/{skill-name}/skill-brief.yaml`
161
+ **File:** `{brief_path from §3 response}`
165
162
  **Skill:** {name}
166
163
  **Language:** {language}
167
164
  **Scope:** {scope type}
@@ -190,4 +187,3 @@ ONLY WHEN the brief file has been written and the success summary displayed will
190
187
  ## CRITICAL STEP COMPLETION NOTE
191
188
 
192
189
  This step chains to the local health-check step (`{nextStepFile}`), which in turn delegates to `shared/health-check.md`. After the health check completes, the brief-skill workflow is fully done.
193
-
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  # `shared/health-check.md` resolves relative to the SKF module root
3
- # (`_bmad/skf/` when installed, `src/` during development), NOT relative
4
- # to this step file.
3
+ # (`{project-root}/_bmad/skf/` when installed, `{project-root}/src/`
4
+ # during development), NOT relative to this step file.
5
5
  nextStepFile: 'shared/health-check.md'
6
6
  ---
7
7
 
@@ -16,7 +16,16 @@ Chain to the shared workflow self-improvement health check at `{nextStepFile}`.
16
16
  - No user-facing reports, file writes, or result contracts in this step — those belong in step-05
17
17
  - Delegate directly to `{nextStepFile}` with no additional commentary
18
18
  - Do not attempt any other action between loading this step and executing `{nextStepFile}`
19
+ - All user-facing output in `{communication_language}`
19
20
 
20
21
  ## MANDATORY SEQUENCE
21
22
 
22
23
  Load `{nextStepFile}`, read it fully, then execute it.
24
+
25
+ ## Completion criteria
26
+
27
+ This is the terminal step of brief-skill. The workflow is complete when `{nextStepFile}` returns control — do not transition to any further step.
28
+
29
+ ## CRITICAL STEP COMPLETION NOTE
30
+
31
+ Step 06 is the terminal stage of brief-skill. After `{nextStepFile}` returns control, the brief-skill workflow is fully complete — do not re-enter step-05 or step-06, do not load any further step file, and do not loop back into the workflow.