@garygentry/feature-forge 0.2.10 → 0.2.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/adapters/claude/.feature-forge-bundle.json +1 -1
  2. package/adapters/claude/references/shared-conventions.md +22 -8
  3. package/adapters/claude/skills/forge-0-epic/SKILL.md +2 -0
  4. package/adapters/claude/skills/forge-1-prd/SKILL.md +1 -1
  5. package/adapters/claude/skills/forge-2-tech/SKILL.md +2 -0
  6. package/adapters/claude/skills/forge-3-specs/SKILL.md +3 -1
  7. package/adapters/claude/skills/forge-4-backlog/SKILL.md +2 -0
  8. package/adapters/codex/.feature-forge-bundle.json +1 -1
  9. package/adapters/codex/references/shared-conventions.md +22 -8
  10. package/adapters/codex/skills/forge-0-epic/SKILL.md +2 -0
  11. package/adapters/codex/skills/forge-1-prd/SKILL.md +1 -1
  12. package/adapters/codex/skills/forge-2-tech/SKILL.md +2 -0
  13. package/adapters/codex/skills/forge-3-specs/SKILL.md +3 -1
  14. package/adapters/codex/skills/forge-4-backlog/SKILL.md +2 -0
  15. package/adapters/copilot/.feature-forge-bundle.json +1 -1
  16. package/adapters/copilot/references/shared-conventions.md +22 -8
  17. package/adapters/copilot/skills/forge-0-epic/forge-0-epic.md +2 -0
  18. package/adapters/copilot/skills/forge-1-prd/forge-1-prd.md +1 -1
  19. package/adapters/copilot/skills/forge-2-tech/forge-2-tech.md +2 -0
  20. package/adapters/copilot/skills/forge-3-specs/forge-3-specs.md +3 -1
  21. package/adapters/copilot/skills/forge-4-backlog/forge-4-backlog.md +2 -0
  22. package/adapters/cursor/.feature-forge-bundle.json +1 -1
  23. package/adapters/cursor/references/shared-conventions.md +22 -8
  24. package/adapters/cursor/skills/forge-0-epic/forge-0-epic.mdc +2 -0
  25. package/adapters/cursor/skills/forge-1-prd/forge-1-prd.mdc +1 -1
  26. package/adapters/cursor/skills/forge-2-tech/forge-2-tech.mdc +2 -0
  27. package/adapters/cursor/skills/forge-3-specs/forge-3-specs.mdc +3 -1
  28. package/adapters/cursor/skills/forge-4-backlog/forge-4-backlog.mdc +2 -0
  29. package/adapters/gemini/.feature-forge-bundle.json +1 -1
  30. package/adapters/gemini/gemini-extension.json +1 -1
  31. package/adapters/gemini/references/shared-conventions.md +22 -8
  32. package/adapters/gemini/skills/forge-0-epic/forge-0-epic.md +2 -0
  33. package/adapters/gemini/skills/forge-1-prd/forge-1-prd.md +1 -1
  34. package/adapters/gemini/skills/forge-2-tech/forge-2-tech.md +2 -0
  35. package/adapters/gemini/skills/forge-3-specs/forge-3-specs.md +3 -1
  36. package/adapters/gemini/skills/forge-4-backlog/forge-4-backlog.md +2 -0
  37. package/package.json +1 -1
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "feature-forge",
3
- "version": "0.12.5",
3
+ "version": "0.12.6",
4
4
  "agent": "claude",
5
5
  "generatedBy": "python3 scripts/build-adapters.py"
6
6
  }
@@ -226,17 +226,31 @@ When `gitCommitAfterStage` is true, follow this exact order to avoid state incon
226
226
  - **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.
227
227
  5. **Never** use `git add -A`, `--amend`, `--no-verify`, or `--force` flags
228
228
 
229
- ## Crash Recovery
229
+ ## Stage-Entry Guard
230
230
 
231
- When a skill detects that `currentStage` matches itself and the stage status is `in-progress`, a previous run was interrupted. Follow this recovery protocol:
231
+ Invoke this block at the **start of an authoring stage** (`forge-1-prd`..`forge-4-backlog`), **after** Feature Directory Resolution and **before** any interview or (re-)authoring. It prevents a re-entered stage — an injected skill body or a re-invoked `Skill` — from blindly re-running the interview over an in-progress or already-complete draft. `{stage}` is the invoking skill's id (e.g. `forge-2-tech`).
232
232
 
233
- 1. **Inventory existing artifacts:** List all files on disk in `{specsDir}/{feature}/` that this stage would produce
234
- 2. **Compare against state:** Check the `artifacts` array in the pipeline state for this stage — it tracks files written incrementally during the previous run
235
- 3. **Present options to user:** "This stage was interrupted. Found {N} artifacts from the previous run: {list}. Would you like to resume from where it left off, or restart the stage from scratch?"
236
- 4. **If resume:** Skip artifact generation for files that already exist and appear complete (non-empty, properly structured). Continue from the next unwritten artifact.
237
- 5. **If restart:** Proceed normally. The version number will increment.
233
+ **Read, then classify** this stage's entry in `{resolvedFeatureDir}/.pipeline-state.json` (`stages.{stage}.status`):
238
234
 
239
- **Incremental artifact tracking:** When a stage writes multiple files (e.g., forge-3-specs writing a suite of spec documents), update the `artifacts` array in `.pipeline-state.json` after writing each file — not just at stage completion. This ensures crash recovery knows exactly which files were successfully written.
235
+ 1. **Fresh** — no state file yet, or `stages.{stage}` is absent/`pending`. First run of this stage. Proceed to the **Entry Stamp** below, then author normally. No prompt.
236
+
237
+ 2. **Interrupted** (`status: "in-progress"`) — a previous run of THIS stage was interrupted before it committed (the exit commit is what flips it to `complete`, so `in-progress` on entry always means a crash/abandon). Do **not** silently re-author. Instead:
238
+ - **Inventory on-disk artifacts:** list the files this stage produces that already exist in `{resolvedFeatureDir}/` (e.g. `PRD.md`; `tech-spec.md`; the `##-*.md` suite + `TRACEABILITY.md`; `backlog.json`), and cross-check against the `stages.{stage}.artifacts` array (written incrementally during the previous run).
239
+ - **Gate via `AskUserQuestion`** (Decision Support protocol): present the inventory as text, then ask "This {stage} run was interrupted — {N} artifact(s) from the previous run are on disk: {list}. Resume the in-progress draft, or start a new version from scratch?" Options: **Resume (recommended)** — continue from the first artifact not yet written/complete, reusing the existing files; do **not** re-stamp or bump the version. · **Start a new version** — treat it as a fresh authoring pass (proceed to the Entry Stamp; the version increments at exit).
240
+ - Skip artifact regeneration for files that already exist and are complete (non-empty, properly structured); continue from the next unwritten artifact.
241
+
242
+ 3. **Re-authoring** (`status: "complete"` or `"stale"`) — a finished draft exists. Warn via `AskUserQuestion` before overwriting: "A completed {stage} artifact already exists for '{feature}' (v{n}{, marked stale}). Continuing will create a new version. Proceed?" On confirm, proceed to the Entry Stamp and author a new version (the version increments at exit, per that stage's Update-Pipeline-State step).
243
+
244
+ **Entry Stamp** (fresh, restart, and re-author paths — NOT the resume path). Before authoring, write to `{resolvedFeatureDir}/.pipeline-state.json` and update `updatedAt`:
245
+ - `stages.{stage}.status` → `"in-progress"`
246
+ - `stages.{stage}.startedAt` → current ISO-8601 UTC timestamp
247
+ - top-level `currentStage` → `"{stage}"` (where the pipeline IS, per O1)
248
+
249
+ This write is **left uncommitted**: it is staged and committed as part of this stage's existing exit commit (Git Commit Protocol), so no extra commit is needed at entry. If the run is interrupted after the stamp but before the exit commit, the marker survives on disk (uncommitted) and the next entry classifies as **Interrupted** — which is exactly the intent.
250
+
251
+ **Force Mode.** When `--force` is passed, skip the interactive gate: do not prompt for resume-vs-restart or the re-author warning. Treat entry as a fresh restart — apply the Entry Stamp and author. (`--force` already skips prerequisite checks; here it likewise bypasses the self-stage gate. Existing on-disk artifacts are still loaded per Force Mode.)
252
+
253
+ **Incremental artifact tracking:** When a stage writes multiple files (e.g. forge-3-specs writing a suite of spec documents), update the `stages.{stage}.artifacts` array in `.pipeline-state.json` after writing each file — not just at stage completion. This is what makes the Interrupted inventory above precise about which files were successfully written.
240
254
 
241
255
  ## Force Mode
242
256
 
@@ -69,6 +69,8 @@ Resolve the epic subtree path `{specsDir}/{epic}/` and decide which branch to ru
69
69
  - **NEW** (no `epic-manifest.json`) → **Creation branch** (Step C1 onward).
70
70
  - **EXISTS** → **Edit branch** (§ Edit Mode below).
71
71
 
72
+ This manifest-existence dispatch **is** forge-0-epic's stage-entry guard: a re-entry on an existing epic lands in Edit Mode (helper-mutated, re-validated) rather than re-running the creation interview, so the **Stage-Entry Guard** block used by `forge-1-prd`..`forge-4-backlog` does not apply here (an epic has no self `.pipeline-state.json` to stamp — it writes member states).
73
+
72
74
  3. **Pre-flight epic-name uniqueness (creation only).** Before composing anything for a NEW
73
75
  epic, confirm the epic name itself does not collide with any existing feature or epic:
74
76
 
@@ -20,7 +20,7 @@ Invoke the **Branch Setup** block in `references/shared-conventions.md` with `{l
20
20
 
21
21
  Set the working directory by invoking the **Feature Directory Resolution** block in `references/shared-conventions.md`, which yields `{resolvedFeatureDir}`. Note one PRD-specific caveat: at PRD time a brand-new standalone feature may have NO directory yet, so resolution is expected to fail `not-found` for a never-started standalone feature — in that case forge-1 creates `{specsDir}/{feature}/` as today. For an epic member the directory already exists (created empty by forge-0-epic with an `epic` back-pointer), so resolution succeeds and yields the nested path.
22
22
 
23
- If `.pipeline-state.json` exists for this feature and `forge-1-prd` is already marked complete, use `AskUserQuestion` to warn: "A PRD already exists for '{feature}'. Continuing will create a new version. Proceed?"
23
+ After resolution, invoke the **Stage-Entry Guard** block in `references/shared-conventions.md` with `{stage}` = `forge-1-prd`. It classifies re-entry (fresh / interrupted / re-authoring), runs the resume-vs-restart gate and the "create a new version?" warning as applicable, and applies the entry stamp on the authoring paths. For a brand-new standalone feature there is no state file yet, so the guard's **fresh** arm applies with nothing to prompt; the entry stamp lands when the state file is first created in Step 6.
24
24
 
25
25
  ## Step 2: Examine Existing Context
26
26
 
@@ -19,6 +19,8 @@ Read and follow `references/shared-conventions.md` for feature name validation,
19
19
 
20
20
  **Prerequisite check:** Read `{resolvedFeatureDir}/.pipeline-state.json`. If not in force mode and `forge-1-prd` is not `complete`, STOP and tell the user: "The PRD for '{feature}' isn't complete yet. Run `/feature-forge:forge-1-prd {feature}` first."
21
21
 
22
+ After the prerequisite check, invoke the **Stage-Entry Guard** block in `references/shared-conventions.md` with `{stage}` = `forge-2-tech` — it detects an interrupted or already-complete tech-spec, runs the resume/restart or new-version gate, and stamps `status: "in-progress"` + `startedAt` + `currentStage` before the research and interview.
23
+
22
24
  Read `{resolvedFeatureDir}/PRD.md` into context. This is your foundation — every technology decision must trace back to a PRD requirement.
23
25
 
24
26
  After reading the PRD, invoke the **Epic Context Injection** block in `references/shared-conventions.md`. It self-gates on the resolved feature's `epic` back-pointer: for a standalone feature it is a no-op; for an epic member it loads EPIC.md, this feature's charter, and the completed direct dependencies' specs into context before the research and interview.
@@ -21,6 +21,8 @@ Read and follow `references/shared-conventions.md` for feature name validation,
21
21
 
22
22
  **Prerequisite check:** Read `{resolvedFeatureDir}/.pipeline-state.json`. If not in force mode, both `forge-1-prd` and `forge-2-tech` must be `complete`. If not, STOP and tell the user which prerequisites are missing.
23
23
 
24
+ After the prerequisite check, invoke the **Stage-Entry Guard** block in `references/shared-conventions.md` with `{stage}` = `forge-3-specs`. Because this stage writes a suite incrementally, the guard's **interrupted** arm uses the `stages.forge-3-specs.artifacts` array (already updated after each spec file — Step 3) to resume from the first unwritten document rather than regenerating the whole suite.
25
+
24
26
  Read both `{resolvedFeatureDir}/PRD.md` and `{resolvedFeatureDir}/tech-spec.md` into context.
25
27
 
26
28
  After reading the PRD and tech spec, invoke the **Epic Context Injection** block in `references/shared-conventions.md`. It self-gates on the resolved feature's `epic` back-pointer: for a standalone feature it is a no-op; for an epic member it loads EPIC.md, this feature's charter, and the completed direct dependencies' specs into context before the spec suite is planned.
@@ -56,7 +58,7 @@ Feature-specific:
56
58
 
57
59
  **Then call `AskUserQuestion`** following the **Decision Support** protocol in `references/shared-conventions.md`: recommend this plan as the default (it's your evidence-backed read of the feature's complexity) and name the trade-off so the user can push back knowingly — more documents means finer separation of concerns but more to keep in sync; fewer means tighter docs but risks one document carrying multiple concerns. Lead with: "I recommend this plan. Add or remove any documents?" Note the guidance below — resist splitting a concern into a sub-50-line document.
58
60
 
59
- **Incremental artifact tracking:** After each spec document is written (by you or a writer subagent), immediately update the `artifacts` array in `.pipeline-state.json` with the new file path. This enables crash recovery if the session is interrupted mid-suite (see shared-conventions.md "Crash Recovery").
61
+ **Incremental artifact tracking:** After each spec document is written (by you or a writer subagent), immediately update the `artifacts` array in `.pipeline-state.json` with the new file path. This enables crash recovery if the session is interrupted mid-suite (see shared-conventions.md "Stage-Entry Guard").
60
62
 
61
63
  ## Step 4: Write the Spec Suite
62
64
 
@@ -39,6 +39,8 @@ Resolve the **loop runner** from the `loopRunner` block in `forge.config.json`,
39
39
 
40
40
  **Prerequisite check:** Read `{resolvedFeatureDir}/.pipeline-state.json`. If not in force mode, stages `forge-1-prd`, `forge-2-tech`, and `forge-3-specs` must all be `complete`. If not, STOP and tell the user which prerequisites are missing.
41
41
 
42
+ After the prerequisite check, invoke the **Stage-Entry Guard** block in `references/shared-conventions.md` with `{stage}` = `forge-4-backlog` — it detects an interrupted or complete `backlog.json`, runs the resume/restart or new-version gate, and stamps entry before Step 2 loads the specs. (The backlog is a single artifact, so "resume" means: reuse the existing `backlog.json` if the previous run wrote it, rather than re-authoring from scratch.)
43
+
42
44
  **Verification check.** Check whether the specs have been verified. If not, use `AskUserQuestion` to warn with the cost of skipping: "Specs haven't been verified yet. Recommended: run `/feature-forge:forge-verify {feature}` first — unverified specs can carry gaps or contradictions that get baked into backlog items and only surface mid-loop, where they're far more expensive to fix. Continue anyway?" Offer **Verify first (recommended)** · **Continue without verifying**.
43
45
 
44
46
  ## Step 2: Load All Specs
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "feature-forge",
3
- "version": "0.12.5",
3
+ "version": "0.12.6",
4
4
  "agent": "codex",
5
5
  "generatedBy": "python3 scripts/build-adapters.py"
6
6
  }
@@ -226,17 +226,31 @@ When `gitCommitAfterStage` is true, follow this exact order to avoid state incon
226
226
  - **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.
227
227
  5. **Never** use `git add -A`, `--amend`, `--no-verify`, or `--force` flags
228
228
 
229
- ## Crash Recovery
229
+ ## Stage-Entry Guard
230
230
 
231
- When a skill detects that `currentStage` matches itself and the stage status is `in-progress`, a previous run was interrupted. Follow this recovery protocol:
231
+ Invoke this block at the **start of an authoring stage** (`forge-1-prd`..`forge-4-backlog`), **after** Feature Directory Resolution and **before** any interview or (re-)authoring. It prevents a re-entered stage — an injected skill body or a re-invoked `Skill` — from blindly re-running the interview over an in-progress or already-complete draft. `{stage}` is the invoking skill's id (e.g. `forge-2-tech`).
232
232
 
233
- 1. **Inventory existing artifacts:** List all files on disk in `{specsDir}/{feature}/` that this stage would produce
234
- 2. **Compare against state:** Check the `artifacts` array in the pipeline state for this stage — it tracks files written incrementally during the previous run
235
- 3. **Present options to user:** "This stage was interrupted. Found {N} artifacts from the previous run: {list}. Would you like to resume from where it left off, or restart the stage from scratch?"
236
- 4. **If resume:** Skip artifact generation for files that already exist and appear complete (non-empty, properly structured). Continue from the next unwritten artifact.
237
- 5. **If restart:** Proceed normally. The version number will increment.
233
+ **Read, then classify** this stage's entry in `{resolvedFeatureDir}/.pipeline-state.json` (`stages.{stage}.status`):
238
234
 
239
- **Incremental artifact tracking:** When a stage writes multiple files (e.g., forge-3-specs writing a suite of spec documents), update the `artifacts` array in `.pipeline-state.json` after writing each file — not just at stage completion. This ensures crash recovery knows exactly which files were successfully written.
235
+ 1. **Fresh** — no state file yet, or `stages.{stage}` is absent/`pending`. First run of this stage. Proceed to the **Entry Stamp** below, then author normally. No prompt.
236
+
237
+ 2. **Interrupted** (`status: "in-progress"`) — a previous run of THIS stage was interrupted before it committed (the exit commit is what flips it to `complete`, so `in-progress` on entry always means a crash/abandon). Do **not** silently re-author. Instead:
238
+ - **Inventory on-disk artifacts:** list the files this stage produces that already exist in `{resolvedFeatureDir}/` (e.g. `PRD.md`; `tech-spec.md`; the `##-*.md` suite + `TRACEABILITY.md`; `backlog.json`), and cross-check against the `stages.{stage}.artifacts` array (written incrementally during the previous run).
239
+ - **Gate via `AskUserQuestion`** (Decision Support protocol): present the inventory as text, then ask "This {stage} run was interrupted — {N} artifact(s) from the previous run are on disk: {list}. Resume the in-progress draft, or start a new version from scratch?" Options: **Resume (recommended)** — continue from the first artifact not yet written/complete, reusing the existing files; do **not** re-stamp or bump the version. · **Start a new version** — treat it as a fresh authoring pass (proceed to the Entry Stamp; the version increments at exit).
240
+ - Skip artifact regeneration for files that already exist and are complete (non-empty, properly structured); continue from the next unwritten artifact.
241
+
242
+ 3. **Re-authoring** (`status: "complete"` or `"stale"`) — a finished draft exists. Warn via `AskUserQuestion` before overwriting: "A completed {stage} artifact already exists for '{feature}' (v{n}{, marked stale}). Continuing will create a new version. Proceed?" On confirm, proceed to the Entry Stamp and author a new version (the version increments at exit, per that stage's Update-Pipeline-State step).
243
+
244
+ **Entry Stamp** (fresh, restart, and re-author paths — NOT the resume path). Before authoring, write to `{resolvedFeatureDir}/.pipeline-state.json` and update `updatedAt`:
245
+ - `stages.{stage}.status` → `"in-progress"`
246
+ - `stages.{stage}.startedAt` → current ISO-8601 UTC timestamp
247
+ - top-level `currentStage` → `"{stage}"` (where the pipeline IS, per O1)
248
+
249
+ This write is **left uncommitted**: it is staged and committed as part of this stage's existing exit commit (Git Commit Protocol), so no extra commit is needed at entry. If the run is interrupted after the stamp but before the exit commit, the marker survives on disk (uncommitted) and the next entry classifies as **Interrupted** — which is exactly the intent.
250
+
251
+ **Force Mode.** When `--force` is passed, skip the interactive gate: do not prompt for resume-vs-restart or the re-author warning. Treat entry as a fresh restart — apply the Entry Stamp and author. (`--force` already skips prerequisite checks; here it likewise bypasses the self-stage gate. Existing on-disk artifacts are still loaded per Force Mode.)
252
+
253
+ **Incremental artifact tracking:** When a stage writes multiple files (e.g. forge-3-specs writing a suite of spec documents), update the `stages.{stage}.artifacts` array in `.pipeline-state.json` after writing each file — not just at stage completion. This is what makes the Interrupted inventory above precise about which files were successfully written.
240
254
 
241
255
  ## Force Mode
242
256
 
@@ -68,6 +68,8 @@ Resolve the epic subtree path `{specsDir}/{epic}/` and decide which branch to ru
68
68
  - **NEW** (no `epic-manifest.json`) → **Creation branch** (Step C1 onward).
69
69
  - **EXISTS** → **Edit branch** (§ Edit Mode below).
70
70
 
71
+ This manifest-existence dispatch **is** forge-0-epic's stage-entry guard: a re-entry on an existing epic lands in Edit Mode (helper-mutated, re-validated) rather than re-running the creation interview, so the **Stage-Entry Guard** block used by `forge-1-prd`..`forge-4-backlog` does not apply here (an epic has no self `.pipeline-state.json` to stamp — it writes member states).
72
+
71
73
  3. **Pre-flight epic-name uniqueness (creation only).** Before composing anything for a NEW
72
74
  epic, confirm the epic name itself does not collide with any existing feature or epic:
73
75
 
@@ -19,7 +19,7 @@ Invoke the **Branch Setup** block in `references/shared-conventions.md` with `{l
19
19
 
20
20
  Set the working directory by invoking the **Feature Directory Resolution** block in `references/shared-conventions.md`, which yields `{resolvedFeatureDir}`. Note one PRD-specific caveat: at PRD time a brand-new standalone feature may have NO directory yet, so resolution is expected to fail `not-found` for a never-started standalone feature — in that case forge-1 creates `{specsDir}/{feature}/` as today. For an epic member the directory already exists (created empty by forge-0-epic with an `epic` back-pointer), so resolution succeeds and yields the nested path.
21
21
 
22
- If `.pipeline-state.json` exists for this feature and `forge-1-prd` is already marked complete, use the host's question mechanism to warn: "A PRD already exists for '{feature}'. Continuing will create a new version. Proceed?"
22
+ After resolution, invoke the **Stage-Entry Guard** block in `references/shared-conventions.md` with `{stage}` = `forge-1-prd`. It classifies re-entry (fresh / interrupted / re-authoring), runs the resume-vs-restart gate and the "create a new version?" warning as applicable, and applies the entry stamp on the authoring paths. For a brand-new standalone feature there is no state file yet, so the guard's **fresh** arm applies with nothing to prompt; the entry stamp lands when the state file is first created in Step 6.
23
23
 
24
24
  ## Step 2: Examine Existing Context
25
25
 
@@ -18,6 +18,8 @@ Read and follow `references/shared-conventions.md` for feature name validation,
18
18
 
19
19
  **Prerequisite check:** Read `{resolvedFeatureDir}/.pipeline-state.json`. If not in force mode and `forge-1-prd` is not `complete`, STOP and tell the user: "The PRD for '{feature}' isn't complete yet. Run `/feature-forge:forge-1-prd {feature}` first."
20
20
 
21
+ After the prerequisite check, invoke the **Stage-Entry Guard** block in `references/shared-conventions.md` with `{stage}` = `forge-2-tech` — it detects an interrupted or already-complete tech-spec, runs the resume/restart or new-version gate, and stamps `status: "in-progress"` + `startedAt` + `currentStage` before the research and interview.
22
+
21
23
  Read `{resolvedFeatureDir}/PRD.md` into context. This is your foundation — every technology decision must trace back to a PRD requirement.
22
24
 
23
25
  After reading the PRD, invoke the **Epic Context Injection** block in `references/shared-conventions.md`. It self-gates on the resolved feature's `epic` back-pointer: for a standalone feature it is a no-op; for an epic member it loads EPIC.md, this feature's charter, and the completed direct dependencies' specs into context before the research and interview.
@@ -20,6 +20,8 @@ Read and follow `references/shared-conventions.md` for feature name validation,
20
20
 
21
21
  **Prerequisite check:** Read `{resolvedFeatureDir}/.pipeline-state.json`. If not in force mode, both `forge-1-prd` and `forge-2-tech` must be `complete`. If not, STOP and tell the user which prerequisites are missing.
22
22
 
23
+ After the prerequisite check, invoke the **Stage-Entry Guard** block in `references/shared-conventions.md` with `{stage}` = `forge-3-specs`. Because this stage writes a suite incrementally, the guard's **interrupted** arm uses the `stages.forge-3-specs.artifacts` array (already updated after each spec file — Step 3) to resume from the first unwritten document rather than regenerating the whole suite.
24
+
23
25
  Read both `{resolvedFeatureDir}/PRD.md` and `{resolvedFeatureDir}/tech-spec.md` into context.
24
26
 
25
27
  After reading the PRD and tech spec, invoke the **Epic Context Injection** block in `references/shared-conventions.md`. It self-gates on the resolved feature's `epic` back-pointer: for a standalone feature it is a no-op; for an epic member it loads EPIC.md, this feature's charter, and the completed direct dependencies' specs into context before the spec suite is planned.
@@ -55,7 +57,7 @@ Feature-specific:
55
57
 
56
58
  **Then call the host's question mechanism** following the **Decision Support** protocol in `references/shared-conventions.md`: recommend this plan as the default (it's your evidence-backed read of the feature's complexity) and name the trade-off so the user can push back knowingly — more documents means finer separation of concerns but more to keep in sync; fewer means tighter docs but risks one document carrying multiple concerns. Lead with: "I recommend this plan. Add or remove any documents?" Note the guidance below — resist splitting a concern into a sub-50-line document.
57
59
 
58
- **Incremental artifact tracking:** After each spec document is written (by you or a writer subagent), immediately update the `artifacts` array in `.pipeline-state.json` with the new file path. This enables crash recovery if the session is interrupted mid-suite (see shared-conventions.md "Crash Recovery").
60
+ **Incremental artifact tracking:** After each spec document is written (by you or a writer subagent), immediately update the `artifacts` array in `.pipeline-state.json` with the new file path. This enables crash recovery if the session is interrupted mid-suite (see shared-conventions.md "Stage-Entry Guard").
59
61
 
60
62
  ## Step 4: Write the Spec Suite
61
63
 
@@ -38,6 +38,8 @@ Resolve the **loop runner** from the `loopRunner` block in `forge.config.json`,
38
38
 
39
39
  **Prerequisite check:** Read `{resolvedFeatureDir}/.pipeline-state.json`. If not in force mode, stages `forge-1-prd`, `forge-2-tech`, and `forge-3-specs` must all be `complete`. If not, STOP and tell the user which prerequisites are missing.
40
40
 
41
+ After the prerequisite check, invoke the **Stage-Entry Guard** block in `references/shared-conventions.md` with `{stage}` = `forge-4-backlog` — it detects an interrupted or complete `backlog.json`, runs the resume/restart or new-version gate, and stamps entry before Step 2 loads the specs. (The backlog is a single artifact, so "resume" means: reuse the existing `backlog.json` if the previous run wrote it, rather than re-authoring from scratch.)
42
+
41
43
  **Verification check.** Check whether the specs have been verified. If not, use the host's question mechanism to warn with the cost of skipping: "Specs haven't been verified yet. Recommended: run `/feature-forge:forge-verify {feature}` first — unverified specs can carry gaps or contradictions that get baked into backlog items and only surface mid-loop, where they're far more expensive to fix. Continue anyway?" Offer **Verify first (recommended)** · **Continue without verifying**.
42
44
 
43
45
  ## Step 2: Load All Specs
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "feature-forge",
3
- "version": "0.12.5",
3
+ "version": "0.12.6",
4
4
  "agent": "copilot",
5
5
  "generatedBy": "python3 scripts/build-adapters.py"
6
6
  }
@@ -226,17 +226,31 @@ When `gitCommitAfterStage` is true, follow this exact order to avoid state incon
226
226
  - **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.
227
227
  5. **Never** use `git add -A`, `--amend`, `--no-verify`, or `--force` flags
228
228
 
229
- ## Crash Recovery
229
+ ## Stage-Entry Guard
230
230
 
231
- When a skill detects that `currentStage` matches itself and the stage status is `in-progress`, a previous run was interrupted. Follow this recovery protocol:
231
+ Invoke this block at the **start of an authoring stage** (`forge-1-prd`..`forge-4-backlog`), **after** Feature Directory Resolution and **before** any interview or (re-)authoring. It prevents a re-entered stage — an injected skill body or a re-invoked `Skill` — from blindly re-running the interview over an in-progress or already-complete draft. `{stage}` is the invoking skill's id (e.g. `forge-2-tech`).
232
232
 
233
- 1. **Inventory existing artifacts:** List all files on disk in `{specsDir}/{feature}/` that this stage would produce
234
- 2. **Compare against state:** Check the `artifacts` array in the pipeline state for this stage — it tracks files written incrementally during the previous run
235
- 3. **Present options to user:** "This stage was interrupted. Found {N} artifacts from the previous run: {list}. Would you like to resume from where it left off, or restart the stage from scratch?"
236
- 4. **If resume:** Skip artifact generation for files that already exist and appear complete (non-empty, properly structured). Continue from the next unwritten artifact.
237
- 5. **If restart:** Proceed normally. The version number will increment.
233
+ **Read, then classify** this stage's entry in `{resolvedFeatureDir}/.pipeline-state.json` (`stages.{stage}.status`):
238
234
 
239
- **Incremental artifact tracking:** When a stage writes multiple files (e.g., forge-3-specs writing a suite of spec documents), update the `artifacts` array in `.pipeline-state.json` after writing each file — not just at stage completion. This ensures crash recovery knows exactly which files were successfully written.
235
+ 1. **Fresh** — no state file yet, or `stages.{stage}` is absent/`pending`. First run of this stage. Proceed to the **Entry Stamp** below, then author normally. No prompt.
236
+
237
+ 2. **Interrupted** (`status: "in-progress"`) — a previous run of THIS stage was interrupted before it committed (the exit commit is what flips it to `complete`, so `in-progress` on entry always means a crash/abandon). Do **not** silently re-author. Instead:
238
+ - **Inventory on-disk artifacts:** list the files this stage produces that already exist in `{resolvedFeatureDir}/` (e.g. `PRD.md`; `tech-spec.md`; the `##-*.md` suite + `TRACEABILITY.md`; `backlog.json`), and cross-check against the `stages.{stage}.artifacts` array (written incrementally during the previous run).
239
+ - **Gate via `AskUserQuestion`** (Decision Support protocol): present the inventory as text, then ask "This {stage} run was interrupted — {N} artifact(s) from the previous run are on disk: {list}. Resume the in-progress draft, or start a new version from scratch?" Options: **Resume (recommended)** — continue from the first artifact not yet written/complete, reusing the existing files; do **not** re-stamp or bump the version. · **Start a new version** — treat it as a fresh authoring pass (proceed to the Entry Stamp; the version increments at exit).
240
+ - Skip artifact regeneration for files that already exist and are complete (non-empty, properly structured); continue from the next unwritten artifact.
241
+
242
+ 3. **Re-authoring** (`status: "complete"` or `"stale"`) — a finished draft exists. Warn via `AskUserQuestion` before overwriting: "A completed {stage} artifact already exists for '{feature}' (v{n}{, marked stale}). Continuing will create a new version. Proceed?" On confirm, proceed to the Entry Stamp and author a new version (the version increments at exit, per that stage's Update-Pipeline-State step).
243
+
244
+ **Entry Stamp** (fresh, restart, and re-author paths — NOT the resume path). Before authoring, write to `{resolvedFeatureDir}/.pipeline-state.json` and update `updatedAt`:
245
+ - `stages.{stage}.status` → `"in-progress"`
246
+ - `stages.{stage}.startedAt` → current ISO-8601 UTC timestamp
247
+ - top-level `currentStage` → `"{stage}"` (where the pipeline IS, per O1)
248
+
249
+ This write is **left uncommitted**: it is staged and committed as part of this stage's existing exit commit (Git Commit Protocol), so no extra commit is needed at entry. If the run is interrupted after the stamp but before the exit commit, the marker survives on disk (uncommitted) and the next entry classifies as **Interrupted** — which is exactly the intent.
250
+
251
+ **Force Mode.** When `--force` is passed, skip the interactive gate: do not prompt for resume-vs-restart or the re-author warning. Treat entry as a fresh restart — apply the Entry Stamp and author. (`--force` already skips prerequisite checks; here it likewise bypasses the self-stage gate. Existing on-disk artifacts are still loaded per Force Mode.)
252
+
253
+ **Incremental artifact tracking:** When a stage writes multiple files (e.g. forge-3-specs writing a suite of spec documents), update the `stages.{stage}.artifacts` array in `.pipeline-state.json` after writing each file — not just at stage completion. This is what makes the Interrupted inventory above precise about which files were successfully written.
240
254
 
241
255
  ## Force Mode
242
256
 
@@ -68,6 +68,8 @@ Resolve the epic subtree path `{specsDir}/{epic}/` and decide which branch to ru
68
68
  - **NEW** (no `epic-manifest.json`) → **Creation branch** (Step C1 onward).
69
69
  - **EXISTS** → **Edit branch** (§ Edit Mode below).
70
70
 
71
+ This manifest-existence dispatch **is** forge-0-epic's stage-entry guard: a re-entry on an existing epic lands in Edit Mode (helper-mutated, re-validated) rather than re-running the creation interview, so the **Stage-Entry Guard** block used by `forge-1-prd`..`forge-4-backlog` does not apply here (an epic has no self `.pipeline-state.json` to stamp — it writes member states).
72
+
71
73
  3. **Pre-flight epic-name uniqueness (creation only).** Before composing anything for a NEW
72
74
  epic, confirm the epic name itself does not collide with any existing feature or epic:
73
75
 
@@ -19,7 +19,7 @@ Invoke the **Branch Setup** block in `references/shared-conventions.md` with `{l
19
19
 
20
20
  Set the working directory by invoking the **Feature Directory Resolution** block in `references/shared-conventions.md`, which yields `{resolvedFeatureDir}`. Note one PRD-specific caveat: at PRD time a brand-new standalone feature may have NO directory yet, so resolution is expected to fail `not-found` for a never-started standalone feature — in that case forge-1 creates `{specsDir}/{feature}/` as today. For an epic member the directory already exists (created empty by forge-0-epic with an `epic` back-pointer), so resolution succeeds and yields the nested path.
21
21
 
22
- If `.pipeline-state.json` exists for this feature and `forge-1-prd` is already marked complete, use the host's question mechanism to warn: "A PRD already exists for '{feature}'. Continuing will create a new version. Proceed?"
22
+ After resolution, invoke the **Stage-Entry Guard** block in `references/shared-conventions.md` with `{stage}` = `forge-1-prd`. It classifies re-entry (fresh / interrupted / re-authoring), runs the resume-vs-restart gate and the "create a new version?" warning as applicable, and applies the entry stamp on the authoring paths. For a brand-new standalone feature there is no state file yet, so the guard's **fresh** arm applies with nothing to prompt; the entry stamp lands when the state file is first created in Step 6.
23
23
 
24
24
  ## Step 2: Examine Existing Context
25
25
 
@@ -18,6 +18,8 @@ Read and follow `references/shared-conventions.md` for feature name validation,
18
18
 
19
19
  **Prerequisite check:** Read `{resolvedFeatureDir}/.pipeline-state.json`. If not in force mode and `forge-1-prd` is not `complete`, STOP and tell the user: "The PRD for '{feature}' isn't complete yet. Run `/feature-forge:forge-1-prd {feature}` first."
20
20
 
21
+ After the prerequisite check, invoke the **Stage-Entry Guard** block in `references/shared-conventions.md` with `{stage}` = `forge-2-tech` — it detects an interrupted or already-complete tech-spec, runs the resume/restart or new-version gate, and stamps `status: "in-progress"` + `startedAt` + `currentStage` before the research and interview.
22
+
21
23
  Read `{resolvedFeatureDir}/PRD.md` into context. This is your foundation — every technology decision must trace back to a PRD requirement.
22
24
 
23
25
  After reading the PRD, invoke the **Epic Context Injection** block in `references/shared-conventions.md`. It self-gates on the resolved feature's `epic` back-pointer: for a standalone feature it is a no-op; for an epic member it loads EPIC.md, this feature's charter, and the completed direct dependencies' specs into context before the research and interview.
@@ -20,6 +20,8 @@ Read and follow `references/shared-conventions.md` for feature name validation,
20
20
 
21
21
  **Prerequisite check:** Read `{resolvedFeatureDir}/.pipeline-state.json`. If not in force mode, both `forge-1-prd` and `forge-2-tech` must be `complete`. If not, STOP and tell the user which prerequisites are missing.
22
22
 
23
+ After the prerequisite check, invoke the **Stage-Entry Guard** block in `references/shared-conventions.md` with `{stage}` = `forge-3-specs`. Because this stage writes a suite incrementally, the guard's **interrupted** arm uses the `stages.forge-3-specs.artifacts` array (already updated after each spec file — Step 3) to resume from the first unwritten document rather than regenerating the whole suite.
24
+
23
25
  Read both `{resolvedFeatureDir}/PRD.md` and `{resolvedFeatureDir}/tech-spec.md` into context.
24
26
 
25
27
  After reading the PRD and tech spec, invoke the **Epic Context Injection** block in `references/shared-conventions.md`. It self-gates on the resolved feature's `epic` back-pointer: for a standalone feature it is a no-op; for an epic member it loads EPIC.md, this feature's charter, and the completed direct dependencies' specs into context before the spec suite is planned.
@@ -55,7 +57,7 @@ Feature-specific:
55
57
 
56
58
  **Then call the host's question mechanism** following the **Decision Support** protocol in `references/shared-conventions.md`: recommend this plan as the default (it's your evidence-backed read of the feature's complexity) and name the trade-off so the user can push back knowingly — more documents means finer separation of concerns but more to keep in sync; fewer means tighter docs but risks one document carrying multiple concerns. Lead with: "I recommend this plan. Add or remove any documents?" Note the guidance below — resist splitting a concern into a sub-50-line document.
57
59
 
58
- **Incremental artifact tracking:** After each spec document is written (by you or a writer subagent), immediately update the `artifacts` array in `.pipeline-state.json` with the new file path. This enables crash recovery if the session is interrupted mid-suite (see shared-conventions.md "Crash Recovery").
60
+ **Incremental artifact tracking:** After each spec document is written (by you or a writer subagent), immediately update the `artifacts` array in `.pipeline-state.json` with the new file path. This enables crash recovery if the session is interrupted mid-suite (see shared-conventions.md "Stage-Entry Guard").
59
61
 
60
62
  ## Step 4: Write the Spec Suite
61
63
 
@@ -38,6 +38,8 @@ Resolve the **loop runner** from the `loopRunner` block in `forge.config.json`,
38
38
 
39
39
  **Prerequisite check:** Read `{resolvedFeatureDir}/.pipeline-state.json`. If not in force mode, stages `forge-1-prd`, `forge-2-tech`, and `forge-3-specs` must all be `complete`. If not, STOP and tell the user which prerequisites are missing.
40
40
 
41
+ After the prerequisite check, invoke the **Stage-Entry Guard** block in `references/shared-conventions.md` with `{stage}` = `forge-4-backlog` — it detects an interrupted or complete `backlog.json`, runs the resume/restart or new-version gate, and stamps entry before Step 2 loads the specs. (The backlog is a single artifact, so "resume" means: reuse the existing `backlog.json` if the previous run wrote it, rather than re-authoring from scratch.)
42
+
41
43
  **Verification check.** Check whether the specs have been verified. If not, use the host's question mechanism to warn with the cost of skipping: "Specs haven't been verified yet. Recommended: run `/feature-forge:forge-verify {feature}` first — unverified specs can carry gaps or contradictions that get baked into backlog items and only surface mid-loop, where they're far more expensive to fix. Continue anyway?" Offer **Verify first (recommended)** · **Continue without verifying**.
42
44
 
43
45
  ## Step 2: Load All Specs
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "feature-forge",
3
- "version": "0.12.5",
3
+ "version": "0.12.6",
4
4
  "agent": "cursor",
5
5
  "generatedBy": "python3 scripts/build-adapters.py"
6
6
  }
@@ -226,17 +226,31 @@ When `gitCommitAfterStage` is true, follow this exact order to avoid state incon
226
226
  - **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.
227
227
  5. **Never** use `git add -A`, `--amend`, `--no-verify`, or `--force` flags
228
228
 
229
- ## Crash Recovery
229
+ ## Stage-Entry Guard
230
230
 
231
- When a skill detects that `currentStage` matches itself and the stage status is `in-progress`, a previous run was interrupted. Follow this recovery protocol:
231
+ Invoke this block at the **start of an authoring stage** (`forge-1-prd`..`forge-4-backlog`), **after** Feature Directory Resolution and **before** any interview or (re-)authoring. It prevents a re-entered stage — an injected skill body or a re-invoked `Skill` — from blindly re-running the interview over an in-progress or already-complete draft. `{stage}` is the invoking skill's id (e.g. `forge-2-tech`).
232
232
 
233
- 1. **Inventory existing artifacts:** List all files on disk in `{specsDir}/{feature}/` that this stage would produce
234
- 2. **Compare against state:** Check the `artifacts` array in the pipeline state for this stage — it tracks files written incrementally during the previous run
235
- 3. **Present options to user:** "This stage was interrupted. Found {N} artifacts from the previous run: {list}. Would you like to resume from where it left off, or restart the stage from scratch?"
236
- 4. **If resume:** Skip artifact generation for files that already exist and appear complete (non-empty, properly structured). Continue from the next unwritten artifact.
237
- 5. **If restart:** Proceed normally. The version number will increment.
233
+ **Read, then classify** this stage's entry in `{resolvedFeatureDir}/.pipeline-state.json` (`stages.{stage}.status`):
238
234
 
239
- **Incremental artifact tracking:** When a stage writes multiple files (e.g., forge-3-specs writing a suite of spec documents), update the `artifacts` array in `.pipeline-state.json` after writing each file — not just at stage completion. This ensures crash recovery knows exactly which files were successfully written.
235
+ 1. **Fresh** — no state file yet, or `stages.{stage}` is absent/`pending`. First run of this stage. Proceed to the **Entry Stamp** below, then author normally. No prompt.
236
+
237
+ 2. **Interrupted** (`status: "in-progress"`) — a previous run of THIS stage was interrupted before it committed (the exit commit is what flips it to `complete`, so `in-progress` on entry always means a crash/abandon). Do **not** silently re-author. Instead:
238
+ - **Inventory on-disk artifacts:** list the files this stage produces that already exist in `{resolvedFeatureDir}/` (e.g. `PRD.md`; `tech-spec.md`; the `##-*.md` suite + `TRACEABILITY.md`; `backlog.json`), and cross-check against the `stages.{stage}.artifacts` array (written incrementally during the previous run).
239
+ - **Gate via `AskUserQuestion`** (Decision Support protocol): present the inventory as text, then ask "This {stage} run was interrupted — {N} artifact(s) from the previous run are on disk: {list}. Resume the in-progress draft, or start a new version from scratch?" Options: **Resume (recommended)** — continue from the first artifact not yet written/complete, reusing the existing files; do **not** re-stamp or bump the version. · **Start a new version** — treat it as a fresh authoring pass (proceed to the Entry Stamp; the version increments at exit).
240
+ - Skip artifact regeneration for files that already exist and are complete (non-empty, properly structured); continue from the next unwritten artifact.
241
+
242
+ 3. **Re-authoring** (`status: "complete"` or `"stale"`) — a finished draft exists. Warn via `AskUserQuestion` before overwriting: "A completed {stage} artifact already exists for '{feature}' (v{n}{, marked stale}). Continuing will create a new version. Proceed?" On confirm, proceed to the Entry Stamp and author a new version (the version increments at exit, per that stage's Update-Pipeline-State step).
243
+
244
+ **Entry Stamp** (fresh, restart, and re-author paths — NOT the resume path). Before authoring, write to `{resolvedFeatureDir}/.pipeline-state.json` and update `updatedAt`:
245
+ - `stages.{stage}.status` → `"in-progress"`
246
+ - `stages.{stage}.startedAt` → current ISO-8601 UTC timestamp
247
+ - top-level `currentStage` → `"{stage}"` (where the pipeline IS, per O1)
248
+
249
+ This write is **left uncommitted**: it is staged and committed as part of this stage's existing exit commit (Git Commit Protocol), so no extra commit is needed at entry. If the run is interrupted after the stamp but before the exit commit, the marker survives on disk (uncommitted) and the next entry classifies as **Interrupted** — which is exactly the intent.
250
+
251
+ **Force Mode.** When `--force` is passed, skip the interactive gate: do not prompt for resume-vs-restart or the re-author warning. Treat entry as a fresh restart — apply the Entry Stamp and author. (`--force` already skips prerequisite checks; here it likewise bypasses the self-stage gate. Existing on-disk artifacts are still loaded per Force Mode.)
252
+
253
+ **Incremental artifact tracking:** When a stage writes multiple files (e.g. forge-3-specs writing a suite of spec documents), update the `stages.{stage}.artifacts` array in `.pipeline-state.json` after writing each file — not just at stage completion. This is what makes the Interrupted inventory above precise about which files were successfully written.
240
254
 
241
255
  ## Force Mode
242
256
 
@@ -69,6 +69,8 @@ Resolve the epic subtree path `{specsDir}/{epic}/` and decide which branch to ru
69
69
  - **NEW** (no `epic-manifest.json`) → **Creation branch** (Step C1 onward).
70
70
  - **EXISTS** → **Edit branch** (§ Edit Mode below).
71
71
 
72
+ This manifest-existence dispatch **is** forge-0-epic's stage-entry guard: a re-entry on an existing epic lands in Edit Mode (helper-mutated, re-validated) rather than re-running the creation interview, so the **Stage-Entry Guard** block used by `forge-1-prd`..`forge-4-backlog` does not apply here (an epic has no self `.pipeline-state.json` to stamp — it writes member states).
73
+
72
74
  3. **Pre-flight epic-name uniqueness (creation only).** Before composing anything for a NEW
73
75
  epic, confirm the epic name itself does not collide with any existing feature or epic:
74
76
 
@@ -20,7 +20,7 @@ Invoke the **Branch Setup** block in `references/shared-conventions.md` with `{l
20
20
 
21
21
  Set the working directory by invoking the **Feature Directory Resolution** block in `references/shared-conventions.md`, which yields `{resolvedFeatureDir}`. Note one PRD-specific caveat: at PRD time a brand-new standalone feature may have NO directory yet, so resolution is expected to fail `not-found` for a never-started standalone feature — in that case forge-1 creates `{specsDir}/{feature}/` as today. For an epic member the directory already exists (created empty by forge-0-epic with an `epic` back-pointer), so resolution succeeds and yields the nested path.
22
22
 
23
- If `.pipeline-state.json` exists for this feature and `forge-1-prd` is already marked complete, use the host's question mechanism to warn: "A PRD already exists for '{feature}'. Continuing will create a new version. Proceed?"
23
+ After resolution, invoke the **Stage-Entry Guard** block in `references/shared-conventions.md` with `{stage}` = `forge-1-prd`. It classifies re-entry (fresh / interrupted / re-authoring), runs the resume-vs-restart gate and the "create a new version?" warning as applicable, and applies the entry stamp on the authoring paths. For a brand-new standalone feature there is no state file yet, so the guard's **fresh** arm applies with nothing to prompt; the entry stamp lands when the state file is first created in Step 6.
24
24
 
25
25
  ## Step 2: Examine Existing Context
26
26
 
@@ -19,6 +19,8 @@ Read and follow `references/shared-conventions.md` for feature name validation,
19
19
 
20
20
  **Prerequisite check:** Read `{resolvedFeatureDir}/.pipeline-state.json`. If not in force mode and `forge-1-prd` is not `complete`, STOP and tell the user: "The PRD for '{feature}' isn't complete yet. Run `/feature-forge:forge-1-prd {feature}` first."
21
21
 
22
+ After the prerequisite check, invoke the **Stage-Entry Guard** block in `references/shared-conventions.md` with `{stage}` = `forge-2-tech` — it detects an interrupted or already-complete tech-spec, runs the resume/restart or new-version gate, and stamps `status: "in-progress"` + `startedAt` + `currentStage` before the research and interview.
23
+
22
24
  Read `{resolvedFeatureDir}/PRD.md` into context. This is your foundation — every technology decision must trace back to a PRD requirement.
23
25
 
24
26
  After reading the PRD, invoke the **Epic Context Injection** block in `references/shared-conventions.md`. It self-gates on the resolved feature's `epic` back-pointer: for a standalone feature it is a no-op; for an epic member it loads EPIC.md, this feature's charter, and the completed direct dependencies' specs into context before the research and interview.
@@ -21,6 +21,8 @@ Read and follow `references/shared-conventions.md` for feature name validation,
21
21
 
22
22
  **Prerequisite check:** Read `{resolvedFeatureDir}/.pipeline-state.json`. If not in force mode, both `forge-1-prd` and `forge-2-tech` must be `complete`. If not, STOP and tell the user which prerequisites are missing.
23
23
 
24
+ After the prerequisite check, invoke the **Stage-Entry Guard** block in `references/shared-conventions.md` with `{stage}` = `forge-3-specs`. Because this stage writes a suite incrementally, the guard's **interrupted** arm uses the `stages.forge-3-specs.artifacts` array (already updated after each spec file — Step 3) to resume from the first unwritten document rather than regenerating the whole suite.
25
+
24
26
  Read both `{resolvedFeatureDir}/PRD.md` and `{resolvedFeatureDir}/tech-spec.md` into context.
25
27
 
26
28
  After reading the PRD and tech spec, invoke the **Epic Context Injection** block in `references/shared-conventions.md`. It self-gates on the resolved feature's `epic` back-pointer: for a standalone feature it is a no-op; for an epic member it loads EPIC.md, this feature's charter, and the completed direct dependencies' specs into context before the spec suite is planned.
@@ -56,7 +58,7 @@ Feature-specific:
56
58
 
57
59
  **Then call the host's question mechanism** following the **Decision Support** protocol in `references/shared-conventions.md`: recommend this plan as the default (it's your evidence-backed read of the feature's complexity) and name the trade-off so the user can push back knowingly — more documents means finer separation of concerns but more to keep in sync; fewer means tighter docs but risks one document carrying multiple concerns. Lead with: "I recommend this plan. Add or remove any documents?" Note the guidance below — resist splitting a concern into a sub-50-line document.
58
60
 
59
- **Incremental artifact tracking:** After each spec document is written (by you or a writer subagent), immediately update the `artifacts` array in `.pipeline-state.json` with the new file path. This enables crash recovery if the session is interrupted mid-suite (see shared-conventions.md "Crash Recovery").
61
+ **Incremental artifact tracking:** After each spec document is written (by you or a writer subagent), immediately update the `artifacts` array in `.pipeline-state.json` with the new file path. This enables crash recovery if the session is interrupted mid-suite (see shared-conventions.md "Stage-Entry Guard").
60
62
 
61
63
  ## Step 4: Write the Spec Suite
62
64
 
@@ -39,6 +39,8 @@ Resolve the **loop runner** from the `loopRunner` block in `forge.config.json`,
39
39
 
40
40
  **Prerequisite check:** Read `{resolvedFeatureDir}/.pipeline-state.json`. If not in force mode, stages `forge-1-prd`, `forge-2-tech`, and `forge-3-specs` must all be `complete`. If not, STOP and tell the user which prerequisites are missing.
41
41
 
42
+ After the prerequisite check, invoke the **Stage-Entry Guard** block in `references/shared-conventions.md` with `{stage}` = `forge-4-backlog` — it detects an interrupted or complete `backlog.json`, runs the resume/restart or new-version gate, and stamps entry before Step 2 loads the specs. (The backlog is a single artifact, so "resume" means: reuse the existing `backlog.json` if the previous run wrote it, rather than re-authoring from scratch.)
43
+
42
44
  **Verification check.** Check whether the specs have been verified. If not, use the host's question mechanism to warn with the cost of skipping: "Specs haven't been verified yet. Recommended: run `/feature-forge:forge-verify {feature}` first — unverified specs can carry gaps or contradictions that get baked into backlog items and only surface mid-loop, where they're far more expensive to fix. Continue anyway?" Offer **Verify first (recommended)** · **Continue without verifying**.
43
45
 
44
46
  ## Step 2: Load All Specs
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "feature-forge",
3
- "version": "0.12.5",
3
+ "version": "0.12.6",
4
4
  "agent": "gemini",
5
5
  "generatedBy": "python3 scripts/build-adapters.py"
6
6
  }
@@ -4,7 +4,7 @@
4
4
  "regenerate": "python3 scripts/build-adapters.py"
5
5
  },
6
6
  "name": "feature-forge",
7
- "version": "0.12.5",
7
+ "version": "0.12.6",
8
8
  "skills": [
9
9
  {
10
10
  "name": "forge-0-epic",
@@ -226,17 +226,31 @@ When `gitCommitAfterStage` is true, follow this exact order to avoid state incon
226
226
  - **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.
227
227
  5. **Never** use `git add -A`, `--amend`, `--no-verify`, or `--force` flags
228
228
 
229
- ## Crash Recovery
229
+ ## Stage-Entry Guard
230
230
 
231
- When a skill detects that `currentStage` matches itself and the stage status is `in-progress`, a previous run was interrupted. Follow this recovery protocol:
231
+ Invoke this block at the **start of an authoring stage** (`forge-1-prd`..`forge-4-backlog`), **after** Feature Directory Resolution and **before** any interview or (re-)authoring. It prevents a re-entered stage — an injected skill body or a re-invoked `Skill` — from blindly re-running the interview over an in-progress or already-complete draft. `{stage}` is the invoking skill's id (e.g. `forge-2-tech`).
232
232
 
233
- 1. **Inventory existing artifacts:** List all files on disk in `{specsDir}/{feature}/` that this stage would produce
234
- 2. **Compare against state:** Check the `artifacts` array in the pipeline state for this stage — it tracks files written incrementally during the previous run
235
- 3. **Present options to user:** "This stage was interrupted. Found {N} artifacts from the previous run: {list}. Would you like to resume from where it left off, or restart the stage from scratch?"
236
- 4. **If resume:** Skip artifact generation for files that already exist and appear complete (non-empty, properly structured). Continue from the next unwritten artifact.
237
- 5. **If restart:** Proceed normally. The version number will increment.
233
+ **Read, then classify** this stage's entry in `{resolvedFeatureDir}/.pipeline-state.json` (`stages.{stage}.status`):
238
234
 
239
- **Incremental artifact tracking:** When a stage writes multiple files (e.g., forge-3-specs writing a suite of spec documents), update the `artifacts` array in `.pipeline-state.json` after writing each file — not just at stage completion. This ensures crash recovery knows exactly which files were successfully written.
235
+ 1. **Fresh** — no state file yet, or `stages.{stage}` is absent/`pending`. First run of this stage. Proceed to the **Entry Stamp** below, then author normally. No prompt.
236
+
237
+ 2. **Interrupted** (`status: "in-progress"`) — a previous run of THIS stage was interrupted before it committed (the exit commit is what flips it to `complete`, so `in-progress` on entry always means a crash/abandon). Do **not** silently re-author. Instead:
238
+ - **Inventory on-disk artifacts:** list the files this stage produces that already exist in `{resolvedFeatureDir}/` (e.g. `PRD.md`; `tech-spec.md`; the `##-*.md` suite + `TRACEABILITY.md`; `backlog.json`), and cross-check against the `stages.{stage}.artifacts` array (written incrementally during the previous run).
239
+ - **Gate via `AskUserQuestion`** (Decision Support protocol): present the inventory as text, then ask "This {stage} run was interrupted — {N} artifact(s) from the previous run are on disk: {list}. Resume the in-progress draft, or start a new version from scratch?" Options: **Resume (recommended)** — continue from the first artifact not yet written/complete, reusing the existing files; do **not** re-stamp or bump the version. · **Start a new version** — treat it as a fresh authoring pass (proceed to the Entry Stamp; the version increments at exit).
240
+ - Skip artifact regeneration for files that already exist and are complete (non-empty, properly structured); continue from the next unwritten artifact.
241
+
242
+ 3. **Re-authoring** (`status: "complete"` or `"stale"`) — a finished draft exists. Warn via `AskUserQuestion` before overwriting: "A completed {stage} artifact already exists for '{feature}' (v{n}{, marked stale}). Continuing will create a new version. Proceed?" On confirm, proceed to the Entry Stamp and author a new version (the version increments at exit, per that stage's Update-Pipeline-State step).
243
+
244
+ **Entry Stamp** (fresh, restart, and re-author paths — NOT the resume path). Before authoring, write to `{resolvedFeatureDir}/.pipeline-state.json` and update `updatedAt`:
245
+ - `stages.{stage}.status` → `"in-progress"`
246
+ - `stages.{stage}.startedAt` → current ISO-8601 UTC timestamp
247
+ - top-level `currentStage` → `"{stage}"` (where the pipeline IS, per O1)
248
+
249
+ This write is **left uncommitted**: it is staged and committed as part of this stage's existing exit commit (Git Commit Protocol), so no extra commit is needed at entry. If the run is interrupted after the stamp but before the exit commit, the marker survives on disk (uncommitted) and the next entry classifies as **Interrupted** — which is exactly the intent.
250
+
251
+ **Force Mode.** When `--force` is passed, skip the interactive gate: do not prompt for resume-vs-restart or the re-author warning. Treat entry as a fresh restart — apply the Entry Stamp and author. (`--force` already skips prerequisite checks; here it likewise bypasses the self-stage gate. Existing on-disk artifacts are still loaded per Force Mode.)
252
+
253
+ **Incremental artifact tracking:** When a stage writes multiple files (e.g. forge-3-specs writing a suite of spec documents), update the `stages.{stage}.artifacts` array in `.pipeline-state.json` after writing each file — not just at stage completion. This is what makes the Interrupted inventory above precise about which files were successfully written.
240
254
 
241
255
  ## Force Mode
242
256
 
@@ -68,6 +68,8 @@ Resolve the epic subtree path `{specsDir}/{epic}/` and decide which branch to ru
68
68
  - **NEW** (no `epic-manifest.json`) → **Creation branch** (Step C1 onward).
69
69
  - **EXISTS** → **Edit branch** (§ Edit Mode below).
70
70
 
71
+ This manifest-existence dispatch **is** forge-0-epic's stage-entry guard: a re-entry on an existing epic lands in Edit Mode (helper-mutated, re-validated) rather than re-running the creation interview, so the **Stage-Entry Guard** block used by `forge-1-prd`..`forge-4-backlog` does not apply here (an epic has no self `.pipeline-state.json` to stamp — it writes member states).
72
+
71
73
  3. **Pre-flight epic-name uniqueness (creation only).** Before composing anything for a NEW
72
74
  epic, confirm the epic name itself does not collide with any existing feature or epic:
73
75
 
@@ -19,7 +19,7 @@ Invoke the **Branch Setup** block in `references/shared-conventions.md` with `{l
19
19
 
20
20
  Set the working directory by invoking the **Feature Directory Resolution** block in `references/shared-conventions.md`, which yields `{resolvedFeatureDir}`. Note one PRD-specific caveat: at PRD time a brand-new standalone feature may have NO directory yet, so resolution is expected to fail `not-found` for a never-started standalone feature — in that case forge-1 creates `{specsDir}/{feature}/` as today. For an epic member the directory already exists (created empty by forge-0-epic with an `epic` back-pointer), so resolution succeeds and yields the nested path.
21
21
 
22
- If `.pipeline-state.json` exists for this feature and `forge-1-prd` is already marked complete, use the host's question mechanism to warn: "A PRD already exists for '{feature}'. Continuing will create a new version. Proceed?"
22
+ After resolution, invoke the **Stage-Entry Guard** block in `references/shared-conventions.md` with `{stage}` = `forge-1-prd`. It classifies re-entry (fresh / interrupted / re-authoring), runs the resume-vs-restart gate and the "create a new version?" warning as applicable, and applies the entry stamp on the authoring paths. For a brand-new standalone feature there is no state file yet, so the guard's **fresh** arm applies with nothing to prompt; the entry stamp lands when the state file is first created in Step 6.
23
23
 
24
24
  ## Step 2: Examine Existing Context
25
25
 
@@ -18,6 +18,8 @@ Read and follow `references/shared-conventions.md` for feature name validation,
18
18
 
19
19
  **Prerequisite check:** Read `{resolvedFeatureDir}/.pipeline-state.json`. If not in force mode and `forge-1-prd` is not `complete`, STOP and tell the user: "The PRD for '{feature}' isn't complete yet. Run `/feature-forge:forge-1-prd {feature}` first."
20
20
 
21
+ After the prerequisite check, invoke the **Stage-Entry Guard** block in `references/shared-conventions.md` with `{stage}` = `forge-2-tech` — it detects an interrupted or already-complete tech-spec, runs the resume/restart or new-version gate, and stamps `status: "in-progress"` + `startedAt` + `currentStage` before the research and interview.
22
+
21
23
  Read `{resolvedFeatureDir}/PRD.md` into context. This is your foundation — every technology decision must trace back to a PRD requirement.
22
24
 
23
25
  After reading the PRD, invoke the **Epic Context Injection** block in `references/shared-conventions.md`. It self-gates on the resolved feature's `epic` back-pointer: for a standalone feature it is a no-op; for an epic member it loads EPIC.md, this feature's charter, and the completed direct dependencies' specs into context before the research and interview.
@@ -20,6 +20,8 @@ Read and follow `references/shared-conventions.md` for feature name validation,
20
20
 
21
21
  **Prerequisite check:** Read `{resolvedFeatureDir}/.pipeline-state.json`. If not in force mode, both `forge-1-prd` and `forge-2-tech` must be `complete`. If not, STOP and tell the user which prerequisites are missing.
22
22
 
23
+ After the prerequisite check, invoke the **Stage-Entry Guard** block in `references/shared-conventions.md` with `{stage}` = `forge-3-specs`. Because this stage writes a suite incrementally, the guard's **interrupted** arm uses the `stages.forge-3-specs.artifacts` array (already updated after each spec file — Step 3) to resume from the first unwritten document rather than regenerating the whole suite.
24
+
23
25
  Read both `{resolvedFeatureDir}/PRD.md` and `{resolvedFeatureDir}/tech-spec.md` into context.
24
26
 
25
27
  After reading the PRD and tech spec, invoke the **Epic Context Injection** block in `references/shared-conventions.md`. It self-gates on the resolved feature's `epic` back-pointer: for a standalone feature it is a no-op; for an epic member it loads EPIC.md, this feature's charter, and the completed direct dependencies' specs into context before the spec suite is planned.
@@ -55,7 +57,7 @@ Feature-specific:
55
57
 
56
58
  **Then call the host's question mechanism** following the **Decision Support** protocol in `references/shared-conventions.md`: recommend this plan as the default (it's your evidence-backed read of the feature's complexity) and name the trade-off so the user can push back knowingly — more documents means finer separation of concerns but more to keep in sync; fewer means tighter docs but risks one document carrying multiple concerns. Lead with: "I recommend this plan. Add or remove any documents?" Note the guidance below — resist splitting a concern into a sub-50-line document.
57
59
 
58
- **Incremental artifact tracking:** After each spec document is written (by you or a writer subagent), immediately update the `artifacts` array in `.pipeline-state.json` with the new file path. This enables crash recovery if the session is interrupted mid-suite (see shared-conventions.md "Crash Recovery").
60
+ **Incremental artifact tracking:** After each spec document is written (by you or a writer subagent), immediately update the `artifacts` array in `.pipeline-state.json` with the new file path. This enables crash recovery if the session is interrupted mid-suite (see shared-conventions.md "Stage-Entry Guard").
59
61
 
60
62
  ## Step 4: Write the Spec Suite
61
63
 
@@ -38,6 +38,8 @@ Resolve the **loop runner** from the `loopRunner` block in `forge.config.json`,
38
38
 
39
39
  **Prerequisite check:** Read `{resolvedFeatureDir}/.pipeline-state.json`. If not in force mode, stages `forge-1-prd`, `forge-2-tech`, and `forge-3-specs` must all be `complete`. If not, STOP and tell the user which prerequisites are missing.
40
40
 
41
+ After the prerequisite check, invoke the **Stage-Entry Guard** block in `references/shared-conventions.md` with `{stage}` = `forge-4-backlog` — it detects an interrupted or complete `backlog.json`, runs the resume/restart or new-version gate, and stamps entry before Step 2 loads the specs. (The backlog is a single artifact, so "resume" means: reuse the existing `backlog.json` if the previous run wrote it, rather than re-authoring from scratch.)
42
+
41
43
  **Verification check.** Check whether the specs have been verified. If not, use the host's question mechanism to warn with the cost of skipping: "Specs haven't been verified yet. Recommended: run `/feature-forge:forge-verify {feature}` first — unverified specs can carry gaps or contradictions that get baked into backlog items and only surface mid-loop, where they're far more expensive to fix. Continue anyway?" Offer **Verify first (recommended)** · **Continue without verifying**.
42
44
 
43
45
  ## Step 2: Load All Specs
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@garygentry/feature-forge",
3
- "version": "0.2.10",
3
+ "version": "0.2.11",
4
4
  "description": "Cross-agent installer for the feature-forge skill suite — installs the canonical forge pipeline into Claude, Codex, Copilot, Cursor, or Gemini.",
5
5
  "license": "MIT",
6
6
  "type": "module",