@sorenllm/opencode-forge 0.3.3 → 0.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 +119 -124
- package/dist/index.js +482 -1570
- package/package.json +64 -61
package/README.md
CHANGED
|
@@ -113,9 +113,10 @@ and the plugin's command of that name is not registered.
|
|
|
113
113
|
4. Done — the hidden native `build`/`plan` agents come back automatically
|
|
114
114
|
(the hide was runtime-only). Your `.opencode/plan/` and `.opencode/goal/`
|
|
115
115
|
files are yours; delete them yourself if you want.
|
|
116
|
-
5. Optional runtime debris: delete `<tmp>/opencode-forge/` (job logs, the
|
|
117
|
-
|
|
118
|
-
|
|
116
|
+
5. Optional runtime debris: delete `<tmp>/opencode-forge/` (job logs, the
|
|
117
|
+
job registry ledger, the watchdog ledger, and any leftover dispatch
|
|
118
|
+
ledger from older versions — the file ledger table above lists
|
|
119
|
+
everything).
|
|
119
120
|
|
|
120
121
|
## File ledger
|
|
121
122
|
|
|
@@ -125,13 +126,13 @@ What this plugin touches, exhaustively:
|
|
|
125
126
|
| --- | --- | --- |
|
|
126
127
|
| `<project>/.opencode/plan/*.md` | plan files | user data — kept forever, uninstall never deletes |
|
|
127
128
|
| `<project>/.opencode/goal/*.md` | goal files (contract, Check Log, Turn Ledger) | user data — kept forever, uninstall never deletes |
|
|
128
|
-
| merged config object (RAM only) | forge agent, native build/plan `disable`, `command.plan`, `command.goal`, goal permission keys, `permission.forge_shell`, stage-0 builtin shell hide | vanishes when the plugin is removed; nothing is written to disk |
|
|
129
|
+
| merged config object (RAM only) | forge agent, static `forge-<id>` subagents, native build/plan `disable`, `command.plan`, `command.goal`, `command.crew`, goal permission keys, `permission.forge_shell`, `permission.crew_close`, stage-0 builtin shell hide | vanishes when the plugin is removed; nothing is written to disk |
|
|
129
130
|
| `<tmp>/opencode-forge/jobs/<jobId>.log` | job output tee (full output; oldest rotated out above 50 files) | runtime debris — delete freely, also after uninstall |
|
|
130
131
|
| `<tmp>/opencode-forge/jobs/ledger.jsonl` | job registry ledger (bounded: 1 MB reset, 200 entries) | runtime debris — delete freely, also after uninstall |
|
|
131
132
|
| `<tmp>/opencode-forge/jobs/registry.json` | persistent survivor registry (bounded: 100 entries) | runtime debris — after uninstall, kill any still-running `survive` jobs yourself first |
|
|
132
133
|
| `<tmp>/opencode-forge/watchdog/log.jsonl` | watchdog interventions ledger (bounded: 200 entries, oldest rotated) | runtime debris — delete freely, also after uninstall |
|
|
133
|
-
| `<tmp>/opencode-forge/dispatch/ledger.jsonl` | dispatch ledger
|
|
134
|
-
| `<project>/.opencode/forge.json`, `~/.config/opencode/forge.json` | your
|
|
134
|
+
| `<tmp>/opencode-forge/dispatch/ledger.jsonl` | dispatch ledger — **no longer written** (the dispatch engine was removed); only present as inert debris from older versions | runtime debris — delete freely |
|
|
135
|
+
| `<project>/.opencode/forge.json`, `~/.config/opencode/forge.json` | your static subagent definitions (JSONC). **User data — the plugin only reads it, never writes or migrates it** | yours — version the project one, keep the global one out of sync tools if it holds machine-specific models |
|
|
135
136
|
| `~/.cache/opencode/packages/...` | installed package copy | written by the `opencode plugin` installer, not the plugin |
|
|
136
137
|
| `~/.config/opencode/opencode.json` | `plugin` array entry | written by the installer |
|
|
137
138
|
|
|
@@ -319,141 +320,135 @@ These are runtime debris, not data — with ONE caveat: **if you uninstall with
|
|
|
319
320
|
/F /T`, or just reboot); deleting the directory afterwards is safe and
|
|
320
321
|
complete.
|
|
321
322
|
|
|
322
|
-
##
|
|
323
|
+
## Forge subagents (static worker agents in forge.json)
|
|
323
324
|
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
325
|
+
Forge subagents are **static, user-authored worker agents**: each forge.json
|
|
326
|
+
entry pins a model and an optional reasoning depth, materializes as a native
|
|
327
|
+
`forge-<id>` subagent, and is dispatched through the host's **native `task`
|
|
328
|
+
tool** — which means every run is visible in the TUI, expandable and
|
|
329
|
+
monitorable, exactly like any native subagent. There is no dispatch tool, no
|
|
330
|
+
child-session engine, and no configuration invitation anywhere: the session
|
|
331
|
+
AI never writes your config.
|
|
330
332
|
|
|
331
|
-
|
|
333
|
+
No forge.json? Nothing happens — the plugin registers nothing and the native
|
|
334
|
+
subagent behavior is untouched. Onboarding is this README, for you the human.
|
|
332
335
|
|
|
333
|
-
|
|
334
|
-
|
|
336
|
+
### forge.json — the configuration
|
|
337
|
+
|
|
338
|
+
A dedicated `forge.json` (JSONC — comments allowed), resolved by a two-level
|
|
339
|
+
cascade with a single winning source (never merged):
|
|
335
340
|
|
|
336
341
|
1. `<project>/.opencode/forge.json` — project-level, versionable, team-shared
|
|
337
342
|
2. `~/.config/opencode/forge.json` — global
|
|
338
|
-
3. the built-in seed — `research {depths: [low, medium]}` and
|
|
339
|
-
`review {depths: [medium, high, max]}`, both pinned to the placeholder
|
|
340
|
-
`Local/GPT Luna` (an identity that never resolves: an unconfigured install
|
|
341
|
-
fails every dispatch with the configuration recipe below)
|
|
342
343
|
|
|
343
344
|
```jsonc
|
|
344
345
|
{
|
|
345
|
-
// forge
|
|
346
|
+
// forge subagents — definitions; see the restart table below for apply timing
|
|
346
347
|
"agents": {
|
|
347
348
|
"research": {
|
|
348
|
-
"model": "zai-coding-plan/glm-5.3", // exact "provider/model" string
|
|
349
|
-
"
|
|
350
|
-
// "prompt": "optional role prompt
|
|
351
|
-
// "shape": "write",
|
|
352
|
-
// "permission": { "bash": "deny" } // optional override; "task" is
|
|
349
|
+
"model": "zai-coding-plan/glm-5.3", // exact "provider/model" string — REQUIRED
|
|
350
|
+
"thoughtLevel": "low", // optional: none/low/medium/high/max or a native level name
|
|
351
|
+
// "prompt": "optional role prompt; built-in research/review defaults exist",
|
|
352
|
+
// "shape": "write", // default readonly denies write/edit/bash
|
|
353
|
+
// "permission": { "bash": "deny" } // optional override; "task" is ALWAYS denied
|
|
353
354
|
}
|
|
354
355
|
}
|
|
355
356
|
}
|
|
356
357
|
```
|
|
357
358
|
|
|
358
359
|
- **The plugin only ever reads this file.** It never creates, writes, or
|
|
359
|
-
migrates it.
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
`
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
the
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
sync-heavy workflows; a killed call still leaves the child session
|
|
452
|
-
reclaimable via `forge_dispatch_list` / the host API.
|
|
453
|
-
- **Child permission asks**: a worker that hits a permission ask surfaces the
|
|
454
|
-
ask on the CHILD's session in the TUI. An unanswered ask stalls the child
|
|
455
|
-
until the dispatch deadline — scope worker prompts to avoid permission
|
|
456
|
-
boundaries (readonly tiers and workspace-relative paths help).
|
|
360
|
+
migrates it. The old AI-authored onboarding path (seed placeholder +
|
|
361
|
+
error recipe) is gone: an unconfigured host is inert and silent, and the
|
|
362
|
+
session AI is never invited to touch config. The ONE exception is the
|
|
363
|
+
`/crew` initialization gate (below), where AI-assisted configuration is
|
|
364
|
+
offered to YOU and happens only on your explicit go-ahead.
|
|
365
|
+
- **Parsing is field-level fail-soft** (ZCode-style): a semantically bad
|
|
366
|
+
agent entry is skipped with an error finding while its siblings apply; a
|
|
367
|
+
mistyped optional field is ignored with a warning; a syntactically broken
|
|
368
|
+
file empties the agent set with one parse-location error. There is no seed
|
|
369
|
+
in any failure path. Findings surface in the plugin diagnostics log.
|
|
370
|
+
- **`depths` is deprecated**: the array is ignored with a warning finding.
|
|
371
|
+
Pin ONE `thoughtLevel` per agent instead.
|
|
372
|
+
- Each agent materializes as `forge-<id>` — a subagent-mode agent visible in
|
|
373
|
+
the task tool's vocabulary (never hidden), carrying the pinned `model`,
|
|
374
|
+
the worker discipline (workspace-relative paths only, verbatim reporting
|
|
375
|
+
of tool refusals, evidence-bearing conclusions) around its role prompt,
|
|
376
|
+
and a deny-style permission: `shape: "readonly"` (the default) denies
|
|
377
|
+
`write`/`edit`/`bash`, `shape: "write"` allows them, an explicit
|
|
378
|
+
`permission` map overrides the shape default — and `task` is ALWAYS
|
|
379
|
+
denied (recursive spawning stays physically impossible).
|
|
380
|
+
|
|
381
|
+
**What applies when** — edits take hold per field:
|
|
382
|
+
|
|
383
|
+
| change | needs a host restart? |
|
|
384
|
+
| --- | --- |
|
|
385
|
+
| `thoughtLevel` on an existing agent | no (applies to NEW sessions of that agent; running sessions keep their frozen depth) |
|
|
386
|
+
| agent added / removed, or `model` / `prompt` / `permission` changed | yes (materialization runs on the config hook) |
|
|
387
|
+
|
|
388
|
+
### Dispatching
|
|
389
|
+
|
|
390
|
+
Say "dispatch a subagent..." in a forge session and the model picks from the
|
|
391
|
+
task tool vocabulary: a configured `forge-*` agent whose description matches
|
|
392
|
+
runs on its pinned brain; if none matches, forge is instructed to say so
|
|
393
|
+
plainly and fall back to the native task channel. During a plan draft the
|
|
394
|
+
native `task` tool is already denied by the plan harness — no plugin-side
|
|
395
|
+
rule needed.
|
|
396
|
+
|
|
397
|
+
**Known pitfall — keyless endpoints × readonly agents**: free/keyless
|
|
398
|
+
providers can return a deterministic EMPTY response for any toolset-reduced
|
|
399
|
+
(readonly) agent. On the native task channel this now surfaces as a visible,
|
|
400
|
+
attributable task failure; the mitigation is unchanged — use
|
|
401
|
+
`shape: "write"` for such endpoints, or a keyed provider.
|
|
402
|
+
|
|
403
|
+
### The thoughtLevel word
|
|
404
|
+
|
|
405
|
+
One word per agent: the canonical `none | low | medium | high | max`, or the
|
|
406
|
+
model's native level name verbatim (e.g. Qwen's `XHigh`). Injection rides the
|
|
407
|
+
`chat.params` hook keyed by agent name, translated per provider family:
|
|
408
|
+
effort-style (OpenAI-compatible) receives `reasoningEffort = <word>`;
|
|
409
|
+
budget-style (Anthropic-style) receives a published thinking tier
|
|
410
|
+
(`low → 8192`, `medium → 16384`, `high → 24576`, `max → 32768`,
|
|
411
|
+
`none → off`); toggle-style (zai/GLM) receives thinking on/off. Rules:
|
|
412
|
+
verbatim-first, no interpolation, unknown family injects nothing. A word the
|
|
413
|
+
model does not natively offer injects NOTHING and records one finding naming
|
|
414
|
+
both vocabularies — the session is never broken by a config word. A
|
|
415
|
+
session's depth is frozen at its first request (editing forge.json
|
|
416
|
+
mid-session never rewrites a running session).
|
|
417
|
+
|
|
418
|
+
## Crew workflow (`/crew`)
|
|
419
|
+
|
|
420
|
+
`/crew <objective>` is the third state-activation command next to `/plan` and
|
|
421
|
+
`/goal`: it enters crew orchestration discipline for the session. The flow:
|
|
422
|
+
|
|
423
|
+
1. **Register** the declared plan: `crew_begin {objective, subtasks}` — one
|
|
424
|
+
titled subtask each, optionally naming the intended `forge-*` agent.
|
|
425
|
+
2. **Execute in waves** of parallel native `task` calls (results return
|
|
426
|
+
in-turn; the next wave launches only after the previous wave's results).
|
|
427
|
+
3. **Missing role?** Run the subtask through a native task call anyway and
|
|
428
|
+
tell the user — suggest configuring the missing role.
|
|
429
|
+
4. **Verify** each subtask against its acceptance-evidence statement;
|
|
430
|
+
retry a failure at most once.
|
|
431
|
+
5. **Close** with `crew_close` — a hard, ask-gated gate cross-checking the
|
|
432
|
+
report against the DECLARED plan: every declared subtask needs a
|
|
433
|
+
PASS/FAIL verdict with evidence; an undeclared subtask in the report
|
|
434
|
+
refuses the close (fold discoveries into an existing verdict, or discard
|
|
435
|
+
and re-crew); a FAIL needs both failure reports. The close output is the
|
|
436
|
+
crew's record — crew state is in-memory and a host restart ends it
|
|
437
|
+
honestly.
|
|
438
|
+
|
|
439
|
+
**Not initialized?** `/crew` on a host with zero usable forge agents refuses
|
|
440
|
+
with one-time setup guidance: the two file paths, a copy-paste template, and
|
|
441
|
+
the choice of configuring it yourself OR having the session AI do it — the
|
|
442
|
+
latter only on your explicit go-ahead in that conversation, through the
|
|
443
|
+
normal visible write path. This is the plugin's only configuration
|
|
444
|
+
invitation. After saving the file, restart opencode to materialize the
|
|
445
|
+
agents.
|
|
446
|
+
|
|
447
|
+
### Debris note
|
|
448
|
+
|
|
449
|
+
The old dispatch suite's ledger at `<tmp>/opencode-forge/dispatch/` is no
|
|
450
|
+
longer written. If it exists on your machine it is inert runtime debris —
|
|
451
|
+
delete the directory freely, also after uninstalling.
|
|
457
452
|
|
|
458
453
|
## Hang watchdog (a stuck builtin shell unblocks itself)
|
|
459
454
|
|