@garygentry/feature-forge 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (231) hide show
  1. package/LICENSE +21 -0
  2. package/adapters/GENERATION-REPORT.md +128 -0
  3. package/adapters/claude/agents/forge-researcher.md +137 -0
  4. package/adapters/claude/agents/forge-spec-writer.md +115 -0
  5. package/adapters/claude/agents/forge-verifier.md +121 -0
  6. package/adapters/claude/references/epic-manifest-schema.json +120 -0
  7. package/adapters/claude/references/forge-config-schema.json +166 -0
  8. package/adapters/claude/references/pipeline-state-schema.json +110 -0
  9. package/adapters/claude/references/portable-root.md +56 -0
  10. package/adapters/claude/references/process-overview.md +123 -0
  11. package/adapters/claude/references/ralph-loop-contract.md +221 -0
  12. package/adapters/claude/references/shared-conventions.md +144 -0
  13. package/adapters/claude/references/skill-frontmatter.schema.json +17 -0
  14. package/adapters/claude/references/stack-resolution.md +51 -0
  15. package/adapters/claude/references/stacks/_generic.md +90 -0
  16. package/adapters/claude/references/stacks/go.md +138 -0
  17. package/adapters/claude/references/stacks/python.md +163 -0
  18. package/adapters/claude/references/stacks/rust.md +151 -0
  19. package/adapters/claude/references/stacks/typescript.md +111 -0
  20. package/adapters/claude/references/vendor-construct-inventory.md +49 -0
  21. package/adapters/claude/scripts/forge-root.sh +50 -0
  22. package/adapters/claude/skills/forge/SKILL.md +165 -0
  23. package/adapters/claude/skills/forge-0-epic/SKILL.md +303 -0
  24. package/adapters/claude/skills/forge-0-epic/references/edit-mode.md +222 -0
  25. package/adapters/claude/skills/forge-0-epic/references/epic-manifest-subcommands.md +64 -0
  26. package/adapters/claude/skills/forge-1-prd/SKILL.md +121 -0
  27. package/adapters/claude/skills/forge-1-prd/references/prd-template.md +106 -0
  28. package/adapters/claude/skills/forge-2-tech/SKILL.md +198 -0
  29. package/adapters/claude/skills/forge-2-tech/references/stack-discovery-checklist.md +95 -0
  30. package/adapters/claude/skills/forge-3-specs/SKILL.md +154 -0
  31. package/adapters/claude/skills/forge-3-specs/references/spec-archetypes.md +106 -0
  32. package/adapters/claude/skills/forge-3-specs/references/spec-examples.md +71 -0
  33. package/adapters/claude/skills/forge-4-backlog/SKILL.md +146 -0
  34. package/adapters/claude/skills/forge-5-loop/SKILL.md +303 -0
  35. package/adapters/claude/skills/forge-5-loop/references/result-reporting.md +63 -0
  36. package/adapters/claude/skills/forge-5-loop/references/runner-contract.md +214 -0
  37. package/adapters/claude/skills/forge-6-docs/SKILL.md +179 -0
  38. package/adapters/claude/skills/forge-6-docs/references/doc-conventions.md +126 -0
  39. package/adapters/claude/skills/forge-fix/SKILL.md +65 -0
  40. package/adapters/claude/skills/forge-init/SKILL.md +29 -0
  41. package/adapters/claude/skills/forge-verify/SKILL.md +219 -0
  42. package/adapters/claude/skills/forge-verify/references/verification-checklists.md +379 -0
  43. package/adapters/codex/agents/forge-researcher.md +133 -0
  44. package/adapters/codex/agents/forge-spec-writer.md +112 -0
  45. package/adapters/codex/agents/forge-verifier.md +115 -0
  46. package/adapters/codex/agents/openai.yaml +10 -0
  47. package/adapters/codex/references/epic-manifest-schema.json +120 -0
  48. package/adapters/codex/references/forge-config-schema.json +166 -0
  49. package/adapters/codex/references/pipeline-state-schema.json +110 -0
  50. package/adapters/codex/references/portable-root.md +56 -0
  51. package/adapters/codex/references/process-overview.md +123 -0
  52. package/adapters/codex/references/ralph-loop-contract.md +221 -0
  53. package/adapters/codex/references/shared-conventions.md +144 -0
  54. package/adapters/codex/references/skill-frontmatter.schema.json +17 -0
  55. package/adapters/codex/references/stack-resolution.md +51 -0
  56. package/adapters/codex/references/stacks/_generic.md +90 -0
  57. package/adapters/codex/references/stacks/go.md +138 -0
  58. package/adapters/codex/references/stacks/python.md +163 -0
  59. package/adapters/codex/references/stacks/rust.md +151 -0
  60. package/adapters/codex/references/stacks/typescript.md +111 -0
  61. package/adapters/codex/references/vendor-construct-inventory.md +49 -0
  62. package/adapters/codex/scripts/forge-root.sh +50 -0
  63. package/adapters/codex/skills/forge/forge.md +164 -0
  64. package/adapters/codex/skills/forge-0-epic/forge-0-epic.md +302 -0
  65. package/adapters/codex/skills/forge-0-epic/references/edit-mode.md +222 -0
  66. package/adapters/codex/skills/forge-0-epic/references/epic-manifest-subcommands.md +64 -0
  67. package/adapters/codex/skills/forge-1-prd/forge-1-prd.md +120 -0
  68. package/adapters/codex/skills/forge-1-prd/references/prd-template.md +106 -0
  69. package/adapters/codex/skills/forge-2-tech/forge-2-tech.md +197 -0
  70. package/adapters/codex/skills/forge-2-tech/references/stack-discovery-checklist.md +95 -0
  71. package/adapters/codex/skills/forge-3-specs/forge-3-specs.md +153 -0
  72. package/adapters/codex/skills/forge-3-specs/references/spec-archetypes.md +106 -0
  73. package/adapters/codex/skills/forge-3-specs/references/spec-examples.md +71 -0
  74. package/adapters/codex/skills/forge-4-backlog/forge-4-backlog.md +145 -0
  75. package/adapters/codex/skills/forge-5-loop/forge-5-loop.md +302 -0
  76. package/adapters/codex/skills/forge-5-loop/references/result-reporting.md +63 -0
  77. package/adapters/codex/skills/forge-5-loop/references/runner-contract.md +214 -0
  78. package/adapters/codex/skills/forge-6-docs/forge-6-docs.md +178 -0
  79. package/adapters/codex/skills/forge-6-docs/references/doc-conventions.md +126 -0
  80. package/adapters/codex/skills/forge-fix/forge-fix.md +64 -0
  81. package/adapters/codex/skills/forge-init/forge-init.md +29 -0
  82. package/adapters/codex/skills/forge-verify/forge-verify.md +218 -0
  83. package/adapters/codex/skills/forge-verify/references/verification-checklists.md +379 -0
  84. package/adapters/copilot/agents/forge-researcher.md +133 -0
  85. package/adapters/copilot/agents/forge-spec-writer.md +112 -0
  86. package/adapters/copilot/agents/forge-verifier.md +115 -0
  87. package/adapters/copilot/references/epic-manifest-schema.json +120 -0
  88. package/adapters/copilot/references/forge-config-schema.json +166 -0
  89. package/adapters/copilot/references/pipeline-state-schema.json +110 -0
  90. package/adapters/copilot/references/portable-root.md +56 -0
  91. package/adapters/copilot/references/process-overview.md +123 -0
  92. package/adapters/copilot/references/ralph-loop-contract.md +221 -0
  93. package/adapters/copilot/references/shared-conventions.md +144 -0
  94. package/adapters/copilot/references/skill-frontmatter.schema.json +17 -0
  95. package/adapters/copilot/references/stack-resolution.md +51 -0
  96. package/adapters/copilot/references/stacks/_generic.md +90 -0
  97. package/adapters/copilot/references/stacks/go.md +138 -0
  98. package/adapters/copilot/references/stacks/python.md +163 -0
  99. package/adapters/copilot/references/stacks/rust.md +151 -0
  100. package/adapters/copilot/references/stacks/typescript.md +111 -0
  101. package/adapters/copilot/references/vendor-construct-inventory.md +49 -0
  102. package/adapters/copilot/scripts/forge-root.sh +50 -0
  103. package/adapters/copilot/skills/forge/forge.md +164 -0
  104. package/adapters/copilot/skills/forge-0-epic/forge-0-epic.md +302 -0
  105. package/adapters/copilot/skills/forge-0-epic/references/edit-mode.md +222 -0
  106. package/adapters/copilot/skills/forge-0-epic/references/epic-manifest-subcommands.md +64 -0
  107. package/adapters/copilot/skills/forge-1-prd/forge-1-prd.md +120 -0
  108. package/adapters/copilot/skills/forge-1-prd/references/prd-template.md +106 -0
  109. package/adapters/copilot/skills/forge-2-tech/forge-2-tech.md +197 -0
  110. package/adapters/copilot/skills/forge-2-tech/references/stack-discovery-checklist.md +95 -0
  111. package/adapters/copilot/skills/forge-3-specs/forge-3-specs.md +153 -0
  112. package/adapters/copilot/skills/forge-3-specs/references/spec-archetypes.md +106 -0
  113. package/adapters/copilot/skills/forge-3-specs/references/spec-examples.md +71 -0
  114. package/adapters/copilot/skills/forge-4-backlog/forge-4-backlog.md +145 -0
  115. package/adapters/copilot/skills/forge-5-loop/forge-5-loop.md +302 -0
  116. package/adapters/copilot/skills/forge-5-loop/references/result-reporting.md +63 -0
  117. package/adapters/copilot/skills/forge-5-loop/references/runner-contract.md +214 -0
  118. package/adapters/copilot/skills/forge-6-docs/forge-6-docs.md +178 -0
  119. package/adapters/copilot/skills/forge-6-docs/references/doc-conventions.md +126 -0
  120. package/adapters/copilot/skills/forge-fix/forge-fix.md +64 -0
  121. package/adapters/copilot/skills/forge-init/forge-init.md +29 -0
  122. package/adapters/copilot/skills/forge-verify/forge-verify.md +218 -0
  123. package/adapters/copilot/skills/forge-verify/references/verification-checklists.md +379 -0
  124. package/adapters/cursor/agents/forge-researcher.mdc +134 -0
  125. package/adapters/cursor/agents/forge-spec-writer.mdc +113 -0
  126. package/adapters/cursor/agents/forge-verifier.mdc +116 -0
  127. package/adapters/cursor/references/epic-manifest-schema.json +120 -0
  128. package/adapters/cursor/references/forge-config-schema.json +166 -0
  129. package/adapters/cursor/references/pipeline-state-schema.json +110 -0
  130. package/adapters/cursor/references/portable-root.md +56 -0
  131. package/adapters/cursor/references/process-overview.md +123 -0
  132. package/adapters/cursor/references/ralph-loop-contract.md +221 -0
  133. package/adapters/cursor/references/shared-conventions.md +144 -0
  134. package/adapters/cursor/references/skill-frontmatter.schema.json +17 -0
  135. package/adapters/cursor/references/stack-resolution.md +51 -0
  136. package/adapters/cursor/references/stacks/_generic.md +90 -0
  137. package/adapters/cursor/references/stacks/go.md +138 -0
  138. package/adapters/cursor/references/stacks/python.md +163 -0
  139. package/adapters/cursor/references/stacks/rust.md +151 -0
  140. package/adapters/cursor/references/stacks/typescript.md +111 -0
  141. package/adapters/cursor/references/vendor-construct-inventory.md +49 -0
  142. package/adapters/cursor/scripts/forge-root.sh +50 -0
  143. package/adapters/cursor/skills/forge/forge.mdc +165 -0
  144. package/adapters/cursor/skills/forge-0-epic/forge-0-epic.mdc +303 -0
  145. package/adapters/cursor/skills/forge-0-epic/references/edit-mode.md +222 -0
  146. package/adapters/cursor/skills/forge-0-epic/references/epic-manifest-subcommands.md +64 -0
  147. package/adapters/cursor/skills/forge-1-prd/forge-1-prd.mdc +121 -0
  148. package/adapters/cursor/skills/forge-1-prd/references/prd-template.md +106 -0
  149. package/adapters/cursor/skills/forge-2-tech/forge-2-tech.mdc +198 -0
  150. package/adapters/cursor/skills/forge-2-tech/references/stack-discovery-checklist.md +95 -0
  151. package/adapters/cursor/skills/forge-3-specs/forge-3-specs.mdc +154 -0
  152. package/adapters/cursor/skills/forge-3-specs/references/spec-archetypes.md +106 -0
  153. package/adapters/cursor/skills/forge-3-specs/references/spec-examples.md +71 -0
  154. package/adapters/cursor/skills/forge-4-backlog/forge-4-backlog.mdc +146 -0
  155. package/adapters/cursor/skills/forge-5-loop/forge-5-loop.mdc +303 -0
  156. package/adapters/cursor/skills/forge-5-loop/references/result-reporting.md +63 -0
  157. package/adapters/cursor/skills/forge-5-loop/references/runner-contract.md +214 -0
  158. package/adapters/cursor/skills/forge-6-docs/forge-6-docs.mdc +179 -0
  159. package/adapters/cursor/skills/forge-6-docs/references/doc-conventions.md +126 -0
  160. package/adapters/cursor/skills/forge-fix/forge-fix.mdc +65 -0
  161. package/adapters/cursor/skills/forge-init/forge-init.mdc +30 -0
  162. package/adapters/cursor/skills/forge-verify/forge-verify.mdc +219 -0
  163. package/adapters/cursor/skills/forge-verify/references/verification-checklists.md +379 -0
  164. package/adapters/gemini/agents/forge-researcher.md +133 -0
  165. package/adapters/gemini/agents/forge-spec-writer.md +112 -0
  166. package/adapters/gemini/agents/forge-verifier.md +115 -0
  167. package/adapters/gemini/gemini-extension.json +54 -0
  168. package/adapters/gemini/references/epic-manifest-schema.json +120 -0
  169. package/adapters/gemini/references/forge-config-schema.json +166 -0
  170. package/adapters/gemini/references/pipeline-state-schema.json +110 -0
  171. package/adapters/gemini/references/portable-root.md +56 -0
  172. package/adapters/gemini/references/process-overview.md +123 -0
  173. package/adapters/gemini/references/ralph-loop-contract.md +221 -0
  174. package/adapters/gemini/references/shared-conventions.md +144 -0
  175. package/adapters/gemini/references/skill-frontmatter.schema.json +17 -0
  176. package/adapters/gemini/references/stack-resolution.md +51 -0
  177. package/adapters/gemini/references/stacks/_generic.md +90 -0
  178. package/adapters/gemini/references/stacks/go.md +138 -0
  179. package/adapters/gemini/references/stacks/python.md +163 -0
  180. package/adapters/gemini/references/stacks/rust.md +151 -0
  181. package/adapters/gemini/references/stacks/typescript.md +111 -0
  182. package/adapters/gemini/references/vendor-construct-inventory.md +49 -0
  183. package/adapters/gemini/scripts/forge-root.sh +50 -0
  184. package/adapters/gemini/skills/forge/forge.md +164 -0
  185. package/adapters/gemini/skills/forge-0-epic/forge-0-epic.md +302 -0
  186. package/adapters/gemini/skills/forge-0-epic/references/edit-mode.md +222 -0
  187. package/adapters/gemini/skills/forge-0-epic/references/epic-manifest-subcommands.md +64 -0
  188. package/adapters/gemini/skills/forge-1-prd/forge-1-prd.md +120 -0
  189. package/adapters/gemini/skills/forge-1-prd/references/prd-template.md +106 -0
  190. package/adapters/gemini/skills/forge-2-tech/forge-2-tech.md +197 -0
  191. package/adapters/gemini/skills/forge-2-tech/references/stack-discovery-checklist.md +95 -0
  192. package/adapters/gemini/skills/forge-3-specs/forge-3-specs.md +153 -0
  193. package/adapters/gemini/skills/forge-3-specs/references/spec-archetypes.md +106 -0
  194. package/adapters/gemini/skills/forge-3-specs/references/spec-examples.md +71 -0
  195. package/adapters/gemini/skills/forge-4-backlog/forge-4-backlog.md +145 -0
  196. package/adapters/gemini/skills/forge-5-loop/forge-5-loop.md +302 -0
  197. package/adapters/gemini/skills/forge-5-loop/references/result-reporting.md +63 -0
  198. package/adapters/gemini/skills/forge-5-loop/references/runner-contract.md +214 -0
  199. package/adapters/gemini/skills/forge-6-docs/forge-6-docs.md +178 -0
  200. package/adapters/gemini/skills/forge-6-docs/references/doc-conventions.md +126 -0
  201. package/adapters/gemini/skills/forge-fix/forge-fix.md +64 -0
  202. package/adapters/gemini/skills/forge-init/forge-init.md +29 -0
  203. package/adapters/gemini/skills/forge-verify/forge-verify.md +218 -0
  204. package/adapters/gemini/skills/forge-verify/references/verification-checklists.md +379 -0
  205. package/dist/agent-targets.d.ts +70 -0
  206. package/dist/agent-targets.js +111 -0
  207. package/dist/apply.d.ts +49 -0
  208. package/dist/apply.js +246 -0
  209. package/dist/cli.d.ts +94 -0
  210. package/dist/cli.js +508 -0
  211. package/dist/detect.d.ts +45 -0
  212. package/dist/detect.js +72 -0
  213. package/dist/fsutil.d.ts +56 -0
  214. package/dist/fsutil.js +175 -0
  215. package/dist/hash.d.ts +50 -0
  216. package/dist/hash.js +107 -0
  217. package/dist/index.d.ts +8 -0
  218. package/dist/index.js +9 -0
  219. package/dist/manifest.d.ts +72 -0
  220. package/dist/manifest.js +222 -0
  221. package/dist/plan.d.ts +66 -0
  222. package/dist/plan.js +166 -0
  223. package/dist/rauf.d.ts +83 -0
  224. package/dist/rauf.js +118 -0
  225. package/dist/report.d.ts +35 -0
  226. package/dist/report.js +110 -0
  227. package/dist/source.d.ts +69 -0
  228. package/dist/source.js +164 -0
  229. package/dist/types.d.ts +264 -0
  230. package/dist/types.js +57 -0
  231. package/package.json +42 -0
@@ -0,0 +1,302 @@
1
+ ---
2
+ # GENERATED — DO NOT EDIT. Source: skills/forge-5-loop/SKILL.md. Regenerate: python3 scripts/build-adapters.py
3
+ name: forge-5-loop
4
+ description: Execute the autonomous coding loop (rauf by default) against a forge feature's backlog. Use when user runs /feature-forge:forge-5-loop or /feature-forge:forge-5-rauf-loop, or asks to run rauf / run the loop / implement a forge feature after the backlog is created and verified. Do NOT trigger for general rauf usage, standalone loop runs, or implementation tasks outside the forge pipeline.
5
+ ---
6
+
7
+ # forge-5-loop — Autonomous Loop Executor
8
+
9
+ Execute the autonomous coding loop against a forge feature's backlog. The loop
10
+ spawns a fresh agent session per backlog item, implementing each task with full
11
+ verification.
12
+
13
+ The loop **runner** is configured, not hardcoded. feature-forge talks to it
14
+ through the `loopRunner` block in `forge.config.json`; rauf is the default and
15
+ reference implementation (see `references/ralph-loop-contract.md`). Every command
16
+ below is rendered from `loopRunner` with token substitution — there are no
17
+ hardcoded `rauf …` commands in this skill, and even the human log filename is
18
+ tokenized as `{loopRunner.logFile}`.
19
+
20
+ ## Resolve the loop runner
21
+
22
+ Read `forge.config.json`. Build the effective `loopRunner` by taking its
23
+ `loopRunner` block (if present) and filling any missing field from the defaults
24
+ in `references/forge-config-schema.json`. **If `forge.config.json` has no
25
+ `loopRunner` block at all, state plainly: "No loopRunner configured — defaulting
26
+ to the rauf loop runner."** then proceed with the full default block.
27
+
28
+ Token substitution applies to every `*Command` string. Substitute:
29
+
30
+ - `{bin}` → `loopRunner.bin` (default `rauf`)
31
+ - `{backlogDir}` → the resolved backlog directory (Step 1d / 2b), relative to project root
32
+ - `{specsDir}` → `specsDir` from config
33
+ - `{iterations}` → the computed iteration count (Step 2a)
34
+
35
+ Whenever this skill says "run the **run command**" / "**status command**" /
36
+ etc., it means the corresponding substituted `loopRunner.*Command`.
37
+
38
+ **Turn structure reminder:** Output analysis/context as text, then route ALL questions through `AskUserQuestion`. Never embed questions in text output — the user will not be prompted and the session will stall.
39
+
40
+ ## Step 1: Validate Prerequisites
41
+
42
+ Read and follow `references/shared-conventions.md` for feature name validation, configuration reading, and force mode handling.
43
+
44
+ ### 1a. Pipeline State Check
45
+
46
+ **Resolve the feature directory first.** Invoke the **Feature Directory Resolution** block in `references/shared-conventions.md` to turn the bare feature name into `{resolvedFeatureDir}` (exit 0 → stdout is the absolute dir; exit ≥ 1 → STOP and surface the finding verbatim). Read state from `{resolvedFeatureDir}/` everywhere this skill previously wrote `{specsDir}/{feature}/` (the 1e backlog path and the Step 3a / Step 5 state writes). Standalone features resolve to their flat path exactly as today.
47
+
48
+ Read `{resolvedFeatureDir}/.pipeline-state.json`. If not in force mode, `stages.forge-4-backlog` must be `complete`. If not, STOP and tell the user: "Backlog hasn't been created yet. Run `/feature-forge:forge-4-backlog {feature}` first."
49
+
50
+ ### 1b. Verification Check
51
+
52
+ Check if `stages.forge-verify-backlog` exists and has status `passed` or `findings-applied`. If not, use `AskUserQuestion` to warn:
53
+
54
+ "Backlog hasn't been verified yet. It's recommended to run `/feature-forge:forge-verify {feature}` first to catch issues before implementation. Continue anyway?"
55
+
56
+ ### 1b-epic. Epic Dependency Gate
57
+
58
+ Read the resolved feature's `.pipeline-state.json`. **If it has no `epic` key, skip this sub-step entirely** (standalone feature — REQ-COMPAT-01; standalone runs are unchanged). Otherwise:
59
+
60
+ 1. Run `render-status "{epic}" --specs-dir "{specsDir}" --json` via the helper:
61
+
62
+ ```bash
63
+ R="$(for d in "$HOME"/.claude/skills/feature-forge "$HOME"/.claude/plugins/*/feature-forge; do [ -x "$d/scripts/forge-root.sh" ] && exec "$d/scripts/forge-root.sh"; done)"
64
+ [ -n "$R" ] || { echo "feature-forge: cannot locate plugin root" >&2; exit 1; }
65
+ python3 "$R/scripts/epic-manifest.py" \
66
+ render-status "{epic}" --specs-dir "{specsDir}" --json
67
+ ```
68
+
69
+ 2. Find this feature's entry; read its `unmetDeps` (the direct `dependsOn` not yet complete-for-orchestration per `00-core-definitions.md §7`).
70
+ 3. **If `unmetDeps` is empty**, proceed to 1c with no prompt.
71
+ 4. **If `unmetDeps` is non-empty**, use `AskUserQuestion` (do NOT inline the question as prose) to warn that the feature depends on the unmet dependencies, which are not yet complete, and that running the loop now means implementing against contracts that may still change:
72
+
73
+ > "{feature} depends on {unmetDeps joined}, which are not yet complete. Running the loop now means implementing against contracts that may still change. Proceed anyway, or stop and finish the dependencies first?"
74
+
75
+ Require an **explicit "Proceed anyway"** choice to continue (REQ-ORCH-04). "Stop" aborts before any runner setup. `--force` (shared-conventions Force Mode) also bypasses this gate with the standard force warning.
76
+ 5. If `render-status` fails, **STOP** — do not silently run a loop whose dependency state is unverifiable (REQ-ROBUST-02). Surface per the exit-1/exit-2 split in the **Feature Directory Resolution** block of `references/shared-conventions.md` (exit 1 → parse `{findings[]}` from stdout; exit 2 → surface the plain `Error:` stderr line verbatim — no findings JSON to parse).
77
+
78
+ This gate runs **before** the runner version/setup gates (1c/1d) so a blocked feature stops early, before any runner side-effects.
79
+
80
+ ### 1c. Runner Version Gate
81
+
82
+ Enforce `loopRunner.minRunnerVersion` **before** doing anything else with the runner. This is what turns "the runner is missing or too old" into a clear, actionable stop instead of a cryptic mid-run failure.
83
+
84
+ 1. Run the **version command** (`loopRunner.versionCommand`, default `rauf version --json`) via Bash.
85
+ 2. Parse `{ "version": "<semver>" }` from stdout. Do NOT use plain `rauf version` (its human output is `rauf v0.6.0` with a `v` prefix) — always the `--json` form.
86
+ 3. **Semver-compare** (NOT string-compare) the reported version against `loopRunner.minRunnerVersion` (default `0.6.0`), numerically by major, then minor, then patch.
87
+
88
+ **Any of the following is a HARD GATE FAILURE — do NOT proceed to run the loop.** STOP, show `loopRunner.installHint`, and include the raw command output for diagnosis:
89
+
90
+ - The version command is not found or exits non-zero (the binary isn't installed).
91
+ - Its stdout is not valid JSON, has no `version` field, or `version` is not a valid semver string.
92
+ - The reported version is **< `minRunnerVersion`**.
93
+
94
+ For the version-too-old case, phrase it concretely, e.g.: "Your rauf is {reported}, but feature-forge needs ≥ {minRunnerVersion} — 0.6.0 is the floor that ships the agent-selection surface (`--agent` / `rauf agents`) the loop relies on. {installHint}". When the gate fails because the output couldn't be parsed, say so and show what the command printed before the `installHint`.
95
+
96
+ > `installHint` points at the runner **CLI** install/upgrade — distinct from
97
+ > `setupHint` (1d), which installs the runner's per-project artifacts.
98
+
99
+ ### 1d. Runner Setup Check (precondition file)
100
+
101
+ Check that `loopRunner.preconditionFile` (default `.rauf.json`) exists in the project root. If not:
102
+
103
+ - **If `loopRunner.name == "rauf"` and a legacy `.ralph.json` (or `.ralph/` directory) exists**, this is an un-migrated Ralph project. STOP and tell the user:
104
+
105
+ "This project is still on the legacy **Ralph** layout. Run `rauf migrate .` first (the loop runner only understands `.rauf/` and `RAUF_*` signals), then re-run `/feature-forge:forge-5-loop {feature}`."
106
+
107
+ - **Otherwise**, STOP and show `loopRunner.setupHint` (default: "Run `rauf install .` …"), e.g.:
108
+
109
+ "The loop runner isn't set up in this project ({preconditionFile} is missing). {setupHint}"
110
+
111
+ ### 1e. Backlog File Check
112
+
113
+ Resolve the backlog file path (matching forge-4-backlog's composition rule, item 015 / §6.2):
114
+ - If `backlogDir` is set in `forge.config.json`: use `{backlogDir}/{feature}/backlog.json` (the per-feature subpath, so each epic member's backlog stays independent — the `{feature}` segment prevents collisions across a multi-feature epic)
115
+ - Otherwise: use `{resolvedFeatureDir}/backlog.json`
116
+
117
+ Verify the file exists on disk. If not, STOP and tell the user: "No backlog.json found at {path}. Run `/feature-forge:forge-4-backlog {feature}` to generate it."
118
+
119
+ ## Step 2: Construct the Loop Command
120
+
121
+ ### 2a. Analyze Backlog
122
+
123
+ Run the **list command** (`loopRunner.listCommand`, default `rauf backlog list . --backlog {backlogDir} --json`) and count items by status: `pending`, `in_progress`, `done`, `blocked`.
124
+
125
+ Calculate the iteration count: `ceil((pending + in_progress) * loopIterationMultiplier)` where `loopIterationMultiplier` comes from `forge.config.json` (default: 1.5). This headroom allows retries without exhausting iterations.
126
+
127
+ If there are no pending or in_progress items, STOP and tell the user: "All backlog items are already done or blocked. Nothing to run."
128
+
129
+ If there are `blocked` items, note them — the user may want `--retry-blocked`.
130
+
131
+ ### 2b. Resolve Backlog Directory
132
+
133
+ `{backlogDir}` is a **directory path** (not a file path), relative to the project root.
134
+
135
+ - If `backlogDir` is set in config: use the per-feature subpath `{backlogDir}/{feature}` (matching the 1e composition rule and forge-4-backlog §6.2).
136
+ - Otherwise: use `{resolvedFeatureDir}` (the directory containing `backlog.json`).
137
+
138
+ **Example:** If `specsDir` is `./specs` and feature is `auth`, `{backlogDir}` is `specs/auth`.
139
+
140
+ ### 2c. Build Command
141
+
142
+ Render the **run command** (`loopRunner.runCommand`) with token substitution, e.g. the rauf default becomes:
143
+
144
+ ```
145
+ rauf loop run . --backlog specs/auth --iterations 15
146
+ ```
147
+
148
+ ### 2d. Confirm with User
149
+
150
+ Use `AskUserQuestion` to present the rendered run command and options. The following block is the content for `AskUserQuestion` — do NOT output it as text:
151
+
152
+ ```
153
+ Ready to run the loop for {feature}:
154
+
155
+ {rendered runCommand}
156
+
157
+ Backlog summary:
158
+ - Pending: {pending}
159
+ - In progress: {in_progress}
160
+ - Done: {done}
161
+ - Blocked: {blocked}
162
+ - Iterations: {iterationCount} ({activeItems} items x {loopIterationMultiplier} multiplier)
163
+
164
+ Optional flags you can add (rauf): --review, --model <model>, --timeout <min>,
165
+ --retry-blocked. For the full optional-flags catalog and the model-selection
166
+ precedence (item.model > --model/options > project default > provider default),
167
+ read references/runner-contract.md.
168
+
169
+ Proceed with this command, or would you like to adjust?
170
+ ```
171
+
172
+ For the full loop-runner contract — event-stream vs. log-fallback launch, the live-supervision/monitor rules, and the model-selection precedence — read `references/runner-contract.md`. If the user requests additional flags, append them to the rendered run command.
173
+
174
+ #### Agent selection (gated on `loopRunner.agentArgument`)
175
+
176
+ **Capability gate.** Everything below applies **only when** the effective `loopRunner.agentArgument` is present and non-empty. **When it is absent or empty, Step 2d is exactly the confirmation above — no probe, no agent question, no availability listing, no `Agent:` line — byte-identical to today** (REQ-PLUG-02, REQ-COMPAT-01). The full algorithm, precedence, and verbatim message shapes are in `## Agent selection` of `references/runner-contract.md`; read it. When the gate is on, augment Step 2d in order:
177
+
178
+ - **(a) Probe once.** Before confirming, run `loopRunner.agentsProbeCommand` (default `{bin} agents --json`) **exactly once** (no retries, no second probe); it exits 0 with `{ agents: [...] }`. Parse `agents[]`; build the advertised set `{ row.id }` — this one parsed array drives (b)–(d).
179
+ - **(b) Agent question.** Add an **"agent"** question to the same `AskUserQuestion` surface: **one option per advertised row** labelled `"{displayName} ({id}) — available/not found"`, **plus an explicit `"default (claude-cli)"` choice mapping to `run_selection = None`**. Resolve the pick (run > project, empty/whitespace unset, an explicit runner-default pick collapses to the default path) into `{resolved.agent, resolved.source}`. Precedence: `item.provider > --agent > project defaultAgent > runner default` (forge never reads a backlog item's provider).
180
+ - **(c) Availability listing.** From the **same** parsed `agents[]` (no second probe), list `id` / `displayName` / available (`yes`/`no`, `detail` on unavailable rows).
181
+ - **(d) Verdict** — only for a **non-default** resolved agent (default path `None`/`claude-cli` → no probe, byte-identical to today). Classify by **membership** then `available` (never by exit code): **UNKNOWN** (`∉` set) → **hard-reject BEFORE any loop side-effect**, error lists the **sorted** valid ids, **NO proceed-anyway**; **UNAVAILABLE** (member, `available False`) → warn with `detail`, `AskUserQuestion` offering **proceed-anyway OR choose-another** (re-presents the same `agents[]`), never silent; **AVAILABLE** → proceed, the validated id fills `{agent}`; **probe failure** (non-zero exit / unparseable / missing or empty `agents[]` / row lacking `id`) → surface it, offer **choose-another OR abort**, **never launch the non-default agent unvalidated** and never silently fall back to the default.
182
+ - **(e) Optional-flags line.** Replace the confirmation's optional-flags line with one that lists `--agent <id>` first plus the agent precedence pointer (`item.provider > --agent > project defaultAgent > runner default`) alongside the model precedence.
183
+ - **(f) Resolved-agent line.** Add to the confirmation block: `Agent: {resolved.agent or claude-cli} (source: {sourceLabel})` — `sourceLabel`: `RUN` → `"per-run selection"`, `PROJECT` → `"project default (loopRunner.defaultAgent)"`, `DEFAULT` → `"runner default — claude-cli"`.
184
+
185
+ ## Step 3: Execute the Loop
186
+
187
+ ### 3a. Update Pipeline State
188
+
189
+ Before launching, update `{resolvedFeatureDir}/.pipeline-state.json`:
190
+ - Set `stages.forge-5-loop.status` to `in-progress`
191
+ - Set `stages.forge-5-loop.startedAt` to current ISO timestamp
192
+ - Set `currentStage` to `forge-5-loop`
193
+ - Update `updatedAt`
194
+
195
+ ### 3b. Launch Background Process
196
+
197
+ Launch the loop **backgrounded** (`run_in_background: true`) so it survives session end and does not block the session, and prefer the machine-readable event stream (`loopRunner.eventStreamCommand`, default for rauf) redirected to a stable `events.ndjson` so the session can supervise it live; fall back to the plain `runCommand` (tailing the human log) when no `eventStreamCommand` is configured. The background task's exit notification is the single authoritative terminal signal (Step 4). For the exact launch commands (incl. the `mkdir -p` state-dir guard) and the event-stream vs. log-fallback detail, read `references/runner-contract.md`.
198
+
199
+ Loop runs can take significant time (minutes to hours depending on backlog size).
200
+
201
+ ### 3c. Inform User
202
+
203
+ Tell the user the run has started and that **this session is now actively
204
+ supervising it** — they don't need to babysit a terminal — and surface the rendered
205
+ `loopRunner` monitoring commands (`statusCommand` / `followCommand` / `logCommand` /
206
+ `listCommand`) and the state-file locations under
207
+ `{backlogDir}/{loopRunner.stateDir}/` so they can watch directly if they like. The
208
+ verbatim "Loop started…" inform-user output template is in
209
+ `references/runner-contract.md`.
210
+
211
+ ### 3d. Arm a Monitor on the event stream, and react to events
212
+
213
+ Arm the **`Monitor` tool** on the structured event stream (the NDJSON file, or the
214
+ human log as fallback) so events flow back into this session as they happen. Use
215
+ **`persistent: true`** — runs can exceed `Monitor`'s maximum `timeout_ms` (1 hour),
216
+ and a bounded timeout would silently stop watching a still-running loop. The filter
217
+ MUST match every terminal and exception state, not just the happy path (silence is
218
+ not success). Monitor the **structured** surface, never raw `RAUF_*` tokens.
219
+
220
+ Each Monitor event arrives as a message; react per type — surface `needs_human` /
221
+ `loop_error` immediately with a `PushNotification`, coalesce `item_completed` into
222
+ milestones, and treat `llm_stuck_warning` as a hang warning. A `needs_human` /
223
+ `blocked` signal does **not** pause the loop — the runner sets the item aside and
224
+ keeps going.
225
+
226
+ For the exact Monitor commands (NDJSON `jq` filter and the log-fallback `grep`
227
+ prefixes), the coverage-complete filter event list, and the full per-event reaction
228
+ rules, read `references/runner-contract.md`.
229
+
230
+ ### 3f. Reach completion
231
+
232
+ Step 4 is reached when the backgrounded process exits (its completion notification is
233
+ authoritative); the `loop_completed` / `loop_error` / `loop_cancelled` event is the live
234
+ heads-up that it's imminent. Stop the Monitor (it ends on its own when `tail` sees the
235
+ process-ended log, or via `TaskStop`) and proceed to Step 4. Do NOT foreground-sleep
236
+ or poll — the harness drives both the Monitor events and the completion notification.
237
+
238
+ ## Step 4: Check Results
239
+
240
+ When the background process completes (its exit notification):
241
+
242
+ ### 4a. Get Final Backlog State
243
+
244
+ Run the **status-json command** (`loopRunner.statusJsonCommand`) and read
245
+ `backlogSummary` for the authoritative counts — it separates the three non-done
246
+ outcomes: genuine `blocked`, `needsHuman`, and runner-`deferred` ("false blocks").
247
+ Fall back to the **list command** (`loopRunner.listCommand`) if `statusJsonCommand`
248
+ is not configured. You will already have most of this from the live tally in 3e.
249
+
250
+ ### 4b. Report Results
251
+
252
+ Present a summary to the user. Pick **every** branch that applies (a run can be both
253
+ blocked and needs-human) and render its report. The five verbatim result-report
254
+ output templates — **all-done**, **needs-human**, **blocked**, **deferred**, and
255
+ **pending** (iteration limit reached) — are in `references/result-reporting.md`.
256
+
257
+ ## Step 5: Update Pipeline State
258
+
259
+ Update `{resolvedFeatureDir}/.pipeline-state.json`:
260
+
261
+ 1. Set `stages.forge-5-loop`:
262
+ - `status`: `"complete"` if all backlog items are `done`, otherwise `"in-progress"`
263
+ - `completedAt`: current ISO timestamp (only if complete)
264
+ - `basedOnVersions`: `{"forge-4-backlog": <current version from pipeline state>}`
265
+ - `artifacts`: `["{backlogDir}/{loopRunner.stateDir}/state.json"]`
266
+ 2. If all items complete: set `currentStage` to `"forge-6-docs"`
267
+ 3. Update `updatedAt`
268
+
269
+ **No git commit is needed** — the loop runner commits atomically per completed item during the run. The implementation code is already committed.
270
+
271
+ > **Note:** Step 5's "no git commit needed" remark refers to *implementation code*, which the runner commits per-item. The epic handoff's commit in Step 6 below is of *pipeline state / manifest* — a distinct artifact — and applies only to epic members.
272
+
273
+ ## Step 6: Epic Handoff
274
+
275
+ **Gate:** only run this step if (a) the resolved feature's `.pipeline-state.json` has an `epic` key **and** (b) Step 5 set `stages.forge-5-loop.status` to `complete` (all backlog items done). If either is false, **skip** — standalone features and partial runs end exactly as today (REQ-COMPAT-01).
276
+
277
+ 1. **Offer impl-verify first (recommended, skippable).** Per the completion rule (`00-core-definitions.md §7`), a feature whose `forge-verify-impl.status == findings-reported` does **not** unblock dependents. Use `AskUserQuestion` (NOT inline prose) to offer:
278
+
279
+ > "{feature}'s loop is done. Recommended: run `/feature-forge:forge-verify {feature} impl` before unblocking dependents. Run it now, or skip and continue the handoff?"
280
+
281
+ The user may skip (then completion is judged on the §7 rule with impl-verify absent).
282
+ 2. **Recompute and announce.** Run `render-status "{epic}" --specs-dir "{specsDir}" --json`. Announce the feature's completion and the epic rollup (e.g. "2/4 features complete") — derived live from disk, never re-computed in prose.
283
+ 3. **Identify the next actionable feature(s).** Read `render-status`'s `actionable` set (features whose every dependency is now complete and that are not themselves complete) and `nextCommand`.
284
+ - **None actionable** (everything done, or remaining features still blocked): say so.
285
+ - If `rollup.total > 0` **AND** `rollup.complete == rollup.total`, suggest `/feature-forge:forge-6-docs {feature}` and note the epic-level documentation offer (§10). The `rollup.total > 0` guard prevents an **empty epic** (`0 == 0`) from being reported complete.
286
+ - Otherwise, list what is still blocked and on which dependencies. End — do not prompt to start a feature that cannot start.
287
+ - **One or more actionable:** use `AskUserQuestion` presenting **each actionable feature** as an option (plus "stop here"). Execution is **serial** — the user picks exactly one (REQ-ORCH-03). Do **not** autonomously chain into the next pipeline.
288
+ 4. **Begin the chosen feature.** For the picked feature:
289
+ - **PRD absent** (no `PRD.md`, or `stages.forge-1-prd` not complete): offer to author it now — "Start `/feature-forge:forge-1-prd {chosen}`?" (REQ-ORCH-02). On yes, hand off to forge-1-prd (which injects epic context per §5.1).
290
+ - **PRD present:** point the user at the chosen feature's `nextCommand` from render-status.
291
+ 5. **Commit (REQ-OBS-01).** When `gitCommitAfterStage` is true, commit the Step 5 completion write (and any manifest `updatedAt` bump) via the shared-conventions **Git Commit Protocol**, staging the epic subtree so the member state change commits atomically: `git add {specsDir}/{epic}/` then `{commitPrefix}({feature}): complete loop`. If `gitCommitAfterStage` is false, skip the commit.
292
+
293
+ ## Gotchas
294
+
295
+ - `{backlogDir}` is a **directory path**, not a file path. Pass `specs/auth`, not `specs/auth/backlog.json`.
296
+ - rauf resolves `RAUF.md` with fallback: checks `{backlogDir}/.rauf/RAUF.md` first, then the project's `.rauf/RAUF.md`. As long as the runner is installed in the project, the prompt template will be found.
297
+ - State files (state.json, {loopRunner.logFile}, etc.) are created at `{backlogDir}/{loopRunner.stateDir}/` — this is within the feature's spec directory and is expected. State is isolated per backlog dir, so concurrent features don't collide.
298
+ - If the session disconnects during a long-running loop, the runner process continues independently. The user can check results later with the status / list commands.
299
+ - Never run the run command in the foreground (without `run_in_background`) — it blocks and will hit the Bash tool timeout for any non-trivial backlog. "Don't block the foreground" is NOT "stay silent": supervise via the `Monitor` tool (3d), which is harness-driven, not a sleep loop. Never `sleep`/poll in the foreground to wait for the loop.
300
+ - The `Monitor` must use `persistent: true` (not a bounded `timeout_ms`), watch the **structured** surface (`events.ndjson`), and never filter on raw `RAUF_*` tokens — they appear in agent prose and false-match. A `needs_human`/`blocked`/`review` signal does **not** pause the loop — the runner sets the item aside and keeps going; surface it live but don't tell the user the loop is waiting. See `references/runner-contract.md` for the full monitoring rules.
301
+ - If a previous loop run left a stale lock, the user may need to pass `--force` to clear it. rauf will report this error clearly.
302
+ - The version gate (1c) uses the `--json` form on purpose; never parse `rauf version`'s human output.
@@ -0,0 +1,63 @@
1
+ # forge-5-loop — Step 4b Result-Report Templates
2
+
3
+ These are the five verbatim result-report output templates for **Step 4b** of
4
+ `forge-5-loop/SKILL.md`. Pick **every** branch that applies (a run can be both
5
+ blocked and needs-human) and render its report.
6
+
7
+ **All items done:**
8
+ ```
9
+ Loop completed for {feature}. All {N} items implemented successfully.
10
+
11
+ Next steps:
12
+ - /feature-forge:forge-verify {feature} impl Verify the implementation
13
+ - /feature-forge:forge-6-docs {feature} Generate architecture docs
14
+ ```
15
+
16
+ **Some items need a human:**
17
+ ```
18
+ Loop completed for {feature}.
19
+ Completed: {done}/{total}
20
+ Needs human: {needsHuman} items (set aside during the run)
21
+
22
+ These items asked a question the loop couldn't answer:
23
+ - {id}: {title} — {reason}
24
+
25
+ Resolve, then retry:
26
+ - Answer the question(s) above, then re-run `/feature-forge:forge-5-loop {feature}`
27
+ (add --retry-blocked to pick the set-aside items back up).
28
+ ```
29
+
30
+ **Some items blocked:**
31
+ ```
32
+ Loop completed for {feature}.
33
+ Completed: {done}/{total}
34
+ Blocked: {blocked} items
35
+
36
+ Blocked items:
37
+ - {id}: {title}
38
+ - {id}: {title}
39
+
40
+ Options:
41
+ - Re-run with --retry-blocked to retry blocked items
42
+ - Review blocked items manually: {bin} backlog show . {id} --backlog {backlogDir}
43
+ - Continue to docs if blocking items are non-critical
44
+ ```
45
+
46
+ **Some items deferred (runner gave up after retries — "false blocks"):**
47
+ ```
48
+ Loop completed for {feature}.
49
+ Completed: {done}/{total}
50
+ Deferred: {deferred} items (no signal after retries — likely just need another pass)
51
+
52
+ Re-run `/feature-forge:forge-5-loop {feature}` to retry deferred items.
53
+ ```
54
+
55
+ **Some items still pending (iteration limit reached):**
56
+ ```
57
+ Loop completed for {feature}.
58
+ Completed: {done}/{total}
59
+ Pending: {pending} items (iteration limit reached)
60
+ Blocked: {blocked} items
61
+
62
+ Re-run `/feature-forge:forge-5-loop {feature}` to continue with remaining items.
63
+ ```
@@ -0,0 +1,214 @@
1
+ # forge-5-loop — Loop-Runner Contract (launch, supervision, model precedence)
2
+
3
+ This file holds the detailed loop-runner contract relocated out of
4
+ `forge-5-loop/SKILL.md`: the event-stream vs. log-fallback **launch** detail
5
+ (Steps 3b/3d/3e), the structured-surface **monitoring** caveats, the **model
6
+ precedence** rule, and the **optional-flags catalog** referenced from Step 2d.
7
+ Every command below is rendered from `loopRunner` with token substitution, as in
8
+ the skill body.
9
+
10
+ ## Model selection precedence (Step 2d)
11
+
12
+ The runner picks the per-iteration model by precedence (highest wins):
13
+
14
+ ```
15
+ item.model > --model / options > project default > provider default
16
+ ```
17
+
18
+ So a backlog item's own `model` field overrides a `--model` flag passed to the
19
+ run, which overrides the project's configured default, which overrides the
20
+ runner/provider default. Pass `--model <model>` (optional flag below) to override
21
+ the project default for the whole run.
22
+
23
+ ## Agent selection (Step 2d)
24
+
25
+ This section is **parallel** to `## Model selection precedence` above: it governs
26
+ which **coding agent** rauf drives for the run. The entire surface is
27
+ **presence-gated** on `loopRunner.agentArgument` — when that field is absent or
28
+ empty, there is no selector, no probe, and no `{agent}` substitution, and Step 2d /
29
+ Step 3c are byte-identical to today (capability gate;
30
+ `02-config-schema-and-gating.md`, REQ-PLUG-02). The rest assumes the gate is on.
31
+
32
+ **Precedence (highest wins):**
33
+
34
+ ```
35
+ item.provider > --agent (run selection) > loopRunner.defaultAgent (project) > runner default (claude-cli)
36
+ ```
37
+
38
+ **Run-layer mapping — why forge never re-implements rauf's resolver.** forge owns
39
+ **only** its run and project layers and collapses them into **one** value
40
+ (`resolve()`: `run_selection or defaultAgent or none`), which it emits as a single
41
+ `--agent {agent}` occupying rauf's **run layer only**. rauf alone resolves
42
+ item-vs-run via its own 5-layer resolver, sitting the per-item `BacklogItem.provider`
43
+ **above** forge's run layer — so a run selection can never clobber a deliberate
44
+ per-item agent. forge **never reads, writes, or overrides** `BacklogItem.provider`
45
+ (REQ-AGENT-05). When forge sends nothing (the default path), rauf applies its own
46
+ default `claude-cli`, byte-identical to today. Empty/whitespace selections are
47
+ treated as unset, and an explicit pick of the runner default id collapses to the
48
+ default path (append nothing, run no probe). See
49
+ `03-selection-resolution-observability.md §3–§4`.
50
+
51
+ **Availability pre-check + disambiguation.** For a **non-default** resolved id only,
52
+ forge runs `loopRunner.agentsProbeCommand` **once** (no retries) and classifies the
53
+ id by **membership** in the advertised set (`{ row.id for row in agents }`), then the
54
+ matching row's `available` flag — **never** by exit code, because `rauf agents
55
+ --json` always exits 0 (an unknown id is simply absent; a known-unavailable one is
56
+ present with `available: false`):
57
+
58
+ - **UNKNOWN** (`∉` advertised set): hard-reject **before any loop side-effect**,
59
+ listing the sorted valid ids; **no proceed-anyway**; the value never interpolates
60
+ into `{agent}` (the advertised set IS the allow-list — REQ-SEC-01).
61
+ - **UNAVAILABLE** (member, `available == False`): warn with the row's `detail`, then
62
+ offer **proceed-anyway OR choose-another** — never silent.
63
+ - **AVAILABLE** (member, `available == True`): proceed; the validated id fills
64
+ `{agent}`.
65
+ - **Probe failure** (non-zero exit / unparseable / wrong shape / empty `agents[]` /
66
+ row missing `id`): surface it and offer **choose-another OR abort**; never launch
67
+ the non-default agent unvalidated, never silently fall back to the default.
68
+
69
+ The default / `claude-cli` path runs **no** probe (zero extra cost). See
70
+ `04-availability-precheck.md` for the full pre-check, classification, and allow-list,
71
+ and `02-config-schema-and-gating.md` for the capability gate.
72
+
73
+ ## Optional flags catalog (Step 2d, rauf)
74
+
75
+ These are the optional flags the user may add to the rendered run command. If the
76
+ user requests additional flags, append them to the rendered run command.
77
+
78
+ ```
79
+ --agent <id> Coding agent rauf drives this run (see Agent selection below).
80
+ Only the runner's advertised ids are valid; an unknown id is
81
+ rejected before launch. Shown only when the runner advertises
82
+ an agent surface (loopRunner.agentArgument present).
83
+ --review Run a review pass after all iterations (extra agent session)
84
+ --model <model> Override the model (see precedence above)
85
+ --timeout <min> Per-session timeout in minutes (default: 60)
86
+ --retry-blocked Unblock and retry previously blocked items
87
+ ```
88
+
89
+ ## Launch detail (Step 3b — background process)
90
+
91
+ Launch the loop **backgrounded** so it survives session end and does not block the
92
+ session, and prefer the machine-readable event stream so the session can supervise
93
+ it live.
94
+
95
+ - **If `loopRunner.eventStreamCommand` is configured (default for rauf):** render it
96
+ (it appends `--ndjson` to the run) and launch via the Bash tool with
97
+ `run_in_background: true`, redirecting stdout to a stable events file:
98
+
99
+ ```
100
+ mkdir -p {backlogDir}/{loopRunner.stateDir} && {rendered eventStreamCommand} > {backlogDir}/{loopRunner.stateDir}/events.ndjson 2>&1
101
+ ```
102
+
103
+ (The `mkdir -p` guards the very first run, before the runner has created its
104
+ state dir.) This emits one JSON event per line **and** keeps the loop detached. The background
105
+ task's exit notification remains the single authoritative terminal signal (Step 4).
106
+ - **Fallback (runner has no `eventStreamCommand`):** launch the plain `runCommand`
107
+ with `run_in_background: true`. The session will then supervise by tailing the
108
+ human log (3d fallback) instead of the NDJSON file.
109
+
110
+ Loop runs can take significant time (minutes to hours depending on backlog size).
111
+
112
+ ## Arm a Monitor on the event stream (Step 3d)
113
+
114
+ Arm the **`Monitor` tool** on the structured event stream so events flow back into
115
+ this session as they happen. Use **`persistent: true`** — runs can exceed `Monitor`'s
116
+ maximum `timeout_ms` (1 hour), and a bounded timeout would silently stop watching a
117
+ still-running loop.
118
+
119
+ **Coverage-complete filter (silence is not success).** The filter MUST match every
120
+ terminal and exception state, not just the happy path — otherwise a crash or hang
121
+ looks identical to "still running." Monitor command (NDJSON path):
122
+
123
+ ```
124
+ tail -n +1 -f {backlogDir}/{loopRunner.stateDir}/events.ndjson 2>&1 \
125
+ | jq -rc --unbuffered 'select(.type | test("item_completed|item_blocked|needs_human|signal_parsed|loop_completed|loop_error|loop_cancelled|llm_stuck_warning"))'
126
+ ```
127
+
128
+ - **Fallback (log tail, no NDJSON):** match the runner's **structured prose
129
+ prefixes**, never the `RAUF_*` tokens (those leak inside agent output and
130
+ false-match). For rauf:
131
+
132
+ ```
133
+ tail -n +1 -f {backlogDir}/{loopRunner.stateDir}/{loopRunner.logFile} \
134
+ | grep -E --line-buffered 'Item [^ ]+ (completed|blocked):|Item [^ ]+ needs human input|Loop completed|Loop error:|Circuit breaker:'
135
+ ```
136
+
137
+ (Match `needs human input` **without** a trailing colon — the runner writes
138
+ `needs human input (set aside):`.)
139
+
140
+ If the Monitor is ever auto-stopped for event volume, re-arm with a tighter filter
141
+ (drop `item_completed`, keep the exception/terminal events).
142
+
143
+ ## React to events as they land (Step 3e)
144
+
145
+ Each Monitor event arrives as a message. React per type — but keep the user signal
146
+ high and the noise low:
147
+
148
+ - **`item_completed`** → increment a running tally. These land minutes apart, so they
149
+ won't trip the volume auto-stop; still, surface a coalesced milestone ("12/30 done")
150
+ rather than echoing every line. For an exact breakdown, run the one-shot
151
+ `{rendered statusJsonCommand}` and report `done/total` from `backlogSummary`.
152
+ - **`needs_human`** (or `signal_parsed` with `signal: "needs_human"`) → **surface
153
+ immediately** and send a **`PushNotification`** (an hours-long run means the user has
154
+ likely stepped away). **Important — the loop is NOT paused:** the runner has set that
155
+ item aside and kept working other items. So report *what* needs a human and *which*
156
+ item, then either (a) collect the user's answer via `AskUserQuestion` to **stage a
157
+ post-run retry**, or (b) offer to **cancel the run early** if the answer changes the
158
+ whole plan. Do not tell the user the loop is waiting on their reply — it isn't.
159
+ - **`item_blocked`** → surface the blocked item + reason now (visibility) and
160
+ accumulate for the final summary. Use `{rendered statusJsonCommand}` to distinguish a
161
+ genuine `blocked` from a runner-`deferred` "false block" (`backlogSummary.deferred`).
162
+ - **`loop_error`** → a real failure (this is also what a circuit-breaker halt — too many
163
+ consecutive infra failures — emits). Surface now and `PushNotification`. Offer
164
+ inspection / `--force` / re-run as appropriate.
165
+ - **Stall detection** → rauf emits an **`llm_stuck_warning`** event when an iteration
166
+ stops making progress; the filter above includes it, so surface it live (a hang
167
+ warning, not yet a failure) and offer `--force` if it persists. If you instead want to
168
+ probe on quiet, run `{rendered watchCommand}` (or read
169
+ `{backlogDir}/{loopRunner.stateDir}/iteration-status.json`) and key off its
170
+ `stuckWarning` flag. Do **not** infer a stall from `state.json.updatedAt` alone — it is
171
+ not a liveness proof.
172
+
173
+ ## Inform-user output template (Step 3c)
174
+
175
+ This is the verbatim "Loop started…" output the session shows the user after
176
+ launch. Commands are the rendered `loopRunner` monitoring commands.
177
+
178
+ When the agent surface is gated on (`loopRunner.agentArgument` present), add the
179
+ `Coding agent:` line shown below immediately after the opening `Loop started …`
180
+ line, using the same `sourceLabel` mapping as the Step 2d confirmation
181
+ (`RUN` → `"per-run selection"`, `PROJECT` →
182
+ `"project default (loopRunner.defaultAgent)"`, `DEFAULT` →
183
+ `"runner default — claude-cli"`). When the gate is off, the line is **absent** and
184
+ the template is byte-identical to today (REQ-PLUG-02). When the launch proceeded via
185
+ the UNAVAILABLE *proceed-anyway* path, use the audit variant instead:
186
+
187
+ ```
188
+ Coding agent: {resolved.agent or claude-cli} (source: {sourceLabel}).
189
+ Coding agent: {resolved.agent} (source: {sourceLabel}; proceeded despite unavailability warning).
190
+ ```
191
+
192
+ (The two lines above are alternatives — the first is the normal line; the second
193
+ replaces it only on the proceed-anyway path. This is session-side prose only; it
194
+ introduces no new event type, so the Step 3d Monitor filter is unchanged.)
195
+
196
+ ```
197
+ Loop started for {feature} ({N} items to process).
198
+ Coding agent: {resolved.agent or claude-cli} (source: {sourceLabel}). # only when the agent surface is gated on
199
+ This session is now monitoring it live — I'll report milestones and stop you in if
200
+ the loop needs a human. The loop also runs detached and survives this session ending.
201
+ Each item gets a fresh agent session with full context from the backlog and specs.
202
+
203
+ Watch directly if you like (another terminal or `!` prefix):
204
+ {rendered statusCommand} # one-shot status
205
+ {rendered followCommand} # stream live events (human)
206
+ {rendered logCommand} # tail log file
207
+ {rendered listCommand} # check item statuses
208
+
209
+ State files are at: {backlogDir}/{loopRunner.stateDir}/
210
+ - state.json (loop state)
211
+ - events.ndjson (structured event stream this session is watching)
212
+ - {loopRunner.logFile} (human event log)
213
+ - iteration-status.json (live activity, incl. stuckWarning)
214
+ ```