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
package/docs/CONFIG.md CHANGED
@@ -48,6 +48,8 @@ If you have both a local `claude` CLI and `ANTHROPIC_API_KEY` set and want to pi
48
48
  | [`agents`](#agents-optional) | No | Default model for pipeline agents |
49
49
  | [`repos`](#repos-optional) | No | Multi-repository routing |
50
50
  | [`project_board`](#project_board-optional) | No | GitHub Projects v2 integration |
51
+ | [`orchestration`](#orchestration-optional) | No | `/orchestrate` concurrency and cascade admission policy |
52
+ | [`pipeline`](#pipeline-optional) | No | `/orchestrate` batch-engine tuning (stall detection, token budget, narration) |
51
53
  | [`services`](#services-optional) | No | External service URLs and IDs |
52
54
  | [`review`](#review-optional) | No | Context injected into review agents |
53
55
  | [`devdocs`](#devdocs-optional) | No | Devdocs knowledge tree path |
@@ -210,6 +212,9 @@ repos:
210
212
  | `satellites[].local_path` | string | No | Absolute local path to the satellite repo's checkout |
211
213
  | `satellites[].subpaths` | map(string→string) | No | Named sub-directory paths within `local_path`, for monorepo satellites that publish multiple packages. Each key is a logical name; the value is the relative path to that package's root. Used by `/sync-ecosystem` to locate per-package version files and publish workflows. |
212
214
  | `satellites[].billing_enabled` | boolean | No | Set to `true` to run Phase 4 (Financial Integrity) of `/security-audit` against this satellite repo. Mirrors the top-level [`billing.enabled`](#billing-optional) flag but scoped per-satellite. Defaults to `false` when absent. |
215
+ | `satellites[].trigger_on_merge` | boolean | No | When `true`, fires a cross-repo trigger when a PR merges in the parent repo and touches paths matching `trigger_paths`. Set to `false` to disable triggering for this satellite. Defaults to `true` when `trigger_paths` is present; otherwise has no effect until runtime trigger support is configured. |
216
+ | `satellites[].trigger_paths` | list of strings | No | Path glob patterns that constrain when the trigger fires. Uses GitHub Actions glob syntax (same as `on: push: paths:`). The trigger fires only when at least one changed file matches a pattern in this list. When omitted, the trigger fires on every merge (if `trigger_on_merge: true`). |
217
+ | `satellites[].auto_run` | boolean | No | When `true`, automatically invokes `/work-on` on the satellite issue when the cross-repo trigger fires. Requires a running Claude Code session with ForgeDock installed in the satellite repo. Advanced opt-in — defaults to `false`. Do not set to `true` unless a persistent Claude Code session is available in the satellite repo. |
213
218
 
214
219
  **Routing syntax in commands**: `<prefix>:<issue_number>` — e.g., `mcp:5`, `sdk:12`
215
220
 
@@ -287,6 +292,124 @@ gh project field-list <project_number> --owner <owner> --format json \
287
292
 
288
293
  ---
289
294
 
295
+ ## `orchestration` (OPTIONAL)
296
+
297
+ Concurrency limits and cascade admission policy for `/orchestrate`'s batch engine. Previously read at runtime (`orchestration.max_concurrent`) but undocumented; this section is the first place it — and the newer `cascade` sub-section (forge#2234) — are formally specified.
298
+
299
+ ```yaml
300
+ orchestration:
301
+ # Maximum number of /work-on sub-agents dispatched concurrently. Guards against
302
+ # saturating the Anthropic API rate limit in one burst on a large ready set.
303
+ # Default: 12.
304
+ max_concurrent: 12
305
+
306
+ cascade:
307
+ # Named preset expanding to the granular keys below. Any granular key set
308
+ # explicitly overrides just that field — the preset supplies defaults, not
309
+ # hard values. Default: "balanced".
310
+ # all — admit everything: no generation cap, no token cap, every
311
+ # heuristic-based defer disabled. For a maintainer draining
312
+ # a backlog who wants /orchestrate to "pick up everything."
313
+ # balanced — the pre-#2234 hardcoded behavior, unchanged: generation
314
+ # cap at 1 (i.e. cascade-spawned findings deferred),
315
+ # 900000-token per-batch ceiling, idle/keyword/same-file
316
+ # heuristics all active.
317
+ # conservative — same admission shape as balanced, with a lower
318
+ # (450000) token ceiling for cost-sensitive or noisy repos.
319
+ policy: "balanced"
320
+
321
+ # Maximum cascade generation depth admitted. Generation 1 = an original
322
+ # issue (not spawned from a review-finding). Generation 2 = spawned from a
323
+ # review-finding. Generation 3 = spawned from a finding that was itself
324
+ # spawned from a review-finding. Accepts a positive integer or the literal
325
+ # string "unlimited". Governs Phase 1 resolve-time admission only (the
326
+ # `cascade`/`review-findings`/`findings` resolution in phase-1-resolve.md)
327
+ # — it does NOT relax Step 4C's absolute autonomous-cascade defer, which
328
+ # stays hardcoded regardless of this value (see phase-4-execution.md Step
329
+ # 4C rule 1). This is what makes "admit gen-2, stop at gen-3" expressible,
330
+ # which the pre-#2234 --allow-gen2 flag (all-or-nothing) could not say.
331
+ # Default: 1 (from the "balanced" preset); "unlimited" under "all".
332
+ max_generation: 1
333
+
334
+ # Per-batch token ceiling for Step 4C's review-finding cascade dispatch.
335
+ # New home for the same lever previously read only as
336
+ # `pipeline.token_budget_per_batch` (kept working as a deprecated alias —
337
+ # see the `pipeline` section below). Accepts a positive integer or
338
+ # "unlimited". Default: 900000 (from "balanced"); 450000 under
339
+ # "conservative"; "unlimited" under "all".
340
+ token_budget: 900000
341
+
342
+ # Whether a fully human-gated original batch (forge#1814's
343
+ # BATCH_FULLY_GATED — every original-batch issue DONE/FAILED/GATED with at
344
+ # least one GATED) suppresses further cascade-finding dispatch. Default:
345
+ # true (from "balanced"); false under "all".
346
+ defer_on_batch_gated: true
347
+
348
+ # Whether the comment/typo title-keyword heuristic defers P3-and-below
349
+ # cascade findings. Default: true (from "balanced"); false under "all".
350
+ keyword_heuristic: true
351
+
352
+ # Whether a P3 finding sharing a file with the active batch is deferred
353
+ # (avoids serializing agents on same-file predecessor edges). Default:
354
+ # true (from "balanced"); false under "all".
355
+ p3_same_file_defer: true
356
+ ```
357
+
358
+ | Field | Type | Required | Description |
359
+ |-------|------|----------|-------------|
360
+ | `max_concurrent` | integer | No | Max concurrent `/work-on` sub-agent dispatch. Default: 12 |
361
+ | `cascade.policy` | string | No | `all` \| `balanced` \| `conservative`. Default: `balanced` |
362
+ | `cascade.max_generation` | integer or `"unlimited"` | No | Max cascade generation admitted at Phase 1 resolve time. Default: 1 |
363
+ | `cascade.token_budget` | integer or `"unlimited"` | No | Per-batch token ceiling for Step 4C cascade dispatch. Default: 900000 (deprecated alias: `pipeline.token_budget_per_batch`) |
364
+ | `cascade.defer_on_batch_gated` | boolean | No | Suppress cascade dispatch when the original batch is fully human-gated. Default: `true` |
365
+ | `cascade.keyword_heuristic` | boolean | No | Defer P3-and-below comment/typo-titled findings. Default: `true` |
366
+ | `cascade.p3_same_file_defer` | boolean | No | Defer P3 findings sharing a file with the active batch. Default: `true` |
367
+
368
+ **Hard invariant — not configurable**: safety exclusions (findings whose `## Problem` section indicates security/billing/anti-bot/auth concerns) are never batched and never auto-admitted by any `cascade.policy`, including `all`. That exclusion is enforced upstream of this section (the P3 batching eligibility check) and has no corresponding key here by design.
369
+
370
+ **CLI overrides**: `--policy`, `--max-generation`, `--token-budget` on `/orchestrate` take precedence over these keys for a single invocation — see `commands/orchestrate/config.md` → "Cascade Policy CLI Flags".
371
+
372
+ **Commands that use this section**: `orchestrate`
373
+
374
+ ---
375
+
376
+ ## `pipeline` (OPTIONAL)
377
+
378
+ Tuning knobs for `/orchestrate`'s batch engine — stall detection, narration verbosity, and (deprecated alias only, see `orchestration.cascade` above) the review-finding cascade token budget. All keys optional; sane defaults apply when omitted.
379
+
380
+ ```yaml
381
+ pipeline:
382
+ # Minutes an agent may sit idle (no FORGE:HEARTBEAT / label change) before
383
+ # /orchestrate's stall detector treats it as stuck and attempts an
384
+ # auto-resume. Default: 15.
385
+ stall_timeout_minutes: 15
386
+
387
+ # Deprecated alias for orchestration.cascade.token_budget (forge#2234) — kept
388
+ # working so existing configs are unaffected. When both are set,
389
+ # orchestration.cascade.token_budget wins. Default: 900000.
390
+ token_budget_per_batch: 900000
391
+
392
+ # Estimated token cost of a single P3-or-lower review-finding /work-on
393
+ # pipeline, used to decrement the token budget above. Default: 150000.
394
+ token_estimate_per_finding: 150000
395
+
396
+ # Narration verbosity for /orchestrate's per-completion status updates.
397
+ # "terse" (default): one line per completion. "verbose": adds a running
398
+ # per-completion recap table. Cosmetic only — never changes which phases run.
399
+ narration: "terse"
400
+ ```
401
+
402
+ | Field | Type | Required | Description |
403
+ |-------|------|----------|-------------|
404
+ | `stall_timeout_minutes` | integer | No | Idle minutes before the stall detector attempts auto-resume. Default: 15 |
405
+ | `token_budget_per_batch` | integer | No | **Deprecated** — use `orchestration.cascade.token_budget`. Default: 900000 |
406
+ | `token_estimate_per_finding` | integer | No | Estimated tokens per P3-or-lower cascade finding. Default: 150000 |
407
+ | `narration` | string | No | `terse` \| `verbose`. Default: `terse` |
408
+
409
+ **Commands that use this section**: `orchestrate`
410
+
411
+ ---
412
+
290
413
  ## `services` (OPTIONAL)
291
414
 
292
415
  External service endpoints and identifiers. Used by analytics and monitoring commands.
@@ -609,6 +732,39 @@ Colors are grouped by semantic meaning:
609
732
 
610
733
  ---
611
734
 
735
+ ## `branding` (OPTIONAL)
736
+
737
+ Controls attribution in FORGE annotation comments posted to GitHub issues and PRs by pipeline commands.
738
+
739
+ When `show_attribution` is `true` (the default), every annotation comment (`FORGE:INVESTIGATOR`, `FORGE:CONTRACT`, `FORGE:BUILDER`, `FORGE:TRAJECTORY`, `FORGE:DECOMPOSED`, etc.) ends with a one-line footer:
740
+
741
+ ```
742
+ > Pipeline powered by [ForgeDock](https://github.com/RapierCraftStudios/ForgeDock)
743
+ ```
744
+
745
+ This follows the pattern established by Dependabot, Renovate, and similar tools. It helps new users discover the tooling when they encounter FORGE: annotations in a public thread. Set to `false` to suppress the attribution entirely.
746
+
747
+ ```yaml
748
+ branding:
749
+ show_attribution: true
750
+ ```
751
+
752
+ | Field | Type | Required | Default | Description |
753
+ |-------|------|----------|---------|-------------|
754
+ | `show_attribution` | boolean | No | `true` | When `true`, annotation comments posted by the pipeline include a one-line attribution footer. Set to `false` to suppress it entirely. Opt-out model — attribution is on by default. |
755
+
756
+ **Commands that use this section**: `work-on` (all phases that post FORGE: annotation comments)
757
+
758
+ **Config read pattern** (yq, with default-true fallback):
759
+
760
+ ```bash
761
+ SHOW_ATTRIBUTION=$(yq '.branding.show_attribution // "true"' forge.yaml 2>/dev/null || echo "true")
762
+ [ "$SHOW_ATTRIBUTION" = "false" ] && ATTRIBUTION_LINE="" || ATTRIBUTION_LINE="
763
+ > Pipeline powered by [ForgeDock](https://github.com/RapierCraftStudios/ForgeDock)"
764
+ ```
765
+
766
+ ---
767
+
612
768
  ## GitHub App Install
613
769
 
614
770
  During `npx forgedock`, the installer prompts you to install the ForgeDock GitHub App (`rapiercraft-forgedock`) on your account or org.
package/docs/CURSOR.md ADDED
@@ -0,0 +1,135 @@
1
+ # Cursor Support
2
+
3
+ ForgeDock has a Cursor adapter that lets Cursor Agent mode run the ForgeDock pipeline via shell commands and the `gh` CLI.
4
+
5
+ ## Architecture
6
+
7
+ Shared source:
8
+ - `commands/**/*.md` remains the canonical workflow spec for all runtimes
9
+
10
+ Cursor wrapper:
11
+ - `templates/cursor/forge.mdc` — a static Cursor rules file that instructs Cursor Agent to execute pipeline phases using shell commands, `gh` CLI, and `git`
12
+ - Users install this file into their repo's `.cursor/rules/forge.mdc`
13
+
14
+ This is a static injection model, not a dynamic skill-loading mechanism. The adapter cannot replicate Claude Code's `Skill()` invocation or Codex's installed skill wrappers. Instead, it instructs the agent to read command specs directly from `commands/` and execute them using available terminal tools.
15
+
16
+ ## Install
17
+
18
+ ### Automatic (via `npx forgedock`)
19
+
20
+ If your project already has a `.cursor/` directory, `npx forgedock` will detect it and automatically write `templates/cursor/forge.mdc` to `.cursor/rules/forge.mdc`:
21
+
22
+ ```bash
23
+ npx forgedock
24
+ ```
25
+
26
+ The installer skips this step if `.cursor/rules/forge.mdc` already exists (idempotent — never overwrites customizations).
27
+
28
+ ### Manual
29
+
30
+ Copy the template directly:
31
+
32
+ ```bash
33
+ mkdir -p .cursor/rules
34
+ cp node_modules/forgedock/templates/cursor/forge.mdc .cursor/rules/forge.mdc
35
+ # or, if installed globally:
36
+ cp "$(npx forgedock which-dir)/templates/cursor/forge.mdc" .cursor/rules/forge.mdc
37
+ ```
38
+
39
+ Commit the file to version control so all team members get it:
40
+
41
+ ```bash
42
+ git add .cursor/rules/forge.mdc
43
+ git commit -m "chore: add ForgeDock Cursor rules adapter"
44
+ ```
45
+
46
+ ## Usage
47
+
48
+ ### Running the Pipeline
49
+
50
+ Open a Cursor Agent session and describe the pipeline task:
51
+
52
+ ```
53
+ Work on GitHub issue #123 using the ForgeDock pipeline.
54
+ Read commands/work-on.md and follow all phases.
55
+ ```
56
+
57
+ The rules file will instruct Cursor Agent to:
58
+
59
+ 1. Load issue context from GitHub using `gh issue view`
60
+ 2. Follow the Universal Phase Dispatcher in `commands/work-on.md`
61
+ 3. Write FORGE annotations (HTML comments) to issue comments after each phase
62
+ 4. Transition `workflow:*` labels as phases complete
63
+ 5. Continue until a terminal label is set
64
+
65
+ ### Checking Pipeline State
66
+
67
+ ```bash
68
+ # See current workflow state
69
+ gh issue view NUMBER --json labels --jq '[.labels[].name]'
70
+
71
+ # Read existing pipeline annotations
72
+ gh api repos/OWNER/REPO/issues/NUMBER/comments \
73
+ --jq '.[] | select(.body | contains("FORGE:")) | {body: .body[:200]}'
74
+ ```
75
+
76
+ ### Continuing After a Phase
77
+
78
+ Because Cursor Agent mode does not persist between invocations, start a new session and describe the resume:
79
+
80
+ ```
81
+ Resume the ForgeDock pipeline for GitHub issue #123.
82
+ Read commands/work-on.md — it will re-read GitHub state and pick up from the current label.
83
+ ```
84
+
85
+ The pipeline is designed for compaction resilience — every phase re-reads GitHub state at the start, so a new Cursor Agent session picks up exactly where the previous session left off.
86
+
87
+ ## Limitations
88
+
89
+ | Capability | Claude Code | Cursor (this adapter) |
90
+ |------------|-------------|----------------------|
91
+ | Skill loading | Dynamic (`~/.claude/commands/`) | Static (this rules file) |
92
+ | Multi-phase pipeline | Automatic (single continuous session) | Manual (re-invoke agent per phase) |
93
+ | Sub-skill invocation | `Skill("review-pr")` | Read `commands/review-pr.md` directly |
94
+ | Session continuity | Native compaction resilience | Re-read GitHub state each invocation |
95
+ | Tool set | Claude-native (`Bash`, `Read`, `Grep`, `Glob`, `WebFetch`) | Cursor Agent terminal tools |
96
+
97
+ ### Multi-Phase Pipeline
98
+
99
+ The ForgeDock pipeline has 7 phases (investigate → build → review → merge → close → trajectory). Cursor Agent mode does not automatically advance through all phases in a single session. After each phase completes, you will need to start a new agent invocation and ask it to continue.
100
+
101
+ The pipeline's compaction resilience handles this correctly: each invocation re-reads the issue's labels and comments, determines the current phase, and continues from there. No context is lost between sessions.
102
+
103
+ ### Sub-Skill Invocation
104
+
105
+ When the pipeline spec calls `Skill("review-pr")` or `Skill("quality-gate")`, Cursor Agent should read the referenced command spec file directly:
106
+
107
+ ```bash
108
+ cat commands/review-pr.md # Then execute that spec
109
+ cat commands/quality-gate.md
110
+ ```
111
+
112
+ ### Project Board Steps
113
+
114
+ Some pipeline phases (0C: Sync to Project board) call GitHub Projects API operations. These work via `gh` CLI but require the project number and field IDs from `forge.yaml`. Verify your `forge.yaml` has the correct project configuration before running the pipeline.
115
+
116
+ ## Configuration
117
+
118
+ ForgeDock reads `forge.yaml` for project-specific settings:
119
+
120
+ ```bash
121
+ cat forge.yaml # Review before running the pipeline
122
+ ```
123
+
124
+ Key fields used by the pipeline:
125
+ - `project.github.owner` / `project.github.repo` — GitHub repo coordinates
126
+ - `branches.staging` — target branch for fast-lane PRs
127
+ - `branches.main` — default branch
128
+
129
+ ## Reference
130
+
131
+ - `commands/work-on.md` — Full pipeline spec (all phases)
132
+ - `commands/review-pr.md` — PR review spec
133
+ - `commands/quality-gate.md` — Pre-commit quality checks (14+ domains)
134
+ - `docs/FORGE-PROTOCOL.md` — FORGE annotation protocol specification
135
+ - `docs/CODEX.md` — Codex CLI adapter (dynamic skill model)
@@ -0,0 +1,312 @@
1
+ # OpenCode Support
2
+
3
+ ForgeDock has an OpenCode adapter that lets OpenCode run the ForgeDock pipeline
4
+ using its native bash tool and the `gh` CLI.
5
+
6
+ ## Architecture
7
+
8
+ Shared source:
9
+ - `commands/**/*.md` remains the workflow spec for all runtimes
10
+
11
+ Claude Code wrapper:
12
+ - `install.sh` (or `npx forgedock`) symlinks command files into `~/.claude/commands/`
13
+
14
+ Codex wrapper:
15
+ - `install-codex.sh` generates namespaced skills in `~/.codex/skills/`
16
+
17
+ Aider wrapper:
18
+ - `install-aider.sh` writes `~/.aider-forge.md` loaded via `--read`
19
+
20
+ **OpenCode wrapper** (this document):
21
+ - `install-opencode.sh` writes `~/.opencode-forge.md` — a conventions file
22
+ OpenCode loads via the `instructions` field in `opencode.json`
23
+ - `install-opencode.sh` also patches `~/.config/opencode/opencode.json` to
24
+ register ForgeDock pipeline commands as native OpenCode slash commands
25
+ (`/work-on`, `/review-pr`, `/quality-gate`, `/orchestrate`)
26
+
27
+ This is a conventions-file + command-registration architecture. The shared
28
+ `commands/` directory remains the single source of truth — the adapter
29
+ registers entry points that read from it.
30
+
31
+ ## Feasibility
32
+
33
+ OpenCode is the **highest-fidelity** non-Claude Code adapter because:
34
+
35
+ | Capability | Requirement | OpenCode support |
36
+ |-----------|-------------|-----------------|
37
+ | Load instruction files | `instructions` field in `opencode.json` | Native |
38
+ | Execute shell commands | `gh`, `git`, standard tools | Native `Bash` tool |
39
+ | Read/write files | File editing | Native `Read`/`Write`/`Edit` tools |
40
+ | GitHub API | `gh` CLI | Via `Bash("gh ...")` |
41
+ | Multi-step workflows | Follow sequential instructions | Supported |
42
+ | Compaction resilience | Re-read GitHub state at phase start | Supported (via `Bash("gh ...")`) |
43
+ | Native slash commands | `/work-on 967` in TUI | Via `command` config |
44
+ | Tool name parity | Same tool names as Claude Code | Direct — no translation needed |
45
+
46
+ **Key advantage over Aider and Cursor**: OpenCode shares Claude Code's tool
47
+ names (`Bash`, `Read`, `Write`, `Edit`, `Glob`, `Grep`, `WebFetch`) — no
48
+ translation table required for most operations. Pipeline command specs run
49
+ nearly unmodified.
50
+
51
+ ## Install
52
+
53
+ ### Option A — standalone bash installer
54
+
55
+ ```bash
56
+ cd /path/to/forgedock
57
+ ./install-opencode.sh
58
+ ```
59
+
60
+ This writes `~/.opencode-forge.md` with ForgeDock conventions and patches
61
+ `~/.config/opencode/opencode.json` with:
62
+ - `instructions`: adds `~/.opencode-forge.md` to OpenCode's system prompt
63
+ - `command`: registers `/work-on`, `/review-pr`, `/quality-gate`, `/orchestrate`
64
+
65
+ ### Option B — via npx forgedock
66
+
67
+ When `opencode` is detected on your PATH, `npx forgedock` writes
68
+ `~/.opencode-forge.md` and patches `opencode.json` as an additional install
69
+ step. No existing Claude Code files are affected.
70
+
71
+ ```bash
72
+ npx forgedock
73
+ ```
74
+
75
+ ## Usage
76
+
77
+ ### Native slash commands (recommended)
78
+
79
+ After running `install-opencode.sh`, use ForgeDock commands in the OpenCode
80
+ TUI:
81
+
82
+ ```
83
+ /work-on 967
84
+ /review-pr 123
85
+ /quality-gate
86
+ ```
87
+
88
+ Or headlessly via `opencode run`:
89
+
90
+ ```bash
91
+ opencode run --command work-on "967"
92
+ opencode run --command review-pr "123"
93
+ ```
94
+
95
+ ### Manual pipeline loading
96
+
97
+ Read a pipeline command spec directly and follow it:
98
+
99
+ ```
100
+ Read the file /path/to/forgedock/commands/work-on.md and run the pipeline for issue 967.
101
+ ```
102
+
103
+ OpenCode will load the spec and execute each phase using its native tools.
104
+
105
+ ### Phase routing with forge-run.sh
106
+
107
+ `forge-run.sh` emits JSON phase state for the current issue without invoking
108
+ an LLM. Use it to determine the current pipeline phase:
109
+
110
+ ```bash
111
+ Bash("/path/to/forgedock/scripts/forge-run.sh work-on 967 -R OWNER/REPO")
112
+ ```
113
+
114
+ Output (NDJSON):
115
+ ```json
116
+ {"event":"phase_detected","command":"work-on","issue":967,"phase":"no-comments","ts":"..."}
117
+ {"event":"phase_detail","phase":"no-comments","lane":"feature","branch":"milestone/dev-exp","labels":[]}
118
+ {"event":"action_required","phase":"no-comments","action":"No pipeline activity detected. Invoke /work-on 967 to start investigation.","ts":"..."}
119
+ ```
120
+
121
+ ## Tool Translation
122
+
123
+ OpenCode and Claude Code share the same tool names. Most pipeline operations
124
+ run without modification:
125
+
126
+ | Claude Code | OpenCode | Notes |
127
+ |-------------|----------|-------|
128
+ | `Bash("git status")` | `Bash("git status")` | Direct |
129
+ | `Read("path/to/file")` | `Read("path/to/file")` | Direct |
130
+ | `Write("path", content)` | `Write("path", content)` | Direct |
131
+ | `Edit("path", ...)` | `Edit("path", ...)` | Direct |
132
+ | `Glob("**/*.md")` | `Glob("**/*.md")` | Direct |
133
+ | `Grep(pattern, path)` | `Grep(pattern, path)` | Direct |
134
+ | `WebFetch(url)` | `WebFetch(url)` | Direct |
135
+ | `Skill("work-on", args="123")` | Read `commands/work-on.md` | No skill loader — read spec directly |
136
+ | `Skill("review-pr", args="456")` | Read `commands/review-pr.md` | No skill loader — read spec directly |
137
+ | `Agent(...)` / `Task(...)` | Continue the sub-task inline | No sub-agent model; inline it |
138
+
139
+ ### Nested Skill references
140
+
141
+ When a command spec calls `Skill("x")` or references another command, read
142
+ the referenced command spec directly:
143
+
144
+ ```
145
+ # Load the referenced command spec:
146
+ Read("/path/to/forgedock/commands/quality-gate.md")
147
+ ```
148
+
149
+ Map command names to file paths:
150
+ - `Skill("work-on")` → `commands/work-on.md`
151
+ - `Skill("review-pr")` → `commands/review-pr.md`
152
+ - `Skill("quality-gate")` → `commands/quality-gate.md`
153
+ - `Skill("orchestrate")` → `commands/orchestrate.md`
154
+
155
+ ## GitHub Operations
156
+
157
+ All FORGE annotations are written to GitHub issue/PR comments via the `gh`
158
+ CLI. Use `Bash()` for every GitHub operation.
159
+
160
+ ### Label management
161
+
162
+ ```bash
163
+ Bash("gh issue edit 123 -R OWNER/REPO --add-label 'workflow:investigating'")
164
+ Bash("gh issue edit 123 -R OWNER/REPO --remove-label 'workflow:investigating'")
165
+ ```
166
+
167
+ ### Reading existing annotations
168
+
169
+ ```bash
170
+ Bash("gh api repos/OWNER/REPO/issues/123/comments \
171
+ --jq '.[] | select(.body | contains(\"FORGE:INVESTIGATOR\")) | .body'")
172
+ ```
173
+
174
+ ### Writing a FORGE annotation comment
175
+
176
+ For multi-line comment bodies, write the content to a temp file first:
177
+
178
+ ```bash
179
+ # Write comment body to temp file (avoids shell quoting issues)
180
+ Write("/tmp/forge_comment.md", """<!-- FORGE:INVESTIGATOR -->
181
+ ## Investigation Report
182
+
183
+ **Verdict**: CONFIRMED
184
+ ...
185
+ <!-- INVESTIGATION:COMPLETE -->""")
186
+
187
+ Bash("gh issue comment 123 -R OWNER/REPO --body \"$(cat /tmp/forge_comment.md)\"")
188
+ ```
189
+
190
+ ### Creating a PR
191
+
192
+ ```bash
193
+ Write("/tmp/pr_body.md", """## Summary
194
+ ...
195
+
196
+ Closes #967""")
197
+
198
+ Bash("gh pr create -R OWNER/REPO \
199
+ --base milestone/developer-experience-distribution \
200
+ --head feat/opencode-adapter-967 \
201
+ --title 'feat: OpenCode adapter (#967)' \
202
+ --body \"$(cat /tmp/pr_body.md)\"")
203
+ ```
204
+
205
+ ## Worktrees
206
+
207
+ ForgeDock uses git worktrees to isolate branch work. Create one with:
208
+
209
+ ```bash
210
+ Bash("git fetch origin")
211
+ Bash("git worktree add .claude/worktrees/feat-my-feature-123 \
212
+ -b feat/my-feature-123 origin/staging")
213
+ ```
214
+
215
+ Work inside the worktree for all file edits and commits:
216
+
217
+ ```bash
218
+ Read("/path/to/repo/.claude/worktrees/feat-my-feature-123/file.py")
219
+ Edit("/path/to/repo/.claude/worktrees/feat-my-feature-123/file.py", ...)
220
+ Bash("git -C /path/to/repo/.claude/worktrees/feat-my-feature-123 status")
221
+ ```
222
+
223
+ ## FORGE Annotation Protocol
224
+
225
+ Every pipeline stage writes a structured annotation to GitHub. Key rules:
226
+
227
+ 1. **Idempotency**: Check for existing annotations BEFORE starting a phase.
228
+ Do not re-run a completed phase.
229
+ 2. **Compaction resilience**: Write annotations AFTER completing each
230
+ significant step. GitHub is the persistent state layer.
231
+ 3. **Restart partial annotations**: If an annotation exists without its
232
+ `:COMPLETE` sentinel, delete it and restart the phase.
233
+ 4. **Respect label state**: Labels track workflow state. Read and set them
234
+ at each phase boundary.
235
+
236
+ ### Label state machine
237
+
238
+ ```
239
+ workflow:investigating
240
+ → workflow:ready-to-build (investigation complete)
241
+ → workflow:building (build started)
242
+ → workflow:in-review (PR created)
243
+ → workflow:merged (PR merged) [TERMINAL]
244
+
245
+ workflow:invalid [TERMINAL]
246
+ workflow:decomposed [TERMINAL]
247
+ needs-human [TERMINAL]
248
+ ```
249
+
250
+ Stop the pipeline when any terminal label is set.
251
+
252
+ ## Limitations
253
+
254
+ | Capability | Claude Code | OpenCode (this adapter) |
255
+ |------------|-------------|------------------------|
256
+ | Skill loading | Dynamic (`~/.claude/commands/`) | Read `commands/*.md` directly |
257
+ | Native slash commands | `/work-on 967` | `/work-on 967` (via `command` config) |
258
+ | Tool name parity | Native | Direct (same names) |
259
+ | Sub-agent invocation | `Skill("review-pr")` | Read `commands/review-pr.md` directly |
260
+ | Session continuity | Native compaction resilience | Re-read GitHub state each session |
261
+ | Multi-phase pipeline | Automatic (single continuous session) | Supported (GitHub state is persistent) |
262
+
263
+ **Sub-skill invocation**: When a command spec calls `Skill("x")`, OpenCode
264
+ has no native skill loader. Read the referenced command spec file directly
265
+ instead.
266
+
267
+ **Parallel tasks**: When a command spec calls `Agent(...)` or `Task(...)` for
268
+ parallelism (e.g., multi-agent review in `review-pr-agents.md`), execute the
269
+ sub-tasks sequentially. OpenCode runs one agent context at a time.
270
+
271
+ ## Configuration
272
+
273
+ `install-opencode.sh` patches `~/.config/opencode/opencode.json`. Example
274
+ of what is added:
275
+
276
+ ```json
277
+ {
278
+ "instructions": [
279
+ "~/.opencode-forge.md"
280
+ ],
281
+ "command": {
282
+ "work-on": {
283
+ "description": "Run the ForgeDock full issue pipeline (investigate → build → review → merge)",
284
+ "template": "Read /path/to/forgedock/commands/work-on.md and execute the pipeline for issue {{args}}."
285
+ },
286
+ "review-pr": {
287
+ "description": "Run the ForgeDock PR review pipeline",
288
+ "template": "Read /path/to/forgedock/commands/review-pr.md and execute the PR review for PR {{args}}."
289
+ },
290
+ "quality-gate": {
291
+ "description": "Run ForgeDock pre-commit quality checks",
292
+ "template": "Read /path/to/forgedock/commands/quality-gate.md and run all quality gate checks."
293
+ },
294
+ "orchestrate": {
295
+ "description": "Run ForgeDock parallel multi-issue orchestration",
296
+ "template": "Read /path/to/forgedock/commands/orchestrate.md and orchestrate the issues: {{args}}."
297
+ }
298
+ }
299
+ }
300
+ ```
301
+
302
+ Existing config keys (provider, model, etc.) are preserved. ForgeDock only
303
+ adds to the `instructions` array and `command` object — never overwrites.
304
+
305
+ ## Reference
306
+
307
+ - [FORGE Protocol spec](FORGE-PROTOCOL.md) — annotation format, label state machine
308
+ - [Aider adapter](AIDER.md) — parallel adapter reference (Aider uses `/run` translation)
309
+ - [Codex adapter](CODEX.md) — parallel adapter reference (Codex skill model)
310
+ - [Pipeline commands](../commands/) — shared workflow specs (authoritative for all runtimes)
311
+ - [`install-opencode.sh`](../install-opencode.sh) — installer script
312
+ - [`scripts/forge-run.sh`](../scripts/forge-run.sh) — universal shell phase router
package/docs/demo.gif CHANGED
Binary file
@@ -8,8 +8,8 @@ Per-release pipeline evaluation results for ForgeDock. Every scorecard here was
8
8
 
9
9
  | Field | Value |
10
10
  |-------|-------|
11
- | Scorecard | [claude-sonnet-5-2026-07-04.json](published/claude-sonnet-5-2026-07-04.json) |
12
- | Model | claude-sonnet-5 |
11
+ | Scorecard | [claude-sonnet-4-6-2026-07-04.json](published/claude-sonnet-4-6-2026-07-04.json) |
12
+ | Model | claude-sonnet-4-6 |
13
13
  | Corpus | seed-v1 |
14
14
  | Run date | 2026-07-04 |
15
15
  | One-shot success rate | — (pending harness) |
@@ -17,7 +17,7 @@ Per-release pipeline evaluation results for ForgeDock. Every scorecard here was
17
17
 
18
18
  > **Note**: The baseline above is a format placeholder. The harness (#1285) and CI gate (#1286) must be operational before real scorecard values can be populated. When the first real run completes, update this table and remove this note.
19
19
  >
20
- > **Model upgrade**: Default model was updated from `claude-sonnet-4-5` to `claude-sonnet-5` in PR #1441 (issue #1248, committed 2026-07-04). The `--model` flag and `FORGEDOCK_MODEL` env var override the default at runtime.
20
+ > **Model upgrade**: Default model was updated from `claude-sonnet-4-5` to `claude-sonnet-5` in PR #1441 (issue #1248, committed 2026-07-04). The `--model` flag and `FORGEDOCK_MODEL` env var override the default at runtime. No `claude-sonnet-5` scorecard has been published yet — see the Published results table below.
21
21
 
22
22
  ---
23
23
 
@@ -25,7 +25,7 @@ Per-release pipeline evaluation results for ForgeDock. Every scorecard here was
25
25
 
26
26
  | Run ID | Model | Corpus | Date | One-shot success | Human interventions/issue | Scorecard |
27
27
  |--------|-------|--------|------|-----------------|--------------------------|-----------|
28
- | claude-sonnet-5-2026-07-04 | claude-sonnet-5 | seed-v1 | 2026-07-04 | pending | pending | [scorecard](published/claude-sonnet-5-2026-07-04.json) |
28
+ | claude-sonnet-5-2026-07-04 | claude-sonnet-5 | seed-v1 | 2026-07-04 | pending | pending | not yet published |
29
29
  | claude-sonnet-4-6-2026-07-04 | claude-sonnet-4-6 | seed-v1 | 2026-07-04 | pending | pending | [scorecard](published/claude-sonnet-4-6-2026-07-04.json) |
30
30
 
31
31
  ---