Files
xiaoshuai 15a1bbcee0 Version OpenCode skills and plugins
Repository sits at the OpenCode config root rather than inside skills/ or
plugins/. OpenCode scans exactly those two subdirectories, and a .git
directory inside either one is picked up as a plugin and fails to load:

  loading plugin id=.../plugins/.git entrypoint=.../plugins/.git/index
  failed to load plugin ... AggregateError: 2 errors building .../plugins/.git/index

The watcher.ignore config option does not help: it only suppresses filesystem
update events, not plugin discovery, and the "-" disable prefix only applies to
plugins listed in opencode.json(c), not auto-discovered ones.

.gitignore admits only skills/ and plugins/ (plus itself). Personal config
(opencode.jsonc, cli.json, service.json) and node_modules stay local.

skills/opencode-plugins  V2-only plugin authoring reference and 7 templates,
                         transcribed from the V2 docs with the URL on every file
plugins/searxng-search   searxng_search tool over a self-hosted SearXNG JSON API
2026-10-08 13:12:10 +08:00

4.4 KiB

Templates

Starter files transcribed from the OpenCode V2 doc pages. Copy one and fill in the blanks rather than writing a plugin from scratch.

Template Use for Source doc
promise-plugin.ts Server plugin, Promise flavor (default) https://opencode.ai/v2/docs/build/plugins
effect-plugin.ts Server plugin, Effect-native https://opencode.ai/v2/docs/build/plugins/effect/
rpc.ts RPC contract, Promise flavor (copy to src/rpc.ts) https://opencode.ai/v2/docs/build/plugins/rpc/
rpc-implementation.ts RPC registration + calls, Promise https://opencode.ai/v2/docs/build/plugins/rpc/
rpc-effect.ts RPC contract, Effect flavor https://opencode.ai/v2/docs/build/plugins/effect/rpc/
rpc-implementation-effect.ts RPC registration + calls, Effect https://opencode.ai/v2/docs/build/plugins/effect/rpc/
tui-plugin.tsx TUI / CLI plugin https://opencode.ai/v2/docs/build/plugins/cli/
opencode-plugin-config.jsonc plugins in opencode.json(c) https://opencode.ai/v2/docs/plugins
package.json Publishing a plugin package (strict JSON) https://opencode.ai/v2/docs/build/plugins
package-json.md Publishing guidance, peer deps, entrypoints build/plugins, build/plugins/effect, build/plugins/cli
README.md This index —

package.json is strict JSON with no comments, because Node, bun, npm, and bundlers parse it with a strict parser. Publishing guidance therefore lives in package-json.md rather than inside the manifest.

The two RPC template pairs are not interchangeable: same contract shape, different schema dialect, handler signature, and registration entrypoint. See the Promise-vs-Effect table in ../references/rpc.md.

Before you write code

  1. Check the version: opencode --version, opencode api get /api/info.
  2. Pick the flavor. Default to Promise. Effect only if the project already uses Effect. TUI is a separate export. RPC is a contract plus a registration.
  3. Open the source doc in the table above and keep it open.
  4. Copy the template. Delete the sections you do not need.
  5. Verify every field name against that page. Do not guess.

Rules the templates encode

These are the constraints the pages state, not stylistic preferences. Note which are type-level rather than documented runtime failures.

  • A transform callback is typed (editor) => void in both flavors — no Promise, no Effect.
  • Tool update preserves name and namespace. Assign a new schema or options object to replace one rather than mutating nested values. In-place edits inside an update callback are fine — that is what the mutable draft is for.
  • reload() replays transforms. It does not rerun setup / effect.
  • Captured inputs are not watched. Load external data before the sync callback, then call reload() when it changes.
  • Use the effective tool name — including its namespace — for update and remove (example_greeting, not greeting). Only add creates a tool.
  • A context hook covers the agent loop only. Register each request kind you actually need.
  • Result shape is per operation, not per flavor: storage.get returns a value, model.list() is enveloped. Copy the page's example for the call you use.
  • Effect plugins use effect, not setup. The two flavors do not have the same context members or the same hook set.
  • Relative plugin paths in config resolve from the config file, not the working directory.
  • Registering an event subscription without tearing it down leaks it. forkScoped handles this in Effect; AbortController in Promise.
  • package.json must be strict JSON — // comments there break bun, npm, and every bundler. opencode.jsonc may use them.

Anything not in a template

The pages carry more detail than fits here. When you need something not in these files, go to the source doc rather than improvising:

  • Every Agent.Info, Provider.Info, Model.Info, Session.Info, Tool.Content, Mcp.Server, Skill.Info, Vcs.Info, Reference.Info, Integration.Info, Connection.Info, Form.Answer, Command.Info, Plugin.Info, WebSearch.*, Worktree* shape: https://opencode.ai/v2/docs/api
  • The exact contract of the running server: /openapi.json on that server.
  • Hook event fields: the Reference code block at the end of each section on the relevant page.