Imported from mcrescenzo/opencode-goals (
AGENTS.md). Install upstream withnpx skills add mcrescenzo/opencode-goals. Copyright stays with the author.
Goals Plugin Notes
Declared contract floor: @opencode-ai/plugin@1.17.7 (range: ^1.17.7)
Resolved contract cell: @opencode-ai/{plugin,sdk}@1.17.14
Verified live host: opencode 1.18.13
- This directory is its own git repo; commit plugin code and tests here.
- The
/goalcommand is self-registered from bundledcommands/goal.md; interception is enabled only while the live definition remains exactly equivalent. Duplicate factories deduplicate each host invocation, while foreign or legacy parent definitions are preserved and diagnosed for migration. - The root
package.jsondeclares@mcrescenzo/opencode-goalsand thetestscript; the tracked CI workflow runs Bun install, Node syntax checks,npm test, andnpm pack --dry-run --json. There is no separate linter, formatter, or typecheck config in this plugin repo. Use plain Node for tests. - Run the full local suite with
node --test tests/*.test.mjsfrom this directory (also wired asnpm test); focused regression files now includetests/goals-plugin.test.mjs,tests/goal-state-lifecycle.test.mjs,tests/runtime-controller.test.mjs,tests/automation-admission.test.mjs,tests/runtime-lifecycle.test.mjs,tests/sdk-adapter.test.mjs,tests/diagnostics.test.mjs, andtests/parser-redaction.test.mjs. - Shared test factories live in
tests/helpers.mjs; keep broad cross-domain helpers there rather than redefining them in individual test files. Raw state/tombstone/queue setup is confined to its__goalsTestSupport-backed fixtures. - Import behavior from its owning module: state lifecycle from
goal-state.js, host coordination fromgoal-runtime.js, session calls fromopencode-session-adapter.js, neutral admission fromautomation-admission.js, and remaining orchestration helpers fromgoals-core.js. Do not add forwarding exports back togoals-core.jsfor tests. .opencode/,node_modules/, logs, and other local dev/agent-tooling state are intentionally ignored by this repo (see.gitignore).- Runtime
/goalstate is written per workspace under.opencode/goals/state.json,.opencode/goals/state.json.ledger.jsonl, and.opencode/goals/cycles.jsonl; neutral cross-plugin admission state is under.opencode/automation-admission/v1/. Do not treat those files as source fixtures unless a test creates them in a temp directory. - The plugin defines canonical hidden agents
mcrescenzo-opencode-goals-evaluator-v1(all tools denied) andmcrescenzo-opencode-goals-researcher-v1(read-only with secret-path deny rules). During the compatibility release it conditionally registers the generic legacy aliases, but internal work routes only to the canonical IDs. - Hidden-agent behavior depends on opencode SDK message/event shapes; when fixing transcript, permission, diff, or tool-result bugs, ground fixtures in the exact installed generated contract and keep handcrafted/injected-client evidence distinct from packed live-host evidence.
- SDK contract direction (re-verified 2026-08-05, goals-woil.15-.17): the verified cell is opencode CLI
1.18.13with installed@opencode-ai/{plugin,sdk}1.17.14; the public plugin range remains^1.17.7. The installed SDK includes generated v1 (dist/gen/) and v2 (dist/v2/gen/) contracts. Source imports no@opencode-ai/*module directly;@opencode-ai/pluginis the sole runtime dependency and@opencode-ai/sdkis a direct development dependency for contract tests. Session-client calls go throughopencode-session-adapter.js, which prefers the generated v2 option-object path shapepath:{sessionID}and falls back only on request-shape incompatibility to the observed injected v1 plugin-client shapepath:{id}. Keep generated-v1-shaped payload defenses unless the runtime contract is proven otherwise: assistant agent identity ininfo.mode,ToolStateCompletedinput/output understate,FileDiff = {file,before,after,additions,deletions}with nopatch, and permission eventspermission.updated/permission.replied. - After changing this plugin or the parent slash-command docs/config, restart opencode; running sessions keep already-loaded plugins, commands, agents, and instructions.
Hooks
goals.js wires exactly six hooks on the plugin factory it exports
(GoalPlugin):
| Hook | What it does here |
|---|---|
dispose |
Reference-counts factories by canonical workspace scope. Non-final duplicate disposal is inert toward shared work; final disposal cancels scoped controllers/timers, detaches bounded queues and diagnostics, and drops only transient in-memory state while leaving durable goal files reloadable. |
config |
Self-registers the /goal command and collision-safely registers the canonical evaluator (all tools denied) and researcher (read-only, secret-path denies), plus temporary compatibility aliases when safe. |
"chat.message" |
Tracks the human-authored build turn's agent/model and, on a genuine human message during an active goal, marks the goal human-interrupted so auto-continuation yields to the user. |
"command.execute.before" |
Intercepts the /goal command (set, status, pause, resume, clear, etc.) before it reaches the model and replaces the turn's parts with the plugin's own output. |
event |
Fire-and-forget session-event listener: records permission/question identities in both Goals state and the neutral root-session admission record, pauses on rejections and session errors, and triggers hidden evaluation on session idle. |
"experimental.session.compacting" |
Injects a deduplicated goal-state context block into the compaction prompt so an active goal survives context compaction. |
opencode compatibility
The plugin targets Node.js >=20.11.0 and the current/latest opencode
session-client contract checked during release preparation (opencode --version
observed as 1.18.13). Its source imports no @opencode-ai/* module directly;
@opencode-ai/plugin is declared only to pin the host contract version.
Session client calls prefer the v2 option-object shape path: { sessionID }.
Because the installed @opencode-ai/sdk/@opencode-ai/plugin 1.17.14 cell
still shows an injected v1-style plugin client requiring path: { id }, the adapter
falls back to that observed v1 path shape only for request-shape incompatibility
errors. Message, tool-result, and diff parsing also retains compatibility with
observed v1 payloads such as assistant agent identity in info.mode, tool
input/output under state, and FileDiff records with before/after.