bmad-module-skill-forge 1.1.0 → 1.2.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/troubleshooting.md +1 -1
- package/docs/why-skf.md +5 -4
- package/package.json +2 -2
- package/src/knowledge/ccc-bridge.md +1 -1
- 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-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-validate-frontmatter.py +9 -3
- package/src/skf-create-skill/steps-c/step-06-validate.md +1 -1
- 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/README.md
CHANGED
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
[](https://discord.gg/gk8jAdXWmj)
|
|
17
17
|
[](https://github.com/armelhbobdad/bmad-module-skill-forge/stargazers)
|
|
18
18
|
|
|
19
|
-
_Skill Forge analyzes your code repositories, documentation, and developer discourse to build verified instruction files for AI agents. Every instruction links back to a specific file
|
|
19
|
+
_Skill Forge analyzes your code repositories, documentation, and developer discourse to build verified instruction files for AI agents. Every instruction links back to its upstream — a specific `file:line` at a pinned commit when source is available, or a documentation URL when it isn't._
|
|
20
20
|
|
|
21
21
|
**If SKF fixes your agent's API guesses, give it a ⭐ — it helps others find this tool.**
|
|
22
22
|
**If it saved you an afternoon, [grab me a coffee ☕](https://buymeacoffee.com/armelhbobdad) — it helps me keep forging.**
|
|
@@ -94,7 +94,7 @@ A skeptical reader is probably already considering one of these alternatives:
|
|
|
94
94
|
|
|
95
95
|
| | **Skill Forge** | MCP doc servers | Hand-edited `.cursorrules` | awesome-\* lists |
|
|
96
96
|
| -------------------------- | ----------------------------------------- | ----------------- | -------------------------- | ---------------- |
|
|
97
|
-
| Reproducible from
|
|
97
|
+
| Reproducible from upstream | AST + pinned commit (or pinned doc URL) | varies; opaque | whatever you wrote | none |
|
|
98
98
|
| Version-pinned & immutable | yes — per-version directories | runtime-dependent | rots silently | no |
|
|
99
99
|
| Audit trail | `provenance-map.json` + test + evidence | depends on server | none | none |
|
|
100
100
|
| Runtime cost | zero (markdown + JSON) | a running process | zero | zero |
|
|
@@ -115,13 +115,15 @@ SKF extracts real function signatures, types, and patterns from code, docs, and
|
|
|
115
115
|
|
|
116
116
|
## Verifying a Skill
|
|
117
117
|
|
|
118
|
-
You can falsify any
|
|
118
|
+
You can falsify any citation in an SKF-compiled skill in under a minute:
|
|
119
119
|
|
|
120
120
|
1. **Open the skill's `provenance-map.json`** — find your symbol; read its `source_file` and `source_line`.
|
|
121
121
|
2. **Open the skill's `metadata.json`** — read `source_commit` and `source_repo`.
|
|
122
122
|
3. **Jump to the upstream repo at that commit**, open that file, find that line. The signature in `SKILL.md` should match the one you're reading.
|
|
123
123
|
|
|
124
|
-
|
|
124
|
+
For docs-only skills, the audit shape is the same — `provenance-map.json` still lists every symbol — but entries cite `[EXT:{url}]` instead of `file:line@SHA`, and step 3 becomes "open the doc URL and confirm the signature matches."
|
|
125
|
+
|
|
126
|
+
If it doesn't, that's a bug — open an issue and SKF will republish the skill with a fresh provenance map (a new commit SHA for source skills, a fresh fetch for docs-only). Falsifiability isn't a feature; it's the whole deal.
|
|
125
127
|
|
|
126
128
|
**Reference output: [oh-my-skills](https://github.com/armelhbobdad/oh-my-skills)** — four Deep-tier skills compiled by SKF (cocoindex, cognee, Storybook v10, uitripled), each shipping its full audit trail in-repo. Scores range from 99.0% to 99.49%. Every claim walks to an upstream line in under 60 seconds. Serves as both the worked example for this section and ongoing proof that the pipeline does what it says.
|
|
127
129
|
|
package/docs/_data/pinned.yaml
CHANGED
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
# Enforced two ways: (1) release.yaml bumps this line in the same commit
|
|
27
27
|
# as package.json + marketplace.json on every release; (2) validate-docs-drift.js
|
|
28
28
|
# cross-checks this value against package.json.version and fails on mismatch.
|
|
29
|
-
skf_version: "1.
|
|
29
|
+
skf_version: "1.2.0"
|
|
30
30
|
|
|
31
31
|
# Path to the oh-my-skills repo, resolved relative to this repo's root.
|
|
32
32
|
# Override at runtime with the OMS environment variable if oh-my-skills
|
package/docs/bmad-synergy.md
CHANGED
|
@@ -9,7 +9,7 @@ This page builds on BMAD concepts (BMM phases, TEA, modules). New to BMAD? Start
|
|
|
9
9
|
|
|
10
10
|
## Launcher Skills vs Content Skills
|
|
11
11
|
|
|
12
|
-
A BMAD project that also uses SKF ends up with two different kinds of `SKILL.md` files living in the same IDE skills directory. SKF supports
|
|
12
|
+
A BMAD project that also uses SKF ends up with two different kinds of `SKILL.md` files living in the same IDE skills directory. SKF supports 24 IDEs — Claude Code (`.claude/skills/`), Cursor (`.cursor/skills/`), GitHub Copilot (`.github/skills/`), Windsurf (`.windsurf/skills/`), Cline (`.cline/skills/`), Roo Code (`.roo/skills/`), Gemini CLI (`.gemini/skills/`), and 17 others — each with its own skill directory. See the [complete IDE → Context File mapping](https://github.com/armelhbobdad/bmad-module-skill-forge/blob/main/src/skf-export-skill/assets/managed-section-format.md) for the full list. They look similar. They are not the same thing. This is the single most durable point of confusion, so get it straight up front.
|
|
13
13
|
|
|
14
14
|
| | BMAD launcher skill | SKF content skill |
|
|
15
15
|
|---|---|---|
|
|
@@ -166,7 +166,7 @@ Beyond briefing, CIS and SKF don't overlap — CIS covers ideation, storytelling
|
|
|
166
166
|
|
|
167
167
|
## Delivery and Lifecycle in a BMAD Project
|
|
168
168
|
|
|
169
|
-
`@Ferris EX` is the **only workflow that introduces new skill context** into the three context files that serve all
|
|
169
|
+
`@Ferris EX` is the **only workflow that introduces new skill context** into the three context files that serve all 24 IDEs: `CLAUDE.md` (Claude Code), `.cursorrules` (Cursor), and `AGENTS.md` (the remaining 22 IDEs — GitHub Copilot, Windsurf, Cline, Roo Code, Gemini CLI, and others). Each IDE also has its own skill root directory where skill files are installed (e.g., `.windsurf/skills/`, `.roo/skills/`, `.gemini/skills/`). Create-skill and update-skill produce draft artifacts that never touch those files directly — nothing reaches an agent's passive context until it has been through the EX gate. See [Skill Model → Dual-Output Strategy](../skill-model/#dual-output-strategy) for the architectural rationale.
|
|
170
170
|
|
|
171
171
|
This matters specifically in a BMAD project: you may have multiple BMAD modules, each with its own launcher skills, plus SKF content skills, all trying to contribute context. The write-guard means only verified, tested SKF skills ever reach an agent's passive context — nothing half-baked sneaks in. `@Ferris EX` injects managed sections that coexist cleanly with whatever BMAD's installer wrote in the same files.
|
|
172
172
|
|
package/docs/getting-started.md
CHANGED
|
@@ -135,7 +135,7 @@ Analyzes your project's dependencies and generates a consolidated stack skill wi
|
|
|
135
135
|
|
|
136
136
|
## Common use cases
|
|
137
137
|
|
|
138
|
-
> **Looking for end-to-end examples?** See [Examples](../examples/) for
|
|
138
|
+
> **Looking for end-to-end examples?** See [Examples](../examples/) for thirteen real-world scenarios with full command transcripts — from Quick Skill under a minute, to brownfield onboarding, stack verification, release-prep drift remediation, and SaaS docs-only skills.
|
|
139
139
|
|
|
140
140
|
---
|
|
141
141
|
|
package/docs/troubleshooting.md
CHANGED
|
@@ -13,7 +13,7 @@ If something isn't working, start here. For general setup help see [Getting Star
|
|
|
13
13
|
|
|
14
14
|
If setup reports that ast-grep was not detected, install it to unlock the Forge tier: <https://ast-grep.github.io>. Re-run `@Ferris SF` afterward — your tier upgrades automatically.
|
|
15
15
|
|
|
16
|
-
### "No brief found"
|
|
16
|
+
### "No skill brief found"
|
|
17
17
|
|
|
18
18
|
Run `@Ferris BS` first to create a skill brief, or use `@Ferris QS` for brief-less generation. `CS` requires either a brief or a direct invocation with scope arguments.
|
|
19
19
|
|
package/docs/why-skf.md
CHANGED
|
@@ -3,7 +3,7 @@ title: Why Skill Forge?
|
|
|
3
3
|
description: The strategic case for SKF — the problem it solves, how it compares to alternatives, who it's for, and who it isn't.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
Skill Forge is the only AI-skills toolchain where every claim your agent reads
|
|
6
|
+
Skill Forge is the only AI-skills toolchain where every claim your agent reads points back to a real upstream location — a `file:line` at a pinned commit when source is available, or a documentation URL when it isn't. Not "sourced from training data." Not "retrieved from context." **Cited.** You can open the upstream repo (or the doc page) and see the function exists — in under a minute. That's the wedge. This page explains why it matters, how SKF compares to alternatives, and who it's for.
|
|
7
7
|
|
|
8
8
|
---
|
|
9
9
|
|
|
@@ -26,7 +26,7 @@ SKF treats this as a citation problem, not a model problem. If a skill claims `c
|
|
|
26
26
|
| RAG / context stuffing | Retrieves relevant code snippets | Returns fragments without synthesis — no coherent skill output |
|
|
27
27
|
| Manual authoring | High initial accuracy | Drifts as the source code changes, doesn't scale across dependencies |
|
|
28
28
|
| IDE built-in context (Copilot, Cursor) | Convenient, zero setup | Uses generic training data, not your project's specific integration patterns |
|
|
29
|
-
| **Skill Forge** | **Every instruction cites upstream `file:line`
|
|
29
|
+
| **Skill Forge** | **Every instruction cites upstream — `file:line@SHA` for source skills, doc URL for docs-only skills. Falsifiable in 60 seconds.** | **Coverage depends on which tools you've installed (Quick / Forge / Forge+ / Deep tiers).** |
|
|
30
30
|
|
|
31
31
|
</div>
|
|
32
32
|
|
|
@@ -40,6 +40,8 @@ Pick any symbol in any SKF-compiled skill. Three clicks:
|
|
|
40
40
|
2. Open the skill's `provenance-map.json` — find your symbol; it lists the file and line.
|
|
41
41
|
3. Visit the upstream repo at that commit and that line. The signature in the skill should match.
|
|
42
42
|
|
|
43
|
+
For docs-only skills, the audit shape is the same — `provenance-map.json` still lists every symbol — but entries cite `[EXT:{url}]` instead of `file:line@SHA`, and step 3 becomes "open the doc URL and confirm the signature matches."
|
|
44
|
+
|
|
43
45
|
If it doesn't, **that's a bug.** [Open an issue](https://github.com/armelhbobdad/bmad-module-skill-forge/issues/new/choose) and SKF republishes the skill with a new commit SHA and a new provenance map. No other AI-skills tool treats disagreement between claim and source as a defect. SKF does.
|
|
44
46
|
|
|
45
47
|
See the [Verifying a Skill](../verifying-a-skill/) page for the full three-step audit on real skills, the test reports that log *exactly* where coverage falls short, and the scoring formula behind the 80% pass threshold.
|
|
@@ -78,9 +80,8 @@ You're considering running SKF across a brownfield platform. You need to know ab
|
|
|
78
80
|
## Not for you if…
|
|
79
81
|
|
|
80
82
|
- You want docs that hand-hold through every happy path with screenshots and emojis. SKF is a citation machine, not a tutorial series.
|
|
81
|
-
- You need perfect coverage of every private implementation detail. SKF extracts public APIs; if you want internals, read the code directly.
|
|
82
83
|
- You don't have Node.js ≥ 22 and Python ≥ 3.10 installed. SKF is a Node/Python toolchain at its core.
|
|
83
|
-
- You
|
|
84
|
+
- You have neither source code nor published documentation for the target. SKF compiles from one or both — a source repo (citations as `file:line@SHA`) or doc URLs (citations as `[EXT:{url}]`). A vague description with no upstream artifact to cite isn't enough.
|
|
84
85
|
|
|
85
86
|
Everything else is downstream of one question: *are the instructions your AI reads provably true?* If yes, SKF isn't adding value. If you can't be sure, SKF is the tool.
|
|
86
87
|
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json.schemastore.org/package.json",
|
|
3
3
|
"name": "bmad-module-skill-forge",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.2.0",
|
|
5
5
|
"description": "BMAD module — Turn code and docs into instructions AI agents can actually follow. Progressive capability tiers (Quick/Forge/Forge+/Deep).",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"bmad",
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
"test:cli": "node test/test-cli-integration.js",
|
|
54
54
|
"test:install": "node test/test-installation-components.js",
|
|
55
55
|
"test:knowledge": "node test/test-knowledge-base.js",
|
|
56
|
-
"test:python": "uv run --with pytest --with pyyaml pytest test/test-compute-score-contract.py test/test-skf-preflight.py test/test-skf-skill-inventory.py test/test-skf-validate-output.py test/test-skf-validate-frontmatter.py test/test-skf-manifest-ops.py test/test-skf-rebuild-managed-sections.py test/test-skf-severity-classify.py test/test-skf-structural-diff.py -v",
|
|
56
|
+
"test:python": "uv run --with pytest --with pyyaml pytest test/test-compute-score-contract.py test/test-skf-preflight.py test/test-skf-skill-inventory.py test/test-skf-validate-output.py test/test-skf-validate-frontmatter.py test/test-skf-manifest-ops.py test/test-skf-rebuild-managed-sections.py test/test-skf-severity-classify.py test/test-skf-structural-diff.py test/test-skf-detect-tools.py test/test-skf-forge-tier-rw.py test/test-skf-emit-result-envelope.py test/test-skf-qmd-classify-collections.py test/test-skf-merge-ccc-exclusions.py -v",
|
|
57
57
|
"test:schemas": "node test/test-agent-schema.js",
|
|
58
58
|
"test:workflow": "node test/test-workflow-state.js",
|
|
59
59
|
"validate:refs": "node tools/validate-file-refs.js --strict",
|
|
@@ -48,7 +48,7 @@ Returns: list of `{file, score, snippet}` entries ranked by semantic relevance t
|
|
|
48
48
|
### `ccc_bridge.status()`
|
|
49
49
|
|
|
50
50
|
**Resolves to:** Two-step verification:
|
|
51
|
-
1. `ccc --help` — confirms binary exists (exit 0)
|
|
51
|
+
1. `ccc --help` — confirms binary exists (exit 0) AND output contains the `CocoIndex Code` identity marker (rejects unrelated `ccc`-named binaries shadowing PATH)
|
|
52
52
|
2. `ccc doctor` — confirms daemon is running, extracts version string, validates embedding model
|
|
53
53
|
|
|
54
54
|
**Usage context:** Called exclusively by setup step-01 during tool detection. Downstream workflows read the result from forge-tier.yaml — they do not re-verify.
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://github.com/armelhbobdad/bmad-module-skill-forge/src/shared/scripts/schemas/skf-setup-result-envelope.v1.json",
|
|
4
|
+
"title": "SKF_SETUP_RESULT_JSON envelope (v1)",
|
|
5
|
+
"description": "Single-line JSON document emitted by skf-setup step-04 §4 when {headless_mode} is true, prefixed with the literal 'SKF_SETUP_RESULT_JSON: '. Pipelines grep one line out of the workflow log without parsing ASCII-art and without racing the forge-tier.yaml writer. Schema added in PR #247, extended in PR #248 (header / outputs / failure modes), extended again in this PR with previous_tier / tier_changed / tools_added / tools_removed / error.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"additionalProperties": false,
|
|
8
|
+
"required": ["skf_setup"],
|
|
9
|
+
"properties": {
|
|
10
|
+
"skf_setup": {
|
|
11
|
+
"type": "object",
|
|
12
|
+
"additionalProperties": false,
|
|
13
|
+
"required": [
|
|
14
|
+
"tier",
|
|
15
|
+
"previous_tier",
|
|
16
|
+
"tier_changed",
|
|
17
|
+
"tools",
|
|
18
|
+
"tools_added",
|
|
19
|
+
"tools_removed",
|
|
20
|
+
"config_path",
|
|
21
|
+
"ccc_index",
|
|
22
|
+
"files_written",
|
|
23
|
+
"tier_override_active",
|
|
24
|
+
"tier_override_invalid",
|
|
25
|
+
"require_tier_satisfied",
|
|
26
|
+
"warnings",
|
|
27
|
+
"error"
|
|
28
|
+
],
|
|
29
|
+
"properties": {
|
|
30
|
+
"tier": {
|
|
31
|
+
"type": "string",
|
|
32
|
+
"enum": ["Quick", "Forge", "Forge+", "Deep"],
|
|
33
|
+
"description": "Active capability tier this run."
|
|
34
|
+
},
|
|
35
|
+
"previous_tier": {
|
|
36
|
+
"type": ["string", "null"],
|
|
37
|
+
"enum": ["Quick", "Forge", "Forge+", "Deep", null],
|
|
38
|
+
"description": "Tier read from the existing forge-tier.yaml at workflow start. Null on first runs."
|
|
39
|
+
},
|
|
40
|
+
"tier_changed": {
|
|
41
|
+
"type": "boolean",
|
|
42
|
+
"description": "True when previous_tier is non-null AND differs from tier. False on first runs and same-tier re-runs. Lets pipelines react to upgrades without re-reading forge-tier.yaml."
|
|
43
|
+
},
|
|
44
|
+
"tools": {
|
|
45
|
+
"type": "object",
|
|
46
|
+
"additionalProperties": false,
|
|
47
|
+
"required": ["ast_grep", "gh_cli", "qmd", "ccc"],
|
|
48
|
+
"properties": {
|
|
49
|
+
"ast_grep": { "type": "boolean" },
|
|
50
|
+
"gh_cli": { "type": "boolean" },
|
|
51
|
+
"qmd": { "type": "boolean" },
|
|
52
|
+
"ccc": { "type": "boolean" }
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
"tools_added": {
|
|
56
|
+
"type": "array",
|
|
57
|
+
"items": { "type": "string", "enum": ["ast_grep", "gh_cli", "qmd", "ccc"] },
|
|
58
|
+
"uniqueItems": true,
|
|
59
|
+
"description": "Tool keys with available=true that were NOT available in previous_tools. On first runs, equals the currently-detected tools."
|
|
60
|
+
},
|
|
61
|
+
"tools_removed": {
|
|
62
|
+
"type": "array",
|
|
63
|
+
"items": { "type": "string", "enum": ["ast_grep", "gh_cli", "qmd", "ccc"] },
|
|
64
|
+
"uniqueItems": true,
|
|
65
|
+
"description": "Tool keys that were available in previous_tools but are NOT available now."
|
|
66
|
+
},
|
|
67
|
+
"config_path": {
|
|
68
|
+
"type": "string",
|
|
69
|
+
"minLength": 1,
|
|
70
|
+
"description": "Absolute path to the forge-tier.yaml that this run wrote (or attempted to write — see error)."
|
|
71
|
+
},
|
|
72
|
+
"ccc_index": {
|
|
73
|
+
"type": "object",
|
|
74
|
+
"additionalProperties": false,
|
|
75
|
+
"required": ["status", "indexed_path", "file_count"],
|
|
76
|
+
"properties": {
|
|
77
|
+
"status": {
|
|
78
|
+
"type": "string",
|
|
79
|
+
"enum": ["fresh", "created", "failed", "none"]
|
|
80
|
+
},
|
|
81
|
+
"indexed_path": { "type": ["string", "null"] },
|
|
82
|
+
"file_count": { "type": ["integer", "null"], "minimum": 0 }
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
"files_written": {
|
|
86
|
+
"type": "array",
|
|
87
|
+
"items": {
|
|
88
|
+
"type": "string",
|
|
89
|
+
"enum": ["forge-tier.yaml", "preferences.yaml", "settings.yml", "ccc_index"]
|
|
90
|
+
},
|
|
91
|
+
"uniqueItems": true,
|
|
92
|
+
"description": "Files actually written this run. Empty array when a write failure halted the run before any file was written."
|
|
93
|
+
},
|
|
94
|
+
"tier_override_active": {
|
|
95
|
+
"type": "boolean",
|
|
96
|
+
"description": "True when a valid tier_override from preferences.yaml was applied."
|
|
97
|
+
},
|
|
98
|
+
"tier_override_invalid": {
|
|
99
|
+
"type": "boolean",
|
|
100
|
+
"description": "True when tier_override was set but did not match Quick|Forge|Forge+|Deep (case-sensitive). Detected tier was used as fallback."
|
|
101
|
+
},
|
|
102
|
+
"require_tier_satisfied": {
|
|
103
|
+
"type": ["boolean", "null"],
|
|
104
|
+
"description": "Null when --require-tier was not set. Otherwise true if the tool prerequisites of the requested tier are met (Deep does NOT subsume Forge+)."
|
|
105
|
+
},
|
|
106
|
+
"warnings": {
|
|
107
|
+
"type": "array",
|
|
108
|
+
"items": { "type": "string" },
|
|
109
|
+
"description": "Non-fatal anomalies surfaced during the run. May include tier_override_invalid, tier_override_unsafe, ccc_exclusion_warnings entries, ccc_registry_stale_removed entries, qmd_daemon_stopped, ccc_indexing_failed, etc. Empty when none."
|
|
110
|
+
},
|
|
111
|
+
"error": {
|
|
112
|
+
"oneOf": [
|
|
113
|
+
{ "type": "null" },
|
|
114
|
+
{
|
|
115
|
+
"type": "object",
|
|
116
|
+
"additionalProperties": false,
|
|
117
|
+
"required": ["phase", "path", "reason"],
|
|
118
|
+
"properties": {
|
|
119
|
+
"phase": {
|
|
120
|
+
"type": "string",
|
|
121
|
+
"minLength": 1,
|
|
122
|
+
"description": "Step or operation that failed (e.g. 'step-02-write-config:forge-tier.yaml')."
|
|
123
|
+
},
|
|
124
|
+
"path": { "type": "string", "minLength": 1, "description": "Absolute path of the file the failed operation targeted." },
|
|
125
|
+
"reason": { "type": "string", "minLength": 1, "description": "Human-readable error message." }
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
],
|
|
129
|
+
"description": "Null on success. Object describing the failure when forge-tier.yaml or preferences.yaml could not be written. Pipelines branch on error !== null for 'exit code 2' semantics."
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|