opencode-goal-plugin 0.1.14 → 0.3.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/CHANGELOG.md +43 -0
- package/README.md +88 -8
- package/package.json +2 -2
- package/src/goal-plugin.js +1384 -138
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,49 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
## 0.3.0 — 2026-06-14
|
|
6
|
+
|
|
7
|
+
> A large feature release. Stronger completion integrity (evidence gate, optional auditor, visible audit messages), durable lifecycle ledger with state reconstruction, multiple goals per session with focus and ordered sisyphus sequences, richer goal schema, more auto-continue guardrails, project-local state with migration, agent-facing tools, a deterministic compaction summary, and npm Trusted Publishing CI. All changes are additive and backward-compatible; older state files load unchanged.
|
|
8
|
+
|
|
9
|
+
### Completion integrity & audit
|
|
10
|
+
|
|
11
|
+
- **Require evidence to complete a goal and a concrete blocker to block one.** A `[goal:complete]` marker is now only honored when the assistant also supplies a non-empty `[goal:evidence] <summary>` line (on or before the completion marker); a `[goal:blocked]` is only honored when a concrete blocker is stated on the line before it. An unsubstantiated `[goal:complete]` or `[goal:blocked]` is rejected (not recorded / does not stop the goal) and the plugin sends a corrective continuation prompt demanding the missing evidence or blocker. The accepted evidence is stored on the result and shown in `/goal status` / `/goal history`. New `extractCompletionEvidence` helper, an `<evidence_required>` structural tag (added to the injection-escaping set), and continuation/system/compaction/creation prompts all updated to instruct the evidence requirement. Implements megalist item 2.1.
|
|
12
|
+
- **Add an optional separate completion auditor that verifies before archival.** When a completion auditor is configured, a `[goal:complete]` (with evidence) is verified before the goal is archived: on approval it archives as achieved, on rejection the goal is *restored* (paused with stop reason `audit rejected` and the reason surfaced) rather than archived. Enable the built-in auditor — which spawns an independent OpenCode child session that replies `[audit:approved]`/`[audit:rejected]` — with `completionAudit: true`, or supply a custom `auditor({ goal, sessionID, latestText }) => { approved, reason }` (takes precedence). The built-in child-session auditor fails open if the session API is unavailable; a custom auditor that throws is treated as a rejection (fail closed). New `parseAuditVerdict` / `buildAuditPrompt` / `createChildSessionAuditor` helpers. Off by default. Implements megalist item 2.2.
|
|
13
|
+
- **Announce completion/blocker audits with visible messages instead of silent background work.** When the assistant marks a goal complete or blocked, the plugin emits an audit-start and an audit-result message (e.g. "Auditing goal completion…" → "Audit result: completion accepted — goal archived"). Delivery defaults to OpenCode's structured log (`client.app.log`) and is pluggable via an `auditMessenger(sessionID, text)` option or disable-able with `auditMessages: false`. New `defaultAuditMessenger` helper. Implements megalist item 2.4.
|
|
14
|
+
|
|
15
|
+
### Durability
|
|
16
|
+
|
|
17
|
+
- **Add an append-only JSONL lifecycle ledger with state reconstruction, and fail-closed terminal-state persistence.** Every lifecycle event (`pushHistory`) is also appended as one JSON line to `<stateFile>.ledger.jsonl` (synchronous, owner-only `0600`). Because in-memory history is capped, the ledger is the durable record: when the main state file is missing on startup, the plugin reconstructs still-active (non-`completed`/`cleared`) goals from the ledger and reloads them paused (new `reconstructed` load status). Terminal events are written to the ledger before the main state write, so a goal's terminal outcome survives a failed state write (fail-closed); `persistState` now returns success/failure and a failed terminal persist is logged at error level. Tied to `persistState`. New `appendLedgerLine` / `readLedgerEntries` / `reconstructGoalsFromLedger` helpers. Implements megalist items 2.3 and 2.5.
|
|
18
|
+
- **Build the compaction summary deterministically from the persisted goal record.** `buildCompactionContext` folds in a reproducible progress summary — recent checkpoints and lifecycle events — derived from the goal's persisted `checkpoints`/`history` (new `buildCompactionProgressSummary` helper) rather than chat memory, and labels it as such. Implements megalist item 6.3.
|
|
19
|
+
|
|
20
|
+
### Auto-continue guardrails
|
|
21
|
+
|
|
22
|
+
- **Pause auto-continue on repeated tool-free continuation turns (no-tool-call gate).** Complementing the low-output no-progress check, the plugin tracks continuation turns whose assistant message has no tool calls (OpenCode `tool` / `subtask` parts) and, after `noToolCallTurnsBeforePause` consecutive such turns (default `2`), pauses with stop reason `no tool calls` to guard against self-chat loops. A tool-using turn resets the counter. Configurable via the `noToolCallTurnsBeforePause` option and `--no-tool-turns <n>` flag. New `messageHasToolCall` helper. Implements megalist item 5.1.
|
|
23
|
+
- **Pause auto-continue when a real user message arrives ("latest instruction wins").** The idle handler detects a genuine human message that arrived after the plugin's most recent continuation and pauses the goal (stop reason `user intervention`) instead of talking over the user; `/goal resume` hands control back. Plugin-generated continuation prompts (user-role messages framed in `<goal_continuation>`) are ignored, and detection requires `turnCount > 0` plus a visible plugin continuation so the first idle and scrolled-out sessions are never misread. New `isPluginContinuationMessage` / `userInterventionDetected` helpers. Implements megalist items 5.2 and 5.3.
|
|
24
|
+
|
|
25
|
+
### Multiple goals
|
|
26
|
+
|
|
27
|
+
- **Support multiple goals per session with `/goal add`, `/goal list`, and `/goal focus`.** A session can hold several live goals via a new `sessionGoals` registry; `goalStates` continues to track the single *focused* goal the idle handler drives. `/goal <condition>` replaces the focused goal; `/goal add <condition>` backgrounds the current goal and focuses a new one (only the focused goal auto-continues). `/goal list` shows numbered live goals plus a per-session archive of completed/cleared goals, and `/goal focus <number|id>` switches the active goal (numeric refs are index-only). Focus is tracked per session and persisted (state files gain a per-goal `focused` flag and an `archives` array; older single-goal files load with their goal focused). New `buildGoalState` / `formatGoalList` / session-registry helpers. Implements megalist items 3.1, 3.2, and 3.3.
|
|
28
|
+
- **Add `/goal sisyphus` ordered goal sequences.** `/goal sisyphus <obj 1>; <obj 2>; …` sets up a strict execution sequence: the first objective is focused and the rest queued, and when the focused goal completes the plugin auto-promotes the next until the sequence is exhausted. The ordered flag is tracked per session, shown in `/goal list`, persisted (`orderedSessions`), and cleared by `/goal clear`. New `promoteNextOrderedGoal` helper. Implements megalist item 3.4.
|
|
29
|
+
|
|
30
|
+
### Schema & command UX
|
|
31
|
+
|
|
32
|
+
- **Add success-criteria, constraints/non-goals, and mode to the goal schema.** A goal can carry `successCriteria` (`--success`), `constraints` (`--constraints` / `--non-goals`), and a `mode` of `normal` or `ordered` (`--mode`, `sisyphus` alias). These thread through state, persistence, the injected goal block (escaped, new `success_criteria` / `constraints` structural tags), creation output, and `/goal status`. New `normalizeMode` helper. Implements megalist items 4.1, 4.2, and 4.3.
|
|
33
|
+
- **Add an inline `--budget <n>` flag** on the create command — a shorthand for the context-token limit accepting a plain integer or `k`/`m` suffix (e.g. `--budget 100k`). New `parseTokenBudget` helper. Implements megalist item 8.1.
|
|
34
|
+
- **Make the slash command configurable (`commandName`) and optional (`registerCommand`).** `commandName` (default `goal`, leading slash tolerated) lets the plugin own e.g. `/objective`, with all user-facing hints following the configured name; `registerCommand: false` skips installing the command hook entirely. New `normalizeCommandOptions` helper. Implements megalist item 8.2.
|
|
35
|
+
|
|
36
|
+
### Storage, tools & packaging
|
|
37
|
+
|
|
38
|
+
- **Default goal state to a project-local path, with an env override and migration fallbacks.** State resolves as `stateFilePath` option → `OPENCODE_GOAL_STATE_PATH` env var → project-local `<cwd>/.opencode/goals/state.json` (previously `~/.opencode-goal-plugin/state.json`). When the default path is empty, the plugin migrates forward on first load from the legacy home path and the XDG path, then writes project-local. Explicit option/env paths are literal with no fallback; a present-but-corrupt primary is preserved. New `resolveStateFilePath` / `xdgStateFilePath` / `legacyStateFilePaths` helpers. Home-based fallback paths resolve from an injectable `env.HOME` (falling back to `os.homedir()`), making path resolution deterministic across platforms — `os.homedir()` ignores `$HOME` on macOS. Implements megalist items 6.1 and 6.2.
|
|
39
|
+
- **Expose agent-facing goal tools (`get_goal`, `get_goal_history`, `set_goal`, `update_goal`, `clear_goal`)** when the host provides `@opencode-ai/plugin` (a new *optional* peer dependency, loaded via a cached dynamic import so the zero-runtime-dependency posture is preserved). `set_goal` is constrained to explicit user requests; `update_goal` supports objective edits and complete/blocked/paused/resumed transitions. Registration is skipped gracefully when the package is absent or with `registerTools: false`. New `buildAgentToolHandlers`. Implements megalist items 7.1 and 7.2.
|
|
40
|
+
- **Add a `Publish` GitHub Actions workflow (`.github/workflows/publish.yml`) for npm Trusted Publishing (OIDC).** On a push to `main` it runs the full check matrix on Node 18/20/22, then publishes via OIDC with no stored `NPM_TOKEN`, using a publish-on-version-change model (only publishes when `package.json`'s version is new). The publish job requires `id-token: write` and is gated behind a `release` environment. First run still requires a human to publish an initial version and configure the npm Trusted Publisher. Implements megalist item 9.1.
|
|
41
|
+
|
|
42
|
+
## 0.2.0 — 2026-06-14
|
|
43
|
+
|
|
44
|
+
- **Add `/goal edit <new objective>`.** Revise the active goal's objective in place while preserving its turn/token/time budget and lifecycle history. Any pause/blocked state is cleared and `noProgressTurns` resets so the revised goal can continue; a goal already at a hard limit re-pauses on the next idle (use `/goal resume` for a fresh budget window). Ported from prevalentWare/opencode-goal-plugin's `update_goal_objective` tool, adapted to the marker-based command model.
|
|
45
|
+
- **Preserve the goal across session compaction.** A new `experimental.session.compacting` hook injects the goal objective, status, budget usage, elapsed time, and latest checkpoint into the compaction context so a compaction no longer drops the goal thread mid-run. Ported from prevalentWare/opencode-goal-plugin's `compactionContext` injection.
|
|
46
|
+
- **Disable generic post-compaction auto-continue while a goal is active.** A new `experimental.compaction.autocontinue` hook sets `enabled = false` whenever an active (non-stopped) goal is present, so OpenCode's native post-compaction continuation does not race the plugin's own idle-triggered continuation. Paused/stopped goals leave the native behavior untouched. Ported from prevalentWare/opencode-goal-plugin.
|
|
47
|
+
|
|
5
48
|
## 0.1.14 — 2026-06-12
|
|
6
49
|
|
|
7
50
|
- **Count cached context tokens in the budget.** `totalTokensForMessage` now includes `tokens.cache.read` / `cache.write` alongside `input + output + reasoning`. On providers with prompt caching (e.g. Anthropic) most of the conversation context arrives as cache reads with a tiny `input`, so the prior estimate undercounted the context window and the token budget / wrap-up could effectively never trigger.
|
package/README.md
CHANGED
|
@@ -50,7 +50,15 @@ Override limits for a single goal:
|
|
|
50
50
|
/goal fix the failing tests --max-turns 20 --max-minutes 30 --max-tokens 400000
|
|
51
51
|
```
|
|
52
52
|
|
|
53
|
-
|
|
53
|
+
Add success criteria, constraints / non-goals, and a mode:
|
|
54
|
+
|
|
55
|
+
```
|
|
56
|
+
/goal ship the release --success "tests pass and changelog updated" --constraints "do not touch the public API" --mode ordered
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
`--success` (alias `--success-criteria`) and `--constraints` (alias `--non-goals`) take quoted text and are injected alongside the objective so the assistant keeps them in view. `--mode` is `normal` (default) or `ordered` (alias `sisyphus`); `ordered` asks the assistant to work through the objective as a strict sequence. Multi-word values must be quoted.
|
|
60
|
+
|
|
61
|
+
Flags accept either `--flag value` or `--flag=value`. If a flag is unknown, missing a value, given a non-positive integer, or (for `--mode`) an unrecognized mode, the plugin rejects the command with a helpful error instead of silently folding the bad flag into the goal text.
|
|
54
62
|
|
|
55
63
|
Check status:
|
|
56
64
|
|
|
@@ -70,6 +78,14 @@ Resume a paused or stopped goal:
|
|
|
70
78
|
/goal resume
|
|
71
79
|
```
|
|
72
80
|
|
|
81
|
+
Edit the active goal's objective without losing its budget or history:
|
|
82
|
+
|
|
83
|
+
```
|
|
84
|
+
/goal edit fix the failing tests and also update the docs
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
`/goal edit <new objective>` revises the goal in place: the turn, token, and time budget plus the lifecycle history are preserved, and any pause/blocked state is cleared so the revised goal can continue. A goal that already hit a hard limit will re-pause on the next idle — run `/goal resume` for a fresh budget window.
|
|
88
|
+
|
|
73
89
|
Pause without clearing the active goal:
|
|
74
90
|
|
|
75
91
|
```
|
|
@@ -84,25 +100,55 @@ Clear the active goal:
|
|
|
84
100
|
|
|
85
101
|
`/goal stop`, `/goal off`, `/goal reset`, `/goal none`, and `/goal cancel` are aliases for `/goal clear`.
|
|
86
102
|
|
|
103
|
+
### Multiple goals
|
|
104
|
+
|
|
105
|
+
A session can hold more than one goal. `/goal <condition>` replaces the focused goal, while `/goal add <condition>` keeps the current goal (backgrounding it) and focuses a new one. Only the **focused** goal is auto-continued; backgrounded goals are paused until you focus them.
|
|
106
|
+
|
|
107
|
+
```
|
|
108
|
+
/goal add write the migration guide
|
|
109
|
+
/goal list
|
|
110
|
+
/goal focus 1
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
`/goal list` shows the numbered live goals (which is focused, which are backgrounded) and a per-session archive of completed/cleared goals so they stay readable. `/goal focus <number>` switches the active goal, backgrounding the previous one. Focus is tracked per session and survives a restart.
|
|
114
|
+
|
|
115
|
+
#### Ordered (sisyphus) sequences
|
|
116
|
+
|
|
117
|
+
`/goal sisyphus` sets up a strict execution sequence: separate the objectives with `;` or newlines, and the plugin runs them one at a time, auto-focusing the next as soon as the current one completes.
|
|
118
|
+
|
|
119
|
+
```
|
|
120
|
+
/goal sisyphus build the parser; write the tests; ship the release
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
The first goal is focused and the rest are queued. `/goal list` marks the session as ordered. Auto-promotion stops when the sequence is exhausted; `/goal clear` ends the sequence.
|
|
124
|
+
|
|
87
125
|
## How it works
|
|
88
126
|
|
|
89
127
|
1. When you set a goal, the plugin stores it in session memory and injects it into the system prompt so the assistant keeps it in view on every turn.
|
|
90
128
|
2. Each time the session goes idle, the plugin sends a continuation prompt containing the goal, the remaining budget, and a completion audit asking the assistant to verify the current state before declaring done.
|
|
91
129
|
3. The plugin stops auto-continuing when the assistant ends a response with `[goal:complete]` or `[goal:blocked]`, or when a safety limit is reached.
|
|
130
|
+
4. If OpenCode compacts the session, the plugin injects a deterministic summary into the compaction context so the goal survives the compaction and the assistant keeps the thread. The summary — objective, status, budget usage, recent checkpoints, and recent lifecycle events — is reconstructed from the plugin's persisted goal record rather than from chat memory, so it is stable and reproducible. While a goal is active, the plugin also disables OpenCode's generic post-compaction auto-continue so it does not race the plugin's own continuation.
|
|
131
|
+
3. The plugin stops auto-continuing when the assistant ends a response with a substantiated `[goal:complete]` or `[goal:blocked]`, or when a safety limit is reached. A `[goal:complete]` is only honored when it is preceded by a `[goal:evidence]` line; a `[goal:blocked]` is only honored when a concrete blocker is stated. Unsubstantiated claims are rejected and the plugin re-prompts for the missing evidence or blocker.
|
|
132
|
+
4. If OpenCode compacts the session, the plugin injects the goal objective, budget usage, and latest checkpoint into the compaction context so the goal survives the compaction and the assistant keeps the thread. While a goal is active, the plugin also disables OpenCode's generic post-compaction auto-continue so it does not race the plugin's own continuation.
|
|
133
|
+
5. If you send a message of your own while the goal is running, the plugin treats it as the latest instruction and pauses auto-continue so it does not talk over you. The plugin's own continuation prompts are ignored for this check (they are not "your" messages). Run `/goal resume` to hand control back to the goal loop.
|
|
92
134
|
|
|
93
135
|
## Completion markers
|
|
94
136
|
|
|
95
137
|
The plugin stops when it sees one of these at the end of an assistant response:
|
|
96
138
|
|
|
97
139
|
```
|
|
140
|
+
[goal:evidence] ran npm test (83 passing), verified the build output
|
|
98
141
|
[goal:complete]
|
|
142
|
+
```
|
|
143
|
+
```
|
|
144
|
+
The deploy step needs a production API token I don't have.
|
|
99
145
|
[goal:blocked]
|
|
100
146
|
```
|
|
101
147
|
|
|
102
|
-
`[goal:complete]` — goal is satisfied.
|
|
103
|
-
`[goal:blocked]` — the assistant needs input from you. The line immediately before the marker
|
|
148
|
+
`[goal:complete]` — goal is satisfied. It is **only honored when the line immediately before it (or an earlier line) begins with `[goal:evidence]` and contains a non-empty summary** of what was verified (commands run and their results, files checked). A `[goal:complete]` with no `[goal:evidence]` line is rejected, not recorded, and the plugin re-prompts for evidence. The accepted evidence is shown in `/goal status` after completion.
|
|
149
|
+
`[goal:blocked]` — the assistant needs input from you. The line immediately before the marker must explain the specific blocker; `/goal status` shows it while the goal remains in memory. A `[goal:blocked]` with no concrete blocker is rejected and the plugin keeps working.
|
|
104
150
|
|
|
105
|
-
Markers must appear on their own final line. The bracketed form is canonical, but the plugin also accepts bare `goal:complete` and `goal:
|
|
151
|
+
Markers must appear on their own final line. The bracketed form is canonical, but the plugin also accepts bare `goal:complete`, `goal:blocked`, and `goal:evidence` lines because some models omit brackets. Natural-language phrases like "goal complete" are intentionally ignored.
|
|
106
152
|
|
|
107
153
|
## Safety limits
|
|
108
154
|
|
|
@@ -122,13 +168,25 @@ Markers must appear on their own final line. The bracketed form is canonical, bu
|
|
|
122
168
|
|
|
123
169
|
**No-progress heuristic.** A low-output turn does not pause immediately anymore. The plugin pauses only after `noProgressTurnsBeforePause` consecutive *stalled* low-output turns — repeated turns with very little output and no meaningful change in the latest assistant checkpoint.
|
|
124
170
|
|
|
171
|
+
**No-tool-call heuristic.** Complementing the no-progress check, the plugin also watches for continuation turns that produce no tool calls at all (a "talk only" turn). Repeated talk-only turns usually mean the assistant is chatting to itself rather than doing work, so after `noToolCallTurnsBeforePause` consecutive tool-free continuation turns the plugin pauses. A turn that uses any tool (or delegates a subtask) resets the counter.
|
|
172
|
+
|
|
125
173
|
**Wrap-up vs. hard stop.** When a limit is reached, the plugin sends one final prompt asking the assistant to summarize what is done, what remains, and the next concrete step — rather than stopping silently. Use `/goal resume` to continue after any stop, including limit stops and no-progress pauses.
|
|
126
174
|
|
|
127
|
-
Goal state is persisted by default to
|
|
175
|
+
Goal state is persisted by default to a **project-local** path, `.opencode/goals/state.json` relative to the working directory, so goals follow the project rather than your home directory. It is only a local workflow checkpoint and is not synchronized across machines or OpenCode instances. You may want to add `.opencode/goals/` to your `.gitignore`.
|
|
176
|
+
|
|
177
|
+
The state-file location is resolved with this precedence:
|
|
178
|
+
|
|
179
|
+
1. the `stateFilePath` plugin option, if set;
|
|
180
|
+
2. the `OPENCODE_GOAL_STATE_PATH` environment variable, if set;
|
|
181
|
+
3. the project-local default `<cwd>/.opencode/goals/state.json`.
|
|
182
|
+
|
|
183
|
+
When the default path has no state yet, the plugin migrates forward from older locations on first load: the legacy `~/.opencode-goal-plugin/state.json` and the XDG path `${XDG_STATE_HOME:-~/.local/state}/opencode-goal-plugin/state.json`. An explicit `stateFilePath` or `OPENCODE_GOAL_STATE_PATH` is used literally with no migration fallback.
|
|
128
184
|
|
|
129
185
|
The state directory is created with owner-only permissions, and the JSON state file is written as `0600` because it may contain goal text, assistant checkpoints, and workflow history.
|
|
130
186
|
|
|
131
|
-
|
|
187
|
+
Alongside the state file the plugin keeps an **append-only lifecycle ledger** (`<stateFile>.ledger.jsonl`, also `0600`). Every lifecycle event — set, edit, auto-continue, pause, resume, blocked, completed, limit — is appended as one JSON line. Because the in-memory history is capped, the ledger is the durable record: if the main state file is missing or corrupted, the plugin reconstructs still-active (non-completed) goals from the ledger on startup and reloads them in the paused recovery state. Terminal events (complete/blocked) are written to the ledger *before* the main state write, so a goal's terminal outcome survives even if that write fails (**fail-closed**); such a failure is logged at error level.
|
|
188
|
+
|
|
189
|
+
Recovered active goals are loaded in a **paused** state with a recovery note, so unattended auto-continue does not resume blindly after a restart. Set `"persistState": false` to keep purely in-memory behavior (this also disables the ledger).
|
|
132
190
|
|
|
133
191
|
`/goal resume` continues the same objective with a fresh local budget window. This lets you continue after pause, blocker, no-progress pause, rate-limit failures, or a limit stop without retyping the objective.
|
|
134
192
|
|
|
@@ -142,9 +200,14 @@ Override any limit for a single goal:
|
|
|
142
200
|
| `--max-minutes <n>` | Duration limit in minutes |
|
|
143
201
|
| `--max-duration-ms <n>` | Duration limit in milliseconds |
|
|
144
202
|
| `--max-tokens <n>` | Context token limit |
|
|
203
|
+
| `--budget <n>` | Context token limit shorthand; accepts a `k`/`m` suffix (e.g. `100k`, `1.5m`) |
|
|
145
204
|
| `--cooldown-ms <n>` | Minimum delay between continues |
|
|
146
205
|
| `--no-progress-threshold <n>` | Output token floor before pausing |
|
|
147
206
|
| `--no-progress-turns <n>` | Consecutive stalled low-output turns before pausing |
|
|
207
|
+
| `--success <text>` | Success criteria that define when the goal is satisfied (quote multi-word text) |
|
|
208
|
+
| `--constraints <text>` | Constraints / non-goals to respect (alias `--non-goals`) |
|
|
209
|
+
| `--mode <normal\|ordered>` | Execution mode; `ordered` (alias `sisyphus`) asks for a strict sequence |
|
|
210
|
+
| `--no-tool-turns <n>` | Consecutive tool-free continuation turns before pausing |
|
|
148
211
|
|
|
149
212
|
Examples:
|
|
150
213
|
|
|
@@ -152,6 +215,7 @@ Examples:
|
|
|
152
215
|
/goal fix tests --max-turns 20 --max-tokens 400000
|
|
153
216
|
/goal fix tests --max-turns=20 --max-tokens=400000
|
|
154
217
|
/goal fix tests --no-progress-threshold 50 --no-progress-turns 2
|
|
218
|
+
/goal fix tests --budget 100k
|
|
155
219
|
```
|
|
156
220
|
|
|
157
221
|
### Plugin-level defaults
|
|
@@ -171,10 +235,11 @@ Pass options when registering the plugin to change the defaults for all goals. T
|
|
|
171
235
|
"maxRecentMessages": 50,
|
|
172
236
|
"noProgressTokenThreshold": 50,
|
|
173
237
|
"noProgressTurnsBeforePause": 2,
|
|
238
|
+
"noToolCallTurnsBeforePause": 2,
|
|
174
239
|
"budgetWrapupRatio": 0.8,
|
|
175
240
|
"maxPromptFailures": 3,
|
|
176
241
|
"persistState": true,
|
|
177
|
-
"stateFilePath": "/
|
|
242
|
+
"stateFilePath": ".opencode/goals/state.json",
|
|
178
243
|
"resultRetentionMs": 604800000,
|
|
179
244
|
"maxStoredResults": 200
|
|
180
245
|
}
|
|
@@ -187,12 +252,27 @@ Additional plugin-level options:
|
|
|
187
252
|
|
|
188
253
|
- `maxRecentMessages` — how many recent session messages to scan when looking for the latest assistant turn before auto-continuing. Higher values make long, tool-heavy sessions less likely to lose the most recent assistant response.
|
|
189
254
|
- `noProgressTurnsBeforePause` — grace window for low-output stalls. The plugin pauses only after this many consecutive stalled low-output turns rather than on the first one.
|
|
255
|
+
- `noToolCallTurnsBeforePause` — grace window for tool-free continuation turns. The plugin pauses after this many consecutive continuation turns that produced no tool calls (anti self-chat loop). Default `2`.
|
|
190
256
|
- `warnTurnsRemaining` / `warnDurationMsRemaining` / `warnTokensRemaining` — thresholds at which the auto-continue prompt appends a "limits are near" warning (default `3` turns, `60000` ms, `25000` context tokens). Lower them to warn closer to the limit, or raise them to warn earlier.
|
|
257
|
+
- `commandName` — the slash command the plugin owns (default `goal`). Set it to e.g. `objective` to drive the workflow with `/objective` instead of `/goal`; a leading slash is tolerated. Remember to register the matching command name in your OpenCode `command` config. User-facing hints (`/goal status`, `/goal resume`, …) follow the configured name.
|
|
258
|
+
- `registerCommand` — whether the plugin installs its `command.execute.before` hook at all (default `true`). Set it to `false` if you only want the auto-continue/persistence behavior driven programmatically and don't want the plugin to own a slash command.
|
|
191
259
|
- `persistState` — whether to persist active goals and recent goal results to disk.
|
|
192
|
-
- `stateFilePath` — where the persisted state JSON is written. Useful if you want
|
|
260
|
+
- `stateFilePath` — where the persisted state JSON is written. Overrides the default project-local path and the `OPENCODE_GOAL_STATE_PATH` env var. Useful if you want a fixed or ephemeral location. When unset, the default is `<cwd>/.opencode/goals/state.json` (see the persistence section above), and `OPENCODE_GOAL_STATE_PATH` can override it without editing config.
|
|
193
261
|
- `resultRetentionMs` — how long a completed goal summary remains available through `/goal status` after the goal leaves active memory.
|
|
194
262
|
- `maxStoredResults` — maximum number of completed-goal summaries retained in process memory before the oldest ones are evicted.
|
|
195
263
|
|
|
264
|
+
## Audit messages
|
|
265
|
+
|
|
266
|
+
When the assistant marks a goal complete or blocked, the plugin announces the audit instead of doing it silently: an audit-start message ("Auditing goal completion…") and an audit-result message ("completion accepted — goal archived" / "paused as blocked — …"). By default these are delivered through OpenCode's structured log (`client.app.log`, visible to the user). Provide an `auditMessenger(sessionID, text)` plugin option to route them elsewhere (for example into the live conversation once a suitable message API is available), or set `auditMessages: false` to disable them.
|
|
267
|
+
## Completion auditor (optional)
|
|
268
|
+
|
|
269
|
+
By default a `[goal:complete]` is accepted on the assistant's word. You can require an independent audit before a goal is archived:
|
|
270
|
+
|
|
271
|
+
- `completionAudit: true` — the plugin spawns an independent OpenCode child session to verify the completion against the goal and workspace. The auditor replies with `[audit:approved]` or `[audit:rejected]` (with a reason).
|
|
272
|
+
- `auditor: async ({ goal, sessionID, latestText }) => ({ approved, reason })` — supply your own auditor function (takes precedence over `completionAudit`).
|
|
273
|
+
|
|
274
|
+
On **approval** the goal is archived as achieved. On **rejection** the goal is *not* archived — it is paused with stop reason `audit rejected` and the reason in its status, so you can address the gap and `/goal resume`. The built-in child-session auditor fails *open* (auto-approves) if the session API is unavailable, while a custom auditor that throws is treated as a rejection (fail closed). The audit is off unless one of these options is set.
|
|
275
|
+
|
|
196
276
|
## Prompt safety
|
|
197
277
|
|
|
198
278
|
The goal text is wrapped in `<goal_objective>` tags and labeled as user-provided task data. The assistant is told to treat it as a task description, not as elevated instructions that can override system, developer, tool, or repository policies.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opencode-goal-plugin",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Session-scoped /goal workflow for OpenCode.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./src/goal-plugin.js",
|
|
@@ -47,4 +47,4 @@
|
|
|
47
47
|
"author": {
|
|
48
48
|
"name": "willytop8"
|
|
49
49
|
}
|
|
50
|
-
}
|
|
50
|
+
}
|