@sorenllm/opencode-forge 0.1.0 → 0.2.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 +110 -17
- package/dist/index.js +1182 -27
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
# opencode-forge
|
|
2
2
|
|
|
3
|
-
Single general-purpose **forge** agent +
|
|
4
|
-
[opencode](https://opencode.ai) ≥ 1.18
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
Single general-purpose **forge** agent + two orthogonal harnesses for
|
|
4
|
+
[opencode](https://opencode.ai) ≥ 1.18: a **plan harness** (decide first,
|
|
5
|
+
execute later) and a **goal harness** (arm an objective, let the loop drive
|
|
6
|
+
itself to a host-verified finish). They share nothing but a safety interop;
|
|
7
|
+
OpenSpec spec workflows remain a third, separate lane.
|
|
7
8
|
|
|
8
9
|
```
|
|
9
10
|
/plan fix login timeout → read-only recon → plan_write (draft, writes denied)
|
|
@@ -16,6 +17,18 @@ confirmation gates for approve/close, and tick-as-you-go task tracking.
|
|
|
16
17
|
/plan discard → abandon the current plan (abandoned, writes restored)
|
|
17
18
|
```
|
|
18
19
|
|
|
20
|
+
```
|
|
21
|
+
/goal make the suite green --check "npm test" --contains "src/a.ts::export const A"
|
|
22
|
+
→ goal_write (arm=true; the user dialog IS the arm action)
|
|
23
|
+
→ loop: work → goal_check (advisory) → idle → continuation brief
|
|
24
|
+
→ goal_complete re-runs EVERY check itself on the host
|
|
25
|
+
(fail-closed) + per-criterion attestations → user dialog
|
|
26
|
+
= completion gate → completed
|
|
27
|
+
/goal add ... → queue an inert goal (no dialog, no loop)
|
|
28
|
+
/goal → live goal + queue overview
|
|
29
|
+
/goal pause | resume | discard/stop/cancel
|
|
30
|
+
```
|
|
31
|
+
|
|
19
32
|
- Plan files: `.opencode/plan/<date>-<slug>.md` in your project, frontmatter
|
|
20
33
|
state machine `draft → approved → done` (exit: `abandoned`).
|
|
21
34
|
- While a plan is in draft, `write` / `edit` / `bash` / `task` are **denied
|
|
@@ -23,9 +36,14 @@ confirmation gates for approve/close, and tick-as-you-go task tracking.
|
|
|
23
36
|
exits are approval and discard. This is deliberate; see Design stance.
|
|
24
37
|
- `plan_approve` / `plan_close` are pinned to a confirmation dialog: the
|
|
25
38
|
model can never flip the state itself.
|
|
39
|
+
- Goal files: `.opencode/goal/<date>-<slug>.md`, state machine
|
|
40
|
+
`queued → active ⇄ paused → completed / abandoned`, one live goal per
|
|
41
|
+
session plus a workspace queue. Completion is **verified by the plugin**,
|
|
42
|
+
not attested by the model: `goal_complete` re-executes every check itself
|
|
43
|
+
and refuses (fail-closed) on any failure.
|
|
26
44
|
- The native `build` / `plan` agents are hidden while the plugin is loaded
|
|
27
45
|
(runtime injection, nothing written to your config). Uninstall restores
|
|
28
|
-
them automatically; plan files are never deleted.
|
|
46
|
+
them automatically; plan and goal files are never deleted.
|
|
29
47
|
|
|
30
48
|
## Install
|
|
31
49
|
|
|
@@ -65,22 +83,22 @@ the plugin never writes them):
|
|
|
65
83
|
}
|
|
66
84
|
```
|
|
67
85
|
|
|
68
|
-
If you already have a `command.plan` of your own, it wins
|
|
69
|
-
|
|
86
|
+
If you already have a `command.plan` or `command.goal` of your own, it wins
|
|
87
|
+
and the plugin's command of that name is not registered.
|
|
70
88
|
|
|
71
89
|
## Uninstall (four steps, restores native opencode)
|
|
72
90
|
|
|
73
91
|
1. Remove the plugin entry from the `plugin` array in
|
|
74
92
|
`~/.config/opencode/opencode.json` (global installs).
|
|
75
93
|
2. Delete the package store dir:
|
|
76
|
-
`~/.cache/opencode/packages/
|
|
77
|
-
|
|
78
|
-
`~/.cache/opencode/packages/opencode-forge/`).
|
|
94
|
+
`~/.cache/opencode/packages/@sorenllm/opencode-forge/` (npm installs,
|
|
95
|
+
scope-dir layout; for github installs it is
|
|
96
|
+
`~/.cache/opencode/packages/github_ChengZiiii/opencode-forge/`).
|
|
79
97
|
3. Delete the `agent["forge"]` block from your config if you added one
|
|
80
98
|
(otherwise the name lingers in the agent list).
|
|
81
99
|
4. Done — the hidden native `build`/`plan` agents come back automatically
|
|
82
|
-
(the hide was runtime-only). Your `.opencode/plan/`
|
|
83
|
-
delete them yourself if you want.
|
|
100
|
+
(the hide was runtime-only). Your `.opencode/plan/` and `.opencode/goal/`
|
|
101
|
+
files are yours; delete them yourself if you want.
|
|
84
102
|
|
|
85
103
|
## File ledger
|
|
86
104
|
|
|
@@ -89,11 +107,84 @@ What this plugin touches, exhaustively:
|
|
|
89
107
|
| Where | What | Lifetime |
|
|
90
108
|
| --- | --- | --- |
|
|
91
109
|
| `<project>/.opencode/plan/*.md` | plan files | user data — kept forever, uninstall never deletes |
|
|
92
|
-
|
|
|
110
|
+
| `<project>/.opencode/goal/*.md` | goal files (contract, Check Log, Turn Ledger) | user data — kept forever, uninstall never deletes |
|
|
111
|
+
| merged config object (RAM only) | forge agent, native build/plan `disable`, `skills.paths` entry, `command.plan`, `command.goal`, goal permission keys | vanishes when the plugin is removed; nothing is written to disk |
|
|
93
112
|
| `~/.cache/opencode/packages/...` | installed package copy | written by the `opencode plugin` installer, not the plugin |
|
|
94
113
|
| `~/.config/opencode/opencode.json` | `plugin` array entry | written by the installer |
|
|
95
114
|
|
|
96
|
-
The plugin writes no temp files, no logs, nothing outside the table
|
|
115
|
+
The plugin writes no temp files, no logs, nothing outside the table (a
|
|
116
|
+
`FORGE_GOAL_PROBE=1` env opt-in appends continuation diagnostics to the OS
|
|
117
|
+
temp dir for debugging).
|
|
118
|
+
|
|
119
|
+
## Goal mode (autonomous, host-verified objectives)
|
|
120
|
+
|
|
121
|
+
Three orthogonal workflows — pick per task, they never bind to each other:
|
|
122
|
+
|
|
123
|
+
| Workflow | decides | use when |
|
|
124
|
+
| --- | --- | --- |
|
|
125
|
+
| OpenSpec change | spec deltas, review gates | multi-session features with spec impact |
|
|
126
|
+
| `/plan` | approach + task order, you approve then it executes | single-task execution you want to review first |
|
|
127
|
+
| `/goal` | arm an objective + verification contract, the loop executes | well-defined objective with machine-checkable success |
|
|
128
|
+
|
|
129
|
+
`/goal <objective>` drafts a **contract**: goal, success criteria,
|
|
130
|
+
verification checks, constraints, non-goals, budgets. Contract markers in the
|
|
131
|
+
objective map to structured fields:
|
|
132
|
+
|
|
133
|
+
```
|
|
134
|
+
/goal make the release green --check "npm test" --check "npm run lint"
|
|
135
|
+
--contains "CHANGELOG.md::## Unreleased"
|
|
136
|
+
--success "zero failing tests" --constraint "no dependency bumps"
|
|
137
|
+
--non-goal "refactoring" --max-turns 15 --max-minutes 30
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
Two check types, both **executed by the plugin on the host** (the model never
|
|
141
|
+
grades its own homework):
|
|
142
|
+
|
|
143
|
+
- `--check "cmd"` — shell command in the workspace; passes on exit 0,
|
|
144
|
+
timeout-configurable (default 120 s, max 600 s).
|
|
145
|
+
- `--contains "file::text"` — file contract: the literal text must be present
|
|
146
|
+
in that workspace file.
|
|
147
|
+
|
|
148
|
+
**Arming and the loop.** `goal_write` with `arm=true` pops one confirmation
|
|
149
|
+
dialog — your Allow IS the arm action; nothing autonomous runs before it.
|
|
150
|
+
From then on, whenever the session goes idle, the plugin re-prompts the agent
|
|
151
|
+
with a `[forge:goal-continue]` brief (with debounce, owner-checked, and
|
|
152
|
+
compaction-aware: autocontinue is suppressed for active-goal sessions so a
|
|
153
|
+
context compaction can never silently re-trigger the loop). Each continuation
|
|
154
|
+
turn is counted and recorded in the goal's Turn Ledger.
|
|
155
|
+
|
|
156
|
+
**Budgets and auto-pause.** `--max-turns` (default 25, hard ceiling 200) and
|
|
157
|
+
`--max-minutes` (default 60, hard ceiling 480). The loop pauses itself — with
|
|
158
|
+
a `stop_reason` in the frontmatter — on: budget exhaustion, two consecutive
|
|
159
|
+
no-progress continuation turns, three consecutive transport failures, or a
|
|
160
|
+
live draft plan appearing in the session (the only plan/goal interop: a draft
|
|
161
|
+
plan's write ban would wall the loop off, so the goal pauses instead of
|
|
162
|
+
burning turns against it). `/goal pause` (or `goal_pause` with a blocker
|
|
163
|
+
description) pauses by hand; `/goal resume` re-arms through another
|
|
164
|
+
confirmation dialog.
|
|
165
|
+
|
|
166
|
+
**Completion is fail-closed.** `goal_complete` re-executes every check itself
|
|
167
|
+
at the gate — results recorded in the Check Log never substitute for the
|
|
168
|
+
re-run — and requires one attestation per success criterion. Only then does
|
|
169
|
+
the user dialog appear. Revising the contract (`goal_write` with
|
|
170
|
+
`revise=true`) bumps the revision: earlier evidence no longer counts, but the
|
|
171
|
+
Check Log and Turn Ledger survive as an audit trail.
|
|
172
|
+
|
|
173
|
+
**Queueing.** One live goal per session; `/goal add ...` queues additional
|
|
174
|
+
goals (inert, no dialog). When the live goal reaches a terminal state,
|
|
175
|
+
`/goal resume` promotes the oldest queued goal into the now-free session.
|
|
176
|
+
|
|
177
|
+
**Run-mode limitation.** `opencode run` exits before the idle continuation
|
|
178
|
+
debounce fires, so the autonomous loop effectively requires a TUI/serve
|
|
179
|
+
session. Arming, checks, completion, pause/resume, and queueing all work in
|
|
180
|
+
run mode; `--auto` approves the gates, without it they auto-reject
|
|
181
|
+
(headless cannot silently pass a gate).
|
|
182
|
+
|
|
183
|
+
**Security boundary.** Verification shell commands run on your host, in the
|
|
184
|
+
workspace, via the plugin — that is the point (host-verified completion).
|
|
185
|
+
They are drafted by the model from your objective. Read them in the dialog
|
|
186
|
+
before allowing the arm; `--contains` contracts are strictly
|
|
187
|
+
workspace-relative (path escape is refused).
|
|
97
188
|
|
|
98
189
|
## Design stance (read before filing "bash is blocked" issues)
|
|
99
190
|
|
|
@@ -117,9 +208,11 @@ bun run bundle # rebuild self-contained dist/index.js (committed)
|
|
|
117
208
|
```
|
|
118
209
|
|
|
119
210
|
Architecture: `plugin.ts` (dual entry — v1 `server` full-featured + v2
|
|
120
|
-
`setup` defensive forward-compat) + `src/plan-file.ts`
|
|
121
|
-
|
|
122
|
-
|
|
211
|
+
`setup` defensive forward-compat) + `src/plan-file.ts` / `src/goal-file.ts`
|
|
212
|
+
(pure document cores, unit-tested, no opencode imports) + `src/run-check.ts`
|
|
213
|
+
(shell/file-contract runner with tree-kill timeouts and a workspace path
|
|
214
|
+
guard) + `SKILL.md` (planning discipline, discovered via
|
|
215
|
+
`config.skills.paths`). Behavioral changes go through the
|
|
123
216
|
OpenSpec workflow in `openspec/` — see AGENTS.md. Common pitfalls live in
|
|
124
217
|
`../opencode-plugin-dev-pitfalls.md`.
|
|
125
218
|
|