@sorenllm/opencode-forge 0.1.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 (4) hide show
  1. package/README.md +128 -0
  2. package/SKILL.md +91 -0
  3. package/dist/index.js +13036 -0
  4. package/package.json +59 -0
package/README.md ADDED
@@ -0,0 +1,128 @@
1
+ # opencode-forge
2
+
3
+ Single general-purpose **forge** agent + a plan harness for
4
+ [opencode](https://opencode.ai) ≥ 1.18. Plans become first-class files on
5
+ disk with tool-enforced structure, a hard write-ban while planning, user
6
+ confirmation gates for approve/close, and tick-as-you-go task tracking.
7
+
8
+ ```
9
+ /plan fix login timeout → read-only recon → plan_write (draft, writes denied)
10
+ → present → plan_approve (user dialog = approval gate)
11
+ → execute task by task, plan_tick on each (timestamped audit)
12
+ → all ticked → per-criterion self-check → plan_close
13
+ (user dialog = completion gate) → done
14
+ /plan → list in-progress plans with progress
15
+ /plan resume → continue the most recent unfinished plan
16
+ /plan discard → abandon the current plan (abandoned, writes restored)
17
+ ```
18
+
19
+ - Plan files: `.opencode/plan/<date>-<slug>.md` in your project, frontmatter
20
+ state machine `draft → approved → done` (exit: `abandoned`).
21
+ - While a plan is in draft, `write` / `edit` / `bash` / `task` are **denied
22
+ at the permission layer** — including your own `allow` config. The only
23
+ exits are approval and discard. This is deliberate; see Design stance.
24
+ - `plan_approve` / `plan_close` are pinned to a confirmation dialog: the
25
+ model can never flip the state itself.
26
+ - The native `build` / `plan` agents are hidden while the plugin is loaded
27
+ (runtime injection, nothing written to your config). Uninstall restores
28
+ them automatically; plan files are never deleted.
29
+
30
+ ## Install
31
+
32
+ Requires opencode ≥ 1.18.
33
+
34
+ ```bash
35
+ # npm (recommended)
36
+ opencode plugin @sorenllm/opencode-forge --global
37
+ # or GitHub source
38
+ opencode plugin github:ChengZiiii/opencode-forge --global
39
+ ```
40
+
41
+ Local development: add `"file:///<repo abs path>"` to the `plugin` array in
42
+ your opencode config. Single-file install: copy `dist/index.js` to
43
+ `~/.config/opencode/plugin/forge.js` **and manually copy `SKILL.md`** to
44
+ `~/.config/opencode/skills/plan/SKILL.md` (the package has no installer
45
+ script; that mode has no bundled skill otherwise).
46
+
47
+ Note: do not enable opencode's experimental plan mode
48
+ (`OPENCODE_EXPERIMENTAL_PLAN_MODE`) together with forge — two plan mechanisms
49
+ would overlap.
50
+
51
+ ## Configuration
52
+
53
+ Everything works with zero config. Optional knobs (your config, your files —
54
+ the plugin never writes them):
55
+
56
+ ```jsonc
57
+ {
58
+ "agent": {
59
+ "forge": {
60
+ "model": "provider/model", // pick any model for forge
61
+ "disable": true // one-knob return to native: no forge,
62
+ // build/plan restored, no tools/commands/skill
63
+ }
64
+ }
65
+ }
66
+ ```
67
+
68
+ If you already have a `command.plan` of your own, it wins and the plugin's
69
+ `/plan` is not registered.
70
+
71
+ ## Uninstall (four steps, restores native opencode)
72
+
73
+ 1. Remove the plugin entry from the `plugin` array in
74
+ `~/.config/opencode/opencode.json` (global installs).
75
+ 2. Delete the package store dir:
76
+ `~/.cache/opencode/packages/github_ChengZiiii/opencode-forge/` (github
77
+ installs, owner/repo layout; for npm installs it is
78
+ `~/.cache/opencode/packages/opencode-forge/`).
79
+ 3. Delete the `agent["forge"]` block from your config if you added one
80
+ (otherwise the name lingers in the agent list).
81
+ 4. Done — the hidden native `build`/`plan` agents come back automatically
82
+ (the hide was runtime-only). Your `.opencode/plan/` files are yours;
83
+ delete them yourself if you want.
84
+
85
+ ## File ledger
86
+
87
+ What this plugin touches, exhaustively:
88
+
89
+ | Where | What | Lifetime |
90
+ | --- | --- | --- |
91
+ | `<project>/.opencode/plan/*.md` | plan files | user data — kept forever, uninstall never deletes |
92
+ | merged config object (RAM only) | forge agent, native build/plan `disable`, `skills.paths` entry, `command.plan` | vanishes when the plugin is removed; nothing is written to disk |
93
+ | `~/.cache/opencode/packages/...` | installed package copy | written by the `opencode plugin` installer, not the plugin |
94
+ | `~/.config/opencode/opencode.json` | `plugin` array entry | written by the installer |
95
+
96
+ The plugin writes no temp files, no logs, nothing outside the table.
97
+
98
+ ## Design stance (read before filing "bash is blocked" issues)
99
+
100
+ During a plan's draft phase every mutating tool — `bash` included — is
101
+ denied, and an `allow` in your config does not override it. Reconnaissance is
102
+ read/grep/glob; if you genuinely need a shell command to decide the plan,
103
+ approve the plan first (revising after approval is allowed via a new `/plan`).
104
+ The escape hatches are `plan_approve` and `/plan discard`, by design.
105
+
106
+ A process restart forgets the session binding: the write-ban soft-disables
107
+ (safety over strictness) and the next session's system notice + `/plan
108
+ resume` re-bind from the plan file on disk, which is the source of truth.
109
+
110
+ ## Development
111
+
112
+ ```bash
113
+ npm install
114
+ bun run typecheck # tsc --noEmit
115
+ node --test tests/*.test.mjs
116
+ bun run bundle # rebuild self-contained dist/index.js (committed)
117
+ ```
118
+
119
+ Architecture: `plugin.ts` (dual entry — v1 `server` full-featured + v2
120
+ `setup` defensive forward-compat) + `src/plan-file.ts` (pure plan document
121
+ core, unit-tested, no opencode imports) + `SKILL.md` (planning discipline,
122
+ discovered via `config.skills.paths`). Behavioral changes go through the
123
+ OpenSpec workflow in `openspec/` — see AGENTS.md. Common pitfalls live in
124
+ `../opencode-plugin-dev-pitfalls.md`.
125
+
126
+ ## License
127
+
128
+ MIT
package/SKILL.md ADDED
@@ -0,0 +1,91 @@
1
+ ---
2
+ name: plan
3
+ description: >-
4
+ The plan discipline for the forge agent. You **MUST** load this skill when
5
+ the /plan command routes a task goal to you, OR the user asks to "plan
6
+ first", "make a plan", "think before coding" before implementation. It
7
+ governs the whole plan lifecycle: read-only reconnaissance, clarifying
8
+ questions, plan_write (structured, tool-rendered), user-approval via
9
+ plan_approve, tick-as-you-go execution via plan_tick, per-criterion
10
+ self-check at plan_close, and the OpenSpec boundary for long-horizon work.
11
+ Do NOT load it for direct implementation requests with no planning intent.
12
+ ---
13
+
14
+ # Plan Discipline (forge)
15
+
16
+ Plans are short-horizon, single-task-goal documents on disk
17
+ (`.opencode/plan/<date>-<slug>.md`). The harness (tools + permission layer)
18
+ enforces the hard parts; you supply the engineering judgment.
19
+
20
+ ## Phase 1 — Reconnaissance (read-only)
21
+
22
+ - Explore with read/grep/glob only. **All write tools, bash, and task
23
+ (subagents) are denied while a draft exists** — do not attempt them, do not
24
+ ask the user to bypass.
25
+ - Gather concrete evidence with `file:line` references; the plan's Context
26
+ Findings section must contain findings you actually verified, not guesses.
27
+ - If the goal is ambiguous on scope, behavior, or acceptance — ask the user
28
+ 1-3 focused questions FIRST. Do not plan against assumptions the user could
29
+ settle in one line.
30
+
31
+ ## Phase 2 — Write the plan (plan_write)
32
+
33
+ Call `plan_write` with structured fields; the tool renders and validates the
34
+ fixed sections (Goal / Non-Goals / Context Findings / Approach and
35
+ Alternatives / Task List / Risks / Acceptance Criteria), so a malformed plan
36
+ cannot exist.
37
+
38
+ Quality bar for each field:
39
+
40
+ - **goal**: one line, the outcome — not the activity.
41
+ - **context**: verified findings with `file:line` evidence; include what you
42
+ ruled out and why.
43
+ - **approach**: the chosen approach AND at least one rejected alternative
44
+ with the reason. A plan with no considered alternative is a guess.
45
+ - **tasks**: 3-8 concrete, independently verifiable steps, each doable in one
46
+ sitting. A task like "improve the code" is invalid; "extract timeout
47
+ constant into config.ts and default it to 3000" is valid.
48
+ - **risks**: what could break, blast radius, rollback path.
49
+ - **acceptance**: criteria you can verify with a command, a file, or an
50
+ observable behavior. Vague criteria will fail the plan_close self-check.
51
+ - **nonGoals**: explicit out-of-scope items (what the user might expect but
52
+ will NOT get).
53
+
54
+ Revising: calling `plan_write` again while still in draft overwrites the same
55
+ file. Do this after user feedback instead of hand-editing.
56
+
57
+ ## Phase 3 — Approval gate (plan_approve)
58
+
59
+ Present to the user, briefly: goal, chosen approach (one line why), the
60
+ numbered task list, and the acceptance criteria. Then call `plan_approve`.
61
+ The user confirms in a dialog — that confirmation IS the approval. If they
62
+ object, revise with `plan_write` and present again. Never proceed to
63
+ implementation before approval succeeds.
64
+
65
+ ## Phase 4 — Execution (tick as you go)
66
+
67
+ - Execute tasks in order; after EACH task's work is actually done, call
68
+ `plan_tick` with its number immediately. Never batch ticks; never tick
69
+ ahead of reality — the tick timestamp is an audit trail.
70
+ - If mid-execution you discover the plan is wrong, do not silently improvise:
71
+ tell the user what changed and either finish the affected task anyway or
72
+ ask whether to revise (/plan with the same goal re-enters planning).
73
+
74
+ ## Phase 5 — Completion gate (plan_close)
75
+
76
+ When all tasks are ticked: self-check EVERY acceptance criterion with
77
+ concrete evidence (`file:line`, command output, test result). Call
78
+ `plan_close` with one check per criterion, `pass` honest — a ✗ fails the
79
+ close and that is the design working, not an inconvenience. The user
80
+ confirms closure in a dialog.
81
+
82
+ ## Boundaries
83
+
84
+ - **Abandon**: user cancels → `/plan discard` (or plan_discard). Terminal,
85
+ file kept as history, writes restored.
86
+ - **Resume**: new session with unfinished plan → the system notice carries
87
+ the path; `/plan resume` continues from the remaining tasks.
88
+ - **Spec-workflow boundary**: work expected to span multiple sessions, days
89
+ of multi-file change, or multi-round requirement review is spec work, not
90
+ plan work. Say so once (e.g. "this fits a spec workflow like OpenSpec
91
+ better"), let the user choose, and proceed with a plan only if they insist.