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.
- package/README.md +8 -2
- package/bin/batch-runner.mjs +31 -2
- package/bin/engine/admission.mjs +294 -0
- package/bin/engine/admission.test.mjs +265 -0
- package/bin/engine/invariants.mjs +17 -4
- package/bin/engine/phases.mjs +358 -42
- package/bin/engine/resolve.mjs +256 -0
- package/bin/engine/resolve.test.mjs +149 -0
- package/bin/engine/state.mjs +31 -7
- package/bin/engine-cli.mjs +138 -2
- package/bin/engine.mjs +414 -21
- package/bin/forgedock.mjs +552 -44
- package/bin/hooks/interactive-engine.mjs +50 -24
- package/bin/hooks/pre-tool-use.mjs +189 -19
- package/bin/journey.mjs +109 -11
- package/bin/labels.json +5 -0
- package/bin/runner.mjs +321 -10
- package/bin/watch-utils.mjs +255 -0
- package/commands/cleanup.md +7 -3
- package/commands/forge-stats.md +5 -4
- package/commands/issue.md +5 -1
- package/commands/orchestrate/config.md +41 -1
- package/commands/orchestrate/phase-1-resolve.md +234 -8
- package/commands/orchestrate/phase-3-dependency.md +27 -18
- package/commands/orchestrate/phase-4-execution.md +223 -22
- package/commands/qa-sweep.md +17 -0
- package/commands/quality-gate.md +6 -6
- package/commands/replay.md +16 -2
- package/commands/review-pr-agents/spec-cli.md +179 -0
- package/commands/review-pr.md +65 -0
- package/commands/upgrade-deps.md +523 -0
- package/commands/work-on/build/validate.md +61 -1
- package/commands/work-on/build.md +9 -1
- package/commands/work-on/decompose.md +10 -1
- package/commands/work-on/investigate.md +22 -4
- package/commands/work-on/remediate.md +2 -0
- package/commands/work-on/review.md +40 -1
- package/commands/work-on.md +19 -4
- package/docs/AIDER.md +264 -0
- package/docs/AUTOPILOT-CRON.md +130 -0
- package/docs/CONFIG.md +156 -0
- package/docs/CURSOR.md +135 -0
- package/docs/OPENCODE.md +312 -0
- package/docs/demo.gif +0 -0
- package/docs/eval/README.md +4 -4
- package/docs/launch/show-hn.md +3 -3
- package/docs/site/architecture.md +180 -0
- package/docs/site/command-reference.md +17 -0
- package/docs/site/configuration.md +243 -0
- package/docs/site/for-companies.md +4 -4
- package/docs/site/forge-annotation-protocol.md +1 -1
- package/docs/site/github-is-the-memory.md +2 -2
- package/docs/site/how-it-works.md +1 -1
- package/docs/site/public/llms-full.txt +380 -0
- package/docs/site/public/llms.txt +35 -0
- package/docs/spec/eval-run-result.md +8 -4
- package/docs/spec/label-state-machine.md +9 -0
- package/docs/spec-graph-schema.md +3 -3
- package/package.json +3 -3
- package/packages/protocol/README.md +75 -0
- package/packages/protocol/src/card.js +114 -0
- package/packages/protocol/src/cli.js +4 -77
- package/packages/protocol/src/emit.js +5 -11
- package/packages/protocol/src/html-comment-escape.js +68 -0
- package/packages/protocol/src/index.js +3 -1
- package/packages/protocol/src/parse.js +19 -11
- package/packages/protocol/src/phases.js +105 -0
- package/packages/protocol/src/types.js +18 -1
- package/packages/protocol/src/validate.js +11 -0
- package/scripts/check-admission-parity.mjs +167 -0
- package/scripts/check-command-side-effects.sh +376 -0
- package/scripts/check-phase-registry-drift.mjs +96 -0
- package/scripts/check-spec-markers.sh +274 -0
- package/scripts/classify-lane.sh +29 -7
- package/scripts/forge-run.sh +353 -0
- package/templates/cross-repo-trigger.yml +282 -0
- package/templates/cursor/forge.mdc +148 -0
- 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
|
|
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
|
|
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
|
-
|
|
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 →
|
|
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
|
package/commands/work-on.md
CHANGED
|
@@ -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
|
|
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
|
|
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
|
-
|
|
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.
|