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,5 +1,9 @@
1
1
  ---
2
2
  nextStepFile: './step-03-scope-definition.md'
3
+ versionResolutionFile: 'references/version-resolution.md'
4
+ extractPublicApiScript: '{project-root}/src/shared/scripts/skf-extract-public-api.py'
5
+ detectWorkspacesScript: '{project-root}/src/shared/scripts/skf-detect-workspaces.py'
6
+ detectLanguageScript: '{project-root}/src/shared/scripts/skf-detect-language.py'
3
7
  ---
4
8
 
5
9
  # Step 2: Analyze Target
@@ -13,6 +17,7 @@ To analyze the target repository by resolving its location, reading its structur
13
17
  - Focus only on analysis — do not define scope yet (Step 03)
14
18
  - Do not make scoping decisions or recommendations
15
19
  - Do not hallucinate or guess about repository contents
20
+ - All user-facing output in `{communication_language}`
16
21
 
17
22
  ## MANDATORY SEQUENCE
18
23
 
@@ -21,23 +26,68 @@ To analyze the target repository by resolving its location, reading its structur
21
26
  ### 1. Resolve Target Location
22
27
 
23
28
  **For GitHub URLs:**
24
- - Use `gh api repos/{owner}/{repo}` to verify the repository exists
25
- - Use `gh api repos/{owner}/{repo}/git/trees/HEAD?recursive=1` to get the file tree
29
+ - Issue both probes in **one message with two parallel Bash calls** — they are independent:
30
+ - `gh api repos/{owner}/{repo}` (verify repo exists)
31
+ - `gh api repos/{owner}/{repo}/git/trees/HEAD?recursive=1` (fetch file tree)
32
+ - If the repo-existence probe fails, fall through to the failure-class triage below; the tree response from the parallel call is discarded in that case.
26
33
 
27
34
  **Truncation detection:** After receiving the tree response, check the `truncated` field in the JSON output. If `truncated: true`:
28
35
  - Display: "Note: GitHub API returned a truncated tree response ({count} items). Full analysis may require a local clone."
29
36
  - Record in analysis summary: "Tree listing is partial — some files may not appear in the analysis."
30
- - For very large repos (>1000 files in tree response): suggest local clone for complete analysis.
37
+ - For very large repos (>1000 files in tree response): offer a recovery path instead of just warning. Interactive — present:
38
+ ```
39
+ Tree is truncated. How would you like to proceed?
40
+ [L] Clone locally and re-analyze (slower but complete)
41
+ [P] Proceed with the partial tree (faster, may miss exports under deeper paths)
42
+ ```
43
+ On `[L]`: shallow-clone (`git clone --depth 1 {url} {tmp_dir}`), restart this section against the local path, and remove `{tmp_dir}` after the analysis summary in §5. On `[P]` (or under headless): record `tree_truncated: true` in the analysis summary and continue without HALT.
31
44
 
32
- - If inaccessible: **HALT** "**Error:** Cannot access repository at {url}. Please verify the URL is correct and you have access. If private, ensure `gh auth` is configured."
45
+ **On API failure (non-200 from `gh api`):**
46
+
47
+ Distinguish the failure class before reporting:
48
+ - Auto-run `gh auth status` and capture its output. If it reports an unauthenticated state or expired token: HALT (exit code 3, `halt_reason: "gh-auth-failed"`) — "**Error:** GitHub CLI is not authenticated. `gh auth status` says: `{captured output}`. Run `gh auth login` and retry."
49
+ - If `gh auth status` reports authenticated but the call still failed (404/403): HALT (exit code 3, `halt_reason: "target-inaccessible"`) — "**Error:** Cannot access repository at `{url}`. The CLI is authenticated but the API returned `{status}`. Check the URL and that the account has access to private repositories if applicable."
50
+ - If `gh auth status` itself fails to run (binary missing): HALT (exit code 3, `halt_reason: "gh-auth-failed"`) — "**Error:** `gh` CLI not found on PATH. Install it from <https://cli.github.com> and re-run."
33
51
 
34
52
  **For local paths:**
35
53
  - Verify the directory exists
36
54
  - List the directory tree
37
- - If path doesn't exist: **HALT** — "**Error:** Directory not found at {path}. Please verify the path is correct."
55
+ - If path doesn't exist: **HALT** — "**Error:** Directory not found at {path}. Verify the path is correct."
38
56
 
39
57
  Display: "**Resolving target...**"
40
58
 
59
+ ### 1b. Detect Monorepo / Workspace Layout
60
+
61
+ Delegate workspace detection to `{detectWorkspacesScript}` instead of reasoning through manifest rules in prose. Build a payload from the tree fetched in §1 plus the small set of root manifests the detector needs, then invoke the script:
62
+
63
+ ```bash
64
+ echo '{"tree": [<flat list of repo-relative file paths>], "manifests": {"package.json": "<raw text>", "Cargo.toml": "<raw text>", "pnpm-workspace.yaml": "<raw text>", "lerna.json": "<raw text>"}}' | \
65
+ uv run {detectWorkspacesScript}
66
+ ```
67
+
68
+ - **`tree`** — pass the flat list of repo-relative file paths already fetched in §1 (for GitHub: the `path` values from the `gh api .../git/trees/HEAD?recursive=1` response; for local: the equivalent listing).
69
+ - **`manifests`** — only the root manifests need contents; child-workspace manifests are looked up from the tree by the script. Include any of `package.json`, `Cargo.toml`, `pnpm-workspace.yaml`, `lerna.json` that appears at the repo root. Fetch them in **one message with N parallel Bash calls** (`gh api .../contents/{path}` for GitHub, file reads for local), then base64-decode together. Per-workspace manifest contents (e.g. `packages/foo/package.json`) are optional — including them populates the workspace `name` field with the manifest's declared package name; omitting them falls back to the directory basename.
70
+
71
+ The script returns a JSON envelope: `{is_monorepo, manifest_kind, workspaces[], warnings[]}`. Apply the result deterministically — see `src/shared/scripts/schemas/workspace-detection.v1.json` for the full contract.
72
+
73
+ **If `is_monorepo: false`** — skip this section silently and continue to §2.
74
+
75
+ **If `is_monorepo: true`** — present the discovered workspaces and prompt:
76
+
77
+ ```
78
+ This looks like a monorepo ({manifest_kind}) with these workspaces:
79
+ 1. {workspaces[0].name} ({workspaces[0].path})
80
+ 2. {workspaces[1].name} ({workspaces[1].path})
81
+ ...
82
+ Which one should the skill cover? Pick a number, type 'all' to scope at the repo root, or 'list' to keep listing more.
83
+ ```
84
+
85
+ Interactive: wait for the user choice. On a numbered choice, store `monorepo_workspace: {path}` and rebase §2-§4b against that path. On `'all'`, leave `monorepo_workspace` unset and proceed at the repo root with a note in the analysis summary that scope is unfiltered.
86
+
87
+ Headless: if the input contract supplied an `include` glob that begins with one of the workspace paths, auto-select that workspace (log `"headless: auto-selected workspace {name} from include glob"`). Otherwise default to repo root and log `"warn: monorepo detected ({manifest_kind}) but no workspace pre-selected — analyzing at repo root"`.
88
+
89
+ Surface any non-empty `warnings[]` from the script to the operator log so a malformed root manifest is debuggable; the workflow does not HALT — falling back to repo-root analysis is always safe.
90
+
41
91
  ### 2. Read Repository Structure
42
92
 
43
93
  List the top-level directory structure:
@@ -54,53 +104,79 @@ List the top-level directory structure:
54
104
 
55
105
  ### 3. Detect Primary Language
56
106
 
57
- Examine file extensions and configuration files to detect the primary language:
107
+ Delegate the rule walk to `{detectLanguageScript}` instead of evaluating manifest presence and extension frequency in prose:
108
+
109
+ ```bash
110
+ echo '{"tree": [<flat list of repo-relative file paths from §1>]}' | uv run {detectLanguageScript}
111
+ ```
58
112
 
59
- **Detection signals (check in order):**
60
- 1. `package.json` → JavaScript/TypeScript
61
- 2. `tsconfig.json` → TypeScript
62
- 3. `Cargo.toml` → Rust
63
- 4. `pyproject.toml` or `setup.py` or `setup.cfg` → Python
64
- 5. `go.mod` → Go
65
- 6. `pom.xml` or `build.gradle` → Java
66
- 7. `*.csproj` or `*.sln` → C#
67
- 8. `Gemfile` → Ruby
68
- 9. File extension frequency analysis as fallback
113
+ The script returns `{language, confidence, detection_source, fallback_to_extension_frequency}` after walking the documented rule table (manifest presence first — package.json with tsconfig.json disambiguation, Cargo.toml, pyproject.toml/setup.py/setup.cfg, go.mod, pom.xml, build.gradle.kts, build.gradle Groovy with Java/Kotlin disambiguation, *.csproj/*.sln, Gemfile — then extension-frequency fallback over recognized source extensions). Use the returned values directly:
69
114
 
70
115
  "**Detected language:** {language}
71
- **Confidence:** {high/medium/low}
72
- **Detection source:** {what config file or pattern confirmed it}"
116
+ **Confidence:** {confidence}
117
+ **Detection source:** {detection_source}"
73
118
 
74
- If confidence is low or ambiguous: flag for user override in step 03.
119
+ If `confidence` is `low` (or `unknown` is returned for `language`): flag for user override in step 03 §4.
75
120
 
76
121
  ### 4. List Top-Level Modules and Exports
77
122
 
78
- Based on detected language, identify public API surface:
123
+ Identify the public API surface. **Delegate the parsing to `{extractPublicApiScript}` whenever the detected language is supported** — the script is the single source of truth for manifest parsing, export discovery, and version detection across the whole SKF pipeline. Hand-rolling these in prose creates drift seams the LLM cannot fully close.
79
124
 
80
- **For JavaScript/TypeScript:**
81
- - Check `package.json` for `main`, `exports`, `module` fields
82
- - Look for `index.ts`/`index.js` in `src/`
83
- - List directories under `src/` as potential modules
125
+ **Script-supported languages** (use the script): `js`, `ts`, `javascript`, `typescript`, `python`, `rust`, `go`, `java`, `kotlin`.
84
126
 
85
- **For Python:**
86
- - Check `__init__.py` files for public exports
87
- - List top-level packages under the source directory
127
+ This section runs exactly one of §4.1 (script path) or §4.2 (fallback path) based on the detected language, then always emits §4.3 (output format) and conditionally §4.4 (semantic signals).
88
128
 
89
- **For Rust:**
90
- - Check `lib.rs` for `pub mod` declarations
91
- - List modules from `src/` directory
129
+ #### 4.1 Procedure — script-supported languages
92
130
 
93
- **For other languages:**
94
- - List top-level source directories as potential modules
95
- - Note any obvious entry points
131
+ 1. Read the relevant files into memory (no parsing yet — just collect content). For GitHub sources, issue **all N `gh api repos/{owner}/{repo}/contents/{file}` calls in a single message with N parallel Bash calls** (one per manifest + each entry point), then base64-decode the responses together — these are 2-4 independent fetches per typical run. For local sources read directly (also parallelisable, but local reads are fast enough that serial Read tool calls are acceptable).
132
+
133
+ | Language | Manifest | Entry points (mode=quick) |
134
+ |----------|----------|--------------------------|
135
+ | js / ts / javascript / typescript | `package.json` (root, or primary workspace package per `references/version-resolution.md`) | `index.{ts,js}` and/or `src/index.{ts,js}` if present |
136
+ | python | `pyproject.toml` (or `setup.py` / `setup.cfg` if no `pyproject.toml`) | top-level `__init__.py` of the package, plus `_version.py` if present |
137
+ | rust | `Cargo.toml` (`[package]` — workspace root if `version = { workspace = true }`) | `src/lib.rs` |
138
+ | go | `go.mod` | top-level `*.go` exporting the package surface |
139
+ | java | `pom.xml` | (manifest alone is sufficient for the modules listing) |
140
+ | kotlin | `build.gradle` / `build.gradle.kts` | (manifest alone) |
141
+
142
+ 2. Build a JSON payload matching the script contract:
143
+
144
+ ```json
145
+ {
146
+ "language": "<one of the supported values>",
147
+ "manifest": {"path": "<relative path>", "content": "<file contents>"},
148
+ "entries": [{"path": "<relative path>", "content": "<file contents>"}, ...],
149
+ "mode": "quick"
150
+ }
151
+ ```
152
+
153
+ 3. Invoke the script and parse its JSON stdout:
154
+
155
+ ```bash
156
+ echo '<payload-json>' | uv run {extractPublicApiScript} --language <lang> --mode quick
157
+ ```
158
+
159
+ On a non-zero exit (codes 1 or 2 per the script's docstring), capture stderr, log it, and fall through to §4.2 (the prose-fallback path) — never HALT just because the script choked on an unusual manifest.
160
+
161
+ 4. Render the returned `package_name`, `exports` (each entry's `name`/`type`/`source_file`), `dependencies`, and any `warnings` to the user. The script also returns `version` — feed that into §4b instead of re-deriving.
162
+
163
+ 5. The script does not enumerate directories under `src/`. The LLM still lists those as "Top-Level Modules/Directories" so the user sees structural context (Maven and Gradle are the exception — for those, the script returns a `modules` array which IS the list).
164
+
165
+ #### 4.2 Procedure — fallback (not script-supported)
166
+
167
+ Languages outside the script coverage (Ruby / C# / Swift / etc.) take this path. The §4.1 fall-through on script error also lands here.
168
+
169
+ Fall back to ad-hoc inspection — `Gemfile` / `*.csproj` / `*.sln` / `Package.swift` / file extension frequency. List top-level source directories as potential modules and note any obvious entry points. Flag the limitation in the analysis summary so the user knows scoping is on coarser signals.
170
+
171
+ #### 4.3 Output format (both paths)
96
172
 
97
173
  "**Top-Level Modules/Directories:**
98
174
  {numbered list of modules with brief description of each}
99
175
 
100
176
  **Detected Exports/Entry Points:**
101
- {numbered list of public-facing items found}"
177
+ {numbered list of public-facing items found — from script output when available, ad-hoc inspection otherwise}"
102
178
 
103
- **Semantic Signals (Forge+ and Deep with ccc only):**
179
+ #### 4.4 Semantic Signals (Forge+/Deep with ccc only)
104
180
 
105
181
  **Remote source guard:** If the target source was resolved via GitHub API (remote URL, not a local file path), skip this CCC subsection — CCC requires a local source index and cannot operate on remote-only sources. Note: "CCC semantic discovery skipped — target is remote. CCC discovery will run automatically during create-skill after the source is cloned."
106
182
 
@@ -124,29 +200,21 @@ If CCC is unavailable or returns no results: skip this subsection silently.
124
200
 
125
201
  ### 4b. Detect Source Version
126
202
 
127
- **If `target_version` was provided in step 01:**
128
- - Display: "**Target version:** {target_version} (user-specified)"
129
- - Still run auto-detection below for informational purposes.
203
+ **When the language was script-supported (§4 took the script path):** the `version` field returned by `{extractPublicApiScript}` IS the detected version — do not re-derive it and do not load `{versionResolutionFile}`. The script already implements the language-specific lookups documented in that reference, so loading the reference here only burns context.
130
204
 
131
- Attempt to auto-detect the source version using the rules from the skill-brief-schema.md Version Detection section:
205
+ **When the language was not script-supported:** load `{versionResolutionFile}` and follow the prose Detection Algorithm directly (Ruby / C# / Swift / etc. fall outside the script's coverage).
132
206
 
133
- **For Python:** Check `pyproject.toml` `[project] version` (static) if `dynamic = ["version"]`, check `__init__.py` for `__version__` → `_version.py` if exists → `setup.py` `version=` → `git describe --tags --abbrev=0`
134
- **For JavaScript/TypeScript:** Check root `package.json` `"version"` field → if root has `"private": true` with a `"workspaces"` array or lacks a `"version"` field, fall back to a primary workspace package's `package.json` (e.g., `code/core/package.json`, or the first matching `packages/*/package.json`). For GitHub sources, prefer `gh api repos/{owner}/{repo}/releases/latest` → `tag_name` when a non-pre-release tag exists, over a default-branch pre-release. Treat a version containing `-alpha`, `-beta`, `-rc`, `-next`, or `-canary` as a pre-release.
135
- **For Rust:** Check `Cargo.toml` `[package] version` (static) → if `version = { workspace = true }`, resolve from workspace root `Cargo.toml` → `git describe --tags --abbrev=0`
136
- **For Go:** Check `go.mod` or `git describe --tags --abbrev=0`
207
+ Surface the result regardless of which path produced it:
137
208
 
138
- **For GitHub repos:** Use `gh api repos/{owner}/{repo}/contents/{file}` to read version files (decode base64 content).
139
- **For local repos:** Read the file directly.
209
+ **If `target_version` was provided in step 01:**
210
+ - Display: "**Target version:** {target_version} (user-specified)"
140
211
 
141
212
  Display: "**Detected version:** {version or 'Not detected — will default to 1.0.0'}"
142
213
 
143
214
  {If target_version was provided AND auto-detected version differs:}
144
- "**Note:** Detected version ({detected_version}) differs from your target version ({target_version}). Using target version."
145
-
146
- {If target_version was provided:}
147
- Store `target_version` as the brief's `version` field (overrides auto-detection).
215
+ "**Note:** Detected version ({detected_version}) differs from your target version ({target_version}). Using target version (per `references/version-resolution.md` precedence rules)."
148
216
 
149
- If detection fails or returns a non-semver value: note that version will default to `"1.0.0"` and the user can override in step 04.
217
+ If detection fails or returns a non-semver value: note that version will default to `"1.0.0"` and the user can override in step 04. The actual write happens in step 05.
150
218
 
151
219
  ### 5. Report Analysis Summary
152
220
 
@@ -1,6 +1,7 @@
1
1
  ---
2
2
  nextStepFile: './step-04-confirm-brief.md'
3
3
  scopeTemplatesFile: 'assets/scope-templates.md'
4
+ recommendScopeTypeScript: '{project-root}/src/shared/scripts/skf-recommend-scope-type.py'
4
5
  advancedElicitationSkill: '/bmad-advanced-elicitation'
5
6
  partyModeSkill: '/bmad-party-mode'
6
7
  ---
@@ -16,6 +17,8 @@ To collaboratively define the skill's inclusion and exclusion boundaries using t
16
17
  - Focus only on defining scope boundaries — do not write the brief yet (Step 05)
17
18
  - Do not make scope decisions unilaterally — user drives all scope choices
18
19
  - Produce: scope type, include patterns, exclude patterns
20
+ - All user-facing output in `{communication_language}`
21
+ - **Re-entry from step-04 [R] revise:** prior selections (`scope.type`, `scope.include`, `scope.exclude`, `scope.notes`, `scripts_intent`, `assets_intent`, supplemental `doc_urls`) are preserved as the current state. Re-present them at each section as the existing answer; the user only re-confirms or overrides. Do not reset to the §2c template menu unless the user explicitly asks to start scope over.
19
22
 
20
23
  ## MANDATORY SEQUENCE
21
24
 
@@ -65,6 +68,10 @@ Add, remove, or confirm these URLs."
65
68
 
66
69
  Wait for confirmation. Record any changes to `doc_urls`.
67
70
 
71
+ HEAD-check the URLs in parallel — issue all N `curl -sI --max-time 5 {url}` calls in a **single message with N parallel Bash calls**, then process the responses together. On a 4xx/5xx, DNS failure, or timeout per URL, warn `"Could not reach {url} — {status or error}."` and offer the same correct/keep choice as step-01 §3. The check is best-effort — never HALT on a failed HEAD — but the failure must surface here so it is not discovered downstream during compilation.
72
+
73
+ **On re-entry from step-04 [R]:** if `doc_urls` is byte-identical to the list that was probed on the previous pass through this subsection AND the prior per-URL probe results are still recoverable from conversation context, skip the parallel HEAD-check and reuse those results. Re-running the probes when the list has not changed wastes round-trips and can flap on transient failures. Any addition, removal, or edit to a URL invalidates the cache — re-probe the entire updated set. If the prior results are not recoverable (long session, compaction, etc.), re-probe — never cache-hit on a list whose results you cannot cite.
74
+
68
75
  **If no supplemental doc_urls were collected:** Skip this subsection.
69
76
 
70
77
  **Scope guidance for first-time users:** A well-scoped skill covers one cohesive capability with 3-8 primary functions. If the scope includes unrelated concerns (e.g., authentication AND data visualization), suggest splitting into separate briefs. If the scope is too narrow (single utility function), suggest expanding to the surrounding capability surface.
@@ -73,11 +80,41 @@ Wait for confirmation. Record any changes to `doc_urls`.
73
80
 
74
81
  Load `{scopeTemplatesFile}` for the scope type options ([F], [M], [P], [C], [R]) and their descriptions.
75
82
 
76
- Present: "**How broadly should this skill cover the library?**" followed by the scope type options from the loaded reference.
83
+ **Recommend a scope type — don't present the five options as equal weight.** SKILL.md states this workflow "steers toward the smaller, sharper version when scope is unclear" surface that opinion at decision time. Use the analysis from step-02 and the user's intent from step-01 to pick the best-fit recommendation, then present the menu with that option marked as the suggested default.
84
+
85
+ **Delegate the recommendation to `{recommendScopeTypeScript}`** instead of walking the heuristic ladder in prose. The script is the single source of truth for the five-rule ladder (component-registry → reference-app keywords → specific-modules naming/count → narrow-public-api → default full-library) plus the docs-only short-circuit. Both the interactive recommendation and the §6 headless GATE invoke the same script — same inputs, same outputs, no drift.
86
+
87
+ **Fetch registry-file contents before building the payload.** Step-02 §4.1 fetches `package.json` plus the entry-point files but does not fetch `registry.ts` / `components.ts` — the deep-match branch of the component-registry rule needs those contents. Scan the tree for any of `registry.ts` / `registry.tsx` / `components.ts` / `components.tsx` (any depth). For each match, fetch its contents in **one message with N parallel Bash calls** (`gh api repos/{owner}/{repo}/contents/{path}` for GitHub, file reads for local), then base64-decode the responses together. Skip the fetch if the tree contains no registry files.
88
+
89
+ Build the payload and invoke:
90
+
91
+ ```bash
92
+ echo '{
93
+ "intent": "<combined intent + scope_hint text from step-01>",
94
+ "module_count": <count from step-02 §4.3>,
95
+ "export_count": <count from step-02 §4.3>,
96
+ "tree": [<flat list of repo-relative file paths from step-02 §1>],
97
+ "entry_files": [{"path": "<registry path>", "content": "<contents>"}, ...],
98
+ "source_type": "source",
99
+ "mode": "interactive"
100
+ }' | uv run {recommendScopeTypeScript}
101
+ ```
102
+
103
+ `entry_files` carries the registry contents fetched above; omit when no registry files exist in the tree. `mode: "interactive"` activates the content-inspection branch of the component-registry rule (10+ entries or `Component[]` annotation); the headless GATE in §6 uses `mode: "headless"` which falls back to presence-only matching. `source_type: "docs-only"` short-circuits to `docs-only` regardless of the other signals.
104
+
105
+ The script returns `{scope_type, matched_heuristic, signals, rationale}`. Use `rationale` directly — it already names the specific signals that fired.
106
+
107
+ Present:
108
+
109
+ "**Recommended scope type: [{letter}] {Name}** — {rationale from the script}.
110
+
111
+ How broadly should this skill cover the library?
112
+
113
+ {full menu from `{scopeTemplatesFile}` with the recommended letter marked, e.g. '[F] Full Library', '[M] Specific Modules', '[P] Public API Only ← recommended', '[C] Component Library', '[R] Reference App'}
77
114
 
78
- Ask: "Which scope type fits your needs?"
115
+ Press Enter to accept the recommendation, or pick a different letter."
79
116
 
80
- Wait for user selection.
117
+ Wait for user selection. Empty input or just Enter accepts the recommendation; any of the five letters overrides.
81
118
 
82
119
  ### 3. Define Boundaries Based on Selection
83
120
 
@@ -128,19 +165,25 @@ Record the response as `scripts_intent` and `assets_intent` in the brief. Defaul
128
165
 
129
166
  ### 6. Present MENU OPTIONS
130
167
 
131
- Display: **Select an Option:** [A] Advanced Elicitation [P] Party Mode [C] Continue to Brief Confirmation
168
+ Display: **Select an Option:** [A] Advanced Elicitation [P] Party Mode [C] Continue to Brief Confirmation [X] Cancel and exit
132
169
 
133
170
  #### Menu Handling Logic:
134
171
 
135
172
  - IF A: Invoke {advancedElicitationSkill}, and when finished redisplay the menu
136
173
  - IF P: Invoke {partyModeSkill}, and when finished redisplay the menu
137
174
  - IF C: Load, read entire file, then execute {nextStepFile}
175
+ - IF X: Treat as user-cancellation. Display `"Cancelled — no brief was written."` and HALT (exit code 6, `halt_reason: "user-cancelled"`). Cancellation here is non-destructive — no files have been written yet. `[X]` is interactive-only; the headless GATE never reaches this branch.
138
176
  - IF Any other comments or queries: help user respond then [Redisplay Menu Options](#6-present-menu-options)
139
177
 
140
178
  #### EXECUTION RULES:
141
179
 
142
180
  - ALWAYS halt and wait for user input after presenting menu
143
- - **GATE [default: C]** — If `{headless_mode}`: accept auto-detected scope (full-repo or manifest-based) and auto-proceed, log: "headless: using auto-detected scope"
181
+ - **GATE [default: C]** — If `{headless_mode}`: consume the headless inputs from step-01 in priority order:
182
+ - If `scope_type` was supplied, use it (must match one of the six valid types) and skip the §2c template menu.
183
+ - Otherwise auto-select via `{recommendScopeTypeScript}` — invoke the script with the **same payload shape** documented in §2c but with `mode: "headless"` (presence-only matching for the component-registry rule, since `entry_files` may not be available without an interactive context). Use the returned `scope_type` and log `"headless: scope_type={value} from heuristic={matched_heuristic}"`. The script's docs-only short-circuit handles `source_type=docs-only` automatically.
184
+ - If `include`/`exclude` were supplied, use them verbatim (split on comma) instead of running the boundary prompts in §3.
185
+ - If `scripts_intent`/`assets_intent` were supplied, record them and skip §5b; otherwise default to `detect`.
186
+ - Log: `"headless: scope_type={value} include={n} exclude={n} scripts_intent={value} assets_intent={value}"`.
144
187
  - ONLY proceed to next step when user selects 'C'
145
188
  - After other menu items execution, return to this menu
146
189
  - User can chat or ask questions — always respond and then redisplay menu
@@ -16,16 +16,15 @@ To present the complete skill brief in human-readable format, highlighting all f
16
16
 
17
17
  - Focus only on presenting and confirming — do not write files yet (Step 05)
18
18
  - Do not proceed without explicit user approval (P2 confirmation gate)
19
+ - All user-facing output in `{communication_language}`
19
20
 
20
21
  ## MANDATORY SEQUENCE
21
22
 
22
23
  **CRITICAL:** Follow this sequence exactly. Do not skip, reorder, or improvise unless user explicitly requests a change.
23
24
 
24
- ### 1. Load Schema
25
+ ### 1. Assemble Complete Brief
25
26
 
26
- Load `{briefSchemaFile}` to reference required fields and the human-readable presentation format.
27
-
28
- ### 2. Assemble Complete Brief
27
+ Use the values already accepted in steps 01-03 directly — do not re-load `{briefSchemaFile}` here. The 18 fields below are all in conversation; the schema is only consulted in §4 if an inline adjustment needs a specific field's validation rule cited.
29
28
 
30
29
  Compile all gathered data from steps 01-03 into the complete brief:
31
30
 
@@ -48,11 +47,11 @@ Compile all gathered data from steps 01-03 into the complete brief:
48
47
  - **assets_intent:** {detect/none/description from step 03, or "detect" if not explicitly set}
49
48
  - **source_authority:** {official/community/internal from step 01 — default "community"}
50
49
 
51
- ### 3. Present Brief for Review
50
+ ### 2. Present Brief for Review
52
51
 
53
- Using the presentation format from the schema:
52
+ Using the format below:
54
53
 
55
- "**Please review the complete skill brief before I write it.**
54
+ "**Review the complete skill brief before I write it.**
56
55
 
57
56
  ---
58
57
 
@@ -62,7 +61,7 @@ Skill Brief: {name}
62
61
 
63
62
  Target: {source_repo}
64
63
  Language: {language}
65
- Forge Tier: {forge_tier}
64
+ Forge Tier: {forge_tier} — {tier_gloss}
66
65
  Description: {description}
67
66
 
68
67
  Scope: {scope.type}
@@ -79,9 +78,8 @@ Doc URLs:
79
78
  Supplemental Docs:
80
79
  {doc_urls, one per line with labels}
81
80
 
82
- {If scripts_intent or assets_intent was explicitly set (not default "detect"):}
83
- Scripts: {scripts_intent}
84
- Assets: {assets_intent}
81
+ Scripts: {scripts_intent} {scripts_gloss}
82
+ Assets: {assets_intent} — {assets_gloss}
85
83
 
86
84
  Source Authority: {source_authority}
87
85
 
@@ -95,17 +93,31 @@ Created: {created}
95
93
  Created by: {created_by}
96
94
  ```
97
95
 
98
- ---"
96
+ ---
97
+
98
+ Glosses (substitute the matching one-liner for `{tier_gloss}`, `{scripts_gloss}`, `{assets_gloss}` above so the user can decode each value at a glance):
99
+
100
+ - **Forge tier glosses** —
101
+ - `Quick`: text-only extraction; AST and semantic discovery off
102
+ - `Forge`: AST-grep on; semantic and re-ranking off
103
+ - `Forge+`: AST-grep + ccc semantic discovery; re-ranking off
104
+ - `Deep`: full pipeline — AST + ccc + qmd portfolio search + LLM re-ranking
105
+
106
+ - **`scripts_intent` / `assets_intent` glosses** —
107
+ - `detect`: SKF will scan source for the standard `scripts/`/`bin/`/`tools/`/`cli/` (or `assets/`/`templates/`/`schemas/`/`configs/`) directories during create-skill and decide automatically
108
+ - `none`: no script/asset packaging — create-skill will skip the detection pass
109
+ - free-text (anything else): a description of what to package; create-skill treats it as the user's spec
110
+
111
+ (For `docs-only` and `public-api` scope types the scripts/assets prompt is skipped in step-03 §5b — the values default to `detect` but the create-skill detection pass also no-ops for these scope types, so the gloss just clarifies that the recorded value will not actually fire any scan.)"
99
112
 
100
- ### 4. Highlight Items Needing Attention
113
+ ### 3. Highlight Items Needing Attention
101
114
 
102
115
  Flag any fields that may need review:
103
116
 
104
117
  {If language was overridden or low confidence:}
105
118
  "**Note:** Language was {auto-detected / manually overridden}."
106
119
 
107
- {If description was derived (not stated by user):}
108
- "**Note:** Description was derived from your stated intent. Adjust if needed."
120
+ "**Description:** synthesized and confirmed in step-01 §7b. This is the text agents read when deciding whether to route to your skill — refine here if you want to tighten it now that the full brief is visible."
109
121
 
110
122
  {If forge tier was defaulted:}
111
123
  "**Note:** Forge tier defaulted to Quick (no forge-tier.yaml found)."
@@ -123,16 +135,17 @@ You can:
123
135
  - Revise scope boundaries by selecting [R]
124
136
  - Proceed to write by selecting [C]"
125
137
 
126
- ### 5. Handle Inline Adjustments
138
+ ### 4. Handle Inline Adjustments
127
139
 
128
140
  If the user requests changes to specific fields (name, description, version, etc.):
141
+ - If the adjustment requires explaining a field's validation rule or allowed values, load `{briefSchemaFile}` now (otherwise skip the read — the common path does not need it)
129
142
  - Make the adjustment
130
143
  - Re-present the updated brief
131
144
  - Return to the menu
132
145
 
133
- ### 6. Present MENU OPTIONS
146
+ ### 5. Present MENU OPTIONS
134
147
 
135
- Display: **Select an Option:** [R] Revise Scope [A] Advanced Elicitation [P] Party Mode [C] Approve and Write
148
+ Display: **Select an Option:** [R] Revise Scope [A] Advanced Elicitation [P] Party Mode [C] Approve and Write [X] Cancel and exit
136
149
 
137
150
  #### Menu Handling Logic:
138
151
 
@@ -140,7 +153,8 @@ Display: **Select an Option:** [R] Revise Scope [A] Advanced Elicitation [P] Par
140
153
  - IF A: Invoke {advancedElicitationSkill}, and when finished redisplay the menu
141
154
  - IF P: Invoke {partyModeSkill}, and when finished redisplay the menu
142
155
  - IF C: Load, read entire file, then execute {nextStepFile}
143
- - IF Any other comments or queries: help user respond, apply any field adjustments, re-present brief if changed, then [Redisplay Menu Options](#6-present-menu-options)
156
+ - IF X: Treat as user-cancellation. Display `"Cancelled no brief was written."` and HALT (exit code 6, `halt_reason: "user-cancelled"`). Cancellation here is non-destructive — step-05 has not run, no skill-brief.yaml file exists yet. `[X]` is interactive-only; the headless GATE never reaches this branch.
157
+ - IF Any other comments or queries: help user respond, apply any field adjustments, re-present brief if changed, then [Redisplay Menu Options](#5-present-menu-options)
144
158
 
145
159
  #### EXECUTION RULES:
146
160