Load plugins
Plugins can be loaded from npm packages, explicit local paths, or config directories. Each module must have one default export containing a unique pluginid and a setup function.
Configuration
Add ordered entries to theplugins field in opencode.json(c):
opencode.jsonc
./ or ../ and resolve relative to the configuration file containing
the entry. Absolute paths and file:// URLs are also supported. Both scoped
packages and versioned package specifiers are supported.
Use the object form to pass JSON configuration to the plugin. OpenCode passes
options unchanged as ctx.options; omitted options become an empty object.
The plugin owns validation and defaults for its options.
See Config for configuration locations and precedence.
Entries from all applicable files are processed from lowest to highest
precedence rather than replacing the entire array.
Local discovery
OpenCode automatically scans this directory in every discovered OpenCode config directory:~/.config/opencode/plugins/. Direct .ts
and .js children are loaded. An immediate child directory is also loaded as a
package when OpenCode can resolve a string exports, module, or main
entrypoint, or an index.ts or index.js file.
A plugins/ directory beside a project-root opencode.json is not discovered
automatically. Put it under .opencode/, or add its file explicitly with a
relative config entry.
Enable and disable
A string beginning with- disables plugins by their exported id. *
matches every ID, and a suffix of .* matches an ID prefix. Directives are
applied in order:
opencode.jsonc
id from the plugin’s default export to disable it. A later
ID entry re-enables a loaded or built-in plugin. Explicit config directives run
after local auto-discovery, so they can disable discovered plugins by ID.
User plugins are activated in configured order between OpenCode’s internal
plugin phases. Hooks run sequentially in registration order, and later hooks
observe earlier mutations. Do not depend on the internal phase ordering while
the API is beta.
Installation and dependencies
OpenCode installs bare package entries and their production dependencies into an isolated cache. Package installation does not run lifecycle scripts. Published packages should expose their plugin entrypoint and include every runtime import independencies.
Local files and local package directories are imported directly. OpenCode does
not install their dependencies. Install dependencies in a package.json
visible from the plugin file, for example:
Create a plugin
Export the result ofPlugin.define as the module default:
.opencode/plugins/reviewer.ts
setup runs each time the plugin is activated. Register long-lived behavior
during setup; do not wait there on an infinite event stream.
Context
The plugin context is essentially an OpenCode server client. Its read and action methods use the same inputs and responses as the client. It adds plugin-only methods for transforms, runtime hooks, reloads, registrations, and plugin options.| Capability | Available operations |
|---|---|
ctx.agent | list, transform, reload |
ctx.catalog.provider | list, get |
ctx.catalog.model | list, default |
ctx.catalog | transform, reload |
ctx.command | list, transform, reload |
ctx.integration | list, get, connect, attempt, transform, reload, and connection lookup/resolution |
ctx.plugin | list currently active plugin IDs |
ctx.reference | list, transform, reload |
ctx.session | create, get, prompt, command, interrupt, and hook |
ctx.skill | list, transform, reload |
ctx.tool | transform and hook |
ctx.aisdk | hook |
ctx.event | subscribe to the current public server event stream |
ctx.options | Readonly options from the matching config object |
Transform hooks
Transform hooks let a plugin modify how OpenCode is configured. Use them to add or remove definitions, override settings, choose defaults, and provide tools or other sources.| Transform | Draft operations |
|---|---|
agent.transform | list, get, default, update, remove |
catalog.transform | Provider list, get, update, remove; model get, update, remove; default model get, set |
command.transform | list, get, update, remove |
integration.transform | Integration list, get, update, remove; method list, update, remove |
reference.transform | add, remove, list |
skill.transform | source, list |
tool.transform | add |
.opencode/plugins/remote-models.js
ctx.catalog.reload() replays every catalog transform to derive the new
catalog. Each plugin’s logic remains composed with the others, so a later
plugin can still modify models added by an earlier one. The catalog updates
without restarting OpenCode.
Runtime hooks
Runtime hooks intercept live operations. Their event objects expose specific mutable fields:| Hook | Mutable fields |
|---|---|
ctx.aisdk.hook("sdk", callback) | sdk, after inspecting model, package, and options |
ctx.aisdk.hook("language", callback) | language, after inspecting model, sdk, and options |
ctx.session.hook("request", callback) | system, messages, and the tools record immediately before model dispatch |
ctx.tool.hook("execute.before", callback) | input, before the selected tool executes |
ctx.tool.hook("execute.after", callback) | result, output, and outputPaths, after execution settles |
.opencode/plugins/guards.ts
Examples
Add a tool
Pass a tool declaration totools.add. Define its input with JSON Schema and
use an async executor:
.opencode/plugins/greeting.js
options on the declaration to
configure registration with { group, deferred }:
groupprefixes and groups the exposed tool name.deferred: truemakes the tool available through the deferredexecutetool instead of exposing it directly.
sessionID,
agent, assistantMessageID, and toolCallID.
Add a command
.opencode/plugins/review-command.js
Set the default model
.opencode/plugins/default-model.js
Publish a package
A package plugin uses the same default export as a local plugin. A minimal manifest is:package.json
Verify loading
List active plugin IDs through the V2 API:Effect
OpenCode provides a first-class Effect API for plugins through the@opencode-ai/plugin/v2/effect entrypoint. Install effect alongside the
plugin package and export an effect function instead of setup:
.opencode/plugins/reviewer-effect.ts
ctx.
Typed tools can use Schema from effect and the contracts exported from
@opencode-ai/plugin/v2/effect/tool. Their executors return an Effect and may
fail with the typed tool failure channel.