@garygentry/feature-forge 0.2.3 → 0.2.4
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/README.md +6 -1
- package/adapters/GENERATION-REPORT.md +5 -1
- package/adapters/claude/references/forge-config-schema.json +25 -3
- package/adapters/claude/references/pipeline-state-schema.json +3 -2
- package/adapters/claude/references/portable-root.md +2 -2
- package/adapters/claude/references/process-overview.md +10 -0
- package/adapters/claude/references/shared-conventions.md +14 -9
- package/adapters/claude/references/stage-exit-protocol.md +99 -0
- package/adapters/claude/scripts/epic-manifest.py +10 -0
- package/adapters/claude/scripts/forge-bootstrap.py +94 -16
- package/adapters/claude/scripts/forge-init.sh +7 -1
- package/adapters/claude/scripts/forge-session.py +175 -30
- package/adapters/claude/skills/forge/SKILL.md +28 -14
- package/adapters/claude/skills/forge-0-epic/SKILL.md +20 -15
- package/adapters/claude/skills/forge-0-epic/references/edit-mode.md +6 -4
- package/adapters/claude/skills/forge-0-epic/references/epic-manifest-subcommands.md +1 -1
- package/adapters/claude/skills/forge-1-prd/SKILL.md +14 -4
- package/adapters/claude/skills/forge-2-tech/SKILL.md +14 -3
- package/adapters/claude/skills/forge-3-specs/SKILL.md +14 -3
- package/adapters/claude/skills/forge-4-backlog/SKILL.md +16 -5
- package/adapters/claude/skills/forge-5-loop/SKILL.md +19 -21
- package/adapters/claude/skills/forge-5-loop/references/result-reporting.md +10 -5
- package/adapters/claude/skills/forge-6-docs/SKILL.md +6 -6
- package/adapters/claude/skills/forge-bootstrap/SKILL.md +4 -4
- package/adapters/claude/skills/forge-fix/SKILL.md +27 -6
- package/adapters/claude/skills/forge-guide/SKILL.md +179 -0
- package/adapters/claude/skills/forge-init/SKILL.md +28 -1
- package/adapters/claude/skills/forge-verify/SKILL.md +46 -15
- package/adapters/claude/skills/forge-verify/references/verification-checklists.md +1 -1
- package/adapters/codex/references/forge-config-schema.json +25 -3
- package/adapters/codex/references/pipeline-state-schema.json +3 -2
- package/adapters/codex/references/portable-root.md +2 -2
- package/adapters/codex/references/process-overview.md +10 -0
- package/adapters/codex/references/shared-conventions.md +14 -9
- package/adapters/codex/references/stage-exit-protocol.md +99 -0
- package/adapters/codex/scripts/epic-manifest.py +10 -0
- package/adapters/codex/scripts/forge-bootstrap.py +94 -16
- package/adapters/codex/scripts/forge-init.sh +7 -1
- package/adapters/codex/scripts/forge-session.py +175 -30
- package/adapters/codex/skills/forge/SKILL.md +33 -19
- package/adapters/codex/skills/forge-0-epic/SKILL.md +21 -16
- package/adapters/codex/skills/forge-0-epic/references/edit-mode.md +6 -4
- package/adapters/codex/skills/forge-0-epic/references/epic-manifest-subcommands.md +1 -1
- package/adapters/codex/skills/forge-1-prd/SKILL.md +14 -4
- package/adapters/codex/skills/forge-2-tech/SKILL.md +15 -4
- package/adapters/codex/skills/forge-3-specs/SKILL.md +14 -3
- package/adapters/codex/skills/forge-4-backlog/SKILL.md +16 -5
- package/adapters/codex/skills/forge-5-loop/SKILL.md +21 -23
- package/adapters/codex/skills/forge-5-loop/references/result-reporting.md +10 -5
- package/adapters/codex/skills/forge-6-docs/SKILL.md +6 -6
- package/adapters/codex/skills/forge-bootstrap/SKILL.md +4 -4
- package/adapters/codex/skills/forge-fix/SKILL.md +27 -6
- package/adapters/codex/skills/forge-guide/SKILL.md +188 -0
- package/adapters/codex/skills/forge-init/SKILL.md +28 -1
- package/adapters/codex/skills/forge-verify/SKILL.md +45 -14
- package/adapters/codex/skills/forge-verify/references/verification-checklists.md +1 -1
- package/adapters/copilot/references/forge-config-schema.json +25 -3
- package/adapters/copilot/references/pipeline-state-schema.json +3 -2
- package/adapters/copilot/references/portable-root.md +2 -2
- package/adapters/copilot/references/process-overview.md +10 -0
- package/adapters/copilot/references/shared-conventions.md +14 -9
- package/adapters/copilot/references/stage-exit-protocol.md +99 -0
- package/adapters/copilot/scripts/epic-manifest.py +10 -0
- package/adapters/copilot/scripts/forge-bootstrap.py +94 -16
- package/adapters/copilot/scripts/forge-init.sh +7 -1
- package/adapters/copilot/scripts/forge-session.py +175 -30
- package/adapters/copilot/skills/forge/forge.md +33 -19
- package/adapters/copilot/skills/forge-0-epic/forge-0-epic.md +21 -16
- package/adapters/copilot/skills/forge-0-epic/references/edit-mode.md +6 -4
- package/adapters/copilot/skills/forge-0-epic/references/epic-manifest-subcommands.md +1 -1
- package/adapters/copilot/skills/forge-1-prd/forge-1-prd.md +14 -4
- package/adapters/copilot/skills/forge-2-tech/forge-2-tech.md +15 -4
- package/adapters/copilot/skills/forge-3-specs/forge-3-specs.md +14 -3
- package/adapters/copilot/skills/forge-4-backlog/forge-4-backlog.md +16 -5
- package/adapters/copilot/skills/forge-5-loop/forge-5-loop.md +21 -23
- package/adapters/copilot/skills/forge-5-loop/references/result-reporting.md +10 -5
- package/adapters/copilot/skills/forge-6-docs/forge-6-docs.md +6 -6
- package/adapters/copilot/skills/forge-bootstrap/forge-bootstrap.md +4 -4
- package/adapters/copilot/skills/forge-fix/forge-fix.md +27 -6
- package/adapters/copilot/skills/forge-guide/forge-guide.md +188 -0
- package/adapters/copilot/skills/forge-init/forge-init.md +28 -1
- package/adapters/copilot/skills/forge-verify/forge-verify.md +45 -14
- package/adapters/copilot/skills/forge-verify/references/verification-checklists.md +1 -1
- package/adapters/cursor/references/forge-config-schema.json +25 -3
- package/adapters/cursor/references/pipeline-state-schema.json +3 -2
- package/adapters/cursor/references/portable-root.md +2 -2
- package/adapters/cursor/references/process-overview.md +10 -0
- package/adapters/cursor/references/shared-conventions.md +14 -9
- package/adapters/cursor/references/stage-exit-protocol.md +99 -0
- package/adapters/cursor/scripts/epic-manifest.py +10 -0
- package/adapters/cursor/scripts/forge-bootstrap.py +94 -16
- package/adapters/cursor/scripts/forge-init.sh +7 -1
- package/adapters/cursor/scripts/forge-session.py +175 -30
- package/adapters/cursor/skills/forge/forge.mdc +33 -19
- package/adapters/cursor/skills/forge-0-epic/forge-0-epic.mdc +21 -16
- package/adapters/cursor/skills/forge-0-epic/references/edit-mode.md +6 -4
- package/adapters/cursor/skills/forge-0-epic/references/epic-manifest-subcommands.md +1 -1
- package/adapters/cursor/skills/forge-1-prd/forge-1-prd.mdc +14 -4
- package/adapters/cursor/skills/forge-2-tech/forge-2-tech.mdc +15 -4
- package/adapters/cursor/skills/forge-3-specs/forge-3-specs.mdc +14 -3
- package/adapters/cursor/skills/forge-4-backlog/forge-4-backlog.mdc +16 -5
- package/adapters/cursor/skills/forge-5-loop/forge-5-loop.mdc +21 -23
- package/adapters/cursor/skills/forge-5-loop/references/result-reporting.md +10 -5
- package/adapters/cursor/skills/forge-6-docs/forge-6-docs.mdc +6 -6
- package/adapters/cursor/skills/forge-bootstrap/forge-bootstrap.mdc +4 -4
- package/adapters/cursor/skills/forge-fix/forge-fix.mdc +27 -6
- package/adapters/cursor/skills/forge-guide/forge-guide.mdc +189 -0
- package/adapters/cursor/skills/forge-init/forge-init.mdc +28 -1
- package/adapters/cursor/skills/forge-verify/forge-verify.mdc +45 -14
- package/adapters/cursor/skills/forge-verify/references/verification-checklists.md +1 -1
- package/adapters/gemini/gemini-extension.json +4 -0
- package/adapters/gemini/references/forge-config-schema.json +25 -3
- package/adapters/gemini/references/pipeline-state-schema.json +3 -2
- package/adapters/gemini/references/portable-root.md +2 -2
- package/adapters/gemini/references/process-overview.md +10 -0
- package/adapters/gemini/references/shared-conventions.md +14 -9
- package/adapters/gemini/references/stage-exit-protocol.md +99 -0
- package/adapters/gemini/scripts/epic-manifest.py +10 -0
- package/adapters/gemini/scripts/forge-bootstrap.py +94 -16
- package/adapters/gemini/scripts/forge-init.sh +7 -1
- package/adapters/gemini/scripts/forge-session.py +175 -30
- package/adapters/gemini/skills/forge/forge.md +33 -19
- package/adapters/gemini/skills/forge-0-epic/forge-0-epic.md +21 -16
- package/adapters/gemini/skills/forge-0-epic/references/edit-mode.md +6 -4
- package/adapters/gemini/skills/forge-0-epic/references/epic-manifest-subcommands.md +1 -1
- package/adapters/gemini/skills/forge-1-prd/forge-1-prd.md +14 -4
- package/adapters/gemini/skills/forge-2-tech/forge-2-tech.md +15 -4
- package/adapters/gemini/skills/forge-3-specs/forge-3-specs.md +14 -3
- package/adapters/gemini/skills/forge-4-backlog/forge-4-backlog.md +16 -5
- package/adapters/gemini/skills/forge-5-loop/forge-5-loop.md +21 -23
- package/adapters/gemini/skills/forge-5-loop/references/result-reporting.md +10 -5
- package/adapters/gemini/skills/forge-6-docs/forge-6-docs.md +6 -6
- package/adapters/gemini/skills/forge-bootstrap/forge-bootstrap.md +4 -4
- package/adapters/gemini/skills/forge-fix/forge-fix.md +27 -6
- package/adapters/gemini/skills/forge-guide/forge-guide.md +188 -0
- package/adapters/gemini/skills/forge-init/forge-init.md +28 -1
- package/adapters/gemini/skills/forge-verify/forge-verify.md +45 -14
- package/adapters/gemini/skills/forge-verify/references/verification-checklists.md +1 -1
- package/dist/apply.js +34 -8
- package/dist/cli.js +40 -4
- package/dist/fsutil.d.ts +0 -12
- package/dist/fsutil.js +10 -1
- package/dist/manifest.d.ts +1 -1
- package/dist/plan.js +22 -2
- package/dist/rauf.d.ts +4 -4
- package/dist/rauf.js +3 -3
- package/dist/report.js +1 -1
- package/dist/types.d.ts +1 -1
- package/package.json +1 -1
|
@@ -10,7 +10,7 @@ alwaysApply: false
|
|
|
10
10
|
Run the initialization script to create `forge.config.json` with default settings:
|
|
11
11
|
|
|
12
12
|
```bash
|
|
13
|
-
R="$(for d in "$HOME"/.claude/skills/feature-forge "$HOME"/.claude/plugins/*/feature-forge "$HOME"/.agents/skills/feature-forge ./.agents/skills/feature-forge; do [ -x "$d/scripts/forge-root.sh" ] && exec "$d/scripts/forge-root.sh"; done)"
|
|
13
|
+
R="$(bash -c 'for d in "$HOME"/.claude/skills/feature-forge "$HOME"/.claude/plugins/*/feature-forge "$HOME"/.agents/skills/feature-forge ./.agents/skills/feature-forge; do [ -x "$d/scripts/forge-root.sh" ] && exec "$d/scripts/forge-root.sh"; done')"
|
|
14
14
|
[ -n "$R" ] || { echo "feature-forge: cannot locate plugin root" >&2; exit 1; }
|
|
15
15
|
bash "$R/scripts/forge-init.sh"
|
|
16
16
|
```
|
|
@@ -27,9 +27,36 @@ After initialization, the config file will contain defaults for:
|
|
|
27
27
|
- `autoInvokeNextStage`: `true` (the navigator auto-starts the next stage after you confirm; set `false` to only print the command)
|
|
28
28
|
- `contextWindowTokens`: `null` (the navigator infers the context window; set to your model's window, e.g. `1000000` for a 1M-context model, for accurate context-usage advice)
|
|
29
29
|
- `contextWarnThreshold`: `0.7` (fraction of the window past which the navigator suggests a clean session)
|
|
30
|
+
- `autoVerify`: `false` (set `true` to run `forge-verify` automatically after each stage completes)
|
|
31
|
+
- `autoVerifyStages`: `{}` (per-stage overrides for `autoVerify`)
|
|
32
|
+
- `autoFix`: `false` (set `true` to chain `forge-fix` after an auto-verify finds issues)
|
|
30
33
|
|
|
31
34
|
If `forge.config.json` already exists, the script will not overwrite it.
|
|
32
35
|
|
|
36
|
+
## Offer auto-verify
|
|
37
|
+
|
|
38
|
+
The template writes `autoVerify: false`. After the config is created (and only when the script
|
|
39
|
+
actually created it — skip this if it reported the file already exists), offer to turn
|
|
40
|
+
auto-verify on, then write the choice back into `forge.config.json`.
|
|
41
|
+
|
|
42
|
+
If the host's question mechanism is available, ask exactly one question:
|
|
43
|
+
|
|
44
|
+
> **Enable auto-verify?** Verification runs in a clean-room subagent after each stage
|
|
45
|
+
> completes — it never needs a clear your session / start a fresh session and only returns a compact digest to your session.
|
|
46
|
+
> **Recommended: on.** (Change later by editing `autoVerify` in `forge.config.json`.)
|
|
47
|
+
|
|
48
|
+
Options: **Enable (recommended)** / **Leave off**.
|
|
49
|
+
|
|
50
|
+
- On **Enable**: patch `"autoVerify": false` → `"autoVerify": true` in the generated
|
|
51
|
+
`forge.config.json` in place, preserving formatting and every other key.
|
|
52
|
+
- On **Leave off**: leave the config as written (`autoVerify: false`).
|
|
53
|
+
|
|
54
|
+
If the host lacks a structured question tool but can still prompt the user (e.g. Codex asks in
|
|
55
|
+
plain text), use that — ask the one question directly and wait for the reply; it is the same
|
|
56
|
+
choice, just rendered differently. Only when the host has **no** way to ask at all (a fully
|
|
57
|
+
non-interactive / headless run) do you skip the prompt: leave `autoVerify: false` and print the
|
|
58
|
+
one-line note `Set "autoVerify": true in forge.config.json to verify automatically after each stage.`
|
|
59
|
+
|
|
33
60
|
After initialization, start the pipeline with `/feature-forge:forge-1-prd <feature-name>`.
|
|
34
61
|
|
|
35
62
|
---
|
|
@@ -48,7 +48,7 @@ Pick based on how many checks the mode carries (see the per-mode totals in Step
|
|
|
48
48
|
|
|
49
49
|
The verifier(s) are read-only — they return findings as their response; **you** (the
|
|
50
50
|
parent) assemble and write the single document to
|
|
51
|
-
`{
|
|
51
|
+
`{resolvedFeatureDir}/.verification/VERIFY-{mode}-{YYYY-MM-DD}.md`. When you fanned out:
|
|
52
52
|
1. Concatenate all instances' findings and **renumber `V-NNN` IDs uniquely** across the
|
|
53
53
|
merged set.
|
|
54
54
|
2. **Dedup** overlaps — when two instances flag the same file+location+issue (e.g. a
|
|
@@ -73,15 +73,39 @@ without subagents), fall back to running verification inline in the current sess
|
|
|
73
73
|
|
|
74
74
|
**Inline execution guidance:** If running inline (not as subagent), process verification checklists one category at a time to manage context pressure. Load only the artifacts needed for each category, verify, summarize findings, then move to the next category.
|
|
75
75
|
|
|
76
|
+
### Require-clean (`auto`) mode — unattended auto-verify
|
|
77
|
+
|
|
78
|
+
When the navigator auto-invokes this skill (its `autoVerify` path), it passes a
|
|
79
|
+
**require-clean** signal (e.g. args include `--require-clean`, or the invocation is
|
|
80
|
+
described as auto-verify). In this mode the clean-room guarantee is load-bearing: the
|
|
81
|
+
whole reason auto-verify is safe to run without a clear your session / start a fresh session is that the `forge-verifier`
|
|
82
|
+
subagent inherits none of the dispatching session's context. Running inline would break
|
|
83
|
+
that — it would consume the dispatching session's context and invalidate the no-clear
|
|
84
|
+
justification.
|
|
85
|
+
|
|
86
|
+
So in require-clean mode, **do NOT fall back to inline execution**. If the host's subagent mechanism
|
|
87
|
+
or `forge-verifier` subagent is not dispatchable, return a **sentinel** instead of doing
|
|
88
|
+
any work:
|
|
89
|
+
|
|
90
|
+
> `CLEAN_ROOM_UNAVAILABLE: forge-verifier subagent not dispatchable — verify not run.`
|
|
91
|
+
|
|
92
|
+
Do not analyze artifacts, do not write a findings document, and do not touch pipeline
|
|
93
|
+
state. The navigator detects this sentinel and degrades to its manual verify gate (Tier
|
|
94
|
+
2/3), so verify state stays outstanding and the stage is never marked verified on false
|
|
95
|
+
assurance. **Manual / interactive invocation** (the normal `/feature-forge:forge-verify`
|
|
96
|
+
path, no require-clean signal) keeps the inline fallback above unchanged.
|
|
97
|
+
|
|
76
98
|
## Prerequisites
|
|
77
99
|
|
|
78
100
|
Read and follow `references/shared-conventions.md` for feature name validation, configuration reading, and force mode handling before proceeding.
|
|
79
101
|
|
|
102
|
+
Resolve the feature directory via the **Feature Directory Resolution** block in `references/shared-conventions.md` (so a standalone feature resolves to its flat `{specsDir}/{feature}/` path exactly as today, and an epic member resolves to its nested `{specsDir}/{epic}/{feature}/` path). Use the resulting `{resolvedFeatureDir}` everywhere this skill reads or writes a per-feature artifact or state file — the `{specsDir}/{feature}/…` forms below are shorthand for the resolved path, not a literal flat layout. This does not apply to **epic mode**, whose paths are epic-scoped (`{specsDir}/{epic}/…`) by design.
|
|
103
|
+
|
|
80
104
|
**Turn structure reminder:** Output analysis/context as text, then route ALL questions through the host's question mechanism. Never embed questions in text output — the user will not be prompted and the session will stall.
|
|
81
105
|
|
|
82
106
|
## Step 1: Read Configuration and Determine Mode
|
|
83
107
|
|
|
84
|
-
Read `{
|
|
108
|
+
Read `{resolvedFeatureDir}/.pipeline-state.json` to understand current pipeline state.
|
|
85
109
|
|
|
86
110
|
### Mode Selection
|
|
87
111
|
|
|
@@ -101,16 +125,16 @@ If ambiguous, use the host's question mechanism to ask which stage to verify.
|
|
|
101
125
|
Load into context ALL artifacts for this feature based on mode:
|
|
102
126
|
|
|
103
127
|
**For prd mode:**
|
|
104
|
-
- `{
|
|
128
|
+
- `{resolvedFeatureDir}/PRD.md`
|
|
105
129
|
|
|
106
130
|
**For tech mode:**
|
|
107
|
-
- `{
|
|
108
|
-
- `{
|
|
131
|
+
- `{resolvedFeatureDir}/PRD.md`
|
|
132
|
+
- `{resolvedFeatureDir}/tech-spec.md`
|
|
109
133
|
|
|
110
134
|
**For specs mode:**
|
|
111
|
-
- `{
|
|
112
|
-
- `{
|
|
113
|
-
- `{
|
|
135
|
+
- `{resolvedFeatureDir}/PRD.md`
|
|
136
|
+
- `{resolvedFeatureDir}/tech-spec.md`
|
|
137
|
+
- `{resolvedFeatureDir}/##-*.md` (all implementation specs)
|
|
114
138
|
|
|
115
139
|
**For backlog mode:**
|
|
116
140
|
- All of the above, PLUS
|
|
@@ -151,7 +175,7 @@ Every finding must include:
|
|
|
151
175
|
|
|
152
176
|
## Step 4: Write Findings Document
|
|
153
177
|
|
|
154
|
-
Ensure the `.verification/` subdirectory exists, then write findings to `{
|
|
178
|
+
Ensure the `.verification/` subdirectory exists, then write findings to `{resolvedFeatureDir}/.verification/VERIFY-{mode}-{YYYY-MM-DD}.md`.
|
|
155
179
|
|
|
156
180
|
**For epic mode**, the target is `{specsDir}/{epic}/.verification/VERIFY-epic-{YYYY-MM-DD}.md` (the same format, with `{mode}=epic`).
|
|
157
181
|
|
|
@@ -187,9 +211,16 @@ Do NOT embed this question in your text output.
|
|
|
187
211
|
|
|
188
212
|
Write pipeline state conforming to `references/pipeline-state-schema.json`.
|
|
189
213
|
|
|
190
|
-
Update `{
|
|
191
|
-
- Set the relevant verify entry status to `findings-reported`
|
|
214
|
+
Update `{resolvedFeatureDir}/.pipeline-state.json`:
|
|
215
|
+
- Set the relevant verify entry status to `findings-reported` (or `passed` when there
|
|
216
|
+
are zero findings)
|
|
192
217
|
- Record `findingsFile`, `findingsCount`, `verifiedAt`
|
|
218
|
+
- Record `verifiedStageVersion` = the current `version` of the production stage entry
|
|
219
|
+
this verify covers (e.g. verifying `tech` → `stages["forge-2-tech"].version`). This
|
|
220
|
+
feeds the navigator's freshness ledger: a later revision to that artifact bumps its
|
|
221
|
+
`version`, so the recorded value no longer matches and auto-verify re-fires. Omitting
|
|
222
|
+
this leaves the verify looking stale (safe: the navigator re-verifies rather than
|
|
223
|
+
skips).
|
|
193
224
|
|
|
194
225
|
Do NOT mark as `findings-applied` — that happens after the fix pass.
|
|
195
226
|
|
|
@@ -214,13 +245,13 @@ Do NOT mark as `findings-applied` — that happens after the fix pass.
|
|
|
214
245
|
- Don't verify things that are intentionally left open (check the PRD's "Open Questions" section).
|
|
215
246
|
- If you find zero issues, say so honestly. Don't manufacture findings to seem thorough. But zero findings on a complex feature is suspicious — double-check.
|
|
216
247
|
- The findings document must be self-contained. A fresh agent reading it should be able to apply every fix without needing conversational context from this session.
|
|
217
|
-
- For backlog verification, also run the loop runner's validate command (resolve `loopRunner` from `forge.config.json`, default rauf: `rauf backlog validate . --backlog {backlogDir} --specs-dir {
|
|
248
|
+
- For backlog verification, also run the loop runner's validate command (resolve `loopRunner` from `forge.config.json`, default rauf: `rauf backlog validate . --backlog {backlogDir} --specs-dir {resolvedFeatureDir} --json`). Include any findings it reports (exit 1) as verification findings; if the runner isn't installed yet (command missing), note that backlog validation was skipped rather than failing.
|
|
218
249
|
- For specs verification, also run the deterministic traceability validator to supplement agent-driven traceability checks. Include any uncovered requirements or orphaned references as findings:
|
|
219
250
|
|
|
220
251
|
```bash
|
|
221
|
-
R="$(for d in "$HOME"/.claude/skills/feature-forge "$HOME"/.claude/plugins/*/feature-forge "$HOME"/.agents/skills/feature-forge ./.agents/skills/feature-forge; do [ -x "$d/scripts/forge-root.sh" ] && exec "$d/scripts/forge-root.sh"; done)"
|
|
252
|
+
R="$(bash -c 'for d in "$HOME"/.claude/skills/feature-forge "$HOME"/.claude/plugins/*/feature-forge "$HOME"/.agents/skills/feature-forge ./.agents/skills/feature-forge; do [ -x "$d/scripts/forge-root.sh" ] && exec "$d/scripts/forge-root.sh"; done')"
|
|
222
253
|
[ -n "$R" ] || { echo "feature-forge: cannot locate plugin root" >&2; exit 1; }
|
|
223
|
-
python3 "$R/scripts/validate-traceability.py" {
|
|
254
|
+
python3 "$R/scripts/validate-traceability.py" {resolvedFeatureDir}/PRD.md {resolvedFeatureDir}/ --json
|
|
224
255
|
```
|
|
225
256
|
|
|
226
257
|
---
|
|
@@ -192,7 +192,7 @@ findings to E01/E02/E03/E08. Then perform the judgment checks E04–E07 by readi
|
|
|
192
192
|
manifest, EPIC.md, and completed members' specs.
|
|
193
193
|
|
|
194
194
|
```bash
|
|
195
|
-
R="$(for d in "$HOME"/.claude/skills/feature-forge "$HOME"/.claude/plugins/*/feature-forge "$HOME"/.agents/skills/feature-forge ./.agents/skills/feature-forge; do [ -x "$d/scripts/forge-root.sh" ] && exec "$d/scripts/forge-root.sh"; done)"
|
|
195
|
+
R="$(bash -c 'for d in "$HOME"/.claude/skills/feature-forge "$HOME"/.claude/plugins/*/feature-forge "$HOME"/.agents/skills/feature-forge ./.agents/skills/feature-forge; do [ -x "$d/scripts/forge-root.sh" ] && exec "$d/scripts/forge-root.sh"; done')"
|
|
196
196
|
[ -n "$R" ] || { echo "feature-forge: cannot locate plugin root" >&2; exit 1; }
|
|
197
197
|
python3 "$R/scripts/epic-manifest.py" validate "{epic}" --specs-dir "{specsDir}" --json
|
|
198
198
|
```
|
|
@@ -42,6 +42,10 @@
|
|
|
42
42
|
"name": "forge-fix",
|
|
43
43
|
"description": "Apply fixes from the most recent forge-verify findings document. Use when user runs /feature-forge:forge-fix or asks to apply verification fixes for a forge feature. Do NOT trigger for general code fixes, bug fixes, or repairs outside the forge verification workflow."
|
|
44
44
|
},
|
|
45
|
+
{
|
|
46
|
+
"name": "forge-guide",
|
|
47
|
+
"description": "Explain what feature-forge is, when to use it, how to configure it, and its best practices — advisory guidance, not stage execution. Use when the user or another agent asks what feature-forge is, whether/when to adopt it, how the pipeline works conceptually, how to set up or configure forge.config.json, or for usage tips and best practices. Do NOT trigger to RUN a pipeline stage (use forge-1-prd … forge-6-docs), to show a specific feature's status (use forge), or for general software questions unrelated to feature-forge."
|
|
48
|
+
},
|
|
45
49
|
{
|
|
46
50
|
"name": "forge-init",
|
|
47
51
|
"description": "Initialize feature-forge configuration in the current project. Use when user runs /feature-forge:forge-init or asks to set up forge for the first time. Creates forge.config.json with defaults. Do NOT trigger for general project initialization or setup tasks outside the forge pipeline."
|
|
@@ -16,7 +16,8 @@
|
|
|
16
16
|
},
|
|
17
17
|
"backlogDir": {
|
|
18
18
|
"type": ["string", "null"],
|
|
19
|
-
"
|
|
19
|
+
"default": null,
|
|
20
|
+
"description": "Optional override for the backlog root. If set, the backlog is written to {backlogDir}/{feature}/backlog.json — the {feature} subdirectory is always composed in so multi-feature epics never collide. Default behavior (null): backlog.json is written to {specsDir}/{feature}/backlog.json with the feature specs."
|
|
20
21
|
},
|
|
21
22
|
"gitCommitAfterStage": {
|
|
22
23
|
"type": "boolean",
|
|
@@ -61,6 +62,27 @@
|
|
|
61
62
|
"default": true,
|
|
62
63
|
"description": "When true (default), the /feature-forge:forge navigator auto-invokes the next pipeline stage via the Skill tool after the user confirms it, instead of only printing the command to copy. Set false to keep the old copy-paste behavior (the navigator suggests the command but never launches it). Ignored on non-Claude hosts, which always fall back to printing the command."
|
|
63
64
|
},
|
|
65
|
+
"autoVerify": {
|
|
66
|
+
"type": "boolean",
|
|
67
|
+
"default": false,
|
|
68
|
+
"description": "When true, the /feature-forge:forge navigator automatically runs forge-verify after a stage completes, with no prompt. forge-verify runs in a fresh forge-verifier subagent (clean-room), so it never needs a context clear and costs the current session only a compact findings digest. Default false preserves today's manual-gate behavior. Ignored on non-Claude hosts, which always fall back to printing the verify command. Per-stage overrides in autoVerifyStages take precedence."
|
|
69
|
+
},
|
|
70
|
+
"autoVerifyStages": {
|
|
71
|
+
"type": "object",
|
|
72
|
+
"default": {},
|
|
73
|
+
"description": "Per-stage overrides for autoVerify. Maps a production stage id to a boolean; the effective value for a stage is autoVerifyStages[stage] if present, else autoVerify. Keys are constrained to the five verify-capable stages so a typo (e.g. 'forge-1-prod') is a schema error, not a silent no-op. forge-6-docs has no verify step and is not a valid key.",
|
|
74
|
+
"propertyNames": {
|
|
75
|
+
"enum": ["forge-1-prd", "forge-2-tech", "forge-3-specs", "forge-4-backlog", "forge-5-loop"]
|
|
76
|
+
},
|
|
77
|
+
"additionalProperties": {
|
|
78
|
+
"type": "boolean"
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
"autoFix": {
|
|
82
|
+
"type": "boolean",
|
|
83
|
+
"default": false,
|
|
84
|
+
"description": "When true, the navigator chains forge-fix automatically after an auto-verify that finds issues. Honored ONLY when auto-verify is effectively on for the stage, and ONLY when preconditions hold (findings doc has zero unresolved decision points, working tree is clean, and a mandatory re-verify passes) — otherwise it falls back to surfacing the findings digest and prompting. Default false keeps fixing human-gated."
|
|
85
|
+
},
|
|
64
86
|
"contextWindowTokens": {
|
|
65
87
|
"type": ["integer", "null"],
|
|
66
88
|
"default": null,
|
|
@@ -190,8 +212,8 @@
|
|
|
190
212
|
},
|
|
191
213
|
"installHint": {
|
|
192
214
|
"type": "string",
|
|
193
|
-
"default": "Provision rauf for a multi-agent setup with the cross-agent installer: `npx @garygentry/feature-forge install` (records the pinned @garygentry/rauf@0.
|
|
194
|
-
"description": "Shown when the runner BINARY is missing or too old (version gate fails, minRunnerVersion floor) — how to obtain/upgrade the CLI itself. Names two distinct binary-provisioning paths: (1) the cross-agent installer (`npx @garygentry/feature-forge install`, the multi-agent provisioning path that pins @garygentry/rauf@0.
|
|
215
|
+
"default": "Provision rauf for a multi-agent setup with the cross-agent installer: `npx @garygentry/feature-forge install` (records the pinned @garygentry/rauf@0.12.0 default). Or install/upgrade just the rauf CLI: `npx @garygentry/rauf@0.12.0 --version`, or `curl -fsSL https://raw.githubusercontent.com/garygentry/rauf/main/scripts/install-binary.sh | bash`.",
|
|
216
|
+
"description": "Shown when the runner BINARY is missing or too old (version gate fails, minRunnerVersion floor) — how to obtain/upgrade the CLI itself. Names two distinct binary-provisioning paths: (1) the cross-agent installer (`npx @garygentry/feature-forge install`, the multi-agent provisioning path that pins @garygentry/rauf@0.12.0), and (2) the direct rauf-CLI install/upgrade one-liner. Distinct from setupHint (which installs per-project artifacts); a version-gate failure is ALWAYS this hint, never setupHint."
|
|
195
217
|
},
|
|
196
218
|
"schemaVersion": {
|
|
197
219
|
"type": "string",
|
|
@@ -80,7 +80,7 @@
|
|
|
80
80
|
"completedAt": { "type": ["string", "null"], "format": "date-time" },
|
|
81
81
|
"commitHash": {
|
|
82
82
|
"type": ["string", "null"],
|
|
83
|
-
"description": "Git commit SHA
|
|
83
|
+
"description": "Git commit SHA of this stage's artifact commit (Commit 1 of the two-commit Git Commit Protocol in shared-conventions.md). Written by a small follow-up commit so it points at the artifact commit itself, never at an orphaned amend or the hash-recording commit. null until recorded (or when there was no new artifact commit)."
|
|
84
84
|
},
|
|
85
85
|
"basedOnVersions": {
|
|
86
86
|
"type": "object",
|
|
@@ -107,7 +107,8 @@
|
|
|
107
107
|
},
|
|
108
108
|
"verifiedAt": { "type": ["string", "null"], "format": "date-time" },
|
|
109
109
|
"fixedAt": { "type": ["string", "null"], "format": "date-time" },
|
|
110
|
-
"commitHash": { "type": ["string", "null"] }
|
|
110
|
+
"commitHash": { "type": ["string", "null"], "description": "Git commit SHA of the verify/fix artifact commit. Recorded via the two-commit Git Commit Protocol (shared-conventions.md) so it points at the artifact commit, never an orphaned amend." },
|
|
111
|
+
"verifiedStageVersion": { "type": ["integer", "null"], "description": "The production stage's `version` at the moment this verify was resolved. The navigator's freshness ledger compares it to the stage's current `version`: equal means the verify is fresh; a mismatch (artifact revised since) or an absent field (legacy state) means stale, so auto-verify re-fires. Recorded by forge-verify/forge-fix when writing a passed/findings-applied status." }
|
|
111
112
|
}
|
|
112
113
|
}
|
|
113
114
|
}
|
|
@@ -12,7 +12,7 @@ against the fenced block here, byte-for-byte.
|
|
|
12
12
|
## Canonical bootstrap prelude
|
|
13
13
|
|
|
14
14
|
```bash
|
|
15
|
-
R="$(for d in "$HOME"/.claude/skills/feature-forge "$HOME"/.claude/plugins/*/feature-forge "$HOME"/.agents/skills/feature-forge ./.agents/skills/feature-forge; do [ -x "$d/scripts/forge-root.sh" ] && exec "$d/scripts/forge-root.sh"; done)"
|
|
15
|
+
R="$(bash -c 'for d in "$HOME"/.claude/skills/feature-forge "$HOME"/.claude/plugins/*/feature-forge "$HOME"/.agents/skills/feature-forge ./.agents/skills/feature-forge; do [ -x "$d/scripts/forge-root.sh" ] && exec "$d/scripts/forge-root.sh"; done')"
|
|
16
16
|
[ -n "$R" ] || { echo "feature-forge: cannot locate plugin root" >&2; exit 1; }
|
|
17
17
|
```
|
|
18
18
|
|
|
@@ -24,7 +24,7 @@ makes several calls, add the prelude once and reuse `$R` for each. A fresh block
|
|
|
24
24
|
prelude (per-block re-resolution). Worked example:
|
|
25
25
|
|
|
26
26
|
```bash
|
|
27
|
-
R="$(for d in "$HOME"/.claude/skills/feature-forge "$HOME"/.claude/plugins/*/feature-forge "$HOME"/.agents/skills/feature-forge ./.agents/skills/feature-forge; do [ -x "$d/scripts/forge-root.sh" ] && exec "$d/scripts/forge-root.sh"; done)"
|
|
27
|
+
R="$(bash -c 'for d in "$HOME"/.claude/skills/feature-forge "$HOME"/.claude/plugins/*/feature-forge "$HOME"/.agents/skills/feature-forge ./.agents/skills/feature-forge; do [ -x "$d/scripts/forge-root.sh" ] && exec "$d/scripts/forge-root.sh"; done')"
|
|
28
28
|
[ -n "$R" ] || { echo "feature-forge: cannot locate plugin root" >&2; exit 1; }
|
|
29
29
|
python3 "$R/scripts/epic-manifest.py" render-status "{epic}" --specs-dir "{specsDir}" --json
|
|
30
30
|
```
|
|
@@ -36,6 +36,16 @@ The pipeline compiles a fuzzy feature idea into a machine-executable `backlog.js
|
|
|
36
36
|
**Output:** `{specsDir}/{feature}/.verification/VERIFY-<stage>-<timestamp>.md` (includes both findings and a Fix Execution Plan)
|
|
37
37
|
**Method:** Clean-context analysis producing actionable findings with an ordered fix plan.
|
|
38
38
|
|
|
39
|
+
**Manual or automatic.** By default the navigator offers verification after each stage. Because
|
|
40
|
+
it runs in a fresh, read-only subagent (clean-room by construction, never needs a `/clear`), it is
|
|
41
|
+
safe to automate: set `autoVerify: true` (or per-stage via `autoVerifyStages`) in
|
|
42
|
+
`forge.config.json` and the navigator runs `forge-verify` automatically once a stage completes,
|
|
43
|
+
returning only a compact digest to the session. The freshness ledger (verify entries record the
|
|
44
|
+
artifact `version` they ran against) means a stage is re-verified only when its artifact changes,
|
|
45
|
+
and an explicitly `skipped` verify is respected. Fixing stays human-gated unless `autoFix: true` is
|
|
46
|
+
also set, which chains `forge-fix` only when preconditions hold (zero unresolved decisions, clean
|
|
47
|
+
tree, passing re-verify). See `references/shared-conventions.md` for the config keys.
|
|
48
|
+
|
|
39
49
|
After verification, fixes can be applied via:
|
|
40
50
|
- `/feature-forge:forge-fix <feature>` — reads the Fix Execution Plan from the findings document and applies changes (works in any session)
|
|
41
51
|
- Plan mode workflow — enter plan mode, run verify, review plan, exit and execute
|
|
@@ -71,6 +71,9 @@ Extract these config values (use defaults if not present):
|
|
|
71
71
|
- `autoInvokeNextStage` (default: `true` — the `/feature-forge:forge` navigator auto-invokes the next stage via the `Skill` tool after the user confirms; `false` keeps copy-paste behavior. Navigator-only.)
|
|
72
72
|
- `contextWindowTokens` (default: `null` — context window used by the navigator's context-usage check; `null` infers from the session model and falls back to 200000. Set to the model's window, e.g. `1000000` on a 1M model. Navigator-only.)
|
|
73
73
|
- `contextWarnThreshold` (default: `0.7` — fraction of the window past which the navigator recommends a clean session. Navigator-only.)
|
|
74
|
+
- `autoVerify` (default: `false` — when `true`, the navigator auto-runs `forge-verify` after a stage completes, no prompt; runs in a fresh clean-room subagent so it never needs a `/clear` and costs only a compact digest. Navigator-only.)
|
|
75
|
+
- `autoVerifyStages` (default: `{}` — per-stage overrides for `autoVerify`, e.g. `{"forge-1-prd": false}`. Effective value = `autoVerifyStages[stage]` if present, else `autoVerify`. Keys are constrained to the five verify-capable stages; a typo is a config error surfaced as `invalidAutoVerifyKeys`. Navigator-only.)
|
|
76
|
+
- `autoFix` (default: `false` — when `true`, the navigator chains `forge-fix` after an auto-verify that finds issues, but only when auto-verify is on for that stage AND preconditions hold (zero unresolved decisions, clean tree, passing re-verify); otherwise it surfaces a digest and prompts. Navigator-only.)
|
|
74
77
|
- `loopRunner` (optional object — the loop runner to drive; **defaults to rauf** when absent, with every command templated. See `references/forge-config-schema.json` and `references/ralph-loop-contract.md`.)
|
|
75
78
|
|
|
76
79
|
## Feature Directory Resolution
|
|
@@ -78,7 +81,7 @@ Extract these config values (use defaults if not present):
|
|
|
78
81
|
Before any file I/O against a feature's artifacts, resolve its directory through the deterministic helper rather than hardcoding `{specsDir}/{feature}/`. This makes flat (`{specsDir}/{feature}/`) and nested (`{specsDir}/{epic}/{feature}/`) layouts both resolve from a bare feature name (REQ-DIR-03), with standalone features behaving exactly as today.
|
|
79
82
|
|
|
80
83
|
```bash
|
|
81
|
-
R="$(for d in "$HOME"/.claude/skills/feature-forge "$HOME"/.claude/plugins/*/feature-forge "$HOME"/.agents/skills/feature-forge ./.agents/skills/feature-forge; do [ -x "$d/scripts/forge-root.sh" ] && exec "$d/scripts/forge-root.sh"; done)"
|
|
84
|
+
R="$(bash -c 'for d in "$HOME"/.claude/skills/feature-forge "$HOME"/.claude/plugins/*/feature-forge "$HOME"/.agents/skills/feature-forge ./.agents/skills/feature-forge; do [ -x "$d/scripts/forge-root.sh" ] && exec "$d/scripts/forge-root.sh"; done')"
|
|
82
85
|
[ -n "$R" ] || { echo "feature-forge: cannot locate plugin root" >&2; exit 1; }
|
|
83
86
|
resolvedFeatureDir=$(python3 "$R/scripts/epic-manifest.py" \
|
|
84
87
|
resolve "<feature>" --specs-dir "<specsDir>")
|
|
@@ -108,7 +111,7 @@ Whenever a stage creates the specs tree for the first time (the first PRD or epi
|
|
|
108
111
|
Run this after creating the feature/epic directory, before the stage's git commit:
|
|
109
112
|
|
|
110
113
|
```bash
|
|
111
|
-
R="$(for d in "$HOME"/.claude/skills/feature-forge "$HOME"/.claude/plugins/*/feature-forge "$HOME"/.agents/skills/feature-forge ./.agents/skills/feature-forge; do [ -x "$d/scripts/forge-root.sh" ] && exec "$d/scripts/forge-root.sh"; done)"
|
|
114
|
+
R="$(bash -c 'for d in "$HOME"/.claude/skills/feature-forge "$HOME"/.claude/plugins/*/feature-forge "$HOME"/.agents/skills/feature-forge ./.agents/skills/feature-forge; do [ -x "$d/scripts/forge-root.sh" ] && exec "$d/scripts/forge-root.sh"; done')"
|
|
112
115
|
[ -n "$R" ] || { echo "feature-forge: cannot locate plugin root" >&2; exit 1; }
|
|
113
116
|
mkdir -p "<specsDir>"
|
|
114
117
|
[ -f "<specsDir>/AGENTS.md" ] || cp "$R/references/templates/specs-hygiene/AGENTS.md" "<specsDir>/AGENTS.md"
|
|
@@ -135,7 +138,7 @@ After resolving the feature directory, check the feature's `.pipeline-state.json
|
|
|
135
138
|
To obtain the manifest contracts and the live completion status of each dependency in one deterministic call, run `render-status` and read the per-feature `status` and the `consumes`/`exposes` arrays rather than re-deriving them:
|
|
136
139
|
|
|
137
140
|
```bash
|
|
138
|
-
R="$(for d in "$HOME"/.claude/skills/feature-forge "$HOME"/.claude/plugins/*/feature-forge "$HOME"/.agents/skills/feature-forge ./.agents/skills/feature-forge; do [ -x "$d/scripts/forge-root.sh" ] && exec "$d/scripts/forge-root.sh"; done)"
|
|
141
|
+
R="$(bash -c 'for d in "$HOME"/.claude/skills/feature-forge "$HOME"/.claude/plugins/*/feature-forge "$HOME"/.agents/skills/feature-forge ./.agents/skills/feature-forge; do [ -x "$d/scripts/forge-root.sh" ] && exec "$d/scripts/forge-root.sh"; done')"
|
|
139
142
|
[ -n "$R" ] || { echo "feature-forge: cannot locate plugin root" >&2; exit 1; }
|
|
140
143
|
python3 "$R/scripts/epic-manifest.py" \
|
|
141
144
|
render-status "<epic>" --specs-dir "<specsDir>" --json
|
|
@@ -180,16 +183,18 @@ Invoke this block at the **very start** of a pipeline entry point — `forge-1-p
|
|
|
180
183
|
|
|
181
184
|
## Git Commit Protocol
|
|
182
185
|
|
|
183
|
-
When `gitCommitAfterStage` is true, follow this exact order to avoid state inconsistency
|
|
186
|
+
When `gitCommitAfterStage` is true, follow this exact order to avoid state inconsistency.
|
|
187
|
+
|
|
188
|
+
**Why two commits.** The stage's `.pipeline-state.json` is itself part of the staged commit, but the stage's `commitHash` cannot be known until *after* that commit is made. Recording it *inside* the same commit is a chicken-and-egg with no single-commit solution. Resolve it with a **deterministic two-commit sequence**, and **never** with `git commit --amend`: amending rewrites HEAD, so a hash captured before the amend points at an orphaned commit that is not in the final history (the exact defect this protocol exists to prevent).
|
|
184
189
|
|
|
185
190
|
1. **Stage specific files only:** `git add {specsDir}/{feature}/` — never use `git add -A` or `git add .`
|
|
186
|
-
2. **
|
|
187
|
-
3. **If
|
|
188
|
-
4. **If
|
|
191
|
+
2. **Commit 1 — artifacts + state, hash not yet known:** In `.pipeline-state.json`, set this stage's `status: "complete"` and `commitHash: null`, then `git commit -m "{commitPrefix}({feature}): <action>"`. This is the stage's **artifact commit**; its hash is the provenance hash callers rely on.
|
|
192
|
+
3. **If Commit 1 succeeds — Commit 2 records the hash:** Capture the hash of Commit 1 (`git rev-parse HEAD`). Write it into this stage's `commitHash` in `.pipeline-state.json`, then commit only that one-line change: `git add {specsDir}/{feature}/.pipeline-state.json && git commit -m "{commitPrefix}({feature}): record stage commit hash"`. The stored `commitHash` now points at the artifact commit (Commit 1) — never at Commit 2, and never at an orphaned amend. The working tree is clean afterward, so the next stage's dirty-tree check passes.
|
|
193
|
+
4. **If Commit 1 fails:** do NOT update pipeline state to complete. Report the error to the user and leave state as `in-progress` so the stage can be resumed. Common failure causes:
|
|
189
194
|
- **Pre-commit hook failure:** Report the hook output. Never use `--no-verify` to bypass. Help the user fix the underlying issue.
|
|
190
195
|
- **Merge conflicts:** Report conflicting files. Suggest resolution steps appropriate to the conflict.
|
|
191
|
-
- **Nothing to commit:** If all artifacts were already committed, this is fine —
|
|
192
|
-
5. **Never** use `git add -A`, `--no-verify`, or `--force` flags
|
|
196
|
+
- **Nothing to commit:** If all artifacts were already committed, this is fine — mark the stage `complete`, leave `commitHash` at its existing value (or `null` if there was never an artifact commit), and skip Commit 2. There is no new artifact commit to record.
|
|
197
|
+
5. **Never** use `git add -A`, `--amend`, `--no-verify`, or `--force` flags
|
|
193
198
|
|
|
194
199
|
## Crash Recovery
|
|
195
200
|
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# Stage Exit Protocol
|
|
2
|
+
|
|
3
|
+
The single source of truth for how every forge **authoring** stage closes. It
|
|
4
|
+
replaces the old ad-hoc "Next steps:" bullet lists with one fixed, correctly-ordered
|
|
5
|
+
sequence: **verify (if missing or stale) → `/clear` → run the next command.**
|
|
6
|
+
|
|
7
|
+
Two principles this block encodes (do not relitigate — they are locked product
|
|
8
|
+
decisions):
|
|
9
|
+
|
|
10
|
+
1. **Clearing is recommended on its own merits at every stage boundary** — a clean
|
|
11
|
+
start for the next stage — *not* as a proxy for a full context window. Window
|
|
12
|
+
fullness only changes *how emphatically* the clear is recommended, never *whether*
|
|
13
|
+
it is.
|
|
14
|
+
2. **Verify happens before the clear, never after.** Verify's clean-room subagent is
|
|
15
|
+
dispatched from the *current* session, so the findings digest and any fix decision
|
|
16
|
+
land where the context to act on them still exists. Clearing first throws that
|
|
17
|
+
context away.
|
|
18
|
+
|
|
19
|
+
## How this file is used
|
|
20
|
+
|
|
21
|
+
The blocks below are **stamped verbatim** into each stage skill's closing (a runtime
|
|
22
|
+
`references/` include would not survive the adapter build, which flattens skills into
|
|
23
|
+
`adapters/<agent>/`). A drift-guard test (`tests/test_stage_exit_protocol.py`) asserts
|
|
24
|
+
each stamp site still contains its block, so an edit here must be mirrored into every
|
|
25
|
+
stamp site (and vice-versa).
|
|
26
|
+
|
|
27
|
+
Each stamp site fills three slots; everything else is identical across sites:
|
|
28
|
+
|
|
29
|
+
- `{stage}` — the just-completed stage as a lowercase noun phrase (e.g. `the PRD`,
|
|
30
|
+
`the tech spec`, `the backlog`). Always used mid-sentence, never sentence-initial.
|
|
31
|
+
- `{verify-command}` — the verify command for that stage (e.g.
|
|
32
|
+
`` `/feature-forge:forge-verify {feature}` ``).
|
|
33
|
+
- `{next-command}` — the command that starts the next stage (e.g.
|
|
34
|
+
`` `/feature-forge:forge-2-tech {feature}` ``).
|
|
35
|
+
|
|
36
|
+
`{feature}` / `{epic}` and similar remain runtime placeholders that pass through
|
|
37
|
+
untouched — they are resolved by the skill at run time, not by this template.
|
|
38
|
+
|
|
39
|
+
## Stamp sites
|
|
40
|
+
|
|
41
|
+
| Stamp site | Block | `{stage}` |
|
|
42
|
+
|---|---|---|
|
|
43
|
+
| `forge-0-epic` (epic → first PRD) | standard | the epic decomposition |
|
|
44
|
+
| `forge-1-prd` | standard | the PRD |
|
|
45
|
+
| `forge-2-tech` | standard | the tech spec |
|
|
46
|
+
| `forge-3-specs` | standard | the implementation specs |
|
|
47
|
+
| `forge-4-backlog` | standard | the backlog |
|
|
48
|
+
| `forge-5-loop` (step-6 epic-member handoff) | standard | feature `{feature}`'s loop |
|
|
49
|
+
| `forge-5-loop` (all-done closing → docs) | warm | — |
|
|
50
|
+
|
|
51
|
+
`forge-6-docs` is **terminal** — it stamps no exit block. It is the *target* of the
|
|
52
|
+
warm variant, not a stamp site.
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## Standard block
|
|
57
|
+
|
|
58
|
+
Stamp this at every authoring-stage boundary. It self-adapts: step 1's verify gate
|
|
59
|
+
only fires when verification is actually outstanding, so at a boundary where verify
|
|
60
|
+
already ran (or was explicitly skipped, or auto-verify is on) it silently collapses to
|
|
61
|
+
just the `/clear` → next-command steps.
|
|
62
|
+
|
|
63
|
+
<!-- BEGIN: standard-exit-block -->
|
|
64
|
+
**This stage is done — walk the user through the Stage Exit Protocol** before moving on. The order is fixed, and step 2 is something only the user can do:
|
|
65
|
+
|
|
66
|
+
1. **Verify {stage} first — if it isn't already verified.** When this stage has no fresh verification on record (`verifyState` is **missing or stale**) **and** `autoVerify` is off for it, verify **now, before clearing**. If verify already ran, is pending under auto-verify, or the stage was explicitly skipped, say so and go straight to step 2. Present the **Standard Verify Gate** using `AskUserQuestion` with exactly these three options — but only when the host has a question mechanism **and** the clean-room path is available (the `Agent` tool plus a dispatchable `forge-verifier` subagent):
|
|
67
|
+
- **Verify {stage} now** *(recommended)* — dispatch the clean-room `forge-verifier` subagent from this session in require-clean mode; the digest returns here so any fix decision keeps its context. One-time — it does **not** change config.
|
|
68
|
+
- **Verify now + enable auto-verify going forward** — verify now **and** patch `"autoVerify": true` into `forge.config.json` in place (preserve formatting and every other key) so future stages verify automatically, no prompt. This complements the `forge-init` opt-in. **Do not auto-commit this config change** — treat it like `notes`: a user-facing edit the user commits on their own cadence, never folded into a stage's artifact commit.
|
|
69
|
+
- **Skip for now** — go straight to `/clear` and the next command without verifying. Record this stage's verify status as `"skipped"` in pipeline state (mirroring the existing skip handling) **only** on an explicit skip — a skip does not go stale.
|
|
70
|
+
|
|
71
|
+
**Host / clean-room fallback (not a user-selectable option):** if the question mechanism, the `Agent` tool, or the `forge-verifier` subagent is unavailable, do **not** run clean-room — degrade to printing `{verify-command}` for the user to run inline/manually (mirroring `autoInvokeNextStage`), and offer the auto-verify enable as plain text only if a config write is possible.
|
|
72
|
+
2. **Then `/clear`.** Recommended **unconditionally** at this boundary for a clean start — independent of how full the context window is. Every artifact is on disk, so the work survives the clear. **I can't `/clear` for you — you have to run it yourself.**
|
|
73
|
+
3. **Then run `{next-command}`** in the fresh session — or re-run `/feature-forge:forge` to let the navigator resume from disk.
|
|
74
|
+
<!-- END: standard-exit-block -->
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## Warm-acceptable variant
|
|
79
|
+
|
|
80
|
+
Stamp this only at the `forge-5-loop → forge-6-docs` boundary (the all-done result
|
|
81
|
+
report). Here clearing is **optional**: the docs stage benefits from the still-warm
|
|
82
|
+
context of what the loop actually did, and impl-verify is already offered interactively
|
|
83
|
+
by the loop itself, so this block defers rather than re-presenting a gate.
|
|
84
|
+
|
|
85
|
+
> **Note — no literal `/clear` here.** The warm block lives in `result-reporting.md`, a
|
|
86
|
+
> skill-*own* reference that the adapter build copies **verbatim** (unlike skill bodies,
|
|
87
|
+
> it is not host-term translated), so a literal `/clear` would reach non-Claude adapters
|
|
88
|
+
> undegraded. The warm variant says "clearing is optional" anyway, so it is phrased
|
|
89
|
+
> host-neutrally without the token on purpose — do not reintroduce `/clear` here. (The
|
|
90
|
+
> standard block *does* use `/clear`; that is fine because every standard stamp site is a
|
|
91
|
+
> skill **body**, where `scripts/build-adapters.py` degrades it.)
|
|
92
|
+
|
|
93
|
+
<!-- BEGIN: warm-exit-block -->
|
|
94
|
+
**The loop is complete — this is the one boundary where clearing before the next stage is optional.**
|
|
95
|
+
|
|
96
|
+
1. **Verify is already offered above.** Impl-verify is offered interactively right after this report (Step 5b for a standalone feature, Step 6.1 for an epic member) — run it there rather than as a second gate. It runs clean-room, so it needs no fresh session.
|
|
97
|
+
2. **Clearing is optional here — warm is fine.** `forge-6-docs` benefits from the still-warm context of what the loop actually did, so continuing in this same session is the easy default. A cold start also works — every artifact is on disk — but there is no need to force it.
|
|
98
|
+
3. **Then run `{next-command}`** — in this warm session, or a fresh one if you prefer.
|
|
99
|
+
<!-- END: warm-exit-block -->
|
|
@@ -312,6 +312,16 @@ def atomic_write(path: Path, data: dict) -> None:
|
|
|
312
312
|
handle.flush()
|
|
313
313
|
os.fsync(handle.fileno())
|
|
314
314
|
os.replace(tmp_path, path)
|
|
315
|
+
# fsync the parent dir so the rename itself is durable on crash, not just
|
|
316
|
+
# the file bytes (best-effort — some filesystems reject O_RDONLY dir fsync).
|
|
317
|
+
try:
|
|
318
|
+
dir_fd = os.open(parent, os.O_RDONLY)
|
|
319
|
+
try:
|
|
320
|
+
os.fsync(dir_fd)
|
|
321
|
+
finally:
|
|
322
|
+
os.close(dir_fd)
|
|
323
|
+
except OSError:
|
|
324
|
+
pass
|
|
315
325
|
except OSError as exc:
|
|
316
326
|
tmp_path.unlink(missing_ok=True)
|
|
317
327
|
raise UsageError(f"atomic write to {path} failed: {exc}")
|