Goal mode for OpenCode, with an evidence gate and one pinned beta
OpenCode goal plugin for Codex-style goal mode, /goal slash commands, persistent objectives, and AI coding agent focus.
At a glance
- What is it?
- opencode-goal-plugin gives an OpenCode session a /goal command, per-session goal state that survives compaction, and a close rule that demands evidence. It also splits its configuration across two incompatible formats and pins its OpenCode 2 support to a single beta build.
- Who is it for?
- Adopt this plugin if you run long unattended OpenCode sessions and want a stop condition that is evidence rather than a feeling, and accept that both the goal state and the auto-continuation budget live on disk in your session directory. Skip it if your workflow needs a different plugin contract per OpenCode preview, because the OpenCode 2 path is pinned to beta-19425 and quietly loses compaction context on older builds.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 5 days ago.
- What is it written in?
- Mainly TypeScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 1, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The config key changes name between OpenCode 1 and OpenCode 2
Two versions of the host, two configuration formats, and the project tells you not to mix them. On OpenCode 1 the plugin goes into a `plugin` key, and it has to go into two files. The current project install is one command:
opencode plugin @prevalentware/opencode-goal-pluginThe global form adds a flag:
opencode plugin -g @prevalentware/opencode-goal-pluginOpenCode writes the package into the server and TUI config targets on its own. For a manual install, both files carry the same array. `opencode.json` takes the server side:
{
"plugin": ["@prevalentware/opencode-goal-plugin"]
}`tui.json` takes the terminal side:
{
"plugin": ["@prevalentware/opencode-goal-plugin"]
}On OpenCode 2 the key becomes `plugins`, and the second file moves to the global CLI config, because OpenCode 2 does not read `tui.json` at all. `opencode.json`:
{
"plugins": ["@prevalentware/opencode-goal-plugin"]
}`~/.config/opencode/cli.json`:
{
"plugins": ["@prevalentware/opencode-goal-plugin"]
}The server entrypoint comes from the project file, the sidebar and palette integration from the global one. Miss the rename and the plugin loads on one surface and not the other.
One goal can spend 200,000 tokens and half an hour
The options are where the real cost of goal mode becomes visible. OpenCode 2 uses an object form with the package name and an options block:
{
"plugins": [
{
"package": "@prevalentware/opencode-goal-plugin",
"options": {
"auto_continue": true,
"max_auto_turns": 25,
"locale": "zh-CN",
"default_token_budget": 200000,
"restricted_agents": ["plan"]
}
}
]
}Read those numbers as a ceiling per objective rather than a suggestion. A goal may run 25 automatic turns against a 200,000 token budget and a 1,800 second duration limit. The OpenCode 1 example adds more: `max_turn_time` at 300 seconds a turn, `max_task_block_seconds` at 900, `max_prompt_failures` at 3, `min_continue_interval_seconds` at 3, and a no-progress brake made of `no_progress_token_threshold` at 50 tokens and `max_no_progress_turns` at 2. That brake is the part worth understanding, because a goal that stops making progress pauses instead of burning its budget.
One detail will surprise an English-reading user. The example sets `locale` to `zh-CN`, and the shipped defaults keep it there. Plan-mode safety rides on `restricted_agents`, and the OpenCode 1 example in the documentation is cut off mid-key at `allow_goal_execution_from_plan`, so the full option list is not visible there.
Eleven agent tools, four of which sound interchangeable
The plugin exposes eleven agent tools: `get_goal`, `get_goal_history`, `list_all_goals`, `create_goal`, `set_goal`, `update_goal_objective`, `update_goal_status`, `update_goal`, `stop_goal`, `replace_goal` and `clear_goal`. The documentation lists them without saying when an agent should reach for `create_goal` rather than `set_goal`, or what `replace_goal` does that `update_goal` does not. An agent picking between four similarly named mutators is guessing, and the guess leaves no trace in the transcript.
The close rule is the part with teeth. A goal cannot be marked `complete` without verified evidence, and `unmet` requires a concrete blocker. That is a different contract from a task list, where an item can be ticked and forgotten. State persists per session with history, checkpoints, budgets, and file permissions set to owner-only, which means the record of how a goal reached its verdict sits on disk next to the session.
Three slash commands sit above all that: `/goal <objective>` to set one, `/pause_goal`, and `/resume_goal`. They are registered as OpenCode commands, so they surface on the TUI, desktop, web, and remote integrations that expose the server command catalog.
Plan mode stays paused, and auto-continue cannot switch agents
Auto-continuation is the feature that surprises you first, because it fires on `session.idle` and `session.status` and starts another turn without you asking. The project fences it in three ways, and the fences are worth reading as a specification of what the plugin will not do.
Goals created from the `plan` agent stay paused. The `restricted_agents` list in the configuration defaults to `plan`, so a planning session cannot be dragged into execution by the idle hook. Auto-continue never escapes a Plan-mode session, and it never switches agents on its own. Both are the kind of guarantee that only exists because the continuation is driven by the plugin rather than by the model, which is also why a prompt-level convention cannot make the same promise.
`defer_while_tasks_active` closes the remaining gap. When it is on, the next goal prompt waits for active OpenCode Task child sessions and their orchestrator reconciliation, and a deferral re-checks child sessions on a short timer. Both it and `auto_continue` are listed as `true` by default, which means the aggressive behaviour is what you get without configuring anything.
Compaction context disappears without warning on older betas
Goal compaction context is injected through the V2 `session.compaction` hook, which is how an active goal survives OpenCode summarizing a long conversation. The hook exists only on hosts newer than beta-19425. On older builds the registration degrades to a no-op, and nothing warns you at install time.
That is the pattern to watch in this plugin: a feature is described in the capability list, then quietly disappears depending on the host build. The pinned contract is `0.0.0-beta-19425`, described as the current `@opencode/cli@beta` / `@opencode/plugin@beta` contract, and the plugin APIs are still beta by the project's own admission. Later previews may require a compatible plugin update.
The support claim is also scoped to a branch rather than to the tags. Releases from the `feat/v2-adaptation` line are the ones documented as supporting OpenCode 2 beta while staying compatible with OpenCode 1. The default branch of this repository is `main`, and the published versions in recent history are v0.1.51, v0.1.52, and v0.1.53, without a statement of which line produced them. If you need OpenCode 2 support, that is the first thing to ask the maintainer.
After a restart, deferral state is rebuilt from transcripts
Task-subagent deferral does not survive a restart cleanly on OpenCode 2, and the plugin works around it in a way worth understanding. The V2 plugin context exposes no live child-session query, so after a plugin or server restart the plugin replays each non-closed goal session's persisted transcript to rebuild its deferral state.
Replay is an approximation. A child session that leaves no finalized tool entry in the transcript is not recovered at all, and is observed only through live events once it starts doing something. So a goal that was waiting on a task before the restart can wake up and send its next prompt while that child is still running, because the record of the child was never written down.
This is the same mechanism that carries your goal history, checkpoints, and budget accounting, which is the trade-off: persistence through transcripts instead of a live query, with an accuracy loss exactly at the moment a restart makes stale state dangerous. `defer_while_tasks_active` is documented as `true` by default, so this is the default path.
The TUI entrypoint ships as raw TypeScript
The export map splits the package in two. The server entry is compiled, with `"./server"` pointing at `./dist/server.js`, while `"./tui"` points straight at `./src/tui.ts`. The `files` list ships `dist`, `src/tui.ts`, `src/i18n.ts`, `LICENSE`, and `README.md`. Your host compiles the TUI side at load time while the server side arrives as a bun-targeted bundle, built with `@opencode-ai/plugin`, `effect`, and `zod` marked external. Those three sit in `dependencies` at `^1.17.1`, `^3.21.2`, and `^4.1.8`, and the TUI peer requirements are `@opentui/solid` at `>=0.5.8` and `solid-js` at `>=1.9.0`.
Contributor tooling follows the same split. `bun.lock` and `bunfig.toml` sit at the root, `test` runs `bun test`, and `prepublishOnly` runs the tests and then the build. A `dist/` directory is committed at the top level as well as listed in `files`.
The version field is the odd one out. `package.json` says `"version": "0.1.1"` while the tagged releases are v0.1.51 through v0.1.53, and `scripts/` holds `resolve-ci-version.ts` next to `smoke-v2-lifecycle.ts`. So the version is resolved outside the file, and the number you read in the repository is not the number you install.
A goal skill gets you the prompt, not the enforcement
The alternative worth naming is not another plugin, it is the shape people search for when they type an OpenCode goal skill into a search engine: a written convention in the system prompt or a skill file that tells the model to hold one objective until it is done.
The difference is enforcement, not wording. A prompt-level goal can be forgotten after a compaction, cannot refuse to mark itself complete, has no state file to audit, and cannot fire on `session.idle` because nothing is listening to that event. This plugin owns tools, hooks, a session command catalog, and owner-only state on disk, which is what makes the evidence rule and the Plan-mode fence real rather than advisory. What you give up for that enforcement is host compatibility: a plugin compiled against a beta contract breaks when the host moves, while a prompt convention keeps working through every upgrade.
If your sessions are short and a human watches every turn, the lighter option is enough. If a session runs unattended for half an hour against a 200,000 token budget, the state has to live somewhere the model cannot overwrite, and that is the argument for a plugin.
Editorial conclusion
Adopt this plugin if you run long unattended OpenCode sessions and want a stop condition that is evidence rather than a feeling, and accept that both the goal state and the auto-continuation budget live on disk in your session directory. Skip it if your workflow needs a different plugin contract per OpenCode preview, because the OpenCode 2 path is pinned to beta-19425 and quietly loses compaction context on older builds. First check: open the goal state directory and confirm the files carry owner-only permissions before you let an agent write 200,000 tokens against one objective.
Frequently asked questions
Does OpenCode have a goal mode?
Not in the base install as this project describes it. The plugin adds it, registering /goal <objective>, /pause_goal, and /resume_goal as OpenCode commands, alongside tools such as create_goal, update_goal_status, and clear_goal.
How do I install opencode-goal-plugin on OpenCode 1?
Run opencode plugin @prevalentware/opencode-goal-plugin for the current project, or opencode plugin -g @prevalentware/opencode-goal-plugin for a global install. A manual install puts the package into both opencode.json and tui.json under the plugin key.
Does opencode-goal-plugin work with OpenCode 2?
Releases from the feat/v2-adaptation line support OpenCode 2 beta 0.0.0-beta-19425 and stay compatible with OpenCode 1. OpenCode 2 does not read tui.json; the server entry comes from opencode.json and the sidebar and palette from ~/.config/opencode/cli.json.
What happens when a goal is marked complete?
A goal cannot be closed as complete without verified evidence, and unmet requires a concrete blocker. Goal state is persisted per session with history, checkpoints, budgets, and owner-only file permissions.
How much work can one goal do by default?
The example configuration sets default_token_budget to 200000, max_goal_duration_seconds to 1800, and max_auto_turns to 25 with auto_continue enabled. The defaults list names auto_continue and defer_while_tasks_active as true, and then the documentation is cut off.
Does deferral state survive an OpenCode restart?
On OpenCode 2 it is rebuilt by replaying each non-closed goal session's persisted transcript, because the V2 plugin context exposes no live child-session query. Children that leave no finalized tool entry in the transcript are observed only through live events.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/prevalentware-opencode-goal-plugin)