@garygentry/feature-forge 0.2.4 → 0.2.6

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 (117) hide show
  1. package/adapters/claude/.feature-forge-bundle.json +1 -1
  2. package/adapters/claude/agents/forge-verifier.md +2 -0
  3. package/adapters/claude/references/portable-root.md +6 -3
  4. package/adapters/claude/references/shared-conventions.md +19 -6
  5. package/adapters/claude/references/stage-exit-protocol.md +148 -37
  6. package/adapters/claude/scripts/forge-root.sh +20 -1
  7. package/adapters/claude/scripts/forge-session.py +691 -1
  8. package/adapters/claude/skills/forge/SKILL.md +7 -7
  9. package/adapters/claude/skills/forge-0-epic/SKILL.md +15 -25
  10. package/adapters/claude/skills/forge-0-epic/references/edit-mode.md +2 -2
  11. package/adapters/claude/skills/forge-0-epic/references/epic-manifest-subcommands.md +1 -1
  12. package/adapters/claude/skills/forge-1-prd/SKILL.md +7 -8
  13. package/adapters/claude/skills/forge-2-tech/SKILL.md +7 -8
  14. package/adapters/claude/skills/forge-3-specs/SKILL.md +7 -8
  15. package/adapters/claude/skills/forge-4-backlog/SKILL.md +7 -8
  16. package/adapters/claude/skills/forge-5-loop/SKILL.md +3 -3
  17. package/adapters/claude/skills/forge-6-docs/SKILL.md +1 -1
  18. package/adapters/claude/skills/forge-bootstrap/SKILL.md +4 -4
  19. package/adapters/claude/skills/forge-fix/SKILL.md +11 -9
  20. package/adapters/claude/skills/forge-guide/SKILL.md +6 -3
  21. package/adapters/claude/skills/forge-init/SKILL.md +5 -4
  22. package/adapters/claude/skills/forge-verify/SKILL.md +9 -2
  23. package/adapters/claude/skills/forge-verify/references/verification-checklists.md +1 -1
  24. package/adapters/codex/.feature-forge-bundle.json +1 -1
  25. package/adapters/codex/agents/forge-verifier.toml +2 -0
  26. package/adapters/codex/references/portable-root.md +6 -3
  27. package/adapters/codex/references/shared-conventions.md +19 -6
  28. package/adapters/codex/references/stage-exit-protocol.md +148 -37
  29. package/adapters/codex/scripts/forge-root.sh +20 -1
  30. package/adapters/codex/scripts/forge-session.py +691 -1
  31. package/adapters/codex/skills/forge/SKILL.md +7 -7
  32. package/adapters/codex/skills/forge-0-epic/SKILL.md +15 -25
  33. package/adapters/codex/skills/forge-0-epic/references/edit-mode.md +2 -2
  34. package/adapters/codex/skills/forge-0-epic/references/epic-manifest-subcommands.md +1 -1
  35. package/adapters/codex/skills/forge-1-prd/SKILL.md +7 -8
  36. package/adapters/codex/skills/forge-2-tech/SKILL.md +7 -8
  37. package/adapters/codex/skills/forge-3-specs/SKILL.md +7 -8
  38. package/adapters/codex/skills/forge-4-backlog/SKILL.md +7 -8
  39. package/adapters/codex/skills/forge-5-loop/SKILL.md +3 -3
  40. package/adapters/codex/skills/forge-6-docs/SKILL.md +1 -1
  41. package/adapters/codex/skills/forge-bootstrap/SKILL.md +4 -4
  42. package/adapters/codex/skills/forge-fix/SKILL.md +11 -9
  43. package/adapters/codex/skills/forge-guide/SKILL.md +6 -3
  44. package/adapters/codex/skills/forge-init/SKILL.md +5 -4
  45. package/adapters/codex/skills/forge-verify/SKILL.md +9 -2
  46. package/adapters/codex/skills/forge-verify/references/verification-checklists.md +1 -1
  47. package/adapters/copilot/.feature-forge-bundle.json +1 -1
  48. package/adapters/copilot/agents/forge-verifier.md +2 -0
  49. package/adapters/copilot/references/portable-root.md +6 -3
  50. package/adapters/copilot/references/shared-conventions.md +19 -6
  51. package/adapters/copilot/references/stage-exit-protocol.md +148 -37
  52. package/adapters/copilot/scripts/forge-root.sh +20 -1
  53. package/adapters/copilot/scripts/forge-session.py +691 -1
  54. package/adapters/copilot/skills/forge/forge.md +7 -7
  55. package/adapters/copilot/skills/forge-0-epic/forge-0-epic.md +15 -25
  56. package/adapters/copilot/skills/forge-0-epic/references/edit-mode.md +2 -2
  57. package/adapters/copilot/skills/forge-0-epic/references/epic-manifest-subcommands.md +1 -1
  58. package/adapters/copilot/skills/forge-1-prd/forge-1-prd.md +7 -8
  59. package/adapters/copilot/skills/forge-2-tech/forge-2-tech.md +7 -8
  60. package/adapters/copilot/skills/forge-3-specs/forge-3-specs.md +7 -8
  61. package/adapters/copilot/skills/forge-4-backlog/forge-4-backlog.md +7 -8
  62. package/adapters/copilot/skills/forge-5-loop/forge-5-loop.md +3 -3
  63. package/adapters/copilot/skills/forge-6-docs/forge-6-docs.md +1 -1
  64. package/adapters/copilot/skills/forge-bootstrap/forge-bootstrap.md +4 -4
  65. package/adapters/copilot/skills/forge-fix/forge-fix.md +11 -9
  66. package/adapters/copilot/skills/forge-guide/forge-guide.md +6 -3
  67. package/adapters/copilot/skills/forge-init/forge-init.md +5 -4
  68. package/adapters/copilot/skills/forge-verify/forge-verify.md +9 -2
  69. package/adapters/copilot/skills/forge-verify/references/verification-checklists.md +1 -1
  70. package/adapters/cursor/.feature-forge-bundle.json +1 -1
  71. package/adapters/cursor/agents/forge-verifier.mdc +2 -0
  72. package/adapters/cursor/references/portable-root.md +6 -3
  73. package/adapters/cursor/references/shared-conventions.md +19 -6
  74. package/adapters/cursor/references/stage-exit-protocol.md +148 -37
  75. package/adapters/cursor/scripts/forge-root.sh +20 -1
  76. package/adapters/cursor/scripts/forge-session.py +691 -1
  77. package/adapters/cursor/skills/forge/forge.mdc +7 -7
  78. package/adapters/cursor/skills/forge-0-epic/forge-0-epic.mdc +15 -25
  79. package/adapters/cursor/skills/forge-0-epic/references/edit-mode.md +2 -2
  80. package/adapters/cursor/skills/forge-0-epic/references/epic-manifest-subcommands.md +1 -1
  81. package/adapters/cursor/skills/forge-1-prd/forge-1-prd.mdc +7 -8
  82. package/adapters/cursor/skills/forge-2-tech/forge-2-tech.mdc +7 -8
  83. package/adapters/cursor/skills/forge-3-specs/forge-3-specs.mdc +7 -8
  84. package/adapters/cursor/skills/forge-4-backlog/forge-4-backlog.mdc +7 -8
  85. package/adapters/cursor/skills/forge-5-loop/forge-5-loop.mdc +3 -3
  86. package/adapters/cursor/skills/forge-6-docs/forge-6-docs.mdc +1 -1
  87. package/adapters/cursor/skills/forge-bootstrap/forge-bootstrap.mdc +4 -4
  88. package/adapters/cursor/skills/forge-fix/forge-fix.mdc +11 -9
  89. package/adapters/cursor/skills/forge-guide/forge-guide.mdc +6 -3
  90. package/adapters/cursor/skills/forge-init/forge-init.mdc +5 -4
  91. package/adapters/cursor/skills/forge-verify/forge-verify.mdc +9 -2
  92. package/adapters/cursor/skills/forge-verify/references/verification-checklists.md +1 -1
  93. package/adapters/gemini/.feature-forge-bundle.json +1 -1
  94. package/adapters/gemini/agents/forge-verifier.md +2 -0
  95. package/adapters/gemini/gemini-extension.json +1 -1
  96. package/adapters/gemini/references/portable-root.md +6 -3
  97. package/adapters/gemini/references/shared-conventions.md +19 -6
  98. package/adapters/gemini/references/stage-exit-protocol.md +148 -37
  99. package/adapters/gemini/scripts/forge-root.sh +20 -1
  100. package/adapters/gemini/scripts/forge-session.py +691 -1
  101. package/adapters/gemini/skills/forge/forge.md +7 -7
  102. package/adapters/gemini/skills/forge-0-epic/forge-0-epic.md +15 -25
  103. package/adapters/gemini/skills/forge-0-epic/references/edit-mode.md +2 -2
  104. package/adapters/gemini/skills/forge-0-epic/references/epic-manifest-subcommands.md +1 -1
  105. package/adapters/gemini/skills/forge-1-prd/forge-1-prd.md +7 -8
  106. package/adapters/gemini/skills/forge-2-tech/forge-2-tech.md +7 -8
  107. package/adapters/gemini/skills/forge-3-specs/forge-3-specs.md +7 -8
  108. package/adapters/gemini/skills/forge-4-backlog/forge-4-backlog.md +7 -8
  109. package/adapters/gemini/skills/forge-5-loop/forge-5-loop.md +3 -3
  110. package/adapters/gemini/skills/forge-6-docs/forge-6-docs.md +1 -1
  111. package/adapters/gemini/skills/forge-bootstrap/forge-bootstrap.md +4 -4
  112. package/adapters/gemini/skills/forge-fix/forge-fix.md +11 -9
  113. package/adapters/gemini/skills/forge-guide/forge-guide.md +6 -3
  114. package/adapters/gemini/skills/forge-init/forge-init.md +5 -4
  115. package/adapters/gemini/skills/forge-verify/forge-verify.md +9 -2
  116. package/adapters/gemini/skills/forge-verify/references/verification-checklists.md +1 -1
  117. package/package.json +1 -1
@@ -11,6 +11,8 @@ You are the "second set of eyes." You receive artifacts (PRDs, tech specs, imple
11
11
 
12
12
  You have READ-ONLY access. You cannot and should not modify any files. Your output is returned as your response — the parent agent handles writing the findings document to disk.
13
13
 
14
+ **You ARE the verifier — you never dispatch one.** You have no Agent/host's subagent mechanism. Your pre-loaded `forge-verify` skill contains a "Subagent Delegation (parent orchestrator only)" section describing how a *parent* dispatches a `forge-verifier` — that guidance is for the parent, not for you. Ignore it: do not attempt to delegate, spawn a subagent, or return a "verification is running / will surface shortly" placeholder. Execute the verification checks yourself and return the findings block. Delegating from here is a self-referential loop that produces no work and no findings artifact.
15
+
14
16
  ## How You Work
15
17
 
16
18
  1. Read the pipeline state file to understand what stage the feature is at
@@ -12,7 +12,7 @@ against the fenced block here, byte-for-byte.
12
12
  ## Canonical bootstrap prelude
13
13
 
14
14
  ```bash
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')"
15
+ R="$(bash -c 'for d in "$HOME"/.claude/skills/feature-forge "$HOME"/.claude/plugins/cache/*/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="$(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')"
27
+ R="$(bash -c 'for d in "$HOME"/.claude/skills/feature-forge "$HOME"/.claude/plugins/cache/*/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
  ```
@@ -43,7 +43,10 @@ python3 "$R/scripts/epic-manifest.py" render-status "{epic}" --specs-dir "{specs
43
43
  3. **Prelude candidate set is an agent-neutral bootstrap subset.** The prelude's `for d` list
44
44
  exists only to bootstrap-discover `forge-root.sh`; the authoritative multi-root probe lives in
45
45
  `forge-root.sh` step 2. The list enumerates install roots across agents — the Claude
46
- skill/plugin dirs **and** the agent-neutral `.agents/skills/feature-forge` dirs (`$HOME` and the
46
+ skill/plugin dirs — including the marketplace-cache layout
47
+ `~/.claude/plugins/cache/<marketplace>/feature-forge/<version>/`, listed before the
48
+ single-star plugins glob so a versioned cache install always beats the marketplace clone —
49
+ **and** the agent-neutral `.agents/skills/feature-forge` dirs (`$HOME` and the
47
50
  project-relative `./.agents/...`) — so a non-Claude install (e.g. Codex under `.agents/skills`)
48
51
  can still discover the resolver. When adding an install root, update `forge-root.sh` first;
49
52
  extend the prelude only if the new root is needed to bootstrap-discover `forge-root.sh` itself.
@@ -71,9 +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
+ - `autoVerify` (default: `false` — when `true`, `forge-verify` runs automatically after a stage completes, no prompt. **In-stage-primary:** the just-completed authoring stage runs it itself, in-session, before the exit block (honoring the verify-before-clear principle). The navigator runs it only as a **catch-up** when verify is still pending (a host that could not dispatch a clean-room subagent, or a stage run before this behavior landed). Either way it runs in a fresh clean-room subagent, so it never needs a `/clear` and costs only a compact digest.)
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`. Both the in-stage run and the navigator catch-up read this same effective value.)
76
+ - `autoFix` (default: `false` — when `true`, `forge-fix` is chained after an auto-verify that finds issues — by the in-stage run (primary) or the navigator catch-up — but only when auto-verify is on for that stage AND preconditions hold (zero unresolved decisions, clean tree, passing re-verify); otherwise a digest is surfaced and the gate is presented.)
77
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`.)
78
78
 
79
79
  ## Feature Directory Resolution
@@ -81,7 +81,7 @@ Extract these config values (use defaults if not present):
81
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.
82
82
 
83
83
  ```bash
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')"
84
+ R="$(bash -c 'for d in "$HOME"/.claude/skills/feature-forge "$HOME"/.claude/plugins/cache/*/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')"
85
85
  [ -n "$R" ] || { echo "feature-forge: cannot locate plugin root" >&2; exit 1; }
86
86
  resolvedFeatureDir=$(python3 "$R/scripts/epic-manifest.py" \
87
87
  resolve "<feature>" --specs-dir "<specsDir>")
@@ -93,6 +93,19 @@ resolvedFeatureDir=$(python3 "$R/scripts/epic-manifest.py" \
93
93
 
94
94
  In both failure cases, do not fall back to a guessed path.
95
95
 
96
+ **On `not-found`, check other branches before stopping.** With `branchPerFeature`, the feature's directory (and its `.pipeline-state.json`) may exist only on its topic branch — invisible from the default branch of a fresh clone. Before concluding the pipeline does not exist, run the read-only cross-branch discovery:
97
+
98
+ ```bash
99
+ R="$(bash -c 'for d in "$HOME"/.claude/skills/feature-forge "$HOME"/.claude/plugins/cache/*/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')"
100
+ [ -n "$R" ] || { echo "feature-forge: cannot locate plugin root" >&2; exit 1; }
101
+ python3 "$R/scripts/forge-session.py" discover-feature "<feature>" --specs-dir "<specsDir>" --json
102
+ ```
103
+
104
+ - **Candidates found** (`candidates` and/or `remoteCandidates` non-empty): summarize them as text (branch, recorded stage, whether the state's own `branch` field matches), then use `AskUserQuestion`: **Switch to `{branch}` (recommended)** — run the candidate's `switchCommand` · **Fetch + switch** — for a `needsFetch` remote candidate, run its `fetchCommand` then `switchCommand` (note its contents were matched by name only, not inspected) · **Treat `{feature}` as new on this branch** · **Stop**. A checkout is a mutation inside an otherwise read-only flow: perform it ONLY on the user's explicit accept AND with a clean working tree (`git status --porcelain` prints nothing) — never auto-switch, never with uncommitted changes. After a successful switch, re-run this Feature Directory Resolution block from the top.
105
+ - **Nothing found** (both lists empty): the pipeline genuinely does not exist anywhere discoverable — STOP and surface the original `not-found` stderr line verbatim (or, where the caller offers to start a new pipeline, offer that).
106
+
107
+ **Anti-fabrication guard.** Never describe pipeline state that resolution or discovery did not return: if both come back empty, the pipeline does not exist — say exactly that, and never reconstruct stages, backlogs, or history from conversational memory.
108
+
96
109
  **Resolution algorithm (summary; full spec in `02-manifest-helper-cli.md §4`):**
97
110
  1. Reject the name if unsafe (path separator, `..`, absolute, or failing `SAFE_NAME_RE`) — before any filesystem access.
98
111
  2. If `{specsDir}/{name}/.pipeline-state.json` exists → return that flat path.
@@ -111,7 +124,7 @@ Whenever a stage creates the specs tree for the first time (the first PRD or epi
111
124
  Run this after creating the feature/epic directory, before the stage's git commit:
112
125
 
113
126
  ```bash
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')"
127
+ R="$(bash -c 'for d in "$HOME"/.claude/skills/feature-forge "$HOME"/.claude/plugins/cache/*/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')"
115
128
  [ -n "$R" ] || { echo "feature-forge: cannot locate plugin root" >&2; exit 1; }
116
129
  mkdir -p "<specsDir>"
117
130
  [ -f "<specsDir>/AGENTS.md" ] || cp "$R/references/templates/specs-hygiene/AGENTS.md" "<specsDir>/AGENTS.md"
@@ -138,7 +151,7 @@ After resolving the feature directory, check the feature's `.pipeline-state.json
138
151
  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:
139
152
 
140
153
  ```bash
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')"
154
+ R="$(bash -c 'for d in "$HOME"/.claude/skills/feature-forge "$HOME"/.claude/plugins/cache/*/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')"
142
155
  [ -n "$R" ] || { echo "feature-forge: cannot locate plugin root" >&2; exit 1; }
143
156
  python3 "$R/scripts/epic-manifest.py" \
144
157
  render-status "<epic>" --specs-dir "<specsDir>" --json
@@ -4,66 +4,177 @@ The single source of truth for how every forge **authoring** stage closes. It
4
4
  replaces the old ad-hoc "Next steps:" bullet lists with one fixed, correctly-ordered
5
5
  sequence: **verify (if missing or stale) → `/clear` → run the next command.**
6
6
 
7
- Two principles this block encodes (do not relitigate — they are locked product
7
+ Two principles this protocol encodes (do not relitigate — they are locked product
8
8
  decisions):
9
9
 
10
10
  1. **Clearing is recommended on its own merits at every stage boundary** — a clean
11
11
  start for the next stage — *not* as a proxy for a full context window. Window
12
12
  fullness only changes *how emphatically* the clear is recommended, never *whether*
13
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.
14
+ 2. **Verify happens before the clear, never after** — in the authoring session, whether
15
+ manual **or** auto. Verify's clean-room subagent is dispatched from the *current*
16
+ session, so the findings digest and any fix decision land where the context to act on
17
+ them still exists. This holds for auto-verify too: the stage skill dispatches the
18
+ clean-room verify (and any autoFix) at stage end, in-session, before the exit — it is
19
+ **not** deferred to the navigator, which runs *after* the `/clear` with none of the
20
+ authoring context. Clearing first throws that context away.
18
21
 
19
22
  ## How this file is used
20
23
 
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).
24
+ The five authoring stages (`forge-0-epic` … `forge-4-backlog`) close with the
25
+ **Scripted Stage Exit**: a short stamped block (below) that runs
26
+ `forge-session.py stage-exit`, obeys the DIRECTIVES it prints per the **directive
27
+ contract** in this file, and prints the script-emitted NEXT-STEPS block verbatim as the
28
+ absolute last output. All the conditional logic the old prose blocks asked the model to
29
+ compute (effective auto-verify, freshness collapse, gate selection, host wording) now
30
+ lives in the script, deterministically; only genuinely interactive work (clean-room
31
+ subagent dispatch, `AskUserQuestion` gates) remains prose — specified once here, not
32
+ per stage.
26
33
 
27
- Each stamp site fills three slots; everything else is identical across sites:
34
+ The loop (`forge-5-loop`) keeps its bespoke exits: it stamps the **standard block**
35
+ (step-6 epic-member handoff) and the **warm variant** (all-done closing) below,
36
+ verbatim. `forge-6-docs` is **terminal** — it stamps no exit block.
28
37
 
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
+ A drift-guard test (`tests/test_stage_exit_protocol.py`) asserts each stamp site still
39
+ contains its block, so an edit here must be mirrored into every stamp site (and
40
+ vice-versa).
38
41
 
39
42
  ## Stamp sites
40
43
 
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.
44
+ | Stamp site | Block |
45
+ |---|---|
46
+ | `forge-0-epic` … `forge-4-backlog` | scripted-stage-exit stamp |
47
+ | `forge-5-loop` (step-6 epic-member handoff) | standard |
48
+ | `forge-5-loop` (all-done closing → docs) | warm |
49
+
50
+ The scripted stamp fills one build-time slot, `{stage-exit-args}` — the per-stage
51
+ argument list (e.g. `--feature "{feature}" --stage forge-2-tech`; the epic stage passes
52
+ `--feature "{epic}" --stage forge-0-epic --next-feature "{first-actionable-feature}"`).
53
+ `{feature}` / `{epic}` / `{specsDir}` / `{first-actionable-feature}` remain runtime
54
+ placeholders the skill resolves before running the command, exactly as elsewhere.
55
+
56
+ <!-- BEGIN: scripted-stage-exit-stamp -->
57
+ **Close this stage with the Scripted Stage Exit** (contract: `references/stage-exit-protocol.md`; do not improvise a "Next steps" list). Run:
58
+
59
+ ```bash
60
+ R="$(bash -c 'for d in "$HOME"/.claude/skills/feature-forge "$HOME"/.claude/plugins/cache/*/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')"
61
+ [ -n "$R" ] || { echo "feature-forge: cannot locate plugin root" >&2; exit 1; }
62
+ python3 "$R/scripts/forge-session.py" stage-exit {stage-exit-args} --specs-dir "{specsDir}" --host claude
63
+ ```
64
+
65
+ Obey the DIRECTIVES it prints, in order, per the directive contract: `runInStageVerify: true` → dispatch the in-stage clean-room verify now (honoring `autoFixEligible`); `verifyGate: "standard"` → present the Standard Verify Gate; `verifyGate: "manual-print"` → print the `verifyCommand` for the user; non-empty `invalidAutoVerifyKeys` → print a one-line warning. Then **print the NEXT-STEPS block verbatim as your absolute last output — nothing after its sentinel line.**
66
+ <!-- END: scripted-stage-exit-stamp -->
67
+
68
+ ## Directive contract
69
+
70
+ `stage-exit` emits a DIRECTIVES object and a NEXT-STEPS block. The skill executes the
71
+ directives **in this order**; the script has already computed every conditional, so a
72
+ directive is an instruction, not a question to re-derive.
73
+
74
+ ### `invalidAutoVerifyKeys` (non-empty)
75
+
76
+ Print a one-line warning first (e.g. "⚠️ forge.config.json `autoVerifyStages` has
77
+ unknown keys: … — they are ignored; fix the typo").
78
+
79
+ ### `runInStageVerify: true` — in-stage auto-verify {stageNoun}
80
+
81
+ Auto-verify is effective for this stage and verification is outstanding — verify **now,
82
+ in this session** (principle #2 applied to auto-verify: the digest and any fix decision
83
+ land here, where the authoring context still exists — not deferred to a post-`/clear`
84
+ navigator):
85
+
86
+ 1. **Clean-room verify (require-clean).** Dispatch the clean-room `forge-verifier`
87
+ subagent from this session in require-clean mode — the same path the navigator uses
88
+ (`skills/forge-verify/SKILL.md`). Dispatch it **synchronously and await its digest
89
+ inline** — do **not** run it in the background or announce it as "still running";
90
+ the digest and any fix decision must land in this session. It inherits none of this
91
+ session's context, so no `/clear` is needed and only a compact digest returns.
92
+ **Clean-room unavailable** (no `Agent` tool, `forge-verifier` not dispatchable) **or
93
+ a non-answer returned** (the verifier returned a placeholder / "still running" /
94
+ delegation message instead of a findings block): do **not** run inline and do **not**
95
+ silently accept the non-answer as a pass — leave verify **pending** so the navigator
96
+ catch-up fires on a later Claude-host `/feature-forge:forge`, print the
97
+ `verifyCommand` for the user to run, and continue to the NEXT-STEPS block.
98
+ 2. **Verify passed / no findings** → the fresh verify state is recorded by the
99
+ clean-room run; continue to the NEXT-STEPS block.
100
+ 3. **Verify found findings** →
101
+ - **`autoFixEligible: true` AND the findings document has zero unresolved decision
102
+ points** → chain `feature-forge:forge-fix` in-session (it owns its own commit +
103
+ step tracking), then run a **mandatory re-verify** in require-clean mode. Continue
104
+ to the NEXT-STEPS block only if the re-verify passes. On any precondition miss, a
105
+ forge-fix early stop, or a red re-verify, fall through to the digest gate below —
106
+ never a silent partial mutation. (`autoFixEligible` already folds in the config
107
+ `autoFix` flag and the clean-tree precondition; a dirty tree or
108
+ `gitCommitAfterStage: false` arrives here as `false`.)
109
+ - **`autoFixEligible: false`, or unresolved decision points** → surface a **compact
110
+ findings digest** as text, then present the gate via `AskUserQuestion`: **Run
111
+ `forge-fix` now** *(recommended — you are in-context and the digest is right
112
+ here)* / **Clear + advance anyway** (leave the findings for later) / **Stop
113
+ here**. Do **not** hard-stop and do **not** silently walk past. Act on the choice,
114
+ then continue to the NEXT-STEPS block.
115
+
116
+ ### `verifyGate: "standard"` — the Standard Verify Gate
117
+
118
+ Auto-verify is off for this stage and verification is outstanding (`verifyState` is
119
+ `never`, `stale`, or `failing`). Verify **now, before clearing**, using
120
+ `AskUserQuestion` with exactly these three options — but only when the host has a
121
+ question mechanism **and** the clean-room path is available (the `Agent` tool plus a
122
+ dispatchable `forge-verifier` subagent); otherwise degrade exactly as `manual-print`
123
+ below:
124
+
125
+ - **Verify {stageNoun} now** *(recommended)* — dispatch the clean-room `forge-verifier`
126
+ subagent from this session in require-clean mode; the digest returns here so any fix
127
+ decision keeps its context. One-time — it does **not** change config.
128
+ - **Verify now + enable auto-verify going forward** — verify now **and** patch
129
+ `"autoVerify": true` into `forge.config.json` in place (preserve formatting and every
130
+ other key) so future stages verify automatically, no prompt. This complements the
131
+ `forge-init` opt-in. **Do not auto-commit this config change** — treat it like
132
+ `notes`: a user-facing edit the user commits on their own cadence, never folded into
133
+ a stage's artifact commit.
134
+ - **Skip for now** — go straight to the NEXT-STEPS block without verifying. Record this
135
+ stage's verify status as `"skipped"` in pipeline state (mirroring the existing skip
136
+ handling) **only** on an explicit skip — a skip does not go stale.
137
+
138
+ If verify runs and finds findings, handle them exactly as in the in-stage flow above
139
+ (digest + `AskUserQuestion` gate; `autoFixEligible` applies unchanged).
140
+
141
+ ### `verifyGate: "manual-print"`
142
+
143
+ Verification is outstanding but the host cannot present the gate or dispatch
144
+ clean-room. Do **not** run verify inline — print the `verifyCommand` for the user to
145
+ run (mirroring `autoInvokeNextStage`), offer the auto-verify enable as plain text only
146
+ if a config write is possible, and continue to the NEXT-STEPS block. Verify state stays
147
+ outstanding, so the navigator catch-up can fire later.
148
+
149
+ ### `verifyGate: "none"`
150
+
151
+ Verification is already resolved (fresh or explicitly skipped) or the in-stage run
152
+ above covers it. Say so in one line and continue to the NEXT-STEPS block.
153
+
154
+ ### The NEXT-STEPS block (always last)
155
+
156
+ Print the script's NEXT-STEPS block **verbatim as your absolute last output**. Nothing
157
+ follows its final sentinel line (`─ forge: end of stage ─`) — no caveats, no summary,
158
+ no sign-off. The block already carries the `/clear` recommendation (host-aware wording
159
+ via `--host`) and the exact next command, so trailing prose can only push the user's
160
+ next action out of view.
53
161
 
54
162
  ---
55
163
 
56
164
  ## Standard block
57
165
 
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.
166
+ Stamped at the loop's step-6 epic-member handoff (finishing feature A → starting
167
+ feature B's PRD). It self-adapts: step 1's verify gate only fires when verification is
168
+ actually outstanding, so at a boundary where verify already ran (or was explicitly
169
+ skipped, or auto-verify is on) it silently collapses to just the `/clear` →
170
+ next-command steps.
171
+
172
+ Slots: `{stage}` (a lowercase noun phrase), `{verify-command}`, `{next-command}`.
62
173
 
63
174
  <!-- BEGIN: standard-exit-block -->
64
175
  **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
176
 
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):
177
+ 1. **Verify {stage} first — if it isn't already verified.** If verify already ran in this session — via the in-stage auto-verify on the authoring stages, or the interactive impl-verify offered above on the loop — or is already fresh on record, or the stage was explicitly skipped, say so and go straight to step 2. Only when `autoVerify` is off for this stage **and** verify is **missing or stale** do you present the **Standard Verify Gate**: verify **now, before clearing**, 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
178
  - **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
179
  - **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
180
  - **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.
@@ -31,14 +31,33 @@ if is_root "$root"; then
31
31
  exit 0
32
32
  fi
33
33
 
34
+ # ── Step 2a: Claude marketplace-cache installs — ~/.claude/plugins/cache/<mp>/<plugin>/<ver>/.
35
+ # This is where Claude Code actually installs marketplace plugins (three segments below
36
+ # plugins/, so the single-star plugins/*/feature-forge glob below can never match it). Version
37
+ # dirs can coexist after upgrades, so probe newest plugin.json first — a stale version must
38
+ # never shadow the current install. Deliberately ordered BEFORE the plugins/* glob: that glob
39
+ # can match the marketplace *clone* (~/.claude/plugins/marketplaces/<mp>/ when the marketplace
40
+ # repo root is itself a plugin root), which may sit at a different commit than the installed
41
+ # skills — the versioned cache install must always win to prevent that version skew.
42
+ while IFS= read -r manifest; do
43
+ candidate="${manifest%/.claude-plugin/plugin.json}"
44
+ if is_root "$candidate"; then
45
+ printf '%s\n' "$candidate"
46
+ exit 0
47
+ fi
48
+ done < <(ls -t "$HOME"/.claude/plugins/cache/*/feature-forge/*/.claude-plugin/plugin.json 2>/dev/null || true)
49
+
34
50
  # ── Step 2: candidate-root probe (authoritative multi-agent root list; extend here first). ─
35
51
  # Globs that match nothing expand to themselves; the is_root test rejects such literals. Covers
36
52
  # every supported agent's install destination under BOTH global ($HOME) and project ($PWD) scope,
37
53
  # matching the installer's per-agent layout: claude .claude/skills, codex .agents/skills, copilot
38
- # .github/feature-forge, cursor .cursor/rules, gemini .gemini/extensions.
54
+ # .github/feature-forge, cursor .cursor/rules, gemini .gemini/extensions. The cache glob repeats
55
+ # step 2a's path for a cache install that carries only the neutral bundle sentinel (no
56
+ # plugin.json for ls -t to key on).
39
57
  for candidate in \
40
58
  "$HOME/.claude/skills/feature-forge" \
41
59
  "$PWD/.claude/skills/feature-forge" \
60
+ "$HOME"/.claude/plugins/cache/*/feature-forge/* \
42
61
  "$HOME"/.claude/plugins/*/feature-forge \
43
62
  "$HOME/.agents/skills/feature-forge" \
44
63
  "$PWD/.agents/skills/feature-forge" \