opencode-planner is an OpenCode plugin that adds a dedicated plan agent for read-only planning before implementation. Its functionality is an emulation of the experimental plan agent (it has no hard dependency on EXPERIMENTAL_PLAN_MODE=1, although that setting enables a tool called plan_exit which this plugin will use if available). That is, it likes to use sub-agents and a structured approach to planning, asks clarifying questions, and finally it produces a markdown file.
When Plannotator is installed, it can submit the finished plan for richer review.
Without Plannotator, it can open the plan in your configured external editor for review. A new command /edit-plan will open the plan in the editor if needed.
In either case, changes made while editing will trigger a revision of the plan.
After review, the agent can hand back to implementation mode by calling plan_exit only when the host runtime exposes that tool. In current OpenCode builds, that means experimental plan mode must be enabled and the client must be cli. If it's not enabled, you need to prompt the build agent to start work.
Repository: https://github.com/timrichardson/opencode-planner
Experimental plan mode is not a focus for the core devs, who point out that a plugin can do it, which I set out to prove, at least as a concept. This plugin means, at least for me, a development path for a stronger Plan agent independent of core OpenCode priorities.
Add this to opencode.jsonc (or opencode.json):
{
"plugin": ["opencode-planner"]
}Then restart OpenCode.
opencode-planner now publishes stable releases to latest, so the unqualified package name is the recommended install channel.
If you want reproducible installs instead of automatic plugin refreshes, pin an exact version:
{
"plugin": ["opencode-planner@0.3.1"]
}- adds a
planagent intended for design and implementation planning - constrains that agent to read-only tools plus markdown plan editing
- injects a system reminder that keeps the planning workflow explicit
- lets users replace the plugin's base
planprompt with their ownagent.plan.prompt - lets users override agent settings such as
agent.plan.modeland provider-specific options likeagent.plan.reasoningEffort - denies
submit_plan,edit_plan, andplan_exitto the built-ingeneralandexploresubagents so review and implementation handoff stay on the primaryplanagent - exposes a
planner_configtool so theplanagent can inspect planner-specific runtime and editor configuration - exposes a
plan_prompttool so theplanagent can reveal the plugin's prompt basis for customization - exposes an
edit_plantool so theplanagent can open the current plan in the configured external editor - registers an
/edit-plancommand that routes to theplanagent and asks it to calledit_plan - registers a
/planner-configcommand that routes to theplanagent and asks it to callplanner_config - uses
submit_planfor review when available, otherwise falls back to external-editor review - keeps the agent in planner mode if the plan file changed after
submit_plan; the revised plan must be resubmitted beforeplan_exit - can leave planner mode with
plan_exitafter approval when experimental plan mode is enabled in the CLI runtime (because the plan_exit tool is only available withEXPERIMENTAL_PLAN_MODEenabled; se OpenCode docs for Experiments)
If you set agent.plan.prompt, the plugin replaces its built-in base planning prompt with your text. Other agent settings, such as agent.plan.model and provider-specific options like agent.plan.reasoningEffort, are merged in normally.
{
"agent": {
"plan": {
"model": "openai/gpt-5.4",
"reasoningEffort": "high",
"prompt": "You are my planning agent. Focus on migration risk, rollout steps, and testing strategy."
}
}
}The runtime planner reminder still applies, so the agent stays in planner mode and continues to use the review handoff flow. That reminder is injected by the plugin at runtime and is not customized through agent.plan.prompt.
The plugin also adds a read-only plan_prompt tool. Ask the plan agent to use it when you want the plugin's own prompt text and planner reminder as a starting point for customization.
Example:
Use the plan_prompt tool and show me the plugin prompt so I can customize it.
The tool returns:
- the plugin base prompt
- the injected planner reminder, which is plugin-controlled runtime guidance and is not customized via
agent.plan.prompt - a short note explaining that the final runtime prompt can still differ because of user config, other plugins, or runtime tool availability like
plan_exit
The plugin also adds a read-only planner_config tool. Use it when you want to inspect planner-specific configuration, especially editor selection precedence across PLAN_VISUAL, VISUAL, and EDITOR.
In the TUI, /planner-config is the shortcut for this diagnostic flow.
Example:
/planner-config
The output includes:
- the current session plan path
- planner tool availability from the plugin's perspective
- whether
submit_planis available for Plannotator review andedit_planis available as the local-editor fallback - editor precedence:
PLAN_VISUAL->VISUAL->EDITOR - which editor variable won
- the resolved editor command
- relevant runtime flags that affect planner behavior, such as
OPENCODE_EXPERIMENTAL_PLAN_MODEandOPENCODE_CLIENT
This is the quickest way to understand why edit_plan is using a specific editor command before you try /edit-plan.
In the TUI, you can use /edit-plan as a shortcut to ask the plan agent to reopen the current plan in your configured external editor. This routes through the existing edit_plan tool behavior.
Example:
/edit-plan
This expects the current session to already have a plan file, and it still requires PLAN_VISUAL, VISUAL, or EDITOR to launch a blocking editor command.
If submit_plan is not registered by the runtime, the plugin's edit_plan tool gives the plan agent a fallback way to open the current plan in your configured external editor.
Example:
If submit_plan is unavailable, call edit_plan so I can review the plan in my editor.
If you want to reopen the same plan after an initial review pass, prompt the plan agent with something like edit the plan again externally. That will cause it to call edit_plan again and reopen the current plan in the configured editor.
When the editor closes, edit_plan compares the plan before and after editing. If nothing changed, it reports that no changes were made. If the user edited the plan, the tool returns the previous and updated plan content so the plan agent can treat that as review feedback, summarize the edits, and continue planning from the revised plan.
edit_plan uses PLAN_VISUAL first, then VISUAL, then EDITOR. PLAN_VISUAL is useful when you want planner review to use a different editor from the rest of your shell tools. The command must launch a separate process and block until editing is complete.
Compatible examples:
PLAN_VISUAL="gvim -f"VISUAL="gvim -f"EDITOR="gedit --wait"EDITOR="kate --block"EDITOR="code --wait"
These work because they open a separate editor process and do not try to take over the OpenCode TUI terminal.
If you use gVim and want a larger planner window, you can set geometry directly, for example:
PLAN_VISUAL="gvim -f -geometry 120x100"
That opens gVim in the foreground with a window that is roughly 120 columns wide and 100 lines tall.
Bare terminal editors like vim or nvim are not sufficient on their own because the plugin does not hand the current TUI terminal over to the editor. If you want to use them, wrap them in a terminal-emulator command that opens a new window and waits for it to exit.
Examples:
EDITOR="gnome-terminal --wait -- nvim"EDITOR="kitty --wait nvim"- a small wrapper script for your terminal emulator that launches
vimornvimin a separate window and blocks until it exits
If edit_plan fails, the plan agent should fall back to telling you the plan file path and asking for review in chat.
If you edit the plan after calling submit_plan, the plugin treats that as a new draft. In that case the agent should stay in planner mode and call submit_plan again before plan_exit.
OpenCode installs and updates npm plugins automatically. opencode-planner tracks @latest by default, which is the recommended channel for most users.
@latest: pick up stable plugin versions on restart- exact version pin: stay fixed until the config is changed deliberately
If OpenCode appears to keep an older cached plugin, clear the cache under ~/.cache/opencode/ and restart.
npm test
npm run debug:plan
npm run opencode:no-plannotator -- debug confignpm run debug:plan checks the active OpenCode runtime and reports whether the local repo plugin is loaded, whether planner_config, plan_prompt, edit_plan, submit_plan, and plan_exit are allowed by the plan agent, and whether they are actually registered as runtime tools.
This is the fastest way to distinguish:
- prompt/config issues inside this repo
- runtime tool-registration issues in OpenCode or Plannotator
To test this plugin without the globally installed Plannotator plugin, use the sandbox launcher:
npm run opencode:no-plannotatorIt starts OpenCode with an isolated temporary home/config, keeps the local repo plugin loaded, and filters out @plannotator/opencode from the plugin list without changing your real global config.
- Update
CHANGELOG.md. - Bump the version in
package.json. - Commit the release.
- Create and push a git tag like
v0.3.1for the release. - Let GitHub Actions publish to npm
latest. - Publish matching GitHub release notes.
The repository includes GitHub Actions templates for CI and npm publishing from version tags.
Configure npm Trusted Publishing for this package:
- Open the
opencode-plannerpackage settings on npm. - Add a GitHub Actions trusted publisher.
- Use:
- GitHub user/org:
timrichardson - Repository:
opencode-planner - Workflow filename:
release.yml
- GitHub user/org:
The release workflow publishes stable tags like v0.3.1 to npm latest and creates matching GitHub release notes automatically.
Trusted Publishing uses GitHub OIDC and does not require an NPM_TOKEN secret for publishing.
MIT