bmad-module-skill-forge 1.1.0 → 1.3.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.
- package/.claude-plugin/marketplace.json +1 -1
- package/README.md +6 -4
- package/docs/_data/pinned.yaml +1 -1
- package/docs/bmad-synergy.md +2 -2
- package/docs/getting-started.md +1 -1
- package/docs/skill-model.md +26 -32
- package/docs/troubleshooting.md +13 -1
- package/docs/why-skf.md +5 -4
- package/docs/workflows.md +53 -0
- package/package.json +2 -2
- package/src/knowledge/ccc-bridge.md +1 -1
- package/src/shared/references/output-contract-schema.md +10 -0
- package/src/shared/scripts/schemas/skf-setup-result-envelope.v1.json +134 -0
- package/src/shared/scripts/skf-detect-tools.py +359 -0
- package/src/shared/scripts/skf-emit-result-envelope.py +419 -0
- package/src/shared/scripts/skf-extract-public-api.py +505 -0
- package/src/shared/scripts/skf-forge-tier-rw.py +413 -0
- package/src/shared/scripts/skf-merge-ccc-exclusions.py +324 -0
- package/src/shared/scripts/skf-preflight.py +14 -4
- package/src/shared/scripts/skf-qmd-classify-collections.py +212 -0
- package/src/shared/scripts/skf-render-quick-metadata.py +192 -0
- package/src/shared/scripts/skf-resolve-package.py +264 -0
- package/src/shared/scripts/skf-validate-frontmatter.py +9 -3
- package/src/shared/scripts/skf-validate-output.py +24 -7
- package/src/skf-create-skill/steps-c/step-06-validate.md +1 -1
- package/src/skf-quick-skill/SKILL.md +178 -10
- package/src/skf-quick-skill/assets/skill-template.md +5 -1
- package/src/skf-quick-skill/references/registry-resolution.md +2 -0
- package/src/skf-quick-skill/steps-c/step-01-resolve-target.md +84 -16
- package/src/skf-quick-skill/steps-c/step-02-ecosystem-check.md +3 -3
- package/src/skf-quick-skill/steps-c/step-03-quick-extract.md +86 -43
- package/src/skf-quick-skill/steps-c/step-04-compile.md +49 -56
- package/src/skf-quick-skill/steps-c/step-05-write-and-validate.md +164 -0
- package/src/skf-quick-skill/steps-c/{step-06-write.md → step-06-finalize.md} +15 -7
- package/src/skf-quick-skill/steps-c/step-07-health-check.md +5 -3
- package/src/skf-setup/SKILL.md +25 -10
- package/src/skf-setup/references/tier-rules.md +2 -2
- package/src/skf-setup/steps-c/step-01-detect-and-tier.md +58 -71
- package/src/skf-setup/steps-c/step-01b-ccc-index.md +49 -66
- package/src/skf-setup/steps-c/step-02-write-config.md +59 -86
- package/src/skf-setup/steps-c/step-03-auto-index.md +73 -91
- package/src/skf-setup/steps-c/step-04-report.md +135 -11
- package/src/skf-setup/steps-c/step-05-health-check.md +4 -2
- package/src/skf-test-skill/steps-c/step-01-init.md +4 -4
- package/src/skf-quick-skill/steps-c/step-05-validate.md +0 -193
|
@@ -1,111 +1,98 @@
|
|
|
1
1
|
---
|
|
2
2
|
nextStepFile: './step-01b-ccc-index.md'
|
|
3
|
-
|
|
3
|
+
# Resolve `{detectToolsHelper}` by probing `{detectToolsProbeOrder}` in order
|
|
4
|
+
# (installed SKF module path first, src/ dev-checkout fallback); first existing
|
|
5
|
+
# path wins. HALT if neither resolves — the script is the source of truth for
|
|
6
|
+
# tool detection and tier calculation; no fallback to prose-driven probes.
|
|
7
|
+
detectToolsProbeOrder:
|
|
8
|
+
- '{project-root}/_bmad/skf/shared/scripts/skf-detect-tools.py'
|
|
9
|
+
- '{project-root}/src/shared/scripts/skf-detect-tools.py'
|
|
4
10
|
---
|
|
5
11
|
|
|
12
|
+
<!-- Config: communicate in {communication_language}. The first-run preamble below is user-visible — render it in the user's language. -->
|
|
13
|
+
|
|
6
14
|
# Step 1: Detect Tools and Determine Tier
|
|
7
15
|
|
|
8
16
|
## STEP GOAL:
|
|
9
17
|
|
|
10
|
-
Verify availability of the four forge tools (ast-grep, gh, qmd, ccc), read any existing configuration for re-run comparison, check for tier override, and calculate the capability tier.
|
|
18
|
+
Verify availability of the four forge tools (ast-grep, gh, qmd, ccc), read any existing configuration for re-run comparison, check for tier override, and calculate the capability tier — all via `{detectToolsHelper}` so the deterministic work is done once, by a tested script, never by the LLM.
|
|
11
19
|
|
|
12
20
|
## Rules
|
|
13
21
|
|
|
14
22
|
- Focus only on tool detection and tier calculation — do not write any files (Step 02)
|
|
15
|
-
-
|
|
16
|
-
- Tool command failures are not errors — they indicate unavailability
|
|
23
|
+
- Never reimplement tool probes or the tier rules in prose — the script is authoritative
|
|
24
|
+
- Tool command failures are not errors — they indicate unavailability (the script swallows them)
|
|
17
25
|
|
|
18
26
|
## MANDATORY SEQUENCE
|
|
19
27
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
### 1. Load Tier Rules
|
|
23
|
-
|
|
24
|
-
Load and read {tierRulesData} for the tool detection commands and tier calculation logic.
|
|
25
|
-
|
|
26
|
-
### 2. Check for Existing Configuration (Re-run Detection)
|
|
28
|
+
### 1. Check for Existing Configuration (Re-run Detection)
|
|
27
29
|
|
|
28
30
|
**Read existing forge-tier.yaml** at `{project-root}/_bmad/_memory/forger-sidecar/forge-tier.yaml`:
|
|
29
|
-
|
|
30
|
-
- If
|
|
31
|
+
|
|
32
|
+
- If exists: store the current `tier` value as `{previous_tier}`, `tier_detected_at` as `{previous_detection_date}`, and the `tools` map as `{previous_tools}` (for the tool-set delta detection step-04 needs to surface newly-installed tools on same-tier re-runs).
|
|
33
|
+
- If not found: set `{previous_tier}` to null and `{previous_tools}` to an empty map (first run).
|
|
31
34
|
|
|
32
35
|
**Read existing preferences.yaml** at `{project-root}/_bmad/_memory/forger-sidecar/preferences.yaml`:
|
|
36
|
+
|
|
33
37
|
- If exists: check for `tier_override` value
|
|
34
38
|
- If not found: set `{tier_override}` to null
|
|
35
39
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
Run: `ast-grep --version`
|
|
39
|
-
|
|
40
|
-
- If succeeds: record `{ast_grep: true}` and store version string
|
|
41
|
-
- If fails (command not found or error): record `{ast_grep: false}`
|
|
42
|
-
|
|
43
|
-
### 4. Verify Tool: gh
|
|
44
|
-
|
|
45
|
-
Run: `gh --version`
|
|
46
|
-
|
|
47
|
-
- If succeeds: record `{gh_cli: true}` and store version string
|
|
48
|
-
- If fails: record `{gh_cli: false}`
|
|
49
|
-
|
|
50
|
-
### 5. Verify Tool: qmd
|
|
51
|
-
|
|
52
|
-
Run: `qmd status`
|
|
53
|
-
|
|
54
|
-
- If succeeds and indicates operational: record `{qmd: true}`
|
|
55
|
-
- If fails or indicates not initialized: record `{qmd: false}`
|
|
56
|
-
|
|
57
|
-
### 6. Check Optional: Security Scan (SNYK_TOKEN)
|
|
58
|
-
|
|
59
|
-
Check if the `SNYK_TOKEN` environment variable is set:
|
|
60
|
-
|
|
61
|
-
- If `SNYK_TOKEN` is non-empty: record `{security_scan: true}`
|
|
62
|
-
- If `SNYK_TOKEN` is empty or unset: record `{security_scan: false}`
|
|
63
|
-
|
|
64
|
-
This is informational only — security scan availability does NOT affect the tier level. It is recorded in forge-tier.yaml so that create-skill's validation step can report actionable guidance when security scanning is unavailable.
|
|
65
|
-
|
|
66
|
-
### 7. Verify Tool: ccc (cocoindex-code)
|
|
40
|
+
**First-run preamble** — when `{previous_tier}` is null AND `{headless_mode}` is `false`, display this preamble before continuing so the user knows what is about to happen and can abort cleanly with Esc / Ctrl+C before any writes:
|
|
67
41
|
|
|
68
|
-
**
|
|
42
|
+
"**About to set up the forge.** This workflow will:
|
|
69
43
|
|
|
70
|
-
-
|
|
71
|
-
-
|
|
44
|
+
- Detect available tools (ast-grep, gh, qmd, ccc) — read-only probes only
|
|
45
|
+
- Write `{project-root}/_bmad/_memory/forger-sidecar/forge-tier.yaml` (capability tier + tool state)
|
|
46
|
+
- Write `{project-root}/_bmad/_memory/forger-sidecar/preferences.yaml` (first-run defaults)
|
|
47
|
+
- Create `{forge_data_folder}/` if missing
|
|
48
|
+
- When ccc is available: augment `{project-root}/.cocoindex_code/settings.yml` with SKF exclusion patterns, then create or refresh the project ccc index
|
|
72
49
|
|
|
73
|
-
**
|
|
50
|
+
**About tiers:** SKF picks one of four tiers (Quick / Forge / Forge+ / Deep) based on which tools are installed. **All four are fully usable** — higher tiers add power, they don't fix gaps. If you're new and only have a base Python install, Quick tier is the right starting point and the report at the end will show you exactly which tools to install if you want to climb later.
|
|
74
51
|
|
|
75
|
-
|
|
76
|
-
- If daemon is not running: record `{ccc: true, ccc_daemon: "stopped"}` — binary available, daemon needs starting. Step-01b will handle this.
|
|
77
|
-
- If error or timeout: record `{ccc: true, ccc_daemon: "error"}` — binary works but daemon has issues.
|
|
52
|
+
Press Esc or Ctrl+C now if this isn't the right project — no files have been written yet."
|
|
78
53
|
|
|
79
|
-
|
|
54
|
+
### 2. Run Detection Helper
|
|
80
55
|
|
|
81
|
-
|
|
56
|
+
Build the Bash invocation. Start with `uv run {detectToolsHelper}` — `uv run` honors the script's PEP 723 inline-metadata dependency declarations (resolved automatically on first call; cached thereafter), which is why uv is documented as a runtime prerequisite in `docs/getting-started.md`. Do NOT call the script via bare `python3` — `python3` ignores PEP 723 metadata, and on a fresh interpreter without the declared deps installed system-wide the call fails with `ModuleNotFoundError`. If `{tier_override}` is non-null, append `--tier-override "{tier_override}"` (the script handles invalid values by flagging them — do NOT pre-validate). If `{require_tier}` (resolved in On Activation) is non-null, append `--require-tier "{require_tier}"`. Then execute.
|
|
82
57
|
|
|
83
|
-
|
|
84
|
-
- Use `{tier_override}` as `{calculated_tier}`
|
|
85
|
-
- Note that override is active for the report step
|
|
58
|
+
The script (see `src/shared/scripts/skf-detect-tools.py` docstring for the full `DETECT_OUTPUT_SCHEMA`) probes ast-grep / gh / qmd / ccc concurrently with two-step verification for qmd and ccc (binary-identity check + daemon-health check, including the `CocoIndex Code` identity-marker substring check that rejects PATH-shadowing aliases). It applies the 4-rule tier table, performs the tier-override sanity check (override is honored but flagged unsafe when underlying tools are missing), and evaluates `--require-tier` using a tool-prerequisite check (Deep does NOT subsume Forge+ — Deep does not require ccc). Output is one JSON document on stdout.
|
|
86
59
|
|
|
87
|
-
|
|
88
|
-
- `{ast_grep}` AND `{gh_cli}` AND `{qmd}` all true → **Deep**
|
|
89
|
-
- `{ast_grep}` AND `{ccc}` both true, but NOT (`{gh_cli}` AND `{qmd}`) → **Forge+**
|
|
90
|
-
- `{ast_grep}` true (regardless of ccc/gh/qmd) → **Forge**
|
|
91
|
-
- Otherwise → **Quick**
|
|
60
|
+
### 3. Parse Output and Set Context Flags
|
|
92
61
|
|
|
93
|
-
|
|
62
|
+
From the JSON, set these context flags. Field paths are relative to the script's top-level object.
|
|
94
63
|
|
|
95
|
-
|
|
64
|
+
From `tools`:
|
|
96
65
|
|
|
97
|
-
|
|
66
|
+
- `{ast_grep}` ← `tools.ast_grep.available`
|
|
67
|
+
- `{ast_grep_version}` ← `tools.ast_grep.version`
|
|
68
|
+
- `{gh_cli}` ← `tools.gh_cli.available`
|
|
69
|
+
- `{gh_cli_version}` ← `tools.gh_cli.version`
|
|
70
|
+
- `{qmd}` ← `tools.qmd.available`
|
|
71
|
+
- `{qmd_status}` ← `tools.qmd.status` (`"absent" | "daemon_stopped" | "healthy"` — drives the climb-hint distinction in step-04)
|
|
72
|
+
- `{qmd_version}` ← `tools.qmd.version`
|
|
73
|
+
- `{ccc}` ← `tools.ccc.available`
|
|
74
|
+
- `{ccc_daemon}` ← `tools.ccc.daemon` (`"healthy" | "stopped" | "error" | null`)
|
|
75
|
+
- `{ccc_version}` ← `tools.ccc.version`
|
|
76
|
+
- `{security_scan}` ← `tools.security_scan.available` (informational only — never affects tier)
|
|
98
77
|
|
|
99
|
-
|
|
78
|
+
From `tier`:
|
|
100
79
|
|
|
101
|
-
-
|
|
80
|
+
- `{calculated_tier}` ← `tier.calculated` — the tier downstream steps act on
|
|
81
|
+
- `{detected_tier}` ← `tier.detected` — what would have been chosen without override
|
|
82
|
+
- `{tier_override_active}` ← `tier.override_applied`
|
|
83
|
+
- `{tier_override_invalid}` ← `tier.override_invalid`
|
|
84
|
+
- `{tier_override_invalid_value}` ← `tier.override_invalid_value`
|
|
85
|
+
- `{tier_override_invalid_suggestion}` ← `tier.override_invalid_suggestion` (closest valid tier name from a fuzzy match — `null` when no candidate cleared the cutoff or when override is valid; consumed by step-04's invalid-override note as a "did you mean ...?" hint)
|
|
86
|
+
- `{tier_override_unsafe}` ← `tier.override_unsafe`
|
|
87
|
+
- `{tier_override_unsafe_missing}` ← `tier.override_unsafe_missing` (a list — step-04 joins with `", "` for display)
|
|
102
88
|
|
|
103
|
-
|
|
89
|
+
From `require_tier`:
|
|
104
90
|
|
|
105
|
-
-
|
|
106
|
-
-
|
|
91
|
+
- `{require_tier_satisfied}` ← `require_tier.satisfied` (`true | false | null`; null when `--require-tier` was not set)
|
|
92
|
+
- `{require_tier_failure_missing_tools}` ← `require_tier.missing_tools` (a list)
|
|
107
93
|
|
|
108
|
-
|
|
94
|
+
**The script is the source of truth.** Every tier-rules edge case (override-honored-but-unsafe, Deep-doesn't-subsume-Forge+, qmd-binary-vs-daemon distinction, ccc-identity-marker rejection of foreign binaries) is locked into the test suite at `test/test-skf-detect-tools.py`. Substituting prose-driven logic for the script's output here will cause subtle re-run regressions that the prompt's prose is no longer detailed enough to catch.
|
|
109
95
|
|
|
110
|
-
|
|
96
|
+
### 4. Auto-Proceed
|
|
111
97
|
|
|
98
|
+
After context flags are populated, display "**Proceeding to CCC index check...**", then load `{nextStepFile}`, read it fully, and execute it.
|
|
@@ -1,31 +1,39 @@
|
|
|
1
1
|
---
|
|
2
2
|
nextStepFile: './step-02-write-config.md'
|
|
3
|
+
# Resolve `{mergeCccExclusionsHelper}` by probing `{mergeCccExclusionsProbeOrder}`
|
|
4
|
+
# in order (installed SKF module path first, src/ dev-checkout fallback); first
|
|
5
|
+
# existing path wins. HALT if neither resolves — the script owns config-value
|
|
6
|
+
# validation and the set-union merge into .cocoindex_code/settings.yml; no
|
|
7
|
+
# fallback to prose-driven validation.
|
|
8
|
+
mergeCccExclusionsProbeOrder:
|
|
9
|
+
- '{project-root}/_bmad/skf/shared/scripts/skf-merge-ccc-exclusions.py'
|
|
10
|
+
- '{project-root}/src/shared/scripts/skf-merge-ccc-exclusions.py'
|
|
3
11
|
---
|
|
4
12
|
|
|
13
|
+
<!-- Config: communicate in {communication_language}. User-visible status messages (CCC exclusion summary, indexing progress message) render in the user's language. -->
|
|
14
|
+
|
|
5
15
|
# Step 1b: CCC Index Verification
|
|
6
16
|
|
|
7
17
|
## STEP GOAL:
|
|
8
18
|
|
|
9
|
-
If ccc is available (`{ccc: true}` from step-01),
|
|
19
|
+
If ccc is available (`{ccc: true}` from step-01), invoke `{mergeCccExclusionsHelper}` to validate config-driven SKF exclusion patterns and merge them into `.cocoindex_code/settings.yml`, then verify the project's ccc index exists and create or refresh it if needed. Store index state and exclusion-merge results in context for step-02 to write into forge-tier.yaml and for step-04 to surface in the JSON envelope.
|
|
10
20
|
|
|
11
21
|
For Quick and Forge tiers, or when ccc is unavailable, skip silently and proceed.
|
|
12
22
|
|
|
13
23
|
## Rules
|
|
14
24
|
|
|
15
|
-
- Focus only on ccc index verification and
|
|
25
|
+
- Focus only on ccc index verification, exclusion-pattern merge, and (re-)indexing
|
|
16
26
|
- Do not display skip messages for Quick/Forge tiers
|
|
17
27
|
- Do not fail the workflow if ccc indexing fails
|
|
18
|
-
-
|
|
28
|
+
- Never reimplement the exclusion-pattern validation in prose — the script owns the PR #248 rules
|
|
19
29
|
|
|
20
30
|
## MANDATORY SEQUENCE
|
|
21
31
|
|
|
22
|
-
**CRITICAL:** Follow this sequence exactly. Do not skip, reorder, or improvise.
|
|
23
|
-
|
|
24
32
|
### 1. Check Eligibility
|
|
25
33
|
|
|
26
34
|
Read `{ccc}` from step-01 context.
|
|
27
35
|
|
|
28
|
-
**If `{ccc}` is false:** Set `{ccc_index_result: "none", ccc_indexed_path: null, ccc_last_indexed: null, ccc_exclude_patterns: []}`. Proceed directly to section 4 (Auto-Proceed) — no output, no messaging.
|
|
36
|
+
**If `{ccc}` is false:** Set `{ccc_index_result: "none", ccc_indexed_path: null, ccc_last_indexed: null, ccc_exclude_patterns: [], ccc_exclusion_warnings: [], settings_yml_written: false, settings_yml_patterns_added: 0}`. Proceed directly to section 4 (Auto-Proceed) — no output, no messaging.
|
|
29
37
|
|
|
30
38
|
**If `{ccc}` is true:** Continue to section 2.
|
|
31
39
|
|
|
@@ -36,81 +44,68 @@ Read existing forge-tier.yaml at `{project-root}/_bmad/_memory/forger-sidecar/fo
|
|
|
36
44
|
Read `staleness_threshold_hours` from `ccc_index.staleness_threshold_hours` in the existing forge-tier.yaml (default: 24 if not present or not a number). Use this value for the freshness check below.
|
|
37
45
|
|
|
38
46
|
Check the `ccc_index` section:
|
|
47
|
+
|
|
39
48
|
- If `ccc_index.indexed_path` matches `{project-root}` AND `ccc_index.status` is `"fresh"` or `"created"`:
|
|
40
49
|
- Check freshness: if `ccc_index.last_indexed` is within `staleness_threshold_hours` of now → index is fresh
|
|
41
50
|
- Store `{ccc_index_result: "fresh", ccc_indexed_path: {project-root}, ccc_last_indexed: {existing timestamp}}`
|
|
42
|
-
- Set `{needs_reindex: false}` —
|
|
51
|
+
- Set `{needs_reindex: false}` — exclusions still get merged in section 3, which may force a re-index
|
|
43
52
|
|
|
44
53
|
- If `ccc_index.indexed_path` matches `{project-root}` but timestamp is older than threshold:
|
|
45
|
-
- Set `{needs_reindex: true}`
|
|
54
|
+
- Set `{needs_reindex: true}`
|
|
46
55
|
|
|
47
56
|
- If `ccc_index` is missing, has null values, or path doesn't match:
|
|
48
|
-
- Set `{needs_reindex: true}`
|
|
57
|
+
- Set `{needs_reindex: true}`
|
|
49
58
|
|
|
50
|
-
###
|
|
59
|
+
### 3. Merge SKF Exclusion Patterns
|
|
51
60
|
|
|
52
61
|
SKF infrastructure and output directories must be excluded from the CCC index — they contain workflow instructions, build artifacts, and generated skills that pollute semantic search results with zero extraction value.
|
|
53
62
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
1. Use `{skills_output_folder}` and `{forge_data_folder}` from the workflow activation context (resolved in On Activation from `{project-root}/_bmad/skf/config.yaml`).
|
|
57
|
-
|
|
58
|
-
2. Assemble the exclusion patterns using `**/` prefix format (matching `.cocoindex_code/settings.yml` convention — e.g., `**/node_modules`):
|
|
59
|
-
- `**/_bmad` — SKF framework module (workflows, agents, knowledge files)
|
|
60
|
-
- `**/_bmad-output` — Build output artifacts
|
|
61
|
-
- `**/.claude` — Claude Code configuration
|
|
62
|
-
- `**/_skf-learn` — SKF learning materials
|
|
63
|
-
- `**/{skills_output_folder}` — Generated skill files (from activation context)
|
|
64
|
-
- `**/{forge_data_folder}` — Compilation workspace (from activation context)
|
|
65
|
-
|
|
66
|
-
3. Store `{ccc_exclude_patterns}` in context for step-02 to write into forge-tier.yaml.
|
|
63
|
+
Run the merge helper, forwarding the resolved config values from the workflow activation context. Invoke via `uv run` so PEP 723 inline metadata resolves the script's PyYAML dependency automatically (per `docs/getting-started.md`'s prereq list — uv exists for this exact purpose). Bare `python3` will fail on a fresh Python with `ModuleNotFoundError: No module named 'yaml'`.
|
|
67
64
|
|
|
68
|
-
|
|
65
|
+
```bash
|
|
66
|
+
uv run {mergeCccExclusionsHelper} \
|
|
67
|
+
--project-root "{project-root}" \
|
|
68
|
+
--skills-output-folder "{skills_output_folder}" \
|
|
69
|
+
--forge-data-folder "{forge_data_folder}"
|
|
70
|
+
```
|
|
69
71
|
|
|
70
|
-
|
|
72
|
+
The script (see `src/shared/scripts/skf-merge-ccc-exclusions.py` docstring for the full schema) builds the SKF exclusion list (4 always-include hardcoded patterns + 2 conditional from validated config), applies the PR #248 validation rules to reject empty / absolute / glob-meta config values with actionable warnings, and performs an idempotent set-union merge into `{project-root}/.cocoindex_code/settings.yml`. User customizations are preserved. When the file does not exist yet (first-time setup before `ccc init`) the script creates it; when nothing new needs adding the script skips the write entirely (mtime preserved).
|
|
71
73
|
|
|
72
|
-
|
|
74
|
+
**Parse the JSON output and set context flags:**
|
|
73
75
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
4.
|
|
76
|
+
- `{settings_yml_existed}` ← `settings_yml_existed`
|
|
77
|
+
- `{settings_yml_written}` ← `written`
|
|
78
|
+
- `{settings_yml_patterns_added}` ← `patterns_added`
|
|
79
|
+
- `{ccc_exclude_patterns}` ← derive from the script's behaviour: it always merges the 4 always-include patterns plus any of the 2 config-driven ones whose value passed validation. Step-02 needs this list to write `ccc_index.exclude_patterns` into forge-tier.yaml — read it from the script's `patterns_added_list` PLUS any already-present matching SKF patterns inferred from the input. Pragmatically: re-derive the list as `["**/_bmad", "**/_bmad-output", "**/.claude", "**/_skf-learn"]` plus `"**/{skills_output_folder}"` if no warning names `skills_output_folder` plus `"**/{forge_data_folder}"` if no warning names `forge_data_folder`.
|
|
80
|
+
- `{ccc_exclusion_warnings}` ← `warnings` (a list — step-04 folds them into the envelope's warnings array)
|
|
78
81
|
|
|
79
|
-
|
|
82
|
+
**If `{settings_yml_written}` is true** (new patterns merged into settings.yml): set `{needs_reindex: true}` — new exclusions require re-indexing for the index to reflect them. Display: "**CCC exclusions configured:** {patterns_added} SKF patterns applied to .cocoindex_code/settings.yml"
|
|
80
83
|
|
|
81
|
-
If `{
|
|
84
|
+
**If `{settings_yml_written}` is false** (idempotent re-run, all patterns already present): display nothing (exclusions already configured). Do NOT change `{needs_reindex}` — it stays at whatever section 2 set it to.
|
|
82
85
|
|
|
83
86
|
**Flow decision:**
|
|
84
|
-
- If `{needs_reindex}` is true: proceed to section 3
|
|
85
|
-
- If `{needs_reindex}` is false: proceed to section 4 (Auto-Proceed)
|
|
86
|
-
|
|
87
|
-
### 3. Create or Refresh CCC Index
|
|
88
87
|
|
|
89
|
-
|
|
88
|
+
- If `{needs_reindex}` is true: proceed to section 4
|
|
89
|
+
- If `{needs_reindex}` is false: proceed to section 5 (Auto-Proceed)
|
|
90
90
|
|
|
91
|
-
|
|
91
|
+
### 4. Create or Refresh CCC Index
|
|
92
92
|
|
|
93
|
-
**If `{ccc_daemon}` is `"
|
|
93
|
+
**If `{ccc_daemon}` is `"stopped"` or `"healthy"`:** the `ccc index` command auto-starts the daemon when needed.
|
|
94
94
|
|
|
95
|
-
|
|
95
|
+
**If `{ccc_daemon}` is `"error"`:** attempt indexing anyway — errors will be caught below.
|
|
96
96
|
|
|
97
97
|
Run (CWD must be `{project-root}`):
|
|
98
|
+
|
|
98
99
|
```bash
|
|
99
100
|
ccc init
|
|
100
101
|
```
|
|
101
102
|
|
|
102
|
-
**If init fails** (project may already be initialized): continue — this is not an error.
|
|
103
|
-
|
|
104
|
-
**Apply SKF exclusion patterns (if not already applied in section 2b):**
|
|
103
|
+
**If init fails** (project may already be initialized): continue — this is not an error. Note: when `{settings_yml_existed}` was false and `ccc init` just created the settings.yml, the merge in section 3 ran BEFORE ccc init. The script handles "no settings.yml exists" by creating one with just the SKF exclusions, which `ccc init` will then either preserve (if it merges) or overwrite (in which case the next workflow run re-merges). Either way the SKF exclusions end up in the file by the time `ccc index` runs the second time.
|
|
105
104
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
1. Read `{project-root}/.cocoindex_code/settings.yml` (created by `ccc init`)
|
|
109
|
-
2. For each pattern in `{ccc_exclude_patterns}`: if the pattern is NOT already present in `exclude_patterns`, append it
|
|
110
|
-
3. Write the updated `settings.yml` back
|
|
111
|
-
4. Display: "**CCC exclusions configured:** {count} SKF patterns applied to .cocoindex_code/settings.yml"
|
|
105
|
+
Before invoking `ccc index`, display: "**Building semantic index — this can take several minutes on large codebases (1000+ files). Run `ccc status` in another terminal to monitor progress.**" so the user does not assume the workflow has hung during the long-running call.
|
|
112
106
|
|
|
113
107
|
Then run:
|
|
108
|
+
|
|
114
109
|
```bash
|
|
115
110
|
ccc index
|
|
116
111
|
```
|
|
@@ -118,29 +113,17 @@ ccc index
|
|
|
118
113
|
**Note:** `ccc index` can take several minutes on large codebases (1000+ files). Run with an extended timeout or in background mode. Use `ccc status` to verify completion — check that `Chunks` and `Files` counts are non-zero.
|
|
119
114
|
|
|
120
115
|
**If succeeds:**
|
|
116
|
+
|
|
121
117
|
- Run `ccc status` to get file count
|
|
122
118
|
- Store `{ccc_index_result: "created", ccc_indexed_path: {project-root}, ccc_last_indexed: {current ISO timestamp}, ccc_file_count: {count from ccc status}}`
|
|
123
119
|
- Display: "**CCC index created.** {ccc_file_count} files indexed for semantic discovery."
|
|
124
120
|
|
|
125
121
|
**If fails:**
|
|
126
|
-
|
|
122
|
+
|
|
123
|
+
- Store `{ccc_index_result: "failed", ccc_indexed_path: null, ccc_last_indexed: null, ccc_indexing_failed_reason: {error}}` (the failed-reason flag flows into step-04's envelope warnings)
|
|
127
124
|
- Display: "CCC indexing failed: {error}. Extraction will use direct AST scanning — semantic pre-ranking unavailable this session."
|
|
128
125
|
- Continue — this is NOT a workflow error
|
|
129
126
|
|
|
130
|
-
###
|
|
131
|
-
|
|
132
|
-
"**Proceeding to write configuration...**"
|
|
133
|
-
|
|
134
|
-
#### Menu Handling Logic:
|
|
135
|
-
|
|
136
|
-
- After ccc index check completes (or is skipped), immediately load, read entire file, then execute {nextStepFile}
|
|
137
|
-
|
|
138
|
-
#### EXECUTION RULES:
|
|
139
|
-
|
|
140
|
-
- This is an auto-proceed step with no user choices
|
|
141
|
-
- Proceed directly to next step after ccc index verification
|
|
142
|
-
|
|
143
|
-
## CRITICAL STEP COMPLETION NOTE
|
|
144
|
-
|
|
145
|
-
ONLY WHEN ccc index verification is complete (or step is skipped for ccc unavailable) will you load and read fully `{nextStepFile}` to execute the configuration write step.
|
|
127
|
+
### 5. Auto-Proceed
|
|
146
128
|
|
|
129
|
+
After ccc index verification is complete (or skipped because ccc is unavailable), display "**Proceeding to write configuration...**", then load `{nextStepFile}`, read it fully, and execute it.
|
|
@@ -1,123 +1,96 @@
|
|
|
1
1
|
---
|
|
2
2
|
nextStepFile: './step-03-auto-index.md'
|
|
3
|
+
# Resolve `{forgeTierRwHelper}` by probing `{forgeTierRwProbeOrder}` in order
|
|
4
|
+
# (installed SKF module path first, src/ dev-checkout fallback); first existing
|
|
5
|
+
# path wins. HALT if neither resolves — the script owns the canonical
|
|
6
|
+
# forge-tier.yaml format AND the array-preservation contract that protects
|
|
7
|
+
# qmd_collections / ccc_index_registry / staleness_threshold_hours from being
|
|
8
|
+
# lost on rewrite. NEVER fall back to inline YAML emission — drift between the
|
|
9
|
+
# script and a prose-rendered template will silently corrupt downstream skills.
|
|
10
|
+
forgeTierRwProbeOrder:
|
|
11
|
+
- '{project-root}/_bmad/skf/shared/scripts/skf-forge-tier-rw.py'
|
|
12
|
+
- '{project-root}/src/shared/scripts/skf-forge-tier-rw.py'
|
|
3
13
|
---
|
|
4
14
|
|
|
15
|
+
<!-- Config: communicate in {communication_language}. Halt-on-write-failure messages render in the user's language. -->
|
|
16
|
+
|
|
5
17
|
# Step 2: Write Configuration
|
|
6
18
|
|
|
7
19
|
## STEP GOAL:
|
|
8
20
|
|
|
9
|
-
Write the detected tool availability and calculated tier to forge-tier.yaml, create preferences.yaml with defaults if it does not exist, and ensure the forge-data
|
|
21
|
+
Write the detected tool availability and calculated tier to `forge-tier.yaml` (preserving registry arrays from any existing file), create `preferences.yaml` with first-run defaults if it does not exist, and ensure the `forge-data/` directory is present. All file mutations go through `{forgeTierRwHelper}` so the format is locked, atomic, and array-preservation is guaranteed.
|
|
10
22
|
|
|
11
23
|
## Rules
|
|
12
24
|
|
|
13
25
|
- Focus only on writing configuration files and creating directories
|
|
14
26
|
- Do not re-detect tools — use results from step-01
|
|
15
|
-
-
|
|
16
|
-
- File write failures are errors — report clearly
|
|
27
|
+
- Never inline a YAML template for forge-tier.yaml or preferences.yaml — the script owns the canonical format
|
|
28
|
+
- File write failures are errors — report clearly and halt the workflow
|
|
17
29
|
|
|
18
30
|
## MANDATORY SEQUENCE
|
|
19
31
|
|
|
20
|
-
**CRITICAL:** Follow this sequence exactly. Do not skip, reorder, or improvise.
|
|
21
|
-
|
|
22
32
|
### 1. Write forge-tier.yaml
|
|
23
33
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
status: {ccc_index_result from step-01b: "fresh"|"created"|"none"|"failed"}
|
|
49
|
-
staleness_threshold_hours: 24
|
|
50
|
-
file_count: {ccc_file_count from step-01b, or ~}
|
|
51
|
-
exclude_patterns: {ccc_exclude_patterns from step-01b, or []}
|
|
52
|
-
|
|
53
|
-
# CCC index registry (tracks which source paths have been indexed for skill workflows)
|
|
54
|
-
# PRESERVE existing entries on re-runs — see Note below
|
|
55
|
-
ccc_index_registry: {preserved from existing forge-tier.yaml, or [] if first run}
|
|
56
|
-
|
|
57
|
-
# QMD collection registry (populated by create-skill, consumed by audit/update-skill)
|
|
58
|
-
# PRESERVE existing entries on re-runs — see Note below
|
|
59
|
-
qmd_collections: {preserved from existing forge-tier.yaml, or [] if first run}
|
|
34
|
+
Build the JSON payload from context flags set by step-01 and step-01b. The payload must include `tools`, `tier`, and `ccc_index`; the script handles `tier_detected_at` defaulting to "now" if absent and preserves `qmd_collections`, `ccc_index_registry`, and a user-customized `ccc_index.staleness_threshold_hours` from any existing file.
|
|
35
|
+
|
|
36
|
+
Invoke via `uv run` so the script's PEP 723 PyYAML dependency resolves automatically (this is what `docs/getting-started.md`'s uv prereq exists for). Bare `python3` would fail on a fresh interpreter with `ModuleNotFoundError`.
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
echo '{
|
|
40
|
+
"tools": {
|
|
41
|
+
"ast_grep": {ast_grep},
|
|
42
|
+
"gh_cli": {gh_cli},
|
|
43
|
+
"qmd": {qmd},
|
|
44
|
+
"ccc": {ccc},
|
|
45
|
+
"ccc_daemon": {ccc_daemon},
|
|
46
|
+
"security_scan": {security_scan}
|
|
47
|
+
},
|
|
48
|
+
"tier": "{calculated_tier}",
|
|
49
|
+
"ccc_index": {
|
|
50
|
+
"indexed_path": {ccc_indexed_path},
|
|
51
|
+
"last_indexed": {ccc_last_indexed},
|
|
52
|
+
"status": "{ccc_index_result}",
|
|
53
|
+
"file_count": {ccc_file_count},
|
|
54
|
+
"exclude_patterns": {ccc_exclude_patterns}
|
|
55
|
+
}
|
|
56
|
+
}' | uv run {forgeTierRwHelper} write-tools \
|
|
57
|
+
--target "{project-root}/_bmad/_memory/forger-sidecar/forge-tier.yaml"
|
|
60
58
|
```
|
|
61
59
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
**This file is ALWAYS overwritten** on every run — it reflects current tool state.
|
|
65
|
-
|
|
66
|
-
If the write fails, report the error and halt the workflow.
|
|
60
|
+
The script atomically writes the file via temp + fsync + rename (mirrors `skf-atomic-write.py`'s crash-safety contract) and returns a JSON response with `wrote`, `preserved_arrays.qmd_collections` count, `preserved_arrays.ccc_index_registry` count, and the resolved `tier`.
|
|
67
61
|
|
|
68
|
-
|
|
62
|
+
**Parse the response and set context flags for step-04:**
|
|
69
63
|
|
|
70
|
-
|
|
64
|
+
- `{forge_tier_yaml_path}` ← `wrote`
|
|
65
|
+
- `{forge_tier_qmd_collections_count}` ← `preserved_arrays.qmd_collections`
|
|
66
|
+
- `{forge_tier_ccc_registry_count}` ← `preserved_arrays.ccc_index_registry`
|
|
71
67
|
|
|
72
|
-
**If
|
|
68
|
+
**If the script exits non-zero**: parse the stderr JSON `{"status":"error","message":...}`, set `{error: {phase: "step-02:write-tools", path: "{project-root}/_bmad/_memory/forger-sidecar/forge-tier.yaml", reason: <message>}}` for step-04's envelope, and halt the workflow before chaining to step-03.
|
|
73
69
|
|
|
74
|
-
|
|
75
|
-
# Ferris Sidecar: User Preferences
|
|
76
|
-
# Created by setup workflow on first run
|
|
77
|
-
# Edit this file to customize Ferris behavior
|
|
70
|
+
### 2. Initialize preferences.yaml
|
|
78
71
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
passive_context: true
|
|
72
|
+
```bash
|
|
73
|
+
uv run {forgeTierRwHelper} init-prefs \
|
|
74
|
+
--target "{project-root}/_bmad/_memory/forger-sidecar/preferences.yaml"
|
|
75
|
+
```
|
|
84
76
|
|
|
85
|
-
|
|
86
|
-
headless_mode: false
|
|
77
|
+
The script creates the file with first-run defaults (matching the prior inline template — `tier_override: ~`, `passive_context: true`, `headless_mode: false`, `compact_greeting: false`, plus reserved-for-future-use commented fields) IF the file does not exist. When the file already exists, the script refuses to overwrite (preserves user customization) and reports `wrote: false`.
|
|
87
78
|
|
|
88
|
-
|
|
89
|
-
compact_greeting: false
|
|
79
|
+
**Parse the response and set context flags for step-04:**
|
|
90
80
|
|
|
91
|
-
|
|
92
|
-
# output_language: ~
|
|
93
|
-
# skill_format_version: ~
|
|
94
|
-
# citation_style: ~
|
|
95
|
-
# confidence_display: ~
|
|
96
|
-
```
|
|
81
|
+
- `{preferences_yaml_created}` ← `wrote` (true on first run, false on re-run when the file pre-existed)
|
|
97
82
|
|
|
98
|
-
**If
|
|
83
|
+
**If the script exits non-zero**: same halt-and-report pattern as section 1, with `phase: "step-02:init-prefs"` and the matching path.
|
|
99
84
|
|
|
100
85
|
### 3. Ensure forge-data/ Directory
|
|
101
86
|
|
|
102
87
|
Check if `{forge_data_folder}` directory exists:
|
|
103
88
|
|
|
104
|
-
- If missing: create it
|
|
105
|
-
- If exists: skip silently
|
|
89
|
+
- If missing: create it. Store `{forge_data_dir_created: true}` in context.
|
|
90
|
+
- If exists: skip silently. Store `{forge_data_dir_created: false}` in context.
|
|
106
91
|
|
|
107
|
-
|
|
92
|
+
If the create fails (parent unwritable, disk full, permission denied), set `{error: {phase: "step-02:forge-data-dir", path: "{forge_data_folder}", reason: <error message>}}` for step-04's envelope and halt the workflow.
|
|
108
93
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
#### Menu Handling Logic:
|
|
112
|
-
|
|
113
|
-
- After all file operations complete successfully, immediately load, read entire file, then execute {nextStepFile}
|
|
114
|
-
|
|
115
|
-
#### EXECUTION RULES:
|
|
116
|
-
|
|
117
|
-
- This is an auto-proceed step with no user choices
|
|
118
|
-
- Proceed directly to next step after configuration is written
|
|
119
|
-
|
|
120
|
-
## CRITICAL STEP COMPLETION NOTE
|
|
121
|
-
|
|
122
|
-
ONLY WHEN forge-tier.yaml has been written successfully and preferences.yaml exists (created or pre-existing) will you load and read fully `{nextStepFile}` to execute the QMD hygiene step.
|
|
94
|
+
### 4. Auto-Proceed
|
|
123
95
|
|
|
96
|
+
After forge-tier.yaml has been written successfully and preferences.yaml exists (created or pre-existing), display "**Proceeding to QMD collection hygiene...**", then load `{nextStepFile}`, read it fully, and execute it.
|