Simple, native Goal Mode for OpenCode.
One primary agent, one small server plugin, three tools — no npm sidebar, no command guard, no reviewer army.
You pick the goal agent and give a real task. When the work deserves a finish line, the agent calls goal_set with a verifiable condition (tests green, file exists, command output shows X).
After each turn the session goes idle. A separate evaluator model reads the transcript and answers:
- YES — condition met → goal cleared, loop stops
- NO — not yet → plugin sends a short continuation prompt and the goal agent keeps going
That is the whole product: work → idle → judge → continue or stop.
Casual chat without goal_set behaves like a normal agent — no hidden loops.
OpenCode already knows how to load this. You only need files under your config directory:
~/.config/opencode/
agents/goal.md # primary agent (goal_set / goal_clear / goal_status via tools)
plugins/goal-mode.js # server plugin entry
plugins/goal-mode/ # plugin implementation
opencode.jsonc # register the plugin (see below)
No TUI plugin. No tui.json entry for goal mode. The plugin id is opencode-goal-mode (server only).
In opencode.jsonc (paths relative to that config dir):
evaluatorModel is optional — empty means reuse the same model as the goal session.
npm install -g opencode-goal-modeThe post-install step prints a one-liner. Run it:
opencode-goal-mode-install --global --link # symlinks (recommended)
# or
opencode-goal-mode-install --global # copy installRestart OpenCode.
opencode-goal-mode-install --global --uninstall # removes only files it owns
npm uninstall -g opencode-goal-modeIf you manually added files later, delete them from ~/.config/opencode/agents/ and ~/.config/opencode/plugins/.
node scripts/install.mjs --global --link # symlinks
node scripts/install.mjs --global # copy + manifestSame uninstall command works.
- Open OpenCode TUI (or
opencode run -a goal "…"). - Agent goal (Tab if needed).
- Describe work; the agent calls
goal_setwith a measurable condition when there is a real finish line. - Agent uses normal tools (bash, edit, …); no slash command — only tools + this agent.
- Let turns complete; auto-continue only happens while a condition is active on the goal agent.
goal_clearor “stop the goal” ends the loop.
Plugin tools: goal_set, goal_clear, goal_status.
Good conditions can be checked from the conversation: command exit codes, test output, file contents.
See CUSTOMIZE.md. Short version:
| Key | Default | Meaning |
|---|---|---|
enabled |
true |
Master switch |
evaluatorModel |
(session model) | provider/model for YES/NO |
maxTurns |
0 |
Cap auto-continues (0 = unlimited) |
noProgressLimit |
3 |
Pause if evaluator repeats the same NO |
abortSuppressMs |
120000 |
After user cancel, no auto-continue |
idleGraceMs |
1200 |
Wait after idle before evaluating |
completionMarker |
Goal Completed |
Fallback if evaluator unavailable |
Environment: GOAL_MODE_* mirrors keys (GOAL_MODE_EVALUATOR_MODEL, etc.).
Read GOAL.md for the user-facing walkthrough, or ARCHITECTURE.md for hooks and code layout.
npm test
npm run lintIsolated test harness: goal-mode-opencode-test-instance/opencode-test.sh (see that folder’s NOTES.md).
- Tag a release:
git tag -a vX.Y.Z -m "..." && git push origin vX.Y.Z - The
publish.ymlworkflow runs on the tag and publishes to npm with provenance. - README + package.json already expose the
opencode-goal-modeandopencode-goal-mode-installbins.
MIT
{ "plugin": [ [ "./plugins/goal-mode.js", { "evaluatorModel": "your-provider/your-model-id" } ] ], "default_agent": "goal" }