forgedock 1.1.1 → 1.1.2

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 (171) hide show
  1. package/README.md +53 -8
  2. package/bin/batch-runner.mjs +339 -0
  3. package/bin/demo.mjs +92 -7
  4. package/bin/engine/phases.mjs +20 -0
  5. package/bin/engine/state.mjs +8 -3
  6. package/bin/engine-cli.mjs +177 -5
  7. package/bin/forgedock.mjs +409 -26
  8. package/bin/hooks/interactive-engine.mjs +509 -0
  9. package/bin/hooks/pre-tool-use.mjs +498 -0
  10. package/bin/hooks/subagent-stop-enforce.mjs +197 -0
  11. package/bin/journey.mjs +72 -14
  12. package/bin/registry.mjs +139 -0
  13. package/bin/report.mjs +447 -0
  14. package/bin/runner.mjs +68 -19
  15. package/bin/settings-hook.mjs +235 -1
  16. package/commands/adopt.md +4 -1
  17. package/commands/analytics.md +4 -1
  18. package/commands/audit-agents.md +110 -27
  19. package/commands/audit.md +20 -1
  20. package/commands/autopilot.md +80 -8
  21. package/commands/changelog.md +2 -1
  22. package/commands/ci-audit.md +2 -1
  23. package/commands/cleanup.md +161 -1
  24. package/commands/compat-audit.md +2 -1
  25. package/commands/deploy-info.md +58 -1
  26. package/commands/design-bench.md +5 -1
  27. package/commands/design-render-critique-loop.md +1 -1
  28. package/commands/diagnose.md +2 -1
  29. package/commands/explain.md +2 -1
  30. package/commands/forge-stats.md +121 -2
  31. package/commands/forgedock-init.md +1 -1
  32. package/commands/geo-audit.md +3 -0
  33. package/commands/incident-response.md +2 -1
  34. package/commands/issue.md +23 -2
  35. package/commands/milestone.md +77 -12
  36. package/commands/optimize.md +2 -1
  37. package/commands/orchestrate/config.md +67 -0
  38. package/commands/orchestrate/phase-1-resolve.md +159 -0
  39. package/commands/orchestrate/phase-2-triage.md +126 -0
  40. package/commands/orchestrate/phase-2.5-synthesis.md +156 -0
  41. package/commands/orchestrate/phase-3-dependency.md +591 -0
  42. package/commands/orchestrate/phase-4-execution.md +962 -0
  43. package/commands/orchestrate/phase-5-cleanup.md +47 -0
  44. package/commands/orchestrate/phase-6-report.md +198 -0
  45. package/commands/orchestrate/safety.md +62 -0
  46. package/commands/orchestrate.md +25 -2045
  47. package/commands/pipeline-health/config.md +34 -0
  48. package/commands/pipeline-health/phase-1-context.md +180 -0
  49. package/commands/pipeline-health/phase-2-metrics.md +1729 -0
  50. package/commands/pipeline-health/phase-3-analyze.md +204 -0
  51. package/commands/pipeline-health/phase-4-proposals.md +117 -0
  52. package/commands/pipeline-health/phase-5-report.md +284 -0
  53. package/commands/pipeline-health/phase-6-summary.md +52 -0
  54. package/commands/pipeline-health.md +25 -2401
  55. package/commands/pipeline-resume.md +24 -1
  56. package/commands/pipeline-status.md +65 -0
  57. package/commands/qa-sweep.md +4 -1
  58. package/commands/quality-gate.md +248 -10
  59. package/commands/replay.md +2 -1
  60. package/commands/review-pr-agents/api.md +135 -0
  61. package/commands/review-pr-agents/auth.md +137 -0
  62. package/commands/review-pr-agents/billing.md +101 -0
  63. package/commands/review-pr-agents/concurrency.md +145 -0
  64. package/commands/review-pr-agents/database.md +103 -0
  65. package/commands/review-pr-agents/frontend.md +89 -0
  66. package/commands/review-pr-agents/infra.md +385 -0
  67. package/commands/review-pr-agents/protocols.md +185 -0
  68. package/commands/review-pr-agents/scraper.md +185 -0
  69. package/commands/review-pr-agents/security.md +406 -0
  70. package/commands/review-pr-agents.md +45 -1722
  71. package/commands/review-pr-staging.md +196 -40
  72. package/commands/review-pr.md +591 -52
  73. package/commands/rollback.md +2 -1
  74. package/commands/scope.md +2 -1
  75. package/commands/security-audit.md +2 -1
  76. package/commands/signal-planner.md +623 -0
  77. package/commands/sync-ecosystem.md +1 -0
  78. package/commands/test-gate.md +17 -1
  79. package/commands/validate.md +2 -1
  80. package/commands/work-on/build/architect.md +28 -0
  81. package/commands/work-on/build/context.md +2 -0
  82. package/commands/work-on/build/implement.md +3 -1
  83. package/commands/work-on/build/validate.md +26 -7
  84. package/commands/work-on/build.md +163 -24
  85. package/commands/work-on/close.md +130 -3
  86. package/commands/work-on/decompose.md +19 -1
  87. package/commands/work-on/investigate.md +117 -2
  88. package/commands/work-on/review.md +24 -4
  89. package/commands/work-on-monolithic.md +7 -2
  90. package/commands/work-on.md +202 -4
  91. package/docs/BRAND.md +14 -7
  92. package/docs/CI.md +2 -2
  93. package/docs/CODEX.md +36 -1
  94. package/docs/CONFIG.md +5 -8
  95. package/docs/FORGE-PROTOCOL.md +15 -1064
  96. package/docs/anthropic-devrel-outreach.md +2 -2
  97. package/docs/articles/command-decomposition-token-savings.md +214 -0
  98. package/docs/articles/model-release-playbook.md +131 -0
  99. package/docs/articles/per-repo-adaptive-scripts-token-savings.md +27 -25
  100. package/docs/claude-breakpoints.json +75 -5
  101. package/docs/design/abc-benchmark.md +1 -1
  102. package/docs/design/design-spec-schema.md +1 -1
  103. package/docs/design/divergent-generation.md +1 -1
  104. package/docs/design/eval-gate-runbook.md +178 -0
  105. package/docs/design/show-hn-draft.md +26 -1
  106. package/docs/design/token-cost-baseline-1298.md +59 -0
  107. package/docs/eval/README.md +117 -0
  108. package/docs/eval/corpus/seed-v1.json +6 -0
  109. package/docs/eval/published/claude-sonnet-4-6-2026-07-04.json +33 -0
  110. package/docs/site/annotations-explained.md +24 -0
  111. package/docs/site/command-learning-path.md +51 -14
  112. package/docs/site/command-reference.md +339 -113
  113. package/docs/site/for-companies.md +95 -0
  114. package/docs/site/forge-annotation-protocol.md +12 -256
  115. package/docs/site/getting-started.md +43 -4
  116. package/docs/site/github-is-the-memory.md +113 -0
  117. package/docs/site/how-it-works.md +3 -13
  118. package/docs/site/index.md +9 -1
  119. package/docs/spec/eval-run-result.md +147 -0
  120. package/docs/spec/forge-protocol-v1.md +441 -18
  121. package/docs/spec/label-state-machine.md +55 -0
  122. package/docs/spec/review-protocol.md +158 -0
  123. package/docs/spec-graph-schema.md +28 -0
  124. package/docs/superpowers/specs/2026-07-04-economic-self-governance-design.md +181 -0
  125. package/docs/superpowers/specs/2026-07-04-provenance-trail-design.md +189 -0
  126. package/examples/forgedock-demo/README.md +41 -22
  127. package/examples/forgedock-demo/issues/06-bug-tags-type-validation.md +43 -0
  128. package/examples/forgedock-demo/issues/07-bug-negative-offset-pagination.md +42 -0
  129. package/examples/forgedock-demo/issues/08-bug-patch-mass-assignment.md +49 -0
  130. package/examples/forgedock-demo/issues/09-bug-count-injection.md +47 -0
  131. package/examples/forgedock-demo/issues/10-feature-sort-param.md +39 -0
  132. package/examples/forgedock-demo/issues/11-feature-patch-tags.md +37 -0
  133. package/examples/forgedock-demo/issues/12-feature-bulk-create.md +42 -0
  134. package/examples/forgedock-demo/issues/13-feature-archive-notes.md +46 -0
  135. package/examples/forgedock-demo/issues/14-refactor-extract-title-validation.md +41 -0
  136. package/examples/forgedock-demo/issues/15-refactor-protected-route-flag.md +43 -0
  137. package/examples/forgedock-demo/issues/16-refactor-extract-store.md +45 -0
  138. package/examples/forgedock-demo/issues/17-perf-tags-dedup-set.md +35 -0
  139. package/examples/forgedock-demo/issues/18-perf-remove-redundant-sort.md +37 -0
  140. package/examples/forgedock-demo/issues/19-docs-api-reference-full.md +53 -0
  141. package/examples/forgedock-demo/issues/20-docs-intentional-flaw-convention.md +46 -0
  142. package/examples/forgedock-demo/scripts/smoke.js +18 -1
  143. package/examples/forgedock-demo/src/db.js +36 -11
  144. package/examples/forgedock-demo/src/routes/notes.js +106 -9
  145. package/examples/forgedock-demo/src/server.js +4 -1
  146. package/package.json +3 -1
  147. package/packages/protocol/LICENSE +21 -0
  148. package/packages/protocol/src/cli.js +135 -0
  149. package/packages/protocol/src/emit.js +146 -0
  150. package/packages/protocol/src/index.js +43 -0
  151. package/packages/protocol/src/parse.js +229 -0
  152. package/packages/protocol/src/types.js +171 -0
  153. package/packages/protocol/src/validate.js +122 -0
  154. package/scripts/bench-topology-cost.mjs +372 -0
  155. package/scripts/check-command-docs-drift.sh +198 -0
  156. package/scripts/check-protocol-restatements.sh +176 -0
  157. package/scripts/check-registry/README.md +72 -0
  158. package/scripts/check-registry/manifest.json +6 -0
  159. package/scripts/code-index.sh +454 -0
  160. package/scripts/conformance-check.mjs +168 -0
  161. package/scripts/doctor-pipeline-state.sh +484 -0
  162. package/scripts/eval-gate-baseline.json +17 -0
  163. package/scripts/eval-gate-scorecard.mjs +242 -0
  164. package/scripts/eval-scorecard-aggregator.mjs +252 -0
  165. package/scripts/flaky-quarantine.sh +241 -0
  166. package/scripts/forge-annotation.sh +567 -0
  167. package/scripts/issue-dedup.sh +236 -0
  168. package/scripts/validate-annotation-node.mjs +233 -0
  169. package/scripts/worktree-lifecycle.sh +3 -3
  170. package/templates/devdocs/agent/using-forgedock.md +14 -0
  171. package/docs/site/.vitepress/config.mjs +0 -85
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  description: Track command sizes, detect bloat, compare against baselines and thresholds
3
- argument-hint: [diff | baseline | full]
3
+ argument-hint: [diff | baseline | full | cost]
4
4
  install: internal
5
5
  ---
6
6
  <!-- SPDX-FileCopyrightText: Copyright (c) RapierCraft Studios -->
@@ -8,7 +8,7 @@ install: internal
8
8
 
9
9
  # /forge-stats — Prompt Bloat Tracker
10
10
 
11
- **Input**: $ARGUMENTS (default: `diff`)
11
+ **Input**: $ARGUMENTS (default: `diff`; modes: `diff`, `baseline`, `full`, `cost`)
12
12
 
13
13
  Tracks the size of every Forge command file over time. Detects bloat by comparing current sizes against the git-tracked baseline and per-command thresholds.
14
14
 
@@ -194,3 +194,122 @@ If 3+ commands repeat the same instruction block (e.g., "how to create a worktre
194
194
 
195
195
  ### 4. Remove motivational padding
196
196
  Emojis, ALL CAPS warnings, "YOU MUST", "CRITICAL", "NO EXCEPTIONS" — these are noise. Sonnet follows clear instructions, not emphasis. Replace 5 lines of warnings with 1 line of instruction.
197
+
198
+ ---
199
+
200
+ ## Mode: `cost`
201
+
202
+ Report raw cost-per-issue, cost-per-stage, and cost-per-agent-tier by reading `FORGE:DECISION_RECORD` annotations from merged PRs. **Raw numbers only** — no trend dashboards, no automated regression-flagging, no visualization. Respects the open-core boundary defined in `devdocs/project/architecture.md` (trend analytics are a Platform value-add).
203
+
204
+ ```bash
205
+ cd "$FORGE_HOME"
206
+
207
+ CONFIG_FILE="${FORGE_CONFIG:-forge.yaml}"
208
+ GH_REPO=$(yq e '.project.owner + "/" + .project.repo' "$CONFIG_FILE")
209
+
210
+ echo "=== Forge Cost Report — $(date +%Y-%m-%d) ==="
211
+ echo "Repo: $GH_REPO"
212
+ echo ""
213
+
214
+ # Fetch all merged PRs (last 50) and extract their FORGE:DECISION_RECORD JSON blocks
215
+ RECORDS=$(gh pr list -R "$GH_REPO" --state merged --limit 50 --json number \
216
+ --jq '.[].number' 2>/dev/null | while read pr; do
217
+ gh api "repos/$GH_REPO/issues/$pr/comments" \
218
+ --jq '.[] | select(.body | contains("FORGE:DECISION_RECORD")) | .body' 2>/dev/null
219
+ done)
220
+
221
+ if [ -z "$RECORDS" ]; then
222
+ echo "No FORGE:DECISION_RECORD annotations found in the last 50 merged PRs."
223
+ echo "(Older issues predate the cost block — no data to report.)"
224
+ exit 0
225
+ fi
226
+
227
+ # Extract cost blocks via Python (handles missing cost block gracefully)
228
+ echo "$RECORDS" | python3 - <<'PYEOF'
229
+ import sys, re, json
230
+
231
+ records = []
232
+ for block in sys.stdin.read().split("<!-- FORGE:DECISION_RECORD -->"):
233
+ m = re.search(r'```json\s*(\{.*?\})\s*```', block, re.DOTALL)
234
+ if not m:
235
+ continue
236
+ try:
237
+ data = json.loads(m.group(1))
238
+ except json.JSONDecodeError:
239
+ continue
240
+ records.append(data)
241
+
242
+ if not records:
243
+ print("No parseable FORGE:DECISION_RECORD JSON found.")
244
+ sys.exit(0)
245
+
246
+ print(f"Parsed {len(records)} FORGE:DECISION_RECORD annotation(s).\n")
247
+
248
+ has_cost = [r for r in records if r.get("cost")]
249
+ no_cost = [r for r in records if not r.get("cost")]
250
+
251
+ print(f" With cost block : {len(has_cost)}")
252
+ print(f" Without cost block: {len(no_cost)} (older annotations — no data)")
253
+ print()
254
+
255
+ if not has_cost:
256
+ print("No cost data available. Cost blocks are written starting with #1296.")
257
+ sys.exit(0)
258
+
259
+ # Per-issue raw cost
260
+ print("--- Cost Per Issue ---")
261
+ print(f"{'Issue':<10} {'PR':<8} {'Total ($)':<12} {'Stages'}")
262
+ print(f"{'-----':<10} {'--':<8} {'---------':<12} {'------'}")
263
+ for r in sorted(has_cost, key=lambda x: x.get("issue", 0)):
264
+ cost = r.get("cost", {})
265
+ total = cost.get("total_usd", "n/a")
266
+ stages = cost.get("stages", {})
267
+ stage_str = ", ".join(f"{k}: ${v}" for k, v in stages.items()) if stages else "n/a"
268
+ print(f" #{r.get('issue','?'):<8} #{r.get('pr','?'):<6} {str(total):<12} {stage_str}")
269
+
270
+ print()
271
+
272
+ # Per-stage aggregate
273
+ stage_totals = {}
274
+ for r in has_cost:
275
+ for stage, val in (r.get("cost", {}).get("stages") or {}).items():
276
+ try:
277
+ stage_totals[stage] = stage_totals.get(stage, 0.0) + float(val)
278
+ except (TypeError, ValueError):
279
+ pass
280
+
281
+ if stage_totals:
282
+ print("--- Cost Per Stage (aggregate) ---")
283
+ for stage, total in sorted(stage_totals.items()):
284
+ print(f" {stage:<20}: ${total:.4f}")
285
+ print()
286
+
287
+ # Per-agent-tier aggregate
288
+ tier_totals = {}
289
+ for r in has_cost:
290
+ for tier, val in (r.get("cost", {}).get("agent_tiers") or {}).items():
291
+ try:
292
+ tier_totals[tier] = tier_totals.get(tier, 0.0) + float(val)
293
+ except (TypeError, ValueError):
294
+ pass
295
+
296
+ if tier_totals:
297
+ print("--- Cost Per Agent Tier (aggregate) ---")
298
+ for tier, total in sorted(tier_totals.items()):
299
+ print(f" {tier:<20}: ${total:.4f}")
300
+ print()
301
+
302
+ # Summary
303
+ if has_cost:
304
+ totals = [float(r["cost"]["total_usd"]) for r in has_cost if r.get("cost", {}).get("total_usd") not in (None, "unavailable")]
305
+ if totals:
306
+ print(f"Issues with cost data: {len(totals)}")
307
+ print(f" Total cost (window) : ${sum(totals):.4f}")
308
+ print(f" Average per issue : ${sum(totals)/len(totals):.4f}")
309
+ print(f" Min / Max : ${min(totals):.4f} / ${max(totals):.4f}")
310
+ PYEOF
311
+ ```
312
+
313
+ **Scope constraint**: This mode reports raw numbers sourced from `FORGE:DECISION_RECORD` annotations only. No new data source is invented. Trend visualization, regression-flagging, and alerting logic are Platform features — do not add them here. If a cost block is absent (older annotations predating #1296), report "no data" rather than erroring.
314
+
315
+ <!-- Added: forge#1297 -->
@@ -11,7 +11,7 @@ argument-hint: [--preserve | --interactive | --section <name>]
11
11
 
12
12
  You complete the `forge.yaml` configuration that `npx forgedock init` started. The CLI generates required sections (project, paths, branches) from auto-detection. Your job is to scan the codebase, query GitHub APIs, and produce a complete `forge.yaml` with every applicable optional section filled — using detected values directly, without asking for confirmation.
13
13
 
14
- **Agent model policy**: Default `model: "sonnet"`. Fallback: `model: "opus"` if Sonnet is rate-limited.
14
+ **Agent model policy**: `model: "sonnet"` (standard tier). Fallback: `model: "opus"` if rate-limited. Feature gate: pass `effort` in Task/Skill spawns only on Claude Code >= 2.1.154.
15
15
  **NEVER use plan mode (EnterPlanMode).**
16
16
 
17
17
  ---
@@ -1,5 +1,6 @@
1
1
  ---
2
2
  description: "Run a GEO audit — check AI referral traffic, page compliance, and auto-create improvement issues"
3
+ install: extras
3
4
  ---
4
5
  <!-- SPDX-FileCopyrightText: Copyright (c) RapierCraft Studios -->
5
6
  <!-- SPDX-License-Identifier: AGPL-3.0-or-later -->
@@ -12,6 +13,8 @@ You are the GEO (Generative Engine Optimization) auditor. Pull AI referral data
12
13
 
13
14
  **NEVER use plan mode (EnterPlanMode)** — it breaks execution context.
14
15
 
16
+ <!-- FORGE:SPEC_LOADED — geo-audit.md loaded and active. Agent is bound by this spec. -->
17
+
15
18
  ---
16
19
 
17
20
  ## Phase 0: Load Config
@@ -1,6 +1,7 @@
1
1
  ---
2
2
  description: Coordinate P0 incident response — hotfix validation, timeline reconstruction, and post-incident analysis
3
3
  argument-hint: [issue number | "active" | "postmortem {issue}"]
4
+ install: extras
4
5
  ---
5
6
  <!-- SPDX-FileCopyrightText: Copyright (c) RapierCraft Studios -->
6
7
  <!-- SPDX-License-Identifier: AGPL-3.0-or-later -->
@@ -15,7 +16,7 @@ argument-hint: [issue number | "active" | "postmortem {issue}"]
15
16
 
16
17
  You are the pipeline's incident response coordinator. When production goes down or a critical bug surfaces, this command orchestrates the response: validates the hotfix before deploy, reconstructs the incident timeline, and produces a post-incident analysis.
17
18
 
18
- **Agent model policy**: Default `model: "sonnet"`. If Sonnet is rate-limited, fall back to `model: "opus"`. User can override with `--model <name>`.
19
+ **Agent model policy**: `model: "sonnet"` (standard tier). Fallback: `model: "opus"` if rate-limited. User can override with `--model <name>`. Feature gate: pass `effort` in Task/Skill spawns only on Claude Code >= 2.1.154.
19
20
 
20
21
  **NEVER use plan mode (EnterPlanMode)** — it breaks execution context.
21
22
 
package/commands/issue.md CHANGED
@@ -11,7 +11,7 @@ argument-hint: [description of the problem or feature]
11
11
 
12
12
  You create GitHub issues with the exact structure the `/work-on` pipeline expects. Every issue you create must give the investigation agent enough context to find the right files on the first pass — no vague descriptions, no missing domains, no ambiguous scope.
13
13
 
14
- **Agent model policy**: Default `model: "sonnet"`. Fallback: `model: "opus"` if Sonnet is rate-limited.
14
+ **Agent model policy**: `model: "sonnet"` (standard tier). Fallback: `model: "opus"` if rate-limited. Feature gate: pass `effort` in Task/Skill spawns only on Claude Code >= 2.1.154.
15
15
  **NEVER use plan mode (EnterPlanMode).**
16
16
 
17
17
  ---
@@ -133,8 +133,28 @@ List every file that the fix/feature will need to touch. Be thorough:
133
133
 
134
134
  ### 2D: Check for duplicates
135
135
 
136
+ Run the deterministic dedup script first (authoritative check), then fall back to an LLM pass if the script produces no result:
137
+
138
+ ```bash
139
+ # Authoritative deterministic check — uses token overlap algorithm (see scripts/issue-dedup.sh)
140
+ DEDUP_RESULT=$(scripts/issue-dedup.sh "{PROPOSED_TITLE}" {GH_FLAG} 2>&1)
141
+ DEDUP_EXIT=$?
142
+
143
+ if [ "$DEDUP_EXIT" -eq 1 ]; then
144
+ echo "Near-duplicate detected: $DEDUP_RESULT"
145
+ echo "Existing issue found — do NOT create a new one."
146
+ # STOP here and report to user (see handling rules below)
147
+ elif [ "$DEDUP_EXIT" -eq 2 ]; then
148
+ echo "Dedup check usage error: $DEDUP_RESULT"
149
+ echo "Do NOT proceed to issue creation — fix the invocation and retry."
150
+ # STOP here — do not fall through to gh issue create
151
+ fi
152
+ ```
153
+
154
+ If the script exits 0 (no match found), also run an LLM-side search as a fallback:
155
+
136
156
  ```bash
137
- # Search for existing issues with similar scope
157
+ # LLM fallback — broader semantic search for issues the token algorithm may miss
138
158
  gh issue list {GH_FLAG} --state open --limit 20 --search "{key_terms}" --json number,title,labels --jq '.[] | "#\(.number) [\(.labels | map(.name) | join(","))] \(.title)"'
139
159
 
140
160
  # Also check recently closed issues (might be a regression)
@@ -144,6 +164,7 @@ gh issue list {GH_FLAG} --state closed --limit 10 --search "{key_terms}" --json
144
164
  If a duplicate exists:
145
165
  - **Open duplicate found**: Tell the user. Do NOT create the issue. Show the existing issue number.
146
166
  - **Closed duplicate found (regression)**: Create the issue but reference the prior issue in the body: "Regression of #{N}."
167
+ - **User wants to override**: Pass `--force` to the dedup script — this is an explicit human override path. Agents MUST NOT pass `--force` without user authorization. <!-- Added: forge#1335 -->
147
168
 
148
169
  ### 2E: Check for milestone context
149
170
 
@@ -1,6 +1,7 @@
1
1
  ---
2
2
  description: Create, manage, and ship milestones — the top-level planning layer for feature development
3
3
  argument-hint: [create <name> | status | ship <slug> | sync <slug>]
4
+ install: extras
4
5
  ---
5
6
  <!-- SPDX-FileCopyrightText: Copyright (c) RapierCraft Studios -->
6
7
  <!-- SPDX-License-Identifier: AGPL-3.0-or-later -->
@@ -13,7 +14,12 @@ Milestones are the top-level planning unit. They group related issues into a shi
13
14
 
14
15
  **Hierarchy**: Milestone → Issues → Sub-issues (optional decomposition)
15
16
 
16
- **You have access to ALL tools** — Task tool, Skill tool, sub-agents, everything.
17
+ **NEVER use plan mode (EnterPlanMode).**
18
+ **NEVER use the Agent tool for issue work** — milestone dispatches issue work via `Skill(skill="work-on", ...)` only. The Agent tool bypasses the Skill pipeline's label state machine, FORGE annotations, and structured review. The Agent tool may be used only for coordination tasks within milestone planning itself (e.g., parallel issue list queries) — never for /work-on sub-dispatch.
19
+
20
+ <!-- FORGE:SPEC_LOADED — milestone.md loaded and active. Agent is bound by this spec. -->
21
+
22
+ **You have access to Task, Skill, and Bash tools** for milestone coordination.
17
23
 
18
24
  ## Config Resolution
19
25
 
@@ -498,18 +504,29 @@ ISSUE_EOF
498
504
  fi
499
505
  ```
500
506
 
501
- ### Step 3: Create shipping PR
507
+ ### Step 3: Create or update shipping PR (merge-train mechanics)
508
+
509
+ <!-- Added: forge#1327 (update-in-place), extended: forge#1332 (merge-train) -->
510
+
511
+ **Merge-train policy**: One staging→main PR stays open per deploy cycle. When a milestone ships to staging, it joins the deploy train as a candidate. The train PR is updated in place when fixes are pushed — it is NEVER closed and recreated. Dead-PR chains are eliminated: fix → push → re-request review on the same PR.
512
+
513
+ **Update-in-place policy**: Before creating a new PR, check whether an open shipping PR already exists for this milestone. If one does, push the updated milestone branch and re-request review on the existing PR — do NOT close and recreate. Closing-and-recreating is pure churn: it burns a new PR number, loses review history, and contributes to a low staging→main pass rate. The correct flow is: fix → push → re-request review on the same PR.
502
514
 
503
515
  ```bash
504
- # Get the full diff summary (computed after Step 2.5 rebase, so it reflects the final state)
505
- DIFF_STATS=$(git diff origin/{STAGING_BRANCH}...origin/milestone/{slug} --stat)
506
- COMMIT_LOG=$(git log origin/{STAGING_BRANCH}..origin/milestone/{slug} --oneline)
507
-
508
- gh pr create {GH_FLAG} \
509
- --base {STAGING_BRANCH} \
510
- --head milestone/{slug} \
511
- --title "Ship: {MILESTONE_TITLE}" \
512
- --body "$(cat <<'PR_EOF'
516
+ # Check for an existing open shipping PR for this milestone
517
+ EXISTING_PR=$(gh pr list {GH_FLAG} --head "milestone/{slug}" --base "{STAGING_BRANCH}" --state open \
518
+ --json number,url --jq '.[0] | "\(.number)|\(.url)"' 2>/dev/null)
519
+
520
+ if [ -n "$EXISTING_PR" ]; then
521
+ PR_NUMBER=$(echo "$EXISTING_PR" | cut -d'|' -f1)
522
+ PR_URL=$(echo "$EXISTING_PR" | cut -d'|' -f2)
523
+ echo "Existing open shipping PR #$PR_NUMBER found — updating in place (not recreating)."
524
+
525
+ # Update PR body to reflect latest diff state after fixes were pushed
526
+ DIFF_STATS=$(git diff origin/{STAGING_BRANCH}...origin/milestone/{slug} --stat)
527
+ COMMIT_LOG=$(git log origin/{STAGING_BRANCH}..origin/milestone/{slug} --oneline)
528
+ gh pr edit "$PR_NUMBER" {GH_FLAG} --body "$(cat <<'PR_EOF'
529
+ <!-- FORGE:TRAIN_CANDIDATE milestone={slug} -->
513
530
  ## Milestone: {MILESTONE_TITLE}
514
531
 
515
532
  {MILESTONE_DESCRIPTION}
@@ -529,7 +546,43 @@ gh pr create {GH_FLAG} \
529
546
  ## Commits
530
547
  {COMMIT_LOG}
531
548
  PR_EOF
532
- )"
549
+ )"
550
+
551
+ # Re-request review so reviewers are notified of the updated push
552
+ gh pr review "$PR_NUMBER" {GH_FLAG} --request-review 2>/dev/null || true
553
+ echo "PR #$PR_NUMBER updated and review re-requested."
554
+ else
555
+ # No open PR exists — create a new one
556
+ DIFF_STATS=$(git diff origin/{STAGING_BRANCH}...origin/milestone/{slug} --stat)
557
+ COMMIT_LOG=$(git log origin/{STAGING_BRANCH}..origin/milestone/{slug} --oneline)
558
+
559
+ gh pr create {GH_FLAG} \
560
+ --base {STAGING_BRANCH} \
561
+ --head milestone/{slug} \
562
+ --title "Ship: {MILESTONE_TITLE}" \
563
+ --body "$(cat <<'PR_EOF'
564
+ <!-- FORGE:TRAIN_CANDIDATE milestone={slug} -->
565
+ ## Milestone: {MILESTONE_TITLE}
566
+
567
+ {MILESTONE_DESCRIPTION}
568
+
569
+ ## Issues Included
570
+ {list of all closed issues in this milestone with PR references}
571
+
572
+ ## Hunk-Loss Audit
573
+ {If Step 2.5 rebase ran: "✓ Rebase completed — {AT_RISK_COUNT} at-risk staging-branch hunks absorbed into milestone branch before this PR was created. All staging content is preserved."}
574
+ {If Step 2.5 found no at-risk hunks: "✓ Clean — no at-risk staging-branch hunks detected. Safe to merge."}
575
+
576
+ > ⚠ **IMPORTANT: Merge this PR using a MERGE COMMIT, not squash.** Squash-merging a milestone PR can silently drop staging-only hunks in files the milestone touches. Use the "Create a merge commit" option in the GitHub UI, or `gh pr merge {PR_NUMBER} --merge`.
577
+
578
+ ## Diff Summary
579
+ {DIFF_STATS}
580
+
581
+ ## Commits
582
+ {COMMIT_LOG}
583
+ PR_EOF
584
+ )"
585
+ fi
533
586
  ```
534
587
 
535
588
  ### Step 4: Run staging review
@@ -540,6 +593,16 @@ Use the `/review-pr` skill to review the shipping PR. This is a comprehensive re
540
593
  Skill(skill="review-pr", args="{PR_NUMBER}")
541
594
  ```
542
595
 
596
+ **If the review returns blocking findings (FINDINGS, not PASSED)**:
597
+ - Do NOT close the PR.
598
+ - Do NOT restart from Step 1.
599
+ - Fix the blockers on `milestone/{slug}`, push the commits, then re-invoke review on the same PR:
600
+ ```
601
+ Skill(skill="review-pr", args="{PR_NUMBER}")
602
+ ```
603
+ - Step 3 will detect the open PR on the next `/milestone ship {slug}` call and update it in place — the same PR number is preserved, review history is retained, and the reviewer is re-notified.
604
+ - This eliminates the close-and-recreate churn that inflates the failed-PR count and lowers the staging→main pass rate. <!-- Added: forge#1328 -->
605
+
543
606
  ### Step 5: Report — PR is ready for user to merge
544
607
 
545
608
  ```
@@ -572,6 +635,8 @@ Milestone stays open. Issues remain assigned. Branch milestone/{slug} preserved.
572
635
  Run /milestone ship {slug} again when the milestone is ready for another shipping attempt.
573
636
  ```
574
637
 
638
+ **When the staging review returns blockers (FINDINGS, not PASSED)**: do NOT close the PR. Fix the blockers on `milestone/{slug}`, push the fixes, then re-run `/milestone ship {slug}`. Step 3 will detect the open PR and update it in place — the same PR number is preserved, review history is retained, and the reviewer is re-notified. This eliminates the close-and-recreate churn that inflates the failed-PR count and lowers the staging→main pass rate. <!-- Added: forge#1327 -->
639
+
575
640
  **If the PR merged successfully**, run the following:
576
641
 
577
642
  ```bash
@@ -1,6 +1,7 @@
1
1
  ---
2
2
  description: Analyze this repo and generate per-repo adaptive scripts from learned patterns, git history, and existing configuration
3
3
  argument-hint: [--dry-run | --force | --no-registry]
4
+ install: extras
4
5
  ---
5
6
 
6
7
  # /optimize — Per-Repo Adaptive Script Generation
@@ -9,7 +10,7 @@ argument-hint: [--dry-run | --force | --no-registry]
9
10
 
10
11
  Proactively analyze the current repository and generate `.forgedock/scripts/` entries from `forge.yaml → learned:`, git commit history, and pipeline annotations — without waiting for a correction event. This is the proactive half of the learning loop; reactive capture happens in `/work-on` Phase 1D.
11
12
 
12
- **Agent model policy**: Default `model: "sonnet"`. Fallback: `model: "opus"` if Sonnet is rate-limited.
13
+ **Agent model policy**: `model: "sonnet"` (standard tier). Fallback: `model: "opus"` if rate-limited. Feature gate: pass `effort` in Task/Skill spawns only on Claude Code >= 2.1.154.
13
14
  **NEVER use plan mode (EnterPlanMode).**
14
15
 
15
16
  ---
@@ -0,0 +1,67 @@
1
+ ---
2
+ install: internal
3
+ ---
4
+ <!-- SPDX-FileCopyrightText: Copyright (c) RapierCraft Studios -->
5
+ <!-- SPDX-License-Identifier: AGPL-3.0-or-later -->
6
+
7
+ # /orchestrate — Configuration, Hard Rules & Multi-Repo Support
8
+
9
+ Read this file at the start of every `/orchestrate` invocation.
10
+
11
+ ## HARD RULES — READ BEFORE ANYTHING ELSE
12
+
13
+ 1. **Every agent MUST invoke `/work-on` via the Skill tool.** You do NOT write implementation prompts. You copy the Phase 4A template verbatim and fill in the `{VARIABLES}`. Nothing else. No custom prompts. No "just read and edit" shortcuts. The Skill tool invocation is what triggers labels, investigation comments, structured review, and trajectory tracking. Without it, the agent's work has no paper trail and is worthless.
14
+
15
+ 2. **You are a dispatcher, not a builder.** You resolve issues, build the dependency DAG, spawn agents, and report results. You NEVER read code, edit files, or implement fixes yourself.
16
+
17
+ 3. **After each agent completes, verify it used `/work-on`.** Check that completed issues have `workflow:*` labels and structured comments. If an agent bypassed the pipeline, report it as a failure.
18
+
19
+ ---
20
+
21
+ You are the top-level orchestrator. Your job is to take a batch of issues, plan the execution order, spawn parallel sub-agents (each running the full `/work-on` pipeline), and report consolidated results.
22
+
23
+ **You have access to ALL tools** — Agent tool (critical), Task tool, Skill tool, Bash, everything. Use the Agent tool aggressively to parallelize work.
24
+
25
+ **Agent model policy**: `model: "haiku"`, `effort: low` (mechanical — dispatch bookkeeping, lane routing, classification). Fallback: `model: "sonnet"` if rate-limited. User can override with `--model <name>`. Feature gate: pass `effort` in Task/Skill spawns only on Claude Code >= 2.1.154.
26
+ **NEVER use plan mode (EnterPlanMode).**
27
+
28
+ <!-- FORGE:SPEC_LOADED — orchestrate.md loaded and active. Agent is bound by HARD RULES above. -->
29
+
30
+ ---
31
+
32
+ ## Config Resolution
33
+
34
+ Read `forge.yaml` at the project root to resolve all project-specific variables before running any commands:
35
+
36
+ ```bash
37
+ # Parse forge.yaml for project context
38
+ CONFIG_FILE="${FORGE_CONFIG:-forge.yaml}"
39
+ GH_REPO=$(yq '.project.owner + "/" + .project.repo' "$CONFIG_FILE")
40
+ GH_FLAG="-R $GH_REPO"
41
+ REPO_PATH=$(yq '.paths.root' "$CONFIG_FILE")
42
+ PROJECT_NAME=$(yq '.project.name' "$CONFIG_FILE")
43
+ STAGING_BRANCH=$(yq '.branches.staging' "$CONFIG_FILE")
44
+ DEFAULT_BRANCH=$(yq '.branches.default' "$CONFIG_FILE")
45
+ # Build satellite repo map from repos.satellites list
46
+ # Each satellite: { prefix, repo, staging_branch }
47
+ ```
48
+
49
+ All `{GH_REPO}`, `{GH_FLAG}`, `{REPO_PATH}`, `{PROJECT_NAME}`, `{STAGING_BRANCH}`, and `{DEFAULT_BRANCH}` references below are populated from `forge.yaml`.
50
+
51
+ ---
52
+
53
+ ## Multi-Repo Support
54
+
55
+ This orchestrator supports issues across multiple repositories. See `/work-on` → "Multi-Repo Support" and `forge.yaml → repos` for the full project registry and context variables.
56
+
57
+ ### Cross-Repo Issue References
58
+
59
+ Issues can be prefixed with a project shorthand derived from `forge.yaml → repos.satellites`:
60
+ - `#123` or `123` → default repo (`{GH_REPO}`)
61
+ - `{satellite_prefix}:5` → satellite repo (e.g., `mcp:5`, `n8n:12`) — prefixes and repos come from `forge.yaml → repos.satellites`
62
+ - `all-repos` → Scan all configured repos for open issues (combine and prioritize)
63
+
64
+ When spawning sub-agents, pass the project prefix so `/work-on` resolves to the correct repo.
65
+
66
+ ---
67
+
@@ -0,0 +1,159 @@
1
+ ---
2
+ install: internal
3
+ ---
4
+ <!-- SPDX-FileCopyrightText: Copyright (c) RapierCraft Studios -->
5
+ <!-- SPDX-License-Identifier: AGPL-3.0-or-later -->
6
+
7
+ # /orchestrate — Phase 1: Resolve the Issue Set
8
+
9
+ ## Phase 1: Resolve the Issue Set
10
+
11
+ Parse `$ARGUMENTS` to determine which issues to work on:
12
+
13
+ ### Input Patterns
14
+
15
+ | Input | Resolution |
16
+ |-------|------------|
17
+ | `milestone <slug>` | All open issues assigned to that GitHub milestone (default repo) |
18
+ | `#1 #2 #3` or `1 2 3` | Specific issue numbers, optionally repo-prefixed (e.g., `#123 mcp:5 n8n:12`) |
19
+ | `next <N>` | Top N priority open issues (priority:P0 first, then priority:P1, etc.) |
20
+ | `next <N> all-repos` | Top N across ALL ecosystem repos |
21
+ | `fast-lane` or `fast` | All open fast-lane issues (no milestone, bugs/fixes) |
22
+ | `priority:P0` or `priority:P1` | All open issues with that priority label |
23
+ | `mcp:fast` or `n8n:next 3` | Repo-scoped queries |
24
+ | `<slug>` (no keyword) | Try milestone first, then fall back to label search |
25
+
26
+ ### Fetch the issues
27
+
28
+ For each resolved repo, use the appropriate `-R` flag:
29
+
30
+ ```bash
31
+ # Default repo (no flag needed if using GH_FLAG="" for the default):
32
+ gh issue list {GH_FLAG} --milestone "{TITLE}" --state open --limit 500 --json number,title,labels,milestone --jq '.[] | {number, title, labels: [.labels[].name], milestone: .milestone.title}'
33
+
34
+ # Satellite repos — always include -R flag with the satellite repo from forge.yaml:
35
+ # For each satellite in forge.yaml → repos.satellites:
36
+ gh issue list -R {SATELLITE_REPO} --milestone "{TITLE}" --state open --limit 500 --json number,title,labels,milestone
37
+
38
+ # For specific numbers with repo prefix:
39
+ gh issue view {NUMBER} -R {SATELLITE_REPO} --json number,title,labels,state,milestone,body
40
+
41
+ # For "all-repos" — fetch from all configured repos and combine:
42
+ gh issue list {GH_FLAG} --state open --limit {N} --json number,title,labels,milestone
43
+ # For each satellite in forge.yaml → repos.satellites:
44
+ gh issue list -R {SATELLITE_REPO} --state open --limit 500 --json number,title,labels,milestone
45
+ # Combine, sort by priority, take top N
46
+ ```
47
+
48
+ **Count validation**: After fetching issues, log the count returned. If a milestone query returns exactly 30 issues, warn the user: "WARNING: Exactly 30 issues returned — gh CLI default may have truncated results. Re-running with --limit 500 is recommended." (The --limit 500 above prevents this for standard runs, but verify if the count seems suspiciously low relative to milestone expectations.)
49
+
50
+ **Tag each issue with its project prefix** in your internal tracking so sub-agents receive the correct repo context.
51
+
52
+ ### Filter out ineligible issues
53
+
54
+ Remove issues that should NOT be worked on:
55
+ - Already closed or has `workflow:merged` label
56
+ - Has `workflow:invalid` label
57
+ - Has `needs-human` label (requires manual action)
58
+ - Has `workflow:decomposed` label (parent tracker — its sub-issues should be picked up instead)
59
+ - Has `workflow:building` or `workflow:in-review` label (already in progress)
60
+ - Is an epic (`epic` label) — these are planning containers, not buildable
61
+
62
+ If a `workflow:decomposed` issue is found, automatically expand it to its open sub-issues instead.
63
+
64
+ ### P3 Review-Finding Batching (deterministic grouping rule)
65
+
66
+ <!-- Added: forge#1333 -->
67
+
68
+ Before finalizing the issue set, apply the P3 batching rule to reduce full-pipeline overhead on low-severity review findings.
69
+
70
+ **Trigger conditions** (BOTH must be true to batch):
71
+ 1. The issue has labels `review-finding` + `priority:P3`
72
+ 2. The issue has `<!-- FORGE:BATCHABLE -->` in its body
73
+
74
+ **Safety exclusions — NEVER batch** (override all trigger conditions):
75
+ - Issue body contains the word "security" or "billing" anywhere in the title or `## Problem` section
76
+ - Issue has a `security` label
77
+ - Issue has a `billing` label
78
+
79
+ **Grouping algorithm:**
80
+ ```bash
81
+ # Fetch all open batchable P3 issues
82
+ BATCHABLE_P3=$(gh issue list {GH_FLAG} \
83
+ --state open \
84
+ --label "review-finding,priority:P3" \
85
+ --limit 500 \
86
+ --json number,title,body,labels \
87
+ --jq '.[] | select(.body | test("<!-- FORGE:BATCHABLE -->"))
88
+ | select((.title | test("security|billing"; "i")) | not)
89
+ | select(.body | test("## Problem[\\s\\S]{0,500}(security|billing)"; "i") | not)
90
+ | select(([.labels[].name] | any(. == "security" or . == "billing")) | not)')
91
+
92
+ # Group by domain (file-cluster derived from the affected file path in each issue body)
93
+ # Domain is the top-level directory of the first affected file listed under "## Affected Files"
94
+ # e.g., "services/api/auth/login.py" → domain "services/api/auth"
95
+ # "web/src/app/billing/" → EXCLUDED (billing path)
96
+ # "commands/review-pr.md" → domain "commands"
97
+ ```
98
+
99
+ **Batch creation rule**: When 5+ batchable P3 issues share the same domain, OR when the oldest batchable P3 in a domain exceeds 72 hours, create a single batch issue grouping those issues:
100
+
101
+ ```bash
102
+ BATCH_ISSUE_NUM=$(gh issue create {GH_FLAG} \
103
+ --title "fix(batch): P3 review findings — {DOMAIN} domain (batch #{BATCH_N})" \
104
+ --label "review-finding,priority:P3,batch" \
105
+ --body "$(cat <<'BATCH_EOF'
106
+ ## Problem
107
+
108
+ Batch of P3 review findings in the **{DOMAIN}** domain, grouped to reduce per-finding pipeline overhead.
109
+
110
+ ## Member Findings
111
+
112
+ <!-- FORGE:BATCH_MEMBERS -->
113
+ {for each member issue: "- [ ] #{NUM}: {TITLE}"}
114
+ <!-- /FORGE:BATCH_MEMBERS -->
115
+
116
+ ## Acceptance Criteria
117
+
118
+ - [ ] All member findings addressed or closed as false-positive
119
+ - [ ] Member issues auto-closed with reference to this batch PR on merge
120
+ - [ ] No security or billing paths touched (validated before batching)
121
+
122
+ ## Context
123
+
124
+ **Batch policy**: 5+ open P3 findings in the same domain, or oldest > 72h.
125
+ **Member issues**: #{N1}, #{N2}, #{N3}, ...
126
+
127
+ <!-- FORGE:BATCHABLE -->
128
+ BATCH_EOF
129
+ )")
130
+ ```
131
+
132
+ **Replace member issues with the batch issue** in the resolved issue set. Member issues are NOT individually dispatched to `/work-on` — the batch issue is the single pipeline unit.
133
+
134
+ **Important limits**:
135
+ - Max 10 members per batch issue — if more than 10 batchable P3s exist in a domain, create multiple batch issues of ≤ 10 each
136
+ - P1 and P2 issues are NEVER batched — they keep the standard one-issue-one-PR path
137
+ - Batch issues themselves are never nested inside other batch issues
138
+
139
+ If fewer than 5 batchable P3 findings exist in any domain AND none exceed 72h, skip batch creation entirely — individual P3s run through the standard pipeline.
140
+
141
+ ### CRITICAL: No duplicate detection at orchestrator level
142
+
143
+ **The orchestrator NEVER closes, merges, or deduplicates issues.** Even if two issues look like duplicates (similar titles, same error message, same symptoms), they may target different code paths, different ORM objects, or different failure modes. Only a `/work-on` investigation agent — after reading the actual code — can determine whether an issue is truly a duplicate.
144
+
145
+ **What the orchestrator must NOT do:**
146
+ - Close an issue as "duplicate" based on title/symptom similarity
147
+ - Skip an issue because another issue "covers it"
148
+ - Merge two issues into one agent
149
+ - Make ANY judgment about issue validity
150
+
151
+ **What the orchestrator SHOULD do:**
152
+ - If two issues look related, add a note in the agent prompt: "Note: #{OTHER} has similar symptoms — investigate whether this is the same root cause or a different code path"
153
+ - Let both agents run independently — if one finds it's truly a duplicate, `/work-on`'s investigation phase will close it as invalid with evidence
154
+ - Flag potential overlap in the DAG plan for the user's awareness, but NEVER act on it
155
+
156
+ **Why**: Surface-level similarity hides critical differences. #3842 (api_key.id lazy load) and #4039 (user.id lazy load) had identical error messages but targeted completely different ORM objects. Closing #4039 as a "duplicate" would have left a customer-impacting P0 bug unfixed.
157
+
158
+ ---
159
+