bmad-module-skill-forge 0.7.1 → 0.7.3
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.
- package/package.json +1 -1
- package/src/knowledge/qmd-registry.md +6 -1
- package/src/workflows/analyze-source/data/skill-brief-schema.md +3 -1
- package/src/workflows/analyze-source/steps-c/step-05-recommend.md +4 -4
- package/src/workflows/brief-skill/data/skill-brief-schema.md +18 -1
- package/src/workflows/brief-skill/steps-c/step-01-gather-intent.md +16 -0
- package/src/workflows/brief-skill/steps-c/step-02-analyze-target.md +42 -6
- package/src/workflows/brief-skill/steps-c/step-03-scope-definition.md +19 -5
- package/src/workflows/brief-skill/steps-c/step-04-confirm-brief.md +24 -4
- package/src/workflows/brief-skill/steps-c/step-05-write-brief.md +34 -9
- package/src/workflows/brief-skill/workflow.md +1 -1
- package/src/workflows/create-skill/data/compile-assembly-rules.md +1 -0
- package/src/workflows/create-skill/data/extraction-patterns.md +54 -4
- package/src/workflows/create-skill/data/skill-sections.md +2 -1
- package/src/workflows/create-skill/data/source-resolution-protocols.md +15 -1
- package/src/workflows/create-skill/steps-c/step-01-load-brief.md +4 -4
- package/src/workflows/create-skill/steps-c/step-02b-ccc-discover.md +4 -2
- package/src/workflows/create-skill/steps-c/step-03-extract.md +1 -1
- package/src/workflows/create-skill/steps-c/step-03b-fetch-temporal.md +18 -3
- package/src/workflows/create-skill/steps-c/step-03c-fetch-docs.md +11 -5
- package/src/workflows/create-skill/steps-c/step-05-compile.md +19 -3
- package/src/workflows/create-skill/steps-c/step-06-validate.md +10 -6
- package/src/workflows/create-skill/steps-c/step-07-generate-artifacts.md +1 -1
- package/src/workflows/quick-skill/steps-c/step-04-compile.md +1 -1
- package/src/workflows/test-skill/data/output-section-formats.md +15 -0
- package/src/workflows/test-skill/data/scoring-rules.md +12 -0
- package/src/workflows/test-skill/data/source-access-protocol.md +8 -2
- package/src/workflows/test-skill/steps-c/step-03-coverage-check.md +41 -5
- package/src/workflows/test-skill/steps-c/step-04-coherence-check.md +48 -4
- package/src/workflows/test-skill/steps-c/step-04b-external-validators.md +9 -1
- package/src/workflows/test-skill/steps-c/step-05-score.md +2 -0
- package/tools/cli/lib/installer.js +4 -0
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": "0.7.
|
|
4
|
+
"version": "0.7.3",
|
|
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",
|
|
@@ -40,8 +40,13 @@ qmd_collections:
|
|
|
40
40
|
source_workflow: "brief-skill"
|
|
41
41
|
skill_name: "my-lib"
|
|
42
42
|
created_at: "2026-03-14"
|
|
43
|
+
# status: "pending" # Optional — see below
|
|
43
44
|
```
|
|
44
45
|
|
|
46
|
+
**Optional field: `status`**
|
|
47
|
+
|
|
48
|
+
The `status` field is only present when QMD embed verification fails during collection creation. When `status: "pending"` is set, the collection exists in QMD but vector embeddings may be incomplete — only BM25 keyword `search` is reliable. `vector_search` and `deep_search` may return no results until re-embedded. Collections without a `status` field are fully operational. The setup-forge janitor should flag `"pending"` collections for re-embedding.
|
|
49
|
+
|
|
45
50
|
### Collection Types
|
|
46
51
|
|
|
47
52
|
| Type | Producer | Content | Primary Consumers |
|
|
@@ -122,7 +127,7 @@ These registries are orthogonal — they never reference each other, and their j
|
|
|
122
127
|
|
|
123
128
|
```
|
|
124
129
|
qmd collection remove {name}-extraction (if exists)
|
|
125
|
-
qmd collection add skills/{name} --name {name}-extraction --mask "**/*"
|
|
130
|
+
qmd collection add {project-root}/skills/{name} --name {name}-extraction --mask "**/*"
|
|
126
131
|
qmd embed
|
|
127
132
|
```
|
|
128
133
|
|
|
@@ -9,7 +9,7 @@ Defines the output contract for skill-brief.yaml files generated by analyze-sour
|
|
|
9
9
|
| Field | Type | Constraint | Description |
|
|
10
10
|
|-------|------|------------|-------------|
|
|
11
11
|
| name | string | kebab-case `[a-z0-9-]+` | Unique skill identifier |
|
|
12
|
-
| version | string | Semantic `X.Y.Z` | Auto-detect from source (see Version Detection below), fall back to `1.0.0` |
|
|
12
|
+
| version | string | Semantic version (`X.Y.Z` or `X.Y.Z-prerelease`) | Auto-detect from source (see Version Detection below), fall back to `1.0.0` |
|
|
13
13
|
| source_repo | string | GitHub URL or local path | Repository or project root (optional when `source_type: "docs-only"`) |
|
|
14
14
|
| language | string | Recognized language | Primary programming language |
|
|
15
15
|
| scope | object | See Scope Object below | Boundary definition |
|
|
@@ -49,6 +49,8 @@ If detection succeeds, use the detected version. If it fails or returns a non-se
|
|
|
49
49
|
|
|
50
50
|
The create-skill workflow (step-03-extract) also performs version reconciliation at extraction time — if the source version has changed since the brief was created, the extraction step warns and uses the source version.
|
|
51
51
|
|
|
52
|
+
**Pre-release handling:** If the detected version contains a pre-release tag (e.g., `1.0.0-beta.0`, `2.0.0-rc.1`), preserve it as-is. Pre-release tags are valid semver and must not be stripped. When comparing versions during reconciliation, use semver-aware comparison that respects pre-release ordering.
|
|
53
|
+
|
|
52
54
|
## Scope Object
|
|
53
55
|
|
|
54
56
|
```yaml
|
|
@@ -5,8 +5,8 @@ description: 'Present unit recommendations with rationale for user confirmation
|
|
|
5
5
|
nextStepFile: './step-06-generate-briefs.md'
|
|
6
6
|
outputFile: '{forge_data_folder}/analyze-source-report-{project_name}.md'
|
|
7
7
|
schemaFile: '../data/skill-brief-schema.md'
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
advancedElicitationSkill: '/bmad-advanced-elicitation'
|
|
9
|
+
partyModeSkill: '/bmad-party-mode'
|
|
10
10
|
---
|
|
11
11
|
|
|
12
12
|
# Step 5: Recommend
|
|
@@ -193,8 +193,8 @@ Display: "**Select an Option:** [A] Advanced Elicitation [P] Party Mode [D] Disc
|
|
|
193
193
|
|
|
194
194
|
#### Menu Handling Logic:
|
|
195
195
|
|
|
196
|
-
- IF A:
|
|
197
|
-
- IF P:
|
|
196
|
+
- IF A: Invoke {advancedElicitationSkill}, and when finished redisplay the menu
|
|
197
|
+
- IF P: Invoke {partyModeSkill}, and when finished redisplay the menu
|
|
198
198
|
- IF D: Accept a new repo path/URL from the user. Run a lightweight scan + classify (subset of steps 02-03) for the new source only. Merge new units into the existing report and update `project_paths[]` in frontmatter. Run export mapping for the new units (same logic as step 04 section 2). Generate recommendation cards for the new units and present them for confirmation. Then redisplay this menu.
|
|
199
199
|
- IF C: Save recommendations to {outputFile}, update frontmatter, then load, read entire file, then execute {nextStepFile}
|
|
200
200
|
- IF Any other comments or queries: help user respond then [Redisplay Menu Options](#8-present-menu-options)
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
| Field | Type | Constraint | Description |
|
|
6
6
|
|-------|------|------------|-------------|
|
|
7
7
|
| name | string | kebab-case `[a-z0-9-]+` | Unique skill identifier |
|
|
8
|
-
| version | string | Semantic `X.Y.Z` | Auto-detect from source (see Version Detection below), fall back to `1.0.0` |
|
|
8
|
+
| version | string | Semantic version (`X.Y.Z` or `X.Y.Z-prerelease`) | Auto-detect from source (see Version Detection below), fall back to `1.0.0` |
|
|
9
9
|
| source_repo | string | GitHub URL or local path | Repository or project root (optional when `source_type: "docs-only"`) |
|
|
10
10
|
| language | string | Recognized language | Primary programming language |
|
|
11
11
|
| scope | object | See Scope Object below | Boundary definition |
|
|
@@ -45,6 +45,8 @@ If detection succeeds, use the detected version. If it fails or returns a non-se
|
|
|
45
45
|
|
|
46
46
|
The create-skill workflow (step-03-extract) also performs version reconciliation at extraction time — if the source version has changed since the brief was created, the extraction step warns and uses the source version.
|
|
47
47
|
|
|
48
|
+
**Pre-release handling:** If the detected version contains a pre-release tag (e.g., `1.0.0-beta.0`, `2.0.0-rc.1`), preserve it as-is. Pre-release tags are valid semver and must not be stripped. When comparing versions during reconciliation, use semver-aware comparison that respects pre-release ordering.
|
|
49
|
+
|
|
48
50
|
## Scope Object Structure
|
|
49
51
|
|
|
50
52
|
```yaml
|
|
@@ -106,6 +108,21 @@ Scope: {scope.type}
|
|
|
106
108
|
Exclude: {scope.exclude patterns, one per line}
|
|
107
109
|
Notes: {scope.notes}
|
|
108
110
|
|
|
111
|
+
{If source_type is "docs-only":}
|
|
112
|
+
Source Type: docs-only
|
|
113
|
+
Doc URLs:
|
|
114
|
+
{doc_urls, one per line with labels}
|
|
115
|
+
|
|
116
|
+
{If source_type is "source" AND supplemental doc_urls collected:}
|
|
117
|
+
Supplemental Docs:
|
|
118
|
+
{doc_urls, one per line with labels}
|
|
119
|
+
|
|
120
|
+
{If scripts_intent or assets_intent was explicitly set (not default "detect"):}
|
|
121
|
+
Scripts: {scripts_intent}
|
|
122
|
+
Assets: {assets_intent}
|
|
123
|
+
|
|
124
|
+
Source Authority: {source_authority}
|
|
125
|
+
|
|
109
126
|
Version: {version}
|
|
110
127
|
Created: {created}
|
|
111
128
|
Created by: {created_by}
|
|
@@ -82,6 +82,9 @@ We'll work through this together:
|
|
|
82
82
|
3. **Then:** Define scope boundaries
|
|
83
83
|
4. **Finally:** Confirm and write the brief
|
|
84
84
|
|
|
85
|
+
{If tier override was applied:}
|
|
86
|
+
**Your forge tier:** {override tier} (overridden from {original tier}) — this determines what compilation capabilities are available.
|
|
87
|
+
{Else:}
|
|
85
88
|
**Your forge tier:** {detected tier} — this determines what compilation capabilities are available.
|
|
86
89
|
|
|
87
90
|
Let's get started."
|
|
@@ -110,6 +113,14 @@ Wait for user response.
|
|
|
110
113
|
- Optionally ask: "Are there any documentation URLs you'd like to include for supplemental context? (These will be fetched as T3 external references.)"
|
|
111
114
|
- If yes: collect doc URLs into `doc_urls`
|
|
112
115
|
|
|
116
|
+
**Source authority (for all source-type skills):**
|
|
117
|
+
"**Are you the maintainer of this library, or creating a community skill?**"
|
|
118
|
+
- If maintainer: set `source_authority: "official"`
|
|
119
|
+
- If community user: set `source_authority: "community"` (default)
|
|
120
|
+
- If internal/proprietary: set `source_authority: "internal"`
|
|
121
|
+
|
|
122
|
+
Default to `"community"` if user does not specify or skips. For `docs-only` skills, `source_authority` is always forced to `"community"`.
|
|
123
|
+
|
|
113
124
|
Confirm the target.
|
|
114
125
|
|
|
115
126
|
### 4. Gather User Intent
|
|
@@ -154,6 +165,10 @@ Wait for confirmation or alternative.
|
|
|
154
165
|
- **Intent:** {user's intent summary}
|
|
155
166
|
- **Scope hints:** {any hints, or "None — we'll define scope after analysis"}
|
|
156
167
|
- **Skill name:** {confirmed name}
|
|
168
|
+
- **Source type:** {source or docs-only}
|
|
169
|
+
- **Source authority:** {official/community/internal}
|
|
170
|
+
{If doc_urls collected:}
|
|
171
|
+
- **Doc URLs:** {count} supplemental documentation URLs
|
|
157
172
|
- **Forge tier:** {tier}
|
|
158
173
|
|
|
159
174
|
Ready to analyze the target repository?"
|
|
@@ -187,6 +202,7 @@ ONLY WHEN C is selected and target repository is confirmed will you load and rea
|
|
|
187
202
|
- User intent captured with enough context for scoping
|
|
188
203
|
- Skill name derived and confirmed
|
|
189
204
|
- Scope hints noted (if provided)
|
|
205
|
+
- Source type and source authority captured
|
|
190
206
|
- User ready to proceed to analysis
|
|
191
207
|
|
|
192
208
|
### ❌ SYSTEM FAILURE:
|
|
@@ -60,6 +60,12 @@ To analyze the target repository by resolving its location, reading its structur
|
|
|
60
60
|
**For GitHub URLs:**
|
|
61
61
|
- Use `gh api repos/{owner}/{repo}` to verify the repository exists
|
|
62
62
|
- Use `gh api repos/{owner}/{repo}/git/trees/HEAD?recursive=1` to get the file tree
|
|
63
|
+
|
|
64
|
+
**Truncation detection:** After receiving the tree response, check the `truncated` field in the JSON output. If `truncated: true`:
|
|
65
|
+
- Display: "Note: GitHub API returned a truncated tree response ({count} items). Full analysis may require a local clone."
|
|
66
|
+
- Record in analysis summary: "Tree listing is partial — some files may not appear in the analysis."
|
|
67
|
+
- For very large repos (>1000 files in tree response): suggest local clone for complete analysis.
|
|
68
|
+
|
|
63
69
|
- 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."
|
|
64
70
|
|
|
65
71
|
**For local paths:**
|
|
@@ -133,9 +139,16 @@ Based on detected language, identify public API surface:
|
|
|
133
139
|
|
|
134
140
|
**Semantic Signals (Forge+ and Deep with ccc only):**
|
|
135
141
|
|
|
142
|
+
**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 will be available during create-skill if the source is cloned locally."
|
|
143
|
+
|
|
136
144
|
If `tools.ccc` is true in forge-tier.yaml, supplement the module listing with a semantic discovery pass:
|
|
137
145
|
|
|
138
|
-
|
|
146
|
+
**CCC Semantic Discovery:**
|
|
147
|
+
- **Claude Code:** Use `/ccc search "{repo_name} public API exports modules" {source_path}`
|
|
148
|
+
- **Cursor:** Use `ccc` MCP server `search` tool with query `"{repo_name} public API exports modules"` and path `{source_path}`
|
|
149
|
+
- **CLI fallback:** `ccc search "{repo_name} public API exports modules" --path {source_path} --limit 10`
|
|
150
|
+
|
|
151
|
+
See [knowledge/tool-resolution.md](../../../knowledge/tool-resolution.md) for full bridge-to-tool mapping.
|
|
139
152
|
|
|
140
153
|
If results are returned, display:
|
|
141
154
|
|
|
@@ -146,6 +159,22 @@ This supplements — never replaces — the explicit module list above. CCC may
|
|
|
146
159
|
|
|
147
160
|
If CCC is unavailable or returns no results: skip this subsection silently.
|
|
148
161
|
|
|
162
|
+
### 4b. Detect Source Version
|
|
163
|
+
|
|
164
|
+
Attempt to auto-detect the source version using the rules from the skill-brief-schema.md Version Detection section:
|
|
165
|
+
|
|
166
|
+
**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`
|
|
167
|
+
**For JavaScript/TypeScript:** Check `package.json` `"version"` field
|
|
168
|
+
**For Rust:** Check `Cargo.toml` `[package] version` (static) → if `version = { workspace = true }`, resolve from workspace root `Cargo.toml` → `git describe --tags --abbrev=0`
|
|
169
|
+
**For Go:** Check `go.mod` or `git describe --tags --abbrev=0`
|
|
170
|
+
|
|
171
|
+
**For GitHub repos:** Use `gh api repos/{owner}/{repo}/contents/{file}` to read version files (decode base64 content).
|
|
172
|
+
**For local repos:** Read the file directly.
|
|
173
|
+
|
|
174
|
+
Display: "**Detected version:** {version or 'Not detected — will default to 1.0.0'}"
|
|
175
|
+
|
|
176
|
+
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.
|
|
177
|
+
|
|
149
178
|
### 5. Report Analysis Summary
|
|
150
179
|
|
|
151
180
|
Present the complete analysis:
|
|
@@ -169,6 +198,7 @@ Present the complete analysis:
|
|
|
169
198
|
- Tests: {found/not found — location}
|
|
170
199
|
- Docs: {found/not found — location}
|
|
171
200
|
- Config: {list of config files found}
|
|
201
|
+
- Version: {detected version or "Not detected — defaulting to 1.0.0"}
|
|
172
202
|
|
|
173
203
|
---
|
|
174
204
|
|
|
@@ -179,16 +209,21 @@ Moving to scope definition where you'll choose what to include and exclude."
|
|
|
179
209
|
|
|
180
210
|
### 6. Auto-Proceed to Scope Definition
|
|
181
211
|
|
|
182
|
-
Display: "**Proceeding to scope definition...**
|
|
212
|
+
Display: "**Proceeding to scope definition...**
|
|
213
|
+
|
|
214
|
+
Review the analysis above. If anything looks wrong, let me know now — otherwise I'll proceed to scope definition."
|
|
215
|
+
|
|
216
|
+
Pause briefly for user input. If the user provides corrections or asks questions, address them and re-present any updated analysis findings. Then proceed.
|
|
183
217
|
|
|
184
218
|
#### Menu Handling Logic:
|
|
185
219
|
|
|
186
|
-
- After analysis report is presented to user,
|
|
220
|
+
- After analysis report is presented to user and any corrections addressed, load, read entire file, then execute {nextStepFile}
|
|
187
221
|
|
|
188
222
|
#### EXECUTION RULES:
|
|
189
223
|
|
|
190
|
-
- This is
|
|
191
|
-
-
|
|
224
|
+
- This is a soft auto-proceed step — present the pause prompt, wait briefly for user input
|
|
225
|
+
- If user provides corrections: address them, then proceed
|
|
226
|
+
- If no user input after a brief pause: proceed directly to step 03
|
|
192
227
|
|
|
193
228
|
## CRITICAL STEP COMPLETION NOTE
|
|
194
229
|
|
|
@@ -204,8 +239,9 @@ ONLY WHEN the analysis is complete and the summary has been presented to the use
|
|
|
204
239
|
- Repository structure listed clearly
|
|
205
240
|
- Primary language detected with confidence level
|
|
206
241
|
- Top-level modules and exports identified
|
|
242
|
+
- Source version detected (or default noted)
|
|
207
243
|
- Analysis summary presented factually
|
|
208
|
-
- Auto-proceeded to scope definition
|
|
244
|
+
- Auto-proceeded to scope definition (with pause for corrections)
|
|
209
245
|
|
|
210
246
|
### ❌ SYSTEM FAILURE:
|
|
211
247
|
|
|
@@ -4,8 +4,8 @@ description: 'Collaboratively define skill scope boundaries using analysis findi
|
|
|
4
4
|
|
|
5
5
|
nextStepFile: './step-04-confirm-brief.md'
|
|
6
6
|
scopeTemplatesFile: '../data/scope-templates.md'
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
advancedElicitationSkill: '/bmad-advanced-elicitation'
|
|
8
|
+
partyModeSkill: '/bmad-party-mode'
|
|
9
9
|
---
|
|
10
10
|
|
|
11
11
|
# Step 3: Scope Definition
|
|
@@ -90,7 +90,21 @@ Wait for confirmation. Then skip to section 5 (Summarize Scope Decisions) with:
|
|
|
90
90
|
|
|
91
91
|
**If `source_type: "source"` (default):** Continue to scope templates below.
|
|
92
92
|
|
|
93
|
-
### 2b.
|
|
93
|
+
### 2b. Confirm Supplemental Documentation (if doc_urls collected)
|
|
94
|
+
|
|
95
|
+
**If `source_type: "source"` AND supplemental `doc_urls` were collected in step 01:**
|
|
96
|
+
|
|
97
|
+
"**Supplemental documentation URLs:**
|
|
98
|
+
{numbered list of collected doc_urls with labels}
|
|
99
|
+
|
|
100
|
+
These will be included as T3 external references in the skill brief.
|
|
101
|
+
Add, remove, or confirm these URLs."
|
|
102
|
+
|
|
103
|
+
Wait for confirmation. Record any changes to `doc_urls`.
|
|
104
|
+
|
|
105
|
+
**If no supplemental doc_urls were collected:** Skip this subsection.
|
|
106
|
+
|
|
107
|
+
### 2c. Offer Scope Templates
|
|
94
108
|
|
|
95
109
|
Load `{scopeTemplatesFile}` for the scope type options ([F], [M], [P]) and their descriptions.
|
|
96
110
|
|
|
@@ -153,8 +167,8 @@ Display: **Select an Option:** [A] Advanced Elicitation [P] Party Mode [C] Conti
|
|
|
153
167
|
|
|
154
168
|
#### Menu Handling Logic:
|
|
155
169
|
|
|
156
|
-
- IF A:
|
|
157
|
-
- IF P:
|
|
170
|
+
- IF A: Invoke {advancedElicitationSkill}, and when finished redisplay the menu
|
|
171
|
+
- IF P: Invoke {partyModeSkill}, and when finished redisplay the menu
|
|
158
172
|
- IF C: Load, read entire file, then execute {nextStepFile}
|
|
159
173
|
- IF Any other comments or queries: help user respond then [Redisplay Menu Options](#6-present-menu-options)
|
|
160
174
|
|
|
@@ -5,8 +5,8 @@ description: 'Present complete skill brief for user review and confirmation befo
|
|
|
5
5
|
nextStepFile: './step-05-write-brief.md'
|
|
6
6
|
reviseStepFile: './step-03-scope-definition.md'
|
|
7
7
|
briefSchemaFile: '../data/skill-brief-schema.md'
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
advancedElicitationSkill: '/bmad-advanced-elicitation'
|
|
9
|
+
partyModeSkill: '/bmad-party-mode'
|
|
10
10
|
---
|
|
11
11
|
|
|
12
12
|
# Step 4: Confirm Brief
|
|
@@ -78,6 +78,11 @@ Compile all gathered data from steps 01-03 into the complete brief:
|
|
|
78
78
|
- **scope.include:** {include patterns from step 03}
|
|
79
79
|
- **scope.exclude:** {exclude patterns from step 03}
|
|
80
80
|
- **scope.notes:** {any scope notes from step 03}
|
|
81
|
+
- **source_type:** {source or docs-only, from step 01}
|
|
82
|
+
- **doc_urls:** {collected documentation URLs with labels, from steps 01/03 — include if source_type is "docs-only" or supplemental URLs were collected}
|
|
83
|
+
- **scripts_intent:** {detect/none/description from step 03, or "detect" if not explicitly set}
|
|
84
|
+
- **assets_intent:** {detect/none/description from step 03, or "detect" if not explicitly set}
|
|
85
|
+
- **source_authority:** {official/community/internal from step 01 — default "community"}
|
|
81
86
|
|
|
82
87
|
### 3. Present Brief for Review
|
|
83
88
|
|
|
@@ -101,6 +106,21 @@ Scope: {scope.type}
|
|
|
101
106
|
Exclude: {scope.exclude patterns, one per line}
|
|
102
107
|
Notes: {scope.notes}
|
|
103
108
|
|
|
109
|
+
{If source_type is "docs-only":}
|
|
110
|
+
Source Type: docs-only
|
|
111
|
+
Doc URLs:
|
|
112
|
+
{doc_urls, one per line with labels}
|
|
113
|
+
|
|
114
|
+
{If source_type is "source" AND supplemental doc_urls collected:}
|
|
115
|
+
Supplemental Docs:
|
|
116
|
+
{doc_urls, one per line with labels}
|
|
117
|
+
|
|
118
|
+
{If scripts_intent or assets_intent was explicitly set (not default "detect"):}
|
|
119
|
+
Scripts: {scripts_intent}
|
|
120
|
+
Assets: {assets_intent}
|
|
121
|
+
|
|
122
|
+
Source Authority: {source_authority}
|
|
123
|
+
|
|
104
124
|
Version: {version}
|
|
105
125
|
Created: {created}
|
|
106
126
|
Created by: {created_by}
|
|
@@ -145,8 +165,8 @@ Display: **Select an Option:** [R] Revise Scope [A] Advanced Elicitation [P] Par
|
|
|
145
165
|
#### Menu Handling Logic:
|
|
146
166
|
|
|
147
167
|
- IF R: Load, read entire file, then execute {reviseStepFile} to re-enter scope definition
|
|
148
|
-
- IF A:
|
|
149
|
-
- IF P:
|
|
168
|
+
- IF A: Invoke {advancedElicitationSkill}, and when finished redisplay the menu
|
|
169
|
+
- IF P: Invoke {partyModeSkill}, and when finished redisplay the menu
|
|
150
170
|
- IF C: Load, read entire file, then execute {nextStepFile}
|
|
151
171
|
- 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)
|
|
152
172
|
|
|
@@ -87,19 +87,36 @@ scope:
|
|
|
87
87
|
exclude:
|
|
88
88
|
- "{approved exclude patterns}"
|
|
89
89
|
notes: "{approved scope notes or empty string}"
|
|
90
|
-
# Include doc_urls when source_type is "docs-only" or when supplemental doc URLs were provided
|
|
91
|
-
# doc_urls:
|
|
92
|
-
# - url: "{documentation URL}"
|
|
93
|
-
# label: "{page label}"
|
|
94
|
-
# scripts_intent: detect # Optional: detect | none | description of expected scripts
|
|
95
|
-
# assets_intent: detect # Optional: detect | none | description of expected assets
|
|
96
|
-
# source_authority: community # Optional: official | community | internal
|
|
97
90
|
---
|
|
98
91
|
```
|
|
99
92
|
|
|
100
|
-
**
|
|
93
|
+
**Conditional optional field inclusion:**
|
|
101
94
|
|
|
102
|
-
**If `
|
|
95
|
+
**If `source_type: "docs-only"` OR supplemental `doc_urls` were collected:**
|
|
96
|
+
Include the `doc_urls` array (uncommented) in the generated YAML:
|
|
97
|
+
```yaml
|
|
98
|
+
doc_urls:
|
|
99
|
+
- url: "{documentation URL}"
|
|
100
|
+
label: "{page label}"
|
|
101
|
+
```
|
|
102
|
+
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.
|
|
103
|
+
|
|
104
|
+
**If `scripts_intent` was collected and is not the default `"detect"`:**
|
|
105
|
+
Include the `scripts_intent` field (uncommented):
|
|
106
|
+
```yaml
|
|
107
|
+
scripts_intent: "{none or description}"
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
**If `assets_intent` was collected and is not the default `"detect"`:**
|
|
111
|
+
Include the `assets_intent` field (uncommented):
|
|
112
|
+
```yaml
|
|
113
|
+
assets_intent: "{none or description}"
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
**Always include** `source_authority` (default: `"community"`, forced to `"community"` when `source_type: "docs-only"`):
|
|
117
|
+
```yaml
|
|
118
|
+
source_authority: "{official|community|internal}"
|
|
119
|
+
```
|
|
103
120
|
|
|
104
121
|
### 4. Write the File
|
|
105
122
|
|
|
@@ -128,6 +145,13 @@ qmd collection add {forge_data_folder}/{skill-name} --name {skill-name}-brief --
|
|
|
128
145
|
qmd embed
|
|
129
146
|
```
|
|
130
147
|
|
|
148
|
+
**Embed verification:**
|
|
149
|
+
|
|
150
|
+
After `qmd embed` completes, verify the collection was embedded:
|
|
151
|
+
- Run `qmd status` or `qmd collection list` and confirm `{skill-name}-brief` shows document count > 0
|
|
152
|
+
- If verification succeeds: proceed to registry update normally
|
|
153
|
+
- 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
|
|
154
|
+
|
|
131
155
|
**Registry update:**
|
|
132
156
|
|
|
133
157
|
Read `{sidecar_path}/forge-tier.yaml` and update the `qmd_collections` array.
|
|
@@ -140,6 +164,7 @@ If an entry with `name: "{skill-name}-brief"` already exists, replace it. Otherw
|
|
|
140
164
|
source_workflow: "brief-skill"
|
|
141
165
|
skill_name: "{skill-name}"
|
|
142
166
|
created_at: "{current ISO date}"
|
|
167
|
+
# status: "pending" # Added only when embed verification fails
|
|
143
168
|
```
|
|
144
169
|
|
|
145
170
|
Write the updated forge-tier.yaml.
|
|
@@ -51,7 +51,7 @@ installed_path: '{project-root}/_bmad/skf/workflows/skillforge/brief-skill'
|
|
|
51
51
|
|
|
52
52
|
Load and read full config from {project-root}/_bmad/skf/config.yaml and resolve:
|
|
53
53
|
|
|
54
|
-
- `project_name`, `output_folder`, `user_name`, `communication_language`, `
|
|
54
|
+
- `project_name`, `output_folder`, `user_name`, `communication_language`, `forge_data_folder`, `sidecar_path`
|
|
55
55
|
|
|
56
56
|
### 2. First Step Execution
|
|
57
57
|
|
|
@@ -116,6 +116,7 @@ Do NOT repeat Tier 1's name/purpose/key-params table format in Tier 2. Tier 2 is
|
|
|
116
116
|
4. If Tier 1 alone exceeds 300 lines, reduce Key API Summary and Architecture at a Glance
|
|
117
117
|
5. Tier 1 sections are kept short enough that `split-body` targets the larger Tier 2 sections (`## Full ...` headings) instead
|
|
118
118
|
6. After split-body, SKILL.md must still contain all Tier 1 sections with actionable content
|
|
119
|
+
7. **Signature fidelity:** When populating function entries from the extraction inventory, always use the `params` and `return_type` fields from the provenance-map entry (T1/AST-backed). Do not substitute parameter names, types, or return types from documentation, README examples, or enrichment annotations. T2/T3 sources may enrich descriptions and add usage notes, but structural signature data from AST extraction is authoritative.
|
|
119
120
|
|
|
120
121
|
### Reference File Rules
|
|
121
122
|
|
|
@@ -51,7 +51,7 @@ Structural extraction via ast-grep — verified exports with line-level citation
|
|
|
51
51
|
- Internal/private functions: excluded (not part of public API)
|
|
52
52
|
|
|
53
53
|
### ast-grep Patterns
|
|
54
|
-
- JS/TS: `export function $NAME($$$PARAMS): $RET` / `export const $NAME`
|
|
54
|
+
- JS/TS: `export function $NAME($$$PARAMS): $RET` / `export const $NAME = ($$$PARAMS) => $BODY` / `export const $NAME` / `export class $NAME`
|
|
55
55
|
- Rust: `pub fn $NAME($$$PARAMS) -> $RET`
|
|
56
56
|
- Python: function definitions within `__all__` list
|
|
57
57
|
- Go: capitalized function definitions
|
|
@@ -168,12 +168,19 @@ find_code_by_rule(
|
|
|
168
168
|
|
|
169
169
|
When MCP tools are unavailable or the repo exceeds 500 files in scope, use `--json=stream` (NEVER `--json` or `--json=pretty`) with line-by-line Python processing:
|
|
170
170
|
|
|
171
|
+
**Head cap selection:** The `| head -N` cap at the end of the pipeline controls how many exports are captured. Select `N` based on scope and tier:
|
|
172
|
+
- **Default (Quick/Forge, any scope):** `N = 200`
|
|
173
|
+
- **Forge+/Deep with `scope.type: "full-library"`:** `N = 500`
|
|
174
|
+
|
|
175
|
+
For full-library skills at higher tiers, the larger cap prevents silently dropping internal module exports that maintainers need. The cap is applied AFTER exclude-pattern filtering, so useful results are not wasted on excluded files.
|
|
176
|
+
|
|
171
177
|
```bash
|
|
172
178
|
# Note: use $$$ for variadic params in ast-grep patterns (e.g., 'def $NAME($$$PARAMS)')
|
|
173
179
|
# {exclude_patterns} = Python list from brief's scope.exclude, e.g. ['tests/**', '**/test_*']
|
|
174
180
|
# If scope.exclude is absent or empty in the brief, inject [] as the default.
|
|
175
181
|
# Patterns are matched against the full file path as emitted by ast-grep.
|
|
176
182
|
# Ensure paths are relative to the same root as the patterns (strip ./ prefix if needed).
|
|
183
|
+
# {HEAD_CAP} = 200 (default) or 500 (Forge+/Deep full-library) — see head cap selection above.
|
|
177
184
|
ast-grep -p '{pattern}' -l {language} --json=stream {path} | python3 -c "
|
|
178
185
|
import sys, json, fnmatch, signal
|
|
179
186
|
signal.signal(signal.SIGPIPE, signal.SIG_DFL)
|
|
@@ -193,7 +200,7 @@ for line in sys.stdin:
|
|
|
193
200
|
sig = m.get('text','').split(chr(10))[0].strip()
|
|
194
201
|
print(f'[AST:{f}:L{ln}] {sig}')
|
|
195
202
|
except: pass
|
|
196
|
-
" | head -
|
|
203
|
+
" | head -{HEAD_CAP}
|
|
197
204
|
```
|
|
198
205
|
|
|
199
206
|
**Critical constraints:**
|
|
@@ -201,7 +208,7 @@ for line in sys.stdin:
|
|
|
201
208
|
- ALWAYS use `--json=stream` — never `--json` (loads entire array into memory)
|
|
202
209
|
- ALWAYS process line-by-line (`for line in sys.stdin`) — never `json.load(sys.stdin)`
|
|
203
210
|
- ALWAYS cap output with `| head -N` as a safety valve
|
|
204
|
-
- For repos > 500 files, process in directory batches of 20-50 files each
|
|
211
|
+
- For repos > 500 files, process in directory batches of 20-50 files each: split by top-level source directory, run the CLI streaming template per batch with the same head cap, then merge results and deduplicate by export name (keep the first occurrence if duplicates exist across batches)
|
|
205
212
|
|
|
206
213
|
### YAML Rule Recipes by Language
|
|
207
214
|
|
|
@@ -253,6 +260,32 @@ rule:
|
|
|
253
260
|
pattern: 'export const $NAME = $VALUE'
|
|
254
261
|
```
|
|
255
262
|
|
|
263
|
+
**JavaScript/TypeScript — exported arrow functions:**
|
|
264
|
+
|
|
265
|
+
```yaml
|
|
266
|
+
id: js-exported-arrow-functions
|
|
267
|
+
language: typescript
|
|
268
|
+
rule:
|
|
269
|
+
pattern: 'export const $NAME = ($$$PARAMS) => $BODY'
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
> **JS/TS Pattern Merging:** Modern TypeScript codebases often use `export const` exclusively for all exports (arrow functions, objects, constants). Run ALL four JS/TS patterns (functions, arrow functions, constants, classes) and merge results by `$NAME`. Priority when deduplicating: arrow function match > function declaration match > constant match. Arrow function matches capture parameters directly; constant matches require inspecting `$VALUE` to extract signatures.
|
|
273
|
+
|
|
274
|
+
**JavaScript/TypeScript — exported classes (use `find_code`, not `find_code_by_rule`):**
|
|
275
|
+
|
|
276
|
+
```yaml
|
|
277
|
+
id: js-exported-classes
|
|
278
|
+
language: typescript
|
|
279
|
+
rule:
|
|
280
|
+
pattern: 'export class $NAME'
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
> **Important:** For class patterns, use `find_code()` rather than `find_code_by_rule()`. The `find_code_by_rule` API requires explicit AST `kind` rules for class exports, which adds complexity. The simpler `find_code()` pattern approach works reliably for class detection.
|
|
284
|
+
|
|
285
|
+
**JavaScript/TypeScript — re-export detection (use `find_code`):**
|
|
286
|
+
|
|
287
|
+
Use `find_code()` with pattern `export { $$$NAMES } from $SOURCE` for re-export detection. Note: this pattern may produce multiple AST node matches. Post-process results to split comma-separated names from `$$$NAMES`. For complex re-export chains (aliased exports, default re-exports, namespace re-exports), fall back to the Re-Export Tracing protocol in `extraction-patterns-tracing.md`.
|
|
288
|
+
|
|
256
289
|
**Rust — public functions:**
|
|
257
290
|
|
|
258
291
|
```yaml
|
|
@@ -270,12 +303,29 @@ rule:
|
|
|
270
303
|
id: go-exported-functions
|
|
271
304
|
language: go
|
|
272
305
|
rule:
|
|
273
|
-
|
|
306
|
+
any:
|
|
307
|
+
- pattern: 'func $NAME($$$PARAMS) $RET'
|
|
308
|
+
- pattern: 'func $NAME($$$PARAMS)'
|
|
274
309
|
constraints:
|
|
275
310
|
NAME:
|
|
276
311
|
regex: '^[A-Z]'
|
|
277
312
|
```
|
|
278
313
|
|
|
314
|
+
### Known ast-grep Limitations
|
|
315
|
+
|
|
316
|
+
When using ast-grep for extraction, be aware of these documented limitations:
|
|
317
|
+
|
|
318
|
+
1. **`find_code_by_rule` requires explicit `kind` for class exports:** The `export class $NAME` pattern needs a `kind` rule specifying the tree-sitter node type when used with `find_code_by_rule`. Use the simpler `find_code()` API instead for class detection.
|
|
319
|
+
|
|
320
|
+
2. **Re-export patterns produce multiple AST nodes:** `export { A, B, C } from './module'` decomposes into multiple metavariable bindings for `$$$NAMES`. Results require post-processing to split comma-separated names.
|
|
321
|
+
|
|
322
|
+
3. **Default anonymous exports capture no name:** `export default function $NAME` works, but `export default $EXPR` (anonymous default export) captures no name in `$NAME`. Fall back to source reading (T1-low) for anonymous defaults.
|
|
323
|
+
|
|
324
|
+
4. **Fallback protocol:** If an ast-grep pattern returns errors or zero results when results are expected:
|
|
325
|
+
- First: retry with `find_code()` using a simpler pattern (drop type annotations, use broader match)
|
|
326
|
+
- Second: if `find_code()` also fails, fall back to source reading for that pattern category (T1-low confidence)
|
|
327
|
+
- Never silently accept zero results for a pattern category that the source language commonly uses
|
|
328
|
+
|
|
279
329
|
### Re-Export Tracing and Script/Asset Extraction
|
|
280
330
|
|
|
281
331
|
See `extraction-patterns-tracing.md` for:
|
|
@@ -199,7 +199,8 @@ Each reference file includes:
|
|
|
199
199
|
"source_line": 42,
|
|
200
200
|
"confidence": "T1",
|
|
201
201
|
"extraction_method": "ast-grep",
|
|
202
|
-
"ast_node_type": "export_function_declaration"
|
|
202
|
+
"ast_node_type": "export_function_declaration",
|
|
203
|
+
"signature_source": "T1"
|
|
203
204
|
}
|
|
204
205
|
],
|
|
205
206
|
"file_entries": [
|
|
@@ -102,7 +102,7 @@ If `source_repo` is a remote URL (GitHub URL or owner/repo format) AND tier is F
|
|
|
102
102
|
|
|
103
103
|
After checkout, apply the original glob `include_patterns` as file-level filters when building the extraction file list — sparse-checkout gets the right directories, glob filtering narrows to the exact files. When `--no-cone` mode was used, most exclude filtering is already done at the git level, but apply `exclude_patterns` as a final pass to catch any edge cases where gitignore pattern matching diverges from the brief's glob semantics. Always-included root files (see above) are exempt from post-checkout filtering.
|
|
104
104
|
|
|
105
|
-
3. **If clone succeeds:** Update the working source path to `{temp_path}` for all subsequent AST operations in this step. Proceed with the **Forge/Deep Tier** extraction strategy below. Mark `ephemeral_clone_active = true` for cleanup.
|
|
105
|
+
3. **If clone succeeds:** Update the working source path to `{temp_path}` for all subsequent AST operations in this step. Capture the source commit: `git -C {temp_path} rev-parse HEAD` — store as `source_commit` in context. Proceed with the **Forge/Deep Tier** extraction strategy below. Mark `ephemeral_clone_active = true` for cleanup.
|
|
106
106
|
|
|
107
107
|
4. **If clone fails (network error, auth failure, timeout):**
|
|
108
108
|
|
|
@@ -116,6 +116,20 @@ If `source_repo` is a remote URL (GitHub URL or owner/repo format) AND tier is F
|
|
|
116
116
|
|
|
117
117
|
---
|
|
118
118
|
|
|
119
|
+
## Source Commit Capture (all tiers, source mode only)
|
|
120
|
+
|
|
121
|
+
**If `source_type: "docs-only"`:** skip — set `source_commit: null`.
|
|
122
|
+
|
|
123
|
+
After the source path is accessible, capture the current commit hash for provenance tracking:
|
|
124
|
+
|
|
125
|
+
- **Local path:** `git -C {source_root} rev-parse HEAD` — if the path is a git repo
|
|
126
|
+
- **Ephemeral clone (Forge/Deep):** already captured during clone (step 3 above)
|
|
127
|
+
- **Quick tier (remote, no clone):** `gh api repos/{owner}/{repo}/commits/{branch} --jq '.sha'`
|
|
128
|
+
|
|
129
|
+
Store the result as `source_commit` in context. If capture fails (not a git repo, API unavailable), set `source_commit: null` — this is not an error.
|
|
130
|
+
|
|
131
|
+
---
|
|
132
|
+
|
|
119
133
|
## Version Reconciliation (all tiers, source mode only)
|
|
120
134
|
|
|
121
135
|
**If `source_type: "docs-only"`:** skip this section — no source files exist to reconcile.
|
|
@@ -111,16 +111,16 @@ Halt with specific error: "Brief validation failed: missing required field `{fie
|
|
|
111
111
|
|
|
112
112
|
### 4. Resolve Source Code Location
|
|
113
113
|
|
|
114
|
-
**If `source_type: "docs-only"`:** Skip source resolution. Set `
|
|
114
|
+
**If `source_type: "docs-only"`:** Skip source resolution. Set `source_root: null` in context. Proceed directly to section 5 (Report Initialization) — docs-only skills have no source to resolve.
|
|
115
115
|
|
|
116
116
|
**If source_repo is a GitHub URL or owner/repo format:**
|
|
117
117
|
- Verify repository exists via `gh_bridge.list_tree(owner, repo, branch)` — **Tool resolution:** `gh api repos/{owner}/{repo}/git/trees/{branch}?recursive=1` or direct file listing if local; see [knowledge/tool-resolution.md](../../../knowledge/tool-resolution.md)
|
|
118
118
|
- If branch not specified, detect default branch
|
|
119
|
-
- Store resolved: owner, repo, branch, file tree
|
|
119
|
+
- Store resolved: owner, repo, branch, file tree — note: `source_root` for remote repos is set to the ephemeral clone path during extraction (step-03)
|
|
120
120
|
|
|
121
121
|
**If source_repo is a local path:**
|
|
122
122
|
- Verify path exists and contains source files
|
|
123
|
-
- Store resolved: local path
|
|
123
|
+
- Store resolved: local path as `source_root`, file listing
|
|
124
124
|
|
|
125
125
|
**If source cannot be resolved:**
|
|
126
126
|
Halt with: "Source not found: `{source_repo}`. Verify the repository exists and is accessible."
|
|
@@ -170,7 +170,7 @@ ONLY WHEN forge-tier.yaml is loaded, skill-brief.yaml is validated, and source c
|
|
|
170
170
|
|
|
171
171
|
- Forge tier loaded from sidecar with tool availability
|
|
172
172
|
- Skill brief loaded and all required fields validated
|
|
173
|
-
- Source code location resolved and accessible (or `
|
|
173
|
+
- Source code location resolved and accessible (or `source_root: null` confirmed for docs-only skills)
|
|
174
174
|
- Initialization summary displayed with tier and capabilities
|
|
175
175
|
- Auto-proceeded to step-02
|
|
176
176
|
|
|
@@ -47,7 +47,7 @@ For Quick and Forge tiers, or when ccc is unavailable, skip silently and proceed
|
|
|
47
47
|
|
|
48
48
|
- Available: tier, tools.ccc, ccc_index from forge-tier.yaml (loaded in step-01)
|
|
49
49
|
- Available: brief_data (name, scope, description) from step-01
|
|
50
|
-
- Available: source_root (resolved source path) from step-01
|
|
50
|
+
- Available: source_root (resolved source path) from step-01 — note: for remote sources, `source_root` may not be a local path until step-03 performs the ephemeral clone
|
|
51
51
|
- Focus: Semantic discovery only — no extraction, no compilation
|
|
52
52
|
- Dependencies: step-02 must have completed
|
|
53
53
|
|
|
@@ -67,11 +67,13 @@ Check `tools.ccc` from forge-tier.yaml. If `tools.ccc` is false, set `{ccc_disco
|
|
|
67
67
|
|
|
68
68
|
If `tools.ccc` is true, continue to section 2.
|
|
69
69
|
|
|
70
|
+
**Remote source guard:** If `source_root` is a remote URL (GitHub repository not yet cloned locally — ephemeral clone happens in step-03), CCC cannot operate. Set `{ccc_discovery: []}` and display: "CCC discovery skipped — remote source not yet available locally. CCC requires a local source index." Auto-proceed to the step completion / next step section.
|
|
71
|
+
|
|
70
72
|
### 2. Check CCC Index State
|
|
71
73
|
|
|
72
74
|
Read `ccc_index` from forge-tier.yaml:
|
|
73
75
|
|
|
74
|
-
- If `ccc_index.status` is `"fresh"`: continue to section 3.
|
|
76
|
+
- If `ccc_index.status` is `"fresh"` or `"created"`: continue to section 3.
|
|
75
77
|
- If `ccc_index.status` is `"stale"`: display brief note — "CCC index is stale — discovery results may miss recent changes." Continue to section 3.
|
|
76
78
|
- If `ccc_index.status` is `"none"` or `"failed"`: attempt lazy indexing via `ccc_bridge.ensure_index(source_root)`. If indexing succeeds, continue to section 3. If indexing fails, set `{ccc_discovery: []}` and auto-proceed to section 5.
|
|
77
79
|
|
|
@@ -46,7 +46,7 @@ To extract all public exports, function signatures, type definitions, and co-imp
|
|
|
46
46
|
|
|
47
47
|
## CONTEXT BOUNDARIES:
|
|
48
48
|
|
|
49
|
-
- Available: brief_data, tier,
|
|
49
|
+
- Available: brief_data, tier, source_root, file_tree from step-01; ecosystem check outcome from step-02 (proceed/halt decision — no named variable stored)
|
|
50
50
|
- Focus: Source code extraction and inventory building
|
|
51
51
|
- Limits: Do NOT compile, assemble, or write any output
|
|
52
52
|
- Dependencies: Source code must be accessible (resolved in step-01)
|
|
@@ -57,11 +57,26 @@ To fetch temporal context (issues, PRs, changelogs, release notes) from the sour
|
|
|
57
57
|
Evaluate the following conditions sequentially. **If ANY condition fails, skip silently to section 5 (auto-proceed) with no output:**
|
|
58
58
|
|
|
59
59
|
1. **Tier is Deep:** If tier is Quick, Forge, or Forge+, skip silently.
|
|
60
|
-
2. **Source is GitHub:** Verify `source_repo` is a GitHub URL (`https://github.com/...`) or `owner/repo` format. If the source is a local path, a non-GitHub URL, or any other format,
|
|
60
|
+
2. **Source is GitHub:** Verify `source_repo` is a GitHub URL (`https://github.com/...`) or `owner/repo` format. If the source is a local path, a non-GitHub URL, or any other format, attempt GitHub remote detection (section 1b) before skipping.
|
|
61
61
|
3. **`gh` CLI is available:** Run `gh auth status` to verify the CLI is installed and authenticated. If it fails, skip silently.
|
|
62
62
|
|
|
63
63
|
All three conditions must pass to proceed to section 2.
|
|
64
64
|
|
|
65
|
+
### 1b. GitHub Remote Detection for Local Sources
|
|
66
|
+
|
|
67
|
+
**Only runs when condition 2 above fails because `source_repo` is a local path.**
|
|
68
|
+
|
|
69
|
+
Local repositories that are clones of GitHub repos contain temporal context (issues, PRs, releases) accessible via `gh`. Detect this automatically:
|
|
70
|
+
|
|
71
|
+
1. Check if the local path is a git repository: `git -C {source_repo} rev-parse --is-inside-work-tree`
|
|
72
|
+
2. If not a git repo: skip silently to section 5 (current behavior).
|
|
73
|
+
3. Extract the origin remote: `git -C {source_repo} remote get-url origin`
|
|
74
|
+
4. If the remote URL contains `github.com`:
|
|
75
|
+
- Extract `owner/repo` from the remote URL (strip `.git` suffix, handle both HTTPS and SSH formats)
|
|
76
|
+
- Log: "**Local source with GitHub remote detected:** {owner}/{repo} — fetching temporal context."
|
|
77
|
+
- Use the extracted `owner/repo` for all `gh` API calls in sections 3-4. Continue to condition 3 (gh CLI check).
|
|
78
|
+
5. If no remote, or remote is not GitHub: skip silently to section 5 (current behavior).
|
|
79
|
+
|
|
65
80
|
### 2. Check Cache (Skip If Fresh)
|
|
66
81
|
|
|
67
82
|
Read `forge-tier.yaml` from the sidecar path.
|
|
@@ -157,7 +172,7 @@ If a `{skill-name}-temporal` collection already exists, remove and recreate for
|
|
|
157
172
|
|
|
158
173
|
```bash
|
|
159
174
|
qmd collection remove {skill-name}-temporal
|
|
160
|
-
qmd collection add _bmad-output/{skill-name}-temporal/ --name {skill-name}-temporal --mask "*.md"
|
|
175
|
+
qmd collection add {project-root}/_bmad-output/{skill-name}-temporal/ --name {skill-name}-temporal --mask "*.md"
|
|
161
176
|
qmd embed
|
|
162
177
|
```
|
|
163
178
|
|
|
@@ -178,7 +193,7 @@ If an entry with `name: "{skill-name}-temporal"` already exists in `qmd_collecti
|
|
|
178
193
|
**Clean up** the staging directory after successful indexing:
|
|
179
194
|
|
|
180
195
|
```bash
|
|
181
|
-
rm -rf _bmad-output/{skill-name}-temporal/
|
|
196
|
+
rm -rf {project-root}/_bmad-output/{skill-name}-temporal/
|
|
182
197
|
```
|
|
183
198
|
|
|
184
199
|
**Error handling:**
|
|
@@ -85,14 +85,20 @@ Content fetched from external URLs is classified as **T3** (external, untrusted)
|
|
|
85
85
|
|
|
86
86
|
After fetching a URL, apply the following heuristic to detect documentation root pages that contain no useful API content. This is common with modern documentation sites (Mintlify, Docusaurus, ReadTheDocs, GitBook) that render API content on subpages.
|
|
87
87
|
|
|
88
|
-
**Root page detection
|
|
88
|
+
**Root page detection — apply only when the URL path ends in `/`, `/index`, `/index.html`, has no path component (bare domain), or has 1 path segment (e.g., `/docs`). For deeper URL paths (2+ segments like `/api/reference`), skip this heuristic and keep the content as-is.**
|
|
89
89
|
|
|
90
|
-
|
|
90
|
+
Subpage discovery is triggered if **either** of the following independent triggers fires:
|
|
91
|
+
|
|
92
|
+
**Trigger 1 — Content-based (both conditions must be true):**
|
|
91
93
|
|
|
92
94
|
1. **Zero API content indicators:** The fetched markdown contains none of: fenced code blocks (`` ``` ``), parameter tables (`|---|`), or function signature patterns (`def `, `function `, `fn `, `func `, `export `).
|
|
93
95
|
2. **High link density:** More than 70% of non-empty lines are markdown links (matching `[text](url)` with no other substantive content on the line).
|
|
94
96
|
|
|
95
|
-
|
|
97
|
+
**Trigger 2 — URL-based (independent of content analysis):**
|
|
98
|
+
|
|
99
|
+
The URL matches the path criteria above (ends in `/`, bare domain, or 1 segment) AND the fetched content is under **2000 words**. Short content on root-like URLs almost certainly indicates a navigation hub or landing page, even if it contains introductory code examples that would prevent Trigger 1 from firing. This handles modern doc sites (Mintlify, Docusaurus, GitBook) that include hero sections with code snippets on their root pages.
|
|
100
|
+
|
|
101
|
+
If neither trigger fires, keep the page content as-is and do NOT trigger subpage discovery.
|
|
96
102
|
|
|
97
103
|
**If a root URL with minimal content is detected:**
|
|
98
104
|
|
|
@@ -147,7 +153,7 @@ Parse the successfully fetched markdown for:
|
|
|
147
153
|
**If tier is Deep and at least one URL was fetched successfully:**
|
|
148
154
|
|
|
149
155
|
1. Write fetched markdown files to a staging directory: `_bmad-output/{skill-name}-docs/`
|
|
150
|
-
2. Index into QMD: `qmd collection add _bmad-output/{skill-name}-docs/ --name {skill-name}-docs --mask "*.md"`
|
|
156
|
+
2. Index into QMD: `qmd collection add {project-root}/_bmad-output/{skill-name}-docs/ --name {skill-name}-docs --mask "*.md"`
|
|
151
157
|
3. Generate embeddings: `qmd embed` (required for `vector_search` and `deep_search`)
|
|
152
158
|
4. Register in forge-tier.yaml `qmd_collections` array:
|
|
153
159
|
|
|
@@ -159,7 +165,7 @@ Parse the successfully fetched markdown for:
|
|
|
159
165
|
created_at: "{current ISO date}"
|
|
160
166
|
```
|
|
161
167
|
|
|
162
|
-
5. Clean up staging directory after indexing: `rm -rf _bmad-output/{skill-name}-docs/`
|
|
168
|
+
5. Clean up staging directory after indexing: `rm -rf {project-root}/_bmad-output/{skill-name}-docs/`
|
|
163
169
|
|
|
164
170
|
**If QMD indexing fails:** Warn: "QMD indexing of fetched docs failed. T3 items are still in the extraction inventory — enrichment will proceed without QMD-indexed docs." Continue.
|
|
165
171
|
|
|
@@ -59,6 +59,17 @@ To assemble the complete skill content from the extraction inventory and enrichm
|
|
|
59
59
|
|
|
60
60
|
Load `{skillSectionsData}` and `{assemblyRulesData}` completely. These define the agentskills.io-compliant format and detailed assembly rules for all output artifacts.
|
|
61
61
|
|
|
62
|
+
### 1b. Signature Fidelity Rule
|
|
63
|
+
|
|
64
|
+
**When assembling function signatures, parameter lists, and return types in any SKILL.md section or reference file:**
|
|
65
|
+
|
|
66
|
+
- **T1 provenance-map entries (AST-extracted) are authoritative** for: function name, parameter names, parameter types, parameter order, return type, and optionality markers (e.g., `?`, `Optional`, `= default`).
|
|
67
|
+
- **T2 (QMD-enriched) and T3 (doc-derived) sources may ADD** contextual descriptions, usage notes, behavioral documentation, and examples to function entries, but **MUST NOT REPLACE** structural signature data from T1 entries.
|
|
68
|
+
- **On conflict:** If a T2/T3 source provides a different signature than the T1 extraction for the same export (e.g., different parameter count, different types, missing `Partial<>` wrapper), keep the T1 signature and log a warning in the evidence report: "Signature conflict for `{export_name}`: T1 shows `{t1_signature}`, T2/T3 shows `{other_signature}`. T1 used as authoritative."
|
|
69
|
+
- **`signature_source` field:** Record `signature_source: "T1" | "T1-low" | "T2" | "T3"` in each provenance-map entry to indicate the highest-confidence tier that contributed the structural signature data (params, return_type). This enables test-skill to verify signature provenance.
|
|
70
|
+
|
|
71
|
+
This rule applies to ALL sections including Tier 1 Key API Summary, Tier 2 Full API Reference, and Section 4b Migration & Deprecation Warnings.
|
|
72
|
+
|
|
62
73
|
### 2. Build SKILL.md Content
|
|
63
74
|
|
|
64
75
|
Assemble each section in order using the assembly rules data file (`{assemblyRulesData}`). The data file specifies frontmatter format, Tier 1 section details (Sections 1-8, including conditional Section 7b for scripts/assets), Tier 2 section details (Sections 9-11), and assembly ordering rules. Follow it exactly. Assemble Section 7b (Scripts & Assets) only if `scripts_inventory` or `assets_inventory` is non-empty.
|
|
@@ -92,7 +103,7 @@ Following the structure from the skill-sections data file:
|
|
|
92
103
|
- Set `source_commit` from resolved source (if available)
|
|
93
104
|
- Set `stats` from extraction aggregate counts:
|
|
94
105
|
- `exports_documented`: count of exports with documentation in the assembled SKILL.md
|
|
95
|
-
- `exports_public_api`: count of exports from public entry points (`__init__.py`, `index.ts`, `lib.rs`, or equivalent)
|
|
106
|
+
- `exports_public_api`: count of exports from public entry points (`__init__.py`, `index.ts`, `lib.rs`, or equivalent) — derive this from step-03's entry-point validation (section 4b), NOT from the provenance-map entry count (which may be incomplete if extraction patterns missed some export types)
|
|
96
107
|
- `exports_internal`: count of all other non-underscore-prefixed exports (internal modules, helpers, adapters)
|
|
97
108
|
- `exports_total`: `exports_public_api` + `exports_internal`
|
|
98
109
|
- `public_api_coverage`: `exports_documented / exports_public_api` (1.0 when all public API exports are documented; `null` if `exports_public_api` is 0)
|
|
@@ -100,7 +111,12 @@ Following the structure from the skill-sections data file:
|
|
|
100
111
|
- Set `description` from the SKILL.md frontmatter `description` field (already assembled in section 2)
|
|
101
112
|
- Set `language` from source analysis (e.g., `"typescript"`, `"python"`) — use the primary language of the entry point file
|
|
102
113
|
- Set `ast_node_count` from extraction stats if ast-grep was used (Forge/Deep tier), otherwise omit
|
|
103
|
-
- Set `tool_versions` based on tier and available tools. Resolve `{skf_version}`
|
|
114
|
+
- Set `tool_versions` based on tier and available tools. Resolve `{skf_version}` using this resolution chain (try each in order, use the first that succeeds):
|
|
115
|
+
1. `{project-root}/_bmad/skf/package.json` → read `.version` field
|
|
116
|
+
2. `node -p "require('./node_modules/bmad-module-skill-forge/package.json').version"`
|
|
117
|
+
3. `{project-root}/_bmad/skf/VERSION` → read plain text file (single line containing version string, written by the SKF installer)
|
|
118
|
+
4. `"unknown"` (final fallback — add a warning to the evidence report)
|
|
119
|
+
Never hardcode the version.
|
|
104
120
|
- Store `commit_short` = first 8 characters of `source_commit` (or `"unknown"` if unavailable) for use in step-08 report.
|
|
105
121
|
- If `scripts_inventory` is non-empty, populate `scripts[]` array and set `stats.scripts_count`. If `assets_inventory` is non-empty, populate `assets[]` array and set `stats.assets_count`. Omit these fields entirely when inventories are empty.
|
|
106
122
|
|
|
@@ -116,7 +132,7 @@ Group functions logically by module, file, or functional area.
|
|
|
116
132
|
|
|
117
133
|
### 6. Build provenance-map.json Content
|
|
118
134
|
|
|
119
|
-
One entry per extracted export: export_name, export_type, params[] (typed strings), return_type, source_file, source_line, confidence tier (T1/T1-low/T2), extraction_method, ast_node_type. If `scripts_inventory` or `assets_inventory` is non-empty, add `file_entries[]` with file_name, file_type, source_file, content_hash, confidence, extraction_method. See `{skillSectionsData}` for full schema.
|
|
135
|
+
One entry per extracted export: export_name, export_type, params[] (typed strings), return_type, source_file, source_line, confidence tier (T1/T1-low/T2), extraction_method, ast_node_type, signature_source ("T1"|"T1-low"|"T2"|"T3" — indicates which tier contributed the structural signature). If `scripts_inventory` or `assets_inventory` is non-empty, add `file_entries[]` with file_name, file_type, source_file, content_hash, confidence, extraction_method. See `{skillSectionsData}` for full schema.
|
|
120
136
|
|
|
121
137
|
### 7. Build evidence-report.md Content
|
|
122
138
|
|
|
@@ -76,6 +76,8 @@ This performs frontmatter validation, description quality checks, body limit enf
|
|
|
76
76
|
|
|
77
77
|
**Context sync after --fix:** If `fixed[]` is non-empty (i.e., `--fix` modified files on disk), re-read the modified SKILL.md to update the in-context copy. Verify the re-read content matches expectations before proceeding. This prevents silent divergence between the in-context SKILL.md and the on-disk version that step-07 will use for artifact generation.
|
|
78
78
|
|
|
79
|
+
**Description preservation after --fix:** After re-reading the modified SKILL.md, compare the frontmatter `description` field against the original step-05 compiled description. If `--fix` replaced the description with a generic or truncated version, restore the original description to the on-disk file and update the in-context copy. The step-05 compiled description is authoritative — auto-fix tools must not replace trigger-optimized descriptions.
|
|
80
|
+
|
|
79
81
|
**Note:** `skill-check` may return non-zero exit code even when `errorCount` is 0. Always rely on parsed JSON, not the shell exit code.
|
|
80
82
|
|
|
81
83
|
- **Score ≥ 70:** Record "Schema: PASS (score: {score}/100)" in evidence-report
|
|
@@ -101,15 +103,17 @@ If fails: auto-fix (deterministic), re-validate once, record result. If passes:
|
|
|
101
103
|
|
|
102
104
|
**If step 2 reported `body.max_lines` failure:**
|
|
103
105
|
|
|
104
|
-
**
|
|
106
|
+
**Description preservation:** Before any split operation, capture the current SKILL.md frontmatter `description` field. After the split completes, verify the `description` was not modified. If it was replaced with a generic placeholder, restore the original immediately.
|
|
105
107
|
|
|
106
|
-
**
|
|
108
|
+
**Mandatory approach — selective split:** Identify Tier 2 sections by their `## Full` heading prefix (e.g., `## Full API Reference`, `## Full Type Definitions`, `## Full Integration Patterns`). Extract ONLY those sections to `references/`, starting with the largest. Keep ALL Tier 1 content and any smaller sections inline. Inline passive context achieves 100% task accuracy vs 79% for on-demand retrieval (per Vercel research).
|
|
107
109
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
110
|
+
**FORBIDDEN:** Running `npx skill-check split-body --write` without prior selective extraction. The `split-body --write` command extracts ALL `##` sections top-to-bottom, destroying Tier 1 inline content that the two-tier design depends on. This command is a LAST RESORT only after selective split has been attempted and proven insufficient.
|
|
111
|
+
|
|
112
|
+
**If selective split alone does not bring body under the limit** (rare — typically only occurs when Tier 1 itself exceeds 300 lines): reduce Tier 1 Key API Summary and Architecture at a Glance sections to fit within limits. Do NOT fall back to automated `split-body --write` to solve a Tier 1 sizing problem.
|
|
113
|
+
|
|
114
|
+
**Tier 1 preservation check:** After ANY split operation, verify that ALL of the following sections remain inline in SKILL.md (not moved to references/): Overview, Quick Start, Common Workflows, Key API Summary, Migration & Deprecation Warnings (if present), Key Types, Architecture at a Glance, CLI (if present), Scripts & Assets (if present), Manual Sections. If any Tier 1 section was moved to references/, restore it immediately and re-split targeting only Tier 2 sections.
|
|
111
115
|
|
|
112
|
-
After any split
|
|
116
|
+
**Anchor validation and remediation:** After any split, verify that context-snippet section anchors (`#quick-start`, `#key-types`) still resolve to headings in SKILL.md. If an anchor no longer resolves (section was split out), restore that section to SKILL.md inline content — the context-snippet must always reference sections that exist in the main file.
|
|
113
117
|
|
|
114
118
|
Then re-validate: `npx skill-check check <staging-skill-dir> --format json --no-security-scan`
|
|
115
119
|
|
|
@@ -43,7 +43,7 @@ To write all compiled content to disk — 4 deliverable files to `{skills_output
|
|
|
43
43
|
|
|
44
44
|
## CONTEXT BOUNDARIES:
|
|
45
45
|
|
|
46
|
-
- Available: All compiled content from step-05, validation results from step-06
|
|
46
|
+
- Available: All compiled content from step-05, validation results from step-06, source_root from step-01 (needed for section 5b CCC registration)
|
|
47
47
|
- Focus: File system operations — create directories, write files
|
|
48
48
|
- Limits: Do NOT modify content during writing
|
|
49
49
|
- Dependencies: All content must be compiled and validated in context
|
|
@@ -145,7 +145,7 @@ Generate metadata.json following the exact structure defined in {skillTemplateDa
|
|
|
145
145
|
"tool_versions": {
|
|
146
146
|
"ast_grep": null,
|
|
147
147
|
"qmd": null,
|
|
148
|
-
"skf": "{skf_version}"
|
|
148
|
+
"skf": "{skf_version}" // Resolution chain: _bmad/skf/package.json → npm require → _bmad/skf/VERSION → "unknown"
|
|
149
149
|
},
|
|
150
150
|
"stats": {
|
|
151
151
|
"exports_documented": "{number of exports found}",
|
|
@@ -17,6 +17,21 @@
|
|
|
17
17
|
**Structural Issues:** {count}
|
|
18
18
|
```
|
|
19
19
|
|
|
20
|
+
## Coherence Analysis — Naive Mode: Reference Consistency (split-body)
|
|
21
|
+
|
|
22
|
+
Only rendered when `references/` directory exists alongside SKILL.md.
|
|
23
|
+
|
|
24
|
+
```markdown
|
|
25
|
+
### Reference Consistency (split-body)
|
|
26
|
+
|
|
27
|
+
| # | Reference File | Export | Issue | SKILL.md Line | Reference Line |
|
|
28
|
+
|---|---------------|--------|-------|---------------|---------------|
|
|
29
|
+
| {per-mismatch rows} |
|
|
30
|
+
|
|
31
|
+
**Exports Cross-Checked:** {count}
|
|
32
|
+
**Mismatches Found:** {count}
|
|
33
|
+
```
|
|
34
|
+
|
|
20
35
|
## Coherence Analysis — Contextual Mode
|
|
21
36
|
|
|
22
37
|
```markdown
|
|
@@ -42,6 +42,18 @@ tessl evaluates SKILL.md body content only — it does not read `references/*.md
|
|
|
42
42
|
- Score based on: structural completeness only
|
|
43
43
|
- Weight redistribution: skipped categories' weights (Signature Accuracy 22% + Type Coverage 14%) redistributed proportionally to remaining active categories
|
|
44
44
|
|
|
45
|
+
### Docs-Only Mode (Quick tier, all [EXT:...] citations)
|
|
46
|
+
|
|
47
|
+
When `docs_only_mode: true` is set by step-03 (indicating a Quick tier skill where all SKILL.md citations are `[EXT:...]` format with no local source code):
|
|
48
|
+
|
|
49
|
+
- **Signature Accuracy:** Not scored (no source to compare against)
|
|
50
|
+
- **Type Coverage:** Not scored (no source to compare against)
|
|
51
|
+
- **Weight redistribution:** Same as Quick tier — Signature Accuracy (22%) and Type Coverage (14%) weights redistributed proportionally to remaining active categories
|
|
52
|
+
- **Export Coverage basis:** Documentation completeness rather than source coverage. Score = (documented_items_with_complete_descriptions / total_documented_items) * 100. A "complete" item has: description, parameters (if function/method), and return type (if function/method).
|
|
53
|
+
- **Coherence:** Standard rules for the detected mode (naive or contextual) apply unchanged
|
|
54
|
+
|
|
55
|
+
This is functionally identical to Quick tier weight redistribution but with a different coverage denominator (self-consistency instead of source comparison).
|
|
56
|
+
|
|
45
57
|
### Forge Tier (ast-grep)
|
|
46
58
|
- Export Coverage: AST-backed export comparison
|
|
47
59
|
- Signature Accuracy: AST-verified signature matching
|
|
@@ -21,9 +21,15 @@ Before analysis, determine source access level. Walk through these states in ord
|
|
|
21
21
|
Check if `{source_path}` (from metadata.json `source_root`) exists on disk. If yes → full analysis at detected tier (AST + signatures). Set `analysis_confidence: full`.
|
|
22
22
|
|
|
23
23
|
**State 2 — Local absent, provenance-map exists:**
|
|
24
|
-
Check `{forge_data_folder}/{skill_name}/provenance-map.json`. If present, use it as the baseline export inventory — each entry contains structured fields: `export_name`, `export_type`, `params[]`, `return_type`, `source_file`, `source_line`, `confidence`, and `ast_node_type`. Cross-reference against SKILL.md documented exports for name-matching and param-by-param coverage. Signature verification compares SKILL.md's documented params/return types against provenance-map entries directly.
|
|
24
|
+
Check `{forge_data_folder}/{skill_name}/provenance-map.json`. If present AND contains at least 1 entry, use it as the baseline export inventory — each entry contains structured fields: `export_name`, `export_type`, `params[]`, `return_type`, `source_file`, `source_line`, `confidence`, and `ast_node_type`. Cross-reference against SKILL.md documented exports for name-matching and param-by-param coverage. Signature verification compares SKILL.md's documented params/return types against provenance-map entries directly.
|
|
25
25
|
|
|
26
|
-
**
|
|
26
|
+
**Cross-reference with metadata.json:** After loading provenance-map entries, compare the entry count against `metadata.json`'s `exports[]` array length and `stats.exports_public_api` count. If metadata reports more exports than provenance-map entries:
|
|
27
|
+
- Compute `gap = metadata.exports.length - provenance_map.entries.length`
|
|
28
|
+
- Report: "Provenance-map contains {pmap_count} entries but metadata.json lists {meta_count} exports ({gap} gap). Coverage denominator uses the union."
|
|
29
|
+
- Build the coverage denominator from the **union** of provenance-map entry names and metadata.json `exports[]` names. Exports present in metadata but absent from provenance-map are counted as "missing documentation" in the coverage calculation.
|
|
30
|
+
- If metadata.json is unavailable or has no `exports[]` array, use provenance-map count alone with a note: "Coverage denominator is provenance-map only — may undercount if extraction was incomplete." If remote reading tools are available (zread, deepwiki, gh API, or similar), supplement by reading the entry point file for live signature verification. Set `analysis_confidence: provenance-map`.
|
|
31
|
+
|
|
32
|
+
**State 2 limitations:** Signature verification at State 2 is **string comparison only**, not semantic. Provenance-map stores parameters as flat string arrays (e.g., `["data: Union[BinaryIO, list, str]"]`), so `str` vs `String` or `list` vs `List[Any]` would be treated as mismatches even when semantically equivalent. For full type-aware verification (handling type aliases, generic equivalence), State 1 (local source) with AST re-parsing is required. When the SKILL.md was compiled from the same provenance-map (typical for create-then-test flows), most strings will match. However, enrichment (step-04) and doc-fetching (step-03c) during compilation may alter parameter descriptions, add type annotations, or normalize signatures, causing mismatches even in create-then-test flows. Expect some string-level mismatches and treat them as compilation artifacts, not source drift signals, until signature fidelity is enforced by step-05's Signature Fidelity Rule (see `signature_source` field in provenance-map entries).
|
|
27
33
|
|
|
28
34
|
**State 3 — No provenance-map, metadata exports exist (quick-skill path):**
|
|
29
35
|
If no provenance-map.json exists (typical for quick-skill output), fall back to `metadata.json`'s `exports[]` array for the export name list. Coverage check becomes a self-consistency comparison: are all names in `exports[]` documented in SKILL.md with description, parameters, and return type? Signatures cannot be verified. If remote reading tools are available, supplement by reading the entry point for live export comparison. Set `analysis_confidence: metadata-only`.
|
|
@@ -87,6 +87,38 @@ Build the **documented inventory** — a list of everything the SKILL.md claims
|
|
|
87
87
|
|
|
88
88
|
**Split-body traversal:** If a `references/` directory exists alongside SKILL.md and SKILL.md's `## Full` headings are absent or stubs (not a stack skill's structural references), extend the documented inventory scan to include all `references/*.md` files. After split-body, Tier 2 content (Full API Reference, Full Type Definitions) lives in reference files — the inventory must reflect the full skill content regardless of where it resides.
|
|
89
89
|
|
|
90
|
+
### 1b. Cross-Check Split-Body Consistency
|
|
91
|
+
|
|
92
|
+
**Only execute if a `references/` directory exists alongside SKILL.md** (detected during split-body traversal in Section 1). Skip silently otherwise.
|
|
93
|
+
|
|
94
|
+
For each function, class, type, or interface that appears in BOTH the SKILL.md body AND any `references/*.md` file, compare the documented signatures:
|
|
95
|
+
|
|
96
|
+
- **Parameters:** name, type, order, optionality
|
|
97
|
+
- **Return types:** exact type match
|
|
98
|
+
- **Description:** no contradictions (brief vs detailed is acceptable; conflicting semantics is not)
|
|
99
|
+
|
|
100
|
+
**SKILL.md body is authoritative.** When a mismatch is found, the reference file is the one that needs updating.
|
|
101
|
+
|
|
102
|
+
Build a split-body consistency findings list:
|
|
103
|
+
|
|
104
|
+
```json
|
|
105
|
+
{
|
|
106
|
+
"cross_check_mismatches": [
|
|
107
|
+
{
|
|
108
|
+
"export": "formatDate",
|
|
109
|
+
"skill_md_line": 42,
|
|
110
|
+
"reference_file": "references/api-reference.md",
|
|
111
|
+
"reference_line": 18,
|
|
112
|
+
"issue": "SKILL.md shows (date: Date) => string, reference shows (date: Date, format?: string) => string"
|
|
113
|
+
}
|
|
114
|
+
],
|
|
115
|
+
"exports_cross_checked": 12,
|
|
116
|
+
"mismatches_found": 1
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Flag each mismatch as **High severity** — signature inconsistency between SKILL.md body and reference files undermines agent trust. These findings feed into the gap report (step-06).
|
|
121
|
+
|
|
90
122
|
### 2. Analyze Source Code (Tier-Dependent)
|
|
91
123
|
|
|
92
124
|
Start from the package entry point (see 0b) and identify the public API surface. Then analyze those exports at the appropriate tier depth.
|
|
@@ -153,6 +185,8 @@ Load `{scoringRulesFile}` to determine category scores:
|
|
|
153
185
|
- **Signature Accuracy:** (matching_signatures / total_documented) * 100 (Forge/Deep only, "N/A" for Quick)
|
|
154
186
|
- **Type Coverage:** (documented_types / total_types) * 100 (Forge/Deep only, "N/A" for Quick)
|
|
155
187
|
|
|
188
|
+
**State 2 denominator validation:** When using provenance-map as the baseline (State 2), cross-reference the provenance-map entry count against `metadata.json`'s `exports[]` array before computing Export Coverage. If they diverge, use the union as the denominator per the source-access-protocol rules. Log the gap size if any.
|
|
189
|
+
|
|
156
190
|
### 5. Append Coverage Analysis to Output
|
|
157
191
|
|
|
158
192
|
Append the **Coverage Analysis** section to `{outputFile}`:
|
|
@@ -181,11 +215,13 @@ Append the **Coverage Analysis** section to `{outputFile}`:
|
|
|
181
215
|
|
|
182
216
|
### Category Scores
|
|
183
217
|
|
|
184
|
-
| Category | Score |
|
|
185
|
-
|
|
186
|
-
| Export Coverage | {N}% |
|
|
187
|
-
| Signature Accuracy | {N}%
|
|
188
|
-
| Type Coverage | {N}%
|
|
218
|
+
| Category | Score |
|
|
219
|
+
|----------|-------|
|
|
220
|
+
| Export Coverage | {N}% |
|
|
221
|
+
| Signature Accuracy | {N}% or N/A |
|
|
222
|
+
| Type Coverage | {N}% or N/A |
|
|
223
|
+
|
|
224
|
+
Note: Weight application is deferred to step-05 where all category weights are calculated after external validation availability is known.
|
|
189
225
|
```
|
|
190
226
|
|
|
191
227
|
### 6. Report Coverage Results
|
|
@@ -91,7 +91,27 @@ Build a simple structural findings list:
|
|
|
91
91
|
}
|
|
92
92
|
```
|
|
93
93
|
|
|
94
|
-
**After naive coherence →
|
|
94
|
+
**After naive coherence → Execute Section 2b if gate conditions met, then skip to Section 6 (Append Results)**
|
|
95
|
+
|
|
96
|
+
### 2b. Migration/Deprecation Verification (Mode-Independent)
|
|
97
|
+
|
|
98
|
+
**Gate check:** Execute this section ONLY IF both conditions are met:
|
|
99
|
+
1. Forge tier is **Deep** (tool-gated)
|
|
100
|
+
2. `{forge_data_folder}/{skill_name}/evidence-report.md` exists (data-gated)
|
|
101
|
+
|
|
102
|
+
If either condition fails, skip silently and proceed to Section 6.
|
|
103
|
+
|
|
104
|
+
**This check runs regardless of naive/contextual mode.** T2-future annotations are a property of the source code and enrichment data, not the skill type.
|
|
105
|
+
|
|
106
|
+
Check whether SKILL.md contains a "Migration & Deprecation Warnings" section (Section 4b). Then check the skill's `evidence-report.md` (at `{forge_data_folder}/{skill_name}/evidence-report.md`) for T2-future annotation counts.
|
|
107
|
+
|
|
108
|
+
- **If T2-future annotations > 0 AND Section 4b is absent:** Flag as Medium severity gap: "Migration section missing — T2-future annotations exist but Section 4b is not present in SKILL.md Tier 1."
|
|
109
|
+
- **If T2-future annotations = 0 AND Section 4b is present:** Flag as Medium severity gap: "Migration section unexpected — Section 4b is present but no T2-future annotations were produced."
|
|
110
|
+
- **If evidence-report.md is unavailable:** Skip this check silently. Note: "Section 4b verification skipped — evidence-report.md not found."
|
|
111
|
+
|
|
112
|
+
Add findings to the coherence analysis results.
|
|
113
|
+
|
|
114
|
+
**After Section 2b (naive path) → Skip to Section 6 (Append Results)**
|
|
95
115
|
|
|
96
116
|
### 3. Contextual Mode: Extract References
|
|
97
117
|
|
|
@@ -121,6 +141,8 @@ DO NOT BE LAZY — For EACH reference found, launch a subprocess that:
|
|
|
121
141
|
|
|
122
142
|
If subprocess unavailable, validate each reference in main thread.
|
|
123
143
|
|
|
144
|
+
4. **Scripts/assets directory check:** If a `scripts/` or `assets/` directory exists alongside SKILL.md, verify that a "Scripts & Assets" section (Section 7b) is present in SKILL.md. This directory-level check applies in both modes (naive mode performs it in Section 2; contextual mode performs it here alongside per-reference validation). Flag absence as Medium severity gap per `{scoringRulesFile}`.
|
|
145
|
+
|
|
124
146
|
### 5. Contextual Mode: Check Integration Pattern Completeness
|
|
125
147
|
|
|
126
148
|
For stack skills, verify integration patterns are complete:
|
|
@@ -146,11 +168,19 @@ Build integration completeness findings:
|
|
|
146
168
|
}
|
|
147
169
|
```
|
|
148
170
|
|
|
149
|
-
|
|
171
|
+
**Zero integration patterns:** If no integration patterns are documented in SKILL.md (e.g., a contextual-mode skill that uses shared types but has no middleware chains, plugin hooks, or event flows): record `patterns_documented: 0`, `patterns_complete: 0`. The coherence score will use reference validity alone — see `{scoringRulesFile}` Coherence Score Aggregation: "If no integration patterns exist, combined coherence equals reference validity."
|
|
150
172
|
|
|
151
|
-
|
|
173
|
+
### 5b. Migration/Deprecation Verification (Contextual Path)
|
|
152
174
|
|
|
153
|
-
|
|
175
|
+
**This section shares logic with Section 2b.** If you are on the contextual mode path (Sections 3-5), execute the migration check here using the same rules as Section 2b:
|
|
176
|
+
|
|
177
|
+
**Gate check:** Execute ONLY IF both conditions are met:
|
|
178
|
+
1. Forge tier is **Deep** (tool-gated)
|
|
179
|
+
2. `{forge_data_folder}/{skill_name}/evidence-report.md` exists (data-gated)
|
|
180
|
+
|
|
181
|
+
If either condition fails, skip silently.
|
|
182
|
+
|
|
183
|
+
Check whether SKILL.md contains a "Migration & Deprecation Warnings" section (Section 4b). Then check the skill's `evidence-report.md` for T2-future annotation counts.
|
|
154
184
|
|
|
155
185
|
- **If T2-future annotations > 0 AND Section 4b is absent:** Flag as Medium severity gap: "Migration section missing — T2-future annotations exist but Section 4b is not present in SKILL.md Tier 1."
|
|
156
186
|
- **If T2-future annotations = 0 AND Section 4b is present:** Flag as Medium severity gap: "Migration section unexpected — Section 4b is present but no T2-future annotations were produced."
|
|
@@ -158,6 +188,20 @@ Check whether SKILL.md contains a "Migration & Deprecation Warnings" section (Se
|
|
|
158
188
|
|
|
159
189
|
Add findings to the coherence analysis results.
|
|
160
190
|
|
|
191
|
+
### 5c. Calculate Coherence Scores
|
|
192
|
+
|
|
193
|
+
**Contextual mode only.** Calculate coherence percentages using the formulas defined in `{scoringRulesFile}` — Coherence Score Aggregation section:
|
|
194
|
+
|
|
195
|
+
```
|
|
196
|
+
reference_validity = (valid_references / total_references) * 100
|
|
197
|
+
integration_completeness = (complete_patterns / total_patterns) * 100
|
|
198
|
+
combined_coherence = (reference_validity * 0.6) + (integration_completeness * 0.4)
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
**Edge case:** If no integration patterns are documented (patterns_documented = 0), combined coherence equals reference validity alone. Do not divide by zero.
|
|
202
|
+
|
|
203
|
+
These values fill the `{percentage}%` placeholders in the output template loaded in Section 6.
|
|
204
|
+
|
|
161
205
|
### 6. Append Coherence Analysis to Output
|
|
162
206
|
|
|
163
207
|
Load `{outputFormatsFile}` and use the appropriate Coherence Analysis section format (naive or contextual) to append findings to `{outputFile}`.
|
|
@@ -60,7 +60,15 @@ Read {outputFile} frontmatter to get the skill directory path (`skillDir`).
|
|
|
60
60
|
|
|
61
61
|
Before running external validators, check if `{forge_data_folder}/{skill_name}/evidence-report.md` contains validation results (a `## Validation Results` section with quality scores).
|
|
62
62
|
|
|
63
|
-
**Staleness check:**
|
|
63
|
+
**Staleness check:** Determine whether SKILL.md has changed since the evidence report was generated.
|
|
64
|
+
|
|
65
|
+
**Primary (git-tracked):** Run `git log -1 --format=%cI -- {skillDir}/SKILL.md` to get the last commit date of SKILL.md. Compare against the evidence report's generation date (from its frontmatter or the `## Validation Results` timestamp). If SKILL.md's last commit is newer, results are stale.
|
|
66
|
+
|
|
67
|
+
**Secondary (uncommitted changes):** Run `git diff --name-only -- {skillDir}/SKILL.md`. If output is non-empty, SKILL.md has uncommitted changes — treat results as stale regardless of commit dates.
|
|
68
|
+
|
|
69
|
+
**Fallback (non-git environments):** If git commands fail (not a git repository), fall back to `metadata.json` `generation_date` comparison with a warning: "Staleness check using metadata.json — may be identical to evidence report timestamp. Consider a git-tracked directory for reliable staleness detection."
|
|
70
|
+
|
|
71
|
+
If SKILL.md was modified after the evidence report was generated (e.g., after update-skill), the cached results are stale — skip auto-reuse and proceed to section 2 for a fresh run.
|
|
64
72
|
|
|
65
73
|
If recent, non-stale results exist (from a create-skill run that just completed), auto-reuse them — skip re-running validators and use the existing scores. Record: "External validation: reused from create-skill evidence report." Skip to section 5 (append results).
|
|
66
74
|
|
|
@@ -64,6 +64,8 @@ Load `{scoringRulesFile}` to get:
|
|
|
64
64
|
- Tier-dependent scoring adjustments
|
|
65
65
|
- Any custom threshold override from workflow input
|
|
66
66
|
|
|
67
|
+
**Docs-only mode check:** If the Coverage Analysis section in `{outputFile}` notes docs-only mode (set by step-03 for skills with all `[EXT:...]` citations and no local source), apply Quick-tier weight redistribution: Signature Accuracy and Type Coverage are not scored, their weights (22% + 14%) are redistributed proportionally to remaining active categories. Coverage score is based on documentation completeness rather than source coverage (as calculated by step-03).
|
|
68
|
+
|
|
67
69
|
### 2. Read Category Scores from Output
|
|
68
70
|
|
|
69
71
|
Read `{outputFile}` and extract the category scores calculated in previous steps:
|
|
@@ -185,6 +185,10 @@ class Installer {
|
|
|
185
185
|
await fs.copy(src, path.join(skfDir, file));
|
|
186
186
|
}
|
|
187
187
|
}
|
|
188
|
+
|
|
189
|
+
// Write VERSION file for SKF version resolution in installed projects
|
|
190
|
+
const packageJson = require('../../../package.json');
|
|
191
|
+
await fs.writeFile(path.join(skfDir, 'VERSION'), packageJson.version, 'utf8');
|
|
188
192
|
}
|
|
189
193
|
|
|
190
194
|
/**
|