forgedock 1.2.0 → 1.4.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 (78) hide show
  1. package/README.md +8 -2
  2. package/bin/batch-runner.mjs +31 -2
  3. package/bin/engine/admission.mjs +294 -0
  4. package/bin/engine/admission.test.mjs +265 -0
  5. package/bin/engine/invariants.mjs +17 -4
  6. package/bin/engine/phases.mjs +358 -42
  7. package/bin/engine/resolve.mjs +256 -0
  8. package/bin/engine/resolve.test.mjs +149 -0
  9. package/bin/engine/state.mjs +31 -7
  10. package/bin/engine-cli.mjs +138 -2
  11. package/bin/engine.mjs +414 -21
  12. package/bin/forgedock.mjs +552 -44
  13. package/bin/hooks/interactive-engine.mjs +50 -24
  14. package/bin/hooks/pre-tool-use.mjs +189 -19
  15. package/bin/journey.mjs +109 -11
  16. package/bin/labels.json +5 -0
  17. package/bin/runner.mjs +321 -10
  18. package/bin/watch-utils.mjs +255 -0
  19. package/commands/cleanup.md +7 -3
  20. package/commands/forge-stats.md +5 -4
  21. package/commands/issue.md +5 -1
  22. package/commands/orchestrate/config.md +41 -1
  23. package/commands/orchestrate/phase-1-resolve.md +234 -8
  24. package/commands/orchestrate/phase-3-dependency.md +27 -18
  25. package/commands/orchestrate/phase-4-execution.md +223 -22
  26. package/commands/qa-sweep.md +17 -0
  27. package/commands/quality-gate.md +6 -6
  28. package/commands/replay.md +16 -2
  29. package/commands/review-pr-agents/spec-cli.md +179 -0
  30. package/commands/review-pr.md +65 -0
  31. package/commands/upgrade-deps.md +523 -0
  32. package/commands/work-on/build/validate.md +61 -1
  33. package/commands/work-on/build.md +9 -1
  34. package/commands/work-on/decompose.md +10 -1
  35. package/commands/work-on/investigate.md +22 -4
  36. package/commands/work-on/remediate.md +2 -0
  37. package/commands/work-on/review.md +40 -1
  38. package/commands/work-on.md +19 -4
  39. package/docs/AIDER.md +264 -0
  40. package/docs/AUTOPILOT-CRON.md +130 -0
  41. package/docs/CONFIG.md +156 -0
  42. package/docs/CURSOR.md +135 -0
  43. package/docs/OPENCODE.md +312 -0
  44. package/docs/demo.gif +0 -0
  45. package/docs/eval/README.md +4 -4
  46. package/docs/launch/show-hn.md +3 -3
  47. package/docs/site/architecture.md +180 -0
  48. package/docs/site/command-reference.md +17 -0
  49. package/docs/site/configuration.md +243 -0
  50. package/docs/site/for-companies.md +4 -4
  51. package/docs/site/forge-annotation-protocol.md +1 -1
  52. package/docs/site/github-is-the-memory.md +2 -2
  53. package/docs/site/how-it-works.md +1 -1
  54. package/docs/site/public/llms-full.txt +380 -0
  55. package/docs/site/public/llms.txt +35 -0
  56. package/docs/spec/eval-run-result.md +8 -4
  57. package/docs/spec/label-state-machine.md +9 -0
  58. package/docs/spec-graph-schema.md +3 -3
  59. package/package.json +3 -3
  60. package/packages/protocol/README.md +75 -0
  61. package/packages/protocol/src/card.js +114 -0
  62. package/packages/protocol/src/cli.js +4 -77
  63. package/packages/protocol/src/emit.js +5 -11
  64. package/packages/protocol/src/html-comment-escape.js +68 -0
  65. package/packages/protocol/src/index.js +3 -1
  66. package/packages/protocol/src/parse.js +19 -11
  67. package/packages/protocol/src/phases.js +105 -0
  68. package/packages/protocol/src/types.js +18 -1
  69. package/packages/protocol/src/validate.js +11 -0
  70. package/scripts/check-admission-parity.mjs +167 -0
  71. package/scripts/check-command-side-effects.sh +376 -0
  72. package/scripts/check-phase-registry-drift.mjs +96 -0
  73. package/scripts/check-spec-markers.sh +274 -0
  74. package/scripts/classify-lane.sh +29 -7
  75. package/scripts/forge-run.sh +353 -0
  76. package/templates/cross-repo-trigger.yml +282 -0
  77. package/templates/cursor/forge.mdc +148 -0
  78. package/templates/github-actions/forgedock-autopilot.yml +113 -0
@@ -263,8 +263,8 @@ gh api repos/{GH_REPO}/issues/{NUMBER}/comments --jq '.[] | {id: .id, body: .bod
263
263
  ```
264
264
 
265
265
  **Resume logic**:
266
- - If `<!-- FORGE:INVESTIGATOR -->` comment exists AND `<!-- INVESTIGATION:COMPLETE -->` is present in the SAME comment → investigation already complete, EXIT (return existing verdict to caller)
267
- - If `<!-- FORGE:INVESTIGATOR -->` comment exists BUT `<!-- INVESTIGATION:COMPLETE -->` is ABSENT → investigation was interrupted, delete the partial comment and restart:
266
+ - If `<!-- FORGE:INVESTIGATOR -->` comment exists AND (`<!-- INVESTIGATION:COMPLETE -->` OR `<!-- INVESTIGATION:INVALID -->`) is present in the SAME comment → investigation already complete, EXIT (return existing verdict to caller). `INVESTIGATION:INVALID` is the terminal sentinel Phase 1C emits for an INVALID verdict (see Phase 1C below) — it is just as much a completion marker as `INVESTIGATION:COMPLETE`, not an "interrupted" state.
267
+ - If `<!-- FORGE:INVESTIGATOR -->` comment exists BUT NEITHER `<!-- INVESTIGATION:COMPLETE -->` NOR `<!-- INVESTIGATION:INVALID -->` is present → investigation was interrupted, delete the partial comment and restart:
268
268
  ```bash
269
269
  gh api repos/{GH_REPO}/issues/comments/{COMMENT_ID} -X DELETE
270
270
  ```
@@ -355,10 +355,25 @@ bash {REPO_PATH}/scripts/code-index.sh query --domain {DOMAIN_LABEL} --repo-path
355
355
 
356
356
  ## Phase 1C: Post Investigation Comment
357
357
 
358
- The comment MUST include `<!-- INVESTIGATION:COMPLETE -->` at the very end, AFTER all required sections are present. This marker signals the investigation finished successfully.
358
+ The comment MUST include a terminal sentinel at the very end, AFTER all required sections are present. **The sentinel is conditional on the resolved Verdict — it is NOT always `<!-- INVESTIGATION:COMPLETE -->`:**
359
+
360
+ - **Verdict is INVALID** → close with `<!-- INVESTIGATION:INVALID -->`. This is a distinct, already-wired-up terminal marker: `bin/engine/phases.mjs`'s `detectOutcome` for the `investigate` phase checks for it explicitly (ahead of `INVESTIGATION:COMPLETE`) and routes to `terminalReason: "invalid"`; `bin/hooks/interactive-engine.mjs`'s `PHASE_MARKERS` table also already treats it as terminal. Emitting `INVESTIGATION:COMPLETE` for an INVALID verdict is what previously caused every completed investigation to read as `{verdict: "CONFIRMED"}` regardless of actual outcome — do NOT regress this (forge#2350).
361
+ - **Verdict is CONFIRMED or PARTIAL** → close with `<!-- INVESTIGATION:COMPLETE -->` as before (PARTIAL still routes to `ready-to-build` in Phase 1D — only INVALID gets the distinct terminal sentinel).
362
+
363
+ Compute the sentinel once, before building the comment body:
364
+
365
+ ```bash
366
+ if [ "{VERDICT}" = "INVALID" ]; then
367
+ INVESTIGATION_SENTINEL="<!-- INVESTIGATION:INVALID -->"
368
+ else
369
+ INVESTIGATION_SENTINEL="<!-- INVESTIGATION:COMPLETE -->"
370
+ fi
371
+ ```
359
372
 
360
373
  **CODEC PATH (forge#1727)**: Construct the annotation body via the protocol codec — do NOT hand-roll the `<!-- FORGE:INVESTIGATOR -->` header. Use `forge-annotation.sh write INVESTIGATOR --field ...` or `node packages/protocol/src/cli.js emit INVESTIGATOR --field ...` to produce the opening tag and completion sentinel. Fill in the Markdown body sections below. The full pattern:
361
374
 
375
+ **Caveat (forge#2368)**: `packages/protocol/src/types.js`'s `INVESTIGATOR.completionSentinel` is a single fixed value (`'INVESTIGATION:COMPLETE'`) and `packages/protocol/src/emit.js` appends it unconditionally — the codec does NOT currently support the verdict-conditional sentinel selection described above, and cannot emit `INVESTIGATION:INVALID`. Using the CODEC PATH for an INVALID-verdict investigation would silently regress the forge#2350 fix (every investigation would again read as `{verdict: "CONFIRMED"}`). Until the codec is extended to support a verdict-conditional sentinel, the hand-rolled block above/below (using the `${INVESTIGATION_SENTINEL}` variable computed above) is the authoritative path for Phase 1C — do not use the CODEC PATH for this annotation.
376
+
362
377
  ```bash
363
378
  # Build the annotation body via codec (escaping and sentinel handled by codec)
364
379
  ANNOTATION_BODY=$(node packages/protocol/src/cli.js emit INVESTIGATOR \
@@ -368,6 +383,7 @@ ANNOTATION_BODY=$(node packages/protocol/src/cli.js emit INVESTIGATOR \
368
383
  --field "Task Type={TASK_TYPE}" \
369
384
  --field "Decomposition Assessment={YES|NO} — {reason}")
370
385
  # ANNOTATION_BODY now has opening tag + required fields + INVESTIGATION:COMPLETE sentinel.
386
+ # NOTE: the codec's sentinel is fixed — do not use this path when Verdict=INVALID (see caveat above).
371
387
  # Append the Markdown body sections to it before posting.
372
388
  ```
373
389
 
@@ -450,9 +466,11 @@ ACCEPTANCE_CHECK: id=ac-4 type=command target="grep -qE '(>= ?2|2\+)' commands/o
450
466
 
451
467
  **Skipping**: if the issue has no verifiable acceptance criteria and none can be derived from the recommendation, emit a single sentinel: `ACCEPTANCE_CHECK: id=ac-skip type=skipped target="none" matcher="none" description=No machine-checkable criteria available — human review required`
452
468
  ${ANNOTATION_LINK_FOOTER}
453
- <!-- INVESTIGATION:COMPLETE -->"
469
+ ${INVESTIGATION_SENTINEL}"
454
470
  ```
455
471
 
472
+ **Do not hardcode `<!-- INVESTIGATION:COMPLETE -->` as the closing line.** The closing line MUST be the `${INVESTIGATION_SENTINEL}` variable computed above — it resolves to `<!-- INVESTIGATION:INVALID -->` for an INVALID verdict and `<!-- INVESTIGATION:COMPLETE -->` otherwise. `INVESTIGATION:COMPLETE` and `INVESTIGATION:INVALID` are mutually exclusive within a single posted comment — never emit both.
473
+
456
474
  ---
457
475
 
458
476
  ## Phase 1C.5: Create Knowledge Gist
@@ -20,6 +20,8 @@ argument-hint: "[PR number] [--issue N] [--repo GH_REPO] [--gh-flag GH_FLAG] [--
20
20
 
21
21
  **Scope note**: This mode owns exactly one gap — re-driving a `needs-human` PR's own remediation. It does NOT implement the `needs-human` sub-label taxonomy (#1815's scope) and it does NOT edit `review-pr.md`'s Phase 8 guard (forge#1810) — that guard's existing safe-default (`workflow:awaiting-merge` on any clean re-review of a previously-escalated PR) is reused as-is; this file only adds a bar-check *after* that guard has already fired.
22
22
 
23
+ **Engine coverage** (forge#2379): this subcommand's `command` name (`work-on/remediate`) and completion marker (`FORGE:REMEDIATION:COMPLETE`, including the `**Re-gate outcome**` field Phase M8 posts below) are now registered in the headless engine's phase table — `RESERVED_TYPES.REMEDIATION` in `packages/protocol/src/types.js`, `remediate` in `packages/protocol/src/phases.js`'s `PHASE_IDS`/`PHASE_MARKERS`, and a matching `remediate` entry in `bin/engine/phases.mjs`'s `PHASES` array (`entryCondition`: review committed + `terminalReason: "needs-human"`; `detectOutcome` maps each re-gate outcome to the right terminal reason). **Known limitation, documented in that engine entry's own comment**: a single continuous `runIssue()` walk cannot reach this phase today — `review`'s `"blocked"` outcome and the needs-human divergence guard both terminate the run before `remediate`'s `entryCondition` is ever evaluated. This subcommand therefore continues to run exactly as documented above — as its own separate top-level entry point — until a follow-up issue live-wires the engine to reconstruct state from GitHub for a dedicated remediation run.
24
+
23
25
  ---
24
26
 
25
27
  ## Inputs
@@ -47,10 +47,49 @@ gh pr list {GH_FLAG} --head {BRANCH} --json number,state,url 2>/dev/null
47
47
  ```
48
48
 
49
49
  **Resume check**:
50
- - If PR already exists AND is OPEN → skip to Phase R3 (invoke /review-pr)
50
+ - If PR already exists AND is OPEN → run the **HEAD-unchanged re-review guard** below before proceeding to Phase R3
51
51
  - If PR already exists AND is MERGED → return `REVIEW_RESULT: status: ALREADY_MERGED`
52
52
  - If no `<!-- FORGE:BUILDER -->` comment exists → EXIT with `REVIEW_RESULT: status: BLOCKED`, blocker: "FORGE:BUILDER comment not found — implement phase may not have completed"
53
53
 
54
+ **HEAD-unchanged re-review guard** (MANDATORY when a PR already exists and is OPEN) <!-- Added: forge#2243 --> — a PR whose most recent review verdict was CHANGES REQUESTED must not be resubmitted for a full domain-agent review fan-out if nothing has changed since that verdict. `/review-pr` records the exact commit it reviewed in its verdict comment (`CHANGES REQUESTED: commit {sha} — ...`, see `commands/review-pr.md` Phase 8/9); compare that recorded sha against the PR's current `headRefOid`:
55
+
56
+ ```bash
57
+ # NOTE: the CHANGES REQUESTED verdict is posted via `gh pr review --comment` (see
58
+ # commands/review-pr.md Phase 7B) — that creates a PullRequestReview, which surfaces under
59
+ # the `reviews` field, NOT `comments` (issue/PR comments are a separate GraphQL object).
60
+ # Query both --json reviews and --json comments (same combined-read pattern already used in
61
+ # work-on.md's REVIEW_BODIES/REVIEW_PRESENT checks) so this guard works regardless of which
62
+ # GitHub object type carries the verdict text.
63
+ LAST_VERDICT=$(gh pr view {PR_NUMBER} {GH_FLAG} --json reviews,comments \
64
+ --jq '([.reviews[] | {body, created_at: (.submittedAt // "")}] + [.comments[] | {body, created_at: (.createdAt // "")}]) | map(select(.body | test("CHANGES REQUESTED: commit "))) | sort_by(.created_at) | last | .body // ""' 2>/dev/null)
65
+ LAST_VERDICT_SHA=$(echo "$LAST_VERDICT" | grep -oE 'CHANGES REQUESTED: commit [0-9a-f]+' | grep -oE '[0-9a-f]+$' | head -1)
66
+ CURRENT_SHA_SHORT=$(gh pr view {PR_NUMBER} {GH_FLAG} --json headRefOid --jq '.headRefOid' 2>/dev/null | cut -c1-7)
67
+
68
+ if [ -n "$LAST_VERDICT_SHA" ] && [ "$LAST_VERDICT_SHA" = "$CURRENT_SHA_SHORT" ]; then
69
+ echo "HEAD unchanged since last CHANGES REQUESTED verdict ($LAST_VERDICT_SHA) — skipping re-review."
70
+ # No DRY_RUN/governor guard here — consistent with every other gh issue comment/edit call
71
+ # already in this file (e.g. the Push Failed / Push Blocked sections below), none of which
72
+ # are gated either. This is a report-and-stop action (blocks re-review, does not merge or
73
+ # delete anything), same risk class as those pre-existing calls.
74
+ REREVIEW_SKIP_BODY=$(cat <<SKIP_EOF
75
+ ## Re-Review Skipped — HEAD Unchanged
76
+
77
+ PR #{PR_NUMBER}'s HEAD (${CURRENT_SHA_SHORT}) has not changed since the last CHANGES REQUESTED verdict. Re-running /review-pr would re-review byte-identical code and reproduce the same verdict — this is a pure waste of a full domain-agent fan-out.
78
+
79
+ The PR is already needs-human (or will be shortly, if this is the first time this guard has fired for it). Progress here now depends on remediation (fix the findings, push a new commit, re-review) rather than another raw review submission. If running under /orchestrate, item 6.4 in phase-4-execution.md auto-dispatches remediation for any needs-human-gated issue, including this one (see forge#2243) — no manual action should be needed. If running standalone, invoke /work-on {PR_NUMBER} --remediate --issue {NUMBER} directly.
80
+
81
+ <!-- FORGE:REREVIEW_SKIPPED -->
82
+ SKIP_EOF
83
+ )
84
+ gh issue comment {NUMBER} {GH_FLAG} --body "$REREVIEW_SKIP_BODY" # <!-- allowlist:check-command-side-effects -->
85
+ gh issue edit {NUMBER} {GH_FLAG} --add-label needs-human 2>/dev/null || true # <!-- allowlist:check-command-side-effects -->
86
+ # Return REVIEW_RESULT: status: BLOCKED — do not invoke /review-pr again on unchanged HEAD
87
+ exit 1
88
+ fi
89
+ ```
90
+
91
+ If `LAST_VERDICT_SHA` is empty (no prior CHANGES REQUESTED verdict found) or differs from the current HEAD (a new commit was pushed since the last verdict — e.g. by remediation), proceed normally to Phase R3.
92
+
54
93
  ---
55
94
 
56
95
  ## Phase R1: Pre-Push Ancestry Guard
@@ -247,6 +247,8 @@ Extract project prefix and issue number. If `next`/`pick`: list open issues sort
247
247
 
248
248
  ### 0A.1: Remediation Mode Detection (`--remediate`) <!-- Added: forge#1813 -->
249
249
 
250
+ **Engine coverage** (forge#2379): `remediate` is now a registered phase in the headless engine's phase table (`packages/protocol/src/phases.js`, `bin/engine/phases.mjs`) — see `commands/work-on/remediate.md`'s own "Engine coverage" note for the current, documented limitation (a single continuous headless `runIssue()` walk cannot yet reach it; this prose-layer standalone-invocation path below remains the only way `remediate` actually runs today).
251
+
250
252
  **Check first, before any other Phase 0 routing** — if `$ARGUMENTS` contains `--remediate`, this is NOT a normal issue-pipeline invocation. The first positional argument is a **PR number**, not an issue number:
251
253
 
252
254
  ```bash
@@ -524,9 +526,9 @@ a hard dependency.
524
526
 
525
527
  ## Phase 1: Investigation
526
528
 
527
- **Skip if**: `<!-- FORGE:INVESTIGATOR -->` exists with `<!-- INVESTIGATION:COMPLETE -->` in the SAME comment.
529
+ **Skip if**: `<!-- FORGE:INVESTIGATOR -->` exists with `<!-- INVESTIGATION:COMPLETE -->` OR `<!-- INVESTIGATION:INVALID -->` in the SAME comment. `INVESTIGATION:INVALID` is the terminal sentinel Phase 1C emits for an INVALID verdict (see 1C below) — it signals investigation completion just as much as `INVESTIGATION:COMPLETE` does, not an interrupted state.
528
530
 
529
- **Partial investigation**: If investigator comment exists BUT `<!-- INVESTIGATION:COMPLETE -->` is ABSENT → investigation was interrupted. Delete the partial comment and restart:
531
+ **Partial investigation**: If investigator comment exists BUT NEITHER `<!-- INVESTIGATION:COMPLETE -->` NOR `<!-- INVESTIGATION:INVALID -->` is present → investigation was interrupted. Delete the partial comment and restart:
530
532
  ```bash
531
533
  COMMENT_ID=$(gh api repos/{GH_REPO}/issues/{NUMBER}/comments \
532
534
  --jq '.[] | select(.body | contains("FORGE:INVESTIGATOR")) | .id')
@@ -686,9 +688,18 @@ Use `forge.yaml → review.tech_stack` and the issue domain labels to identify e
686
688
 
687
689
  ### 1C: Post investigation comment
688
690
 
689
- The comment MUST include `<!-- INVESTIGATION:COMPLETE -->` at the very end.
691
+ The comment MUST include a terminal sentinel at the very end. **The sentinel is conditional on the resolved Verdict — it is NOT always `<!-- INVESTIGATION:COMPLETE -->`:**
692
+
693
+ - **Verdict is INVALID** → close with `<!-- INVESTIGATION:INVALID -->`. This is a distinct, already-wired-up terminal marker: `bin/engine/phases.mjs`'s `detectOutcome` for the `investigate` phase checks for it explicitly (ahead of `INVESTIGATION:COMPLETE`) and routes to `terminalReason: "invalid"`; `bin/hooks/interactive-engine.mjs`'s `PHASE_MARKERS` table also already treats it as terminal. Emitting `INVESTIGATION:COMPLETE` for an INVALID verdict is what previously caused every completed investigation to read as `{verdict: "CONFIRMED"}` regardless of actual outcome — do NOT regress this (forge#2350).
694
+ - **Verdict is CONFIRMED or PARTIAL** → close with `<!-- INVESTIGATION:COMPLETE -->` as before (PARTIAL still routes to `ready-to-build` below — only INVALID gets the distinct terminal sentinel).
690
695
 
691
696
  ```bash
697
+ if [ "{VERDICT}" = "INVALID" ]; then
698
+ INVESTIGATION_SENTINEL="<!-- INVESTIGATION:INVALID -->"
699
+ else
700
+ INVESTIGATION_SENTINEL="<!-- INVESTIGATION:COMPLETE -->"
701
+ fi
702
+
692
703
  gh issue comment {NUMBER} {GH_FLAG} --body "<!-- FORGE:INVESTIGATOR -->
693
704
  ## Investigation Report
694
705
 
@@ -728,9 +739,11 @@ gh issue comment {NUMBER} {GH_FLAG} --body "<!-- FORGE:INVESTIGATOR -->
728
739
  **{YES|NO}** — {reason}
729
740
  {if YES: proposed sub-issues with titles and dependencies}
730
741
 
731
- <!-- INVESTIGATION:COMPLETE -->"
742
+ ${INVESTIGATION_SENTINEL}"
732
743
  ```
733
744
 
745
+ **Do not hardcode `<!-- INVESTIGATION:COMPLETE -->` as the closing line.** The closing line MUST be the `${INVESTIGATION_SENTINEL}` variable computed above — it resolves to `<!-- INVESTIGATION:INVALID -->` for an INVALID verdict and `<!-- INVESTIGATION:COMPLETE -->` otherwise. `INVESTIGATION:COMPLETE` and `INVESTIGATION:INVALID` are mutually exclusive within a single posted comment — never emit both.
746
+
734
747
  ### 1D: Correction capture (MANDATORY — run before label update)
735
748
 
736
749
  Before routing, scan all non-agent comments for correction signals from the repository owner. Correction signals are owner comments that contain phrases like "no, use", "actually use", "use X instead", "not X, use Y", or "wrong branch". If found, write the correction to `forge.yaml → learned:` and emit a `FORGE:LEARNED` annotation.
@@ -890,6 +903,8 @@ gh issue close {NUMBER} {GH_FLAG} --comment "Closing as invalid: {reason from in
890
903
 
891
904
  ## Phase 2: Decomposition (Conditional)
892
905
 
906
+ **Engine coverage** (forge#2379): this phase's dispatch target (`work-on/decompose`) is now a real phase in the headless engine's phase table — `decompose` in `packages/protocol/src/phases.js`/`bin/engine/phases.mjs`, live-wired so `investigate`'s `DECOMPOSE:YES` outcome hands off to it instead of terminating the run in place. This prose Phase 2 remains the interactive/prose dispatch path; the engine path is the headless equivalent, both invoking the same `commands/work-on/decompose.md` subcommand.
907
+
893
908
  **Skip if**: Already decomposed, is a sub-issue, or investigation says decompose: NO.
894
909
 
895
910
  **Trigger if**: Investigation assessment says YES — 2+ signals match (at least 1 Strong): multiple task types, 3+ service groups, phased requirements, 6+ files across directories.
package/docs/AIDER.md ADDED
@@ -0,0 +1,264 @@
1
+ # Aider Support
2
+
3
+ ForgeDock has an additive Aider-native install path. The goal is to give Aider
4
+ users access to the ForgeDock pipeline without regressing the existing Claude
5
+ Code or Codex setups.
6
+
7
+ ## Architecture
8
+
9
+ Shared source:
10
+ - `commands/**/*.md` remains the workflow spec for all runtimes
11
+
12
+ Claude Code wrapper:
13
+ - `install.sh` (or `npx forgedock`) symlinks command files into `~/.claude/commands/`
14
+
15
+ Codex wrapper:
16
+ - `install-codex.sh` generates namespaced skills in `~/.codex/skills/`
17
+
18
+ **Aider wrapper** (this document):
19
+ - `install-aider.sh` writes `~/.aider-forge.md` — a conventions file Aider
20
+ loads at session start via `--read`
21
+ - The conventions file provides runtime mapping rules and entry point references
22
+ - Aider reads ForgeDock command specs on demand with `/read $FORGE_HOME/commands/x.md`
23
+
24
+ This is intentionally a conventions-file architecture, not a duplicate command
25
+ tree. The shared `commands/` directory remains the single source of truth.
26
+
27
+ ## Install
28
+
29
+ ### Option A — standalone bash installer
30
+
31
+ ```bash
32
+ cd /path/to/forgedock
33
+ ./install-aider.sh
34
+ ```
35
+
36
+ This writes `~/.aider-forge.md` with ForgeDock conventions and runtime mapping
37
+ rules.
38
+
39
+ ### Option B — via npx forgedock
40
+
41
+ If you already use `npx forgedock` for Claude Code:
42
+
43
+ ```bash
44
+ npx forgedock
45
+ ```
46
+
47
+ When `aider` is detected on your PATH, `npx forgedock` writes `~/.aider-forge.md`
48
+ as an additional install step. No existing Claude Code files are affected.
49
+
50
+ ## Usage
51
+
52
+ ### Per-session (command line)
53
+
54
+ ```bash
55
+ aider --read ~/.aider-forge.md
56
+ ```
57
+
58
+ ### Always-on (`.aider.conf.yml`)
59
+
60
+ Add to your project's `.aider.conf.yml`:
61
+
62
+ ```yaml
63
+ read:
64
+ - ~/.aider-forge.md
65
+ ```
66
+
67
+ Or to `~/.aider.conf.yml` for global application across all projects.
68
+
69
+ ### Loading a pipeline command
70
+
71
+ Once Aider has the conventions file loaded, load a command spec on demand:
72
+
73
+ ```
74
+ /read /path/to/forgedock/commands/work-on.md
75
+ ```
76
+
77
+ Then follow the command spec step by step, using `/run` for all shell
78
+ operations.
79
+
80
+ ## Tool Translation Rules
81
+
82
+ ForgeDock command specs reference Claude Code-specific tools. Translate them
83
+ to Aider equivalents:
84
+
85
+ | Claude Code | Aider equivalent | Notes |
86
+ |-------------|-----------------|-------|
87
+ | `Skill("work-on", args="123")` | `/read $FORGE_HOME/commands/work-on.md` | Load the spec and execute it |
88
+ | `Skill("review-pr", args="456")` | `/read $FORGE_HOME/commands/review-pr.md` | Load the spec and execute it |
89
+ | `Skill("quality-gate")` | `/read $FORGE_HOME/commands/quality-gate.md` | Load the spec and execute it |
90
+ | `Bash("git status")` | `/run git status` | Direct shell execution |
91
+ | `Read("path/to/file")` | Read the file directly | Aider's native file read |
92
+ | `Grep(pattern, path)` | `/run rg 'pattern' path` | Use `rg` (ripgrep) |
93
+ | `Glob("**/*.md")` | `/run find . -name "*.md"` | Shell find |
94
+ | `WebFetch(url)` | `/run curl -s url` | curl or wget |
95
+ | `Agent(...)` / `Task(...)` | Continue the sub-task yourself | No sub-agent support; inline it |
96
+ | `EnterWorktree(path)` | `/run cd path` then use `/run` | Work in worktree directory |
97
+
98
+ ### Nested Skill references
99
+
100
+ When a command spec calls `Skill("x")` or references another command:
101
+
102
+ ```
103
+ # Load the referenced command spec manually:
104
+ /read $FORGE_HOME/commands/x.md
105
+ ```
106
+
107
+ Map command names to file paths:
108
+ - `Skill("work-on")` → `commands/work-on.md`
109
+ - `Skill("review-pr")` → `commands/review-pr.md`
110
+ - `Skill("quality-gate")` → `commands/quality-gate.md`
111
+ - `Skill("orchestrate")` → `commands/orchestrate.md`
112
+
113
+ ## GitHub Operations
114
+
115
+ All FORGE annotations are written to GitHub issue/PR comments via the `gh`
116
+ CLI. Use `/run gh ...` for every GitHub operation.
117
+
118
+ ### Label management
119
+
120
+ ```bash
121
+ /run gh issue edit 123 -R OWNER/REPO --add-label "workflow:investigating"
122
+ /run gh issue edit 123 -R OWNER/REPO --remove-label "workflow:investigating"
123
+ ```
124
+
125
+ ### Reading existing annotations
126
+
127
+ ```bash
128
+ /run gh api repos/OWNER/REPO/issues/123/comments \
129
+ --jq '.[] | select(.body | contains("FORGE:INVESTIGATOR")) | .body'
130
+ ```
131
+
132
+ ### Writing a FORGE annotation comment
133
+
134
+ ```bash
135
+ /run gh issue comment 123 -R OWNER/REPO --body "<!-- FORGE:INVESTIGATOR -->
136
+ ## Investigation Report
137
+
138
+ **Verdict**: CONFIRMED
139
+ ...
140
+ <!-- INVESTIGATION:COMPLETE -->"
141
+ ```
142
+
143
+ For multi-line comment bodies, write the content to a temp file first:
144
+
145
+ ```bash
146
+ cat > /tmp/comment.md << 'EOF'
147
+ <!-- FORGE:INVESTIGATOR -->
148
+ ## Investigation Report
149
+ ...
150
+ <!-- INVESTIGATION:COMPLETE -->
151
+ EOF
152
+ /run gh issue comment 123 -R OWNER/REPO --body "$(cat /tmp/comment.md)"
153
+ ```
154
+
155
+ ### Creating a PR
156
+
157
+ ```bash
158
+ /run gh pr create -R OWNER/REPO \
159
+ --base staging \
160
+ --head feat/my-branch-123 \
161
+ --title "feat: description (#123)" \
162
+ --body "$(cat /tmp/pr_body.md)"
163
+ ```
164
+
165
+ ## Worktrees
166
+
167
+ ForgeDock uses git worktrees to isolate branch work. Create one with:
168
+
169
+ ```bash
170
+ /run git fetch origin
171
+ /run git worktree add .claude/worktrees/feat-my-feature-123 \
172
+ -b feat/my-feature-123 origin/staging
173
+ ```
174
+
175
+ Work inside the worktree for all file edits and commits. Aider's `/run`
176
+ commands execute in the worktree directory if you `cd` to it:
177
+
178
+ ```bash
179
+ /run cd /path/to/repo/.claude/worktrees/feat-my-feature-123
180
+ ```
181
+
182
+ Or pass the path explicitly in each command:
183
+
184
+ ```bash
185
+ /run git -C /path/to/repo/.claude/worktrees/feat-my-feature-123 status
186
+ ```
187
+
188
+ ## FORGE Annotation Protocol
189
+
190
+ Every pipeline stage writes a structured annotation to GitHub. Key rules:
191
+
192
+ 1. **Idempotency**: Check for existing annotations BEFORE starting a phase.
193
+ Do not re-run a completed phase.
194
+ 2. **Compaction resilience**: Write annotations AFTER completing each
195
+ significant step. GitHub is the persistent state layer.
196
+ 3. **Restart partial annotations**: If an annotation exists without its
197
+ `:COMPLETE` sentinel, delete it and restart the phase.
198
+ 4. **Respect label state**: Labels track workflow state. Read and set them
199
+ at each phase boundary.
200
+
201
+ ### Label state machine
202
+
203
+ ```
204
+ workflow:investigating
205
+ → workflow:ready-to-build (investigation complete)
206
+ → workflow:building (build started)
207
+ → workflow:in-review (PR created)
208
+ → workflow:merged (PR merged) [TERMINAL]
209
+
210
+ workflow:invalid [TERMINAL]
211
+ workflow:decomposed [TERMINAL]
212
+ needs-human [TERMINAL]
213
+ ```
214
+
215
+ Stop the pipeline when any terminal label is set.
216
+
217
+ ## Feasibility Analysis
218
+
219
+ Aider is the highest-feasibility non-Claude agent for ForgeDock because:
220
+
221
+ | Capability | Requirement | Aider support |
222
+ |-----------|-------------|---------------|
223
+ | Load instruction files | `--read` flag / `.aider.conf.yml` | Native |
224
+ | Execute shell commands | `gh`, `git`, `rg` via shell | `/run` command |
225
+ | Read/write files | File editing | Native |
226
+ | GitHub API | `gh` CLI | Via `/run gh ...` |
227
+ | Multi-step workflows | Follow sequential instructions | Supported |
228
+ | Compaction resilience | Re-read GitHub state at phase start | Supported (via `/run gh ...`) |
229
+
230
+ **Limitation**: Aider has no native sub-agent/parallel task model (`Agent(...)`,
231
+ `Task(...)`). Phase 3 parallel context gathering (`FORGE:CONTEXT`) and
232
+ multi-agent review (`review-pr-agents.md`) must be executed sequentially.
233
+ For the orchestrate command (`/orchestrate`), run one issue at a time or
234
+ use separate Aider sessions per issue.
235
+
236
+ ## Trust and Configuration
237
+
238
+ Aider does not have a project trust model. Once `~/.aider-forge.md` is loaded,
239
+ all operations in that session have access to shell execution via `/run`.
240
+
241
+ **Security note**: ForgeDock's shell operations are limited to `gh`, `git`,
242
+ `rg`, `find`, and standard POSIX tools. The conventions file does not execute
243
+ arbitrary code at load time — it only provides instruction text.
244
+
245
+ ## Usage Notes
246
+
247
+ - Use `--read ~/.aider-forge.md` on every session, or add it to
248
+ `.aider.conf.yml` for automatic loading.
249
+ - Load command specs on demand with `/read $FORGE_HOME/commands/x.md` —
250
+ do not load all commands at once.
251
+ - Keep `CLAUDE.md` and `AGENTS.md` aligned with ForgeDock conventions;
252
+ Aider and Claude Code can differ at the wrapper layer but not on FORGE
253
+ workflow invariants (annotation format, label state machine, branch
254
+ naming, worktree conventions).
255
+ - For pipeline stages that post FORGE annotations, always write the body
256
+ to a temp file before passing to `gh issue comment` to avoid shell
257
+ quoting issues with multi-line content.
258
+
259
+ ## Reference
260
+
261
+ - [FORGE Protocol spec](FORGE-PROTOCOL.md) — annotation format, label state machine, conformance tests
262
+ - [Codex adapter](CODEX.md) — parallel reference for OpenAI Codex CLI
263
+ - [Pipeline commands](../commands/) — shared workflow specs (authoritative for all runtimes)
264
+ - [`install-aider.sh`](../install-aider.sh) — installer script
@@ -0,0 +1,130 @@
1
+ # Autopilot Cron Mode — GitHub Actions Setup
2
+
3
+ Run [`/autopilot`](../commands/autopilot.md) on a schedule so your repo gets better while you sleep.
4
+
5
+ ---
6
+
7
+ ## Quick Start
8
+
9
+ 1. **Copy the workflow template** into your repo:
10
+
11
+ ```bash
12
+ mkdir -p .github/workflows
13
+ curl -o .github/workflows/forgedock-autopilot.yml \
14
+ https://raw.githubusercontent.com/RapierCraftStudios/ForgeDock/milestone/developer-experience-distribution/templates/github-actions/forgedock-autopilot.yml
15
+ ```
16
+
17
+ 2. **Add your Anthropic API key** as a repository secret:
18
+ - Go to: `Settings → Secrets and variables → Actions → New repository secret`
19
+ - Name: `ANTHROPIC_API_KEY`
20
+ - Value: your key from [console.anthropic.com](https://console.anthropic.com)
21
+
22
+ 3. **Commit the workflow file** — GitHub Actions picks it up automatically.
23
+
24
+ That's it. The workflow runs every Monday at 9 AM UTC in `recon` mode (safe, read-only).
25
+
26
+ ---
27
+
28
+ ## Modes
29
+
30
+ ### `recon` (default — safe)
31
+
32
+ Runs [`/autopilot --recon-only`](../commands/autopilot.md):
33
+
34
+ - Pulls signals: production health, CI/CD, issue backlog, analytics
35
+ - Creates GitHub issues for findings
36
+ - **No branches, no PRs, no code changes**
37
+
38
+ This is the default for scheduled runs. Safe to enable immediately.
39
+
40
+ ### `fix` (explicit opt-in)
41
+
42
+ Runs [`/autopilot --fix --limit N`](../commands/autopilot.md):
43
+
44
+ - Everything in `recon` mode, plus:
45
+ - Picks up the top N open issues and runs `/work-on` on each
46
+ - Creates branches and PRs targeting `staging` (never `main`)
47
+ - **Requires explicit selection** — not available on scheduled runs without editing the workflow
48
+
49
+ To enable `fix` mode on a scheduled run, edit the `Resolve autopilot arguments` step in the workflow and change the default `MODE` to `fix`.
50
+
51
+ To run `fix` mode on demand, use the **Run workflow** button on GitHub Actions and select `fix` from the mode dropdown.
52
+
53
+ ---
54
+
55
+ ## Permissions
56
+
57
+ The workflow requires these GitHub token permissions (already set in the template):
58
+
59
+ | Permission | Required for |
60
+ |------------|-------------|
61
+ | `contents: write` | Creating branches and pushing commits (`fix` mode) |
62
+ | `issues: write` | Creating and labeling issues (both modes) |
63
+ | `pull-requests: write` | Creating PRs (`fix` mode) |
64
+
65
+ `GITHUB_TOKEN` is provided automatically — no extra setup needed.
66
+
67
+ ---
68
+
69
+ ## Adjusting the Schedule
70
+
71
+ The default cron runs every Monday at 9 AM UTC. To change it, edit the `cron` line:
72
+
73
+ ```yaml
74
+ on:
75
+ schedule:
76
+ - cron: '0 9 * * 1' # Monday 9 AM UTC
77
+ # - cron: '0 8 * * *' # Daily at 8 AM UTC
78
+ # - cron: '0 9 1 * *' # Monthly on the 1st
79
+ ```
80
+
81
+ Cron syntax: `minute hour day-of-month month day-of-week`. Use [crontab.guru](https://crontab.guru) to verify expressions.
82
+
83
+ ---
84
+
85
+ ## Changing the Fix Limit
86
+
87
+ The `limit` input controls how many issues are picked up per run in `fix` mode (default: 3). To change the default for manual runs, edit the `default` value under `inputs.limit` in the workflow file.
88
+
89
+ ---
90
+
91
+ ## Non-Interactive Confirmation Bypass
92
+
93
+ `/autopilot` Phase 4B normally requires interactive user confirmation before running `/work-on` on any issues. In GitHub Actions (a non-interactive environment), this gate is bypassed automatically when the `CI` environment variable is `true` — which is always the case in GHA.
94
+
95
+ **The `workflow_dispatch` mode input serves as the human opt-in.** When you select `fix` and click **Run workflow**, you are explicitly approving the fix run. For scheduled runs, the mode embedded in the workflow YAML is your standing approval.
96
+
97
+ This bypass is narrow: it only skips Phase 4B's interactive prompt. All other safety rules in `/autopilot` remain in force — `needs-human` issues are never picked up, milestone issues are excluded, and the `FIX_LIMIT` cap is always enforced.
98
+
99
+ ---
100
+
101
+ ## Cost Estimates
102
+
103
+ | Mode | Typical token usage | Approximate cost |
104
+ |------|--------------------|--------------------|
105
+ | `recon` | ~5,000–15,000 tokens | ~$0.02–$0.05/run |
106
+ | `fix` (1 issue) | ~50,000–150,000 tokens | ~$0.15–$0.45/run |
107
+ | `fix` (3 issues) | ~150,000–450,000 tokens | ~$0.45–$1.35/run |
108
+
109
+ Estimates based on `claude-sonnet-4` pricing ($3.00/M input, $15.00/M output). Actual usage varies by issue complexity and codebase size.
110
+
111
+ To control costs, keep `mode: recon` for scheduled runs and use `fix` mode only on demand.
112
+
113
+ ---
114
+
115
+ ## Frequently Asked Questions
116
+
117
+ **Will this merge code to `main`?**
118
+ No. `/autopilot` (and `/work-on`) never merge to `main`. All PRs target `staging` or a milestone branch. You deploy when ready.
119
+
120
+ **What if an autopilot run fails?**
121
+ The workflow exits with a non-zero status. GitHub sends a notification email (configurable). The run is logged in the Actions tab. No partial state is left — issues are only created after a full recon cycle.
122
+
123
+ **Can I run this in a private repo?**
124
+ Yes. `GITHUB_TOKEN` has full access to your repo. Only the Anthropic API key is external.
125
+
126
+ **Can I use this with Codex / OpenAI models?**
127
+ No. `/autopilot` requires Claude Code CLI, which runs Anthropic models. The `ANTHROPIC_API_KEY` is mandatory.
128
+
129
+ **What does `/autopilot` do if there are open P0 issues?**
130
+ It skips normal recon and immediately routes to `fix` mode targeting the P0 issues, regardless of the selected mode. P0 always takes priority.