Writing an opencode plugin
AdvancedLast updated: Oct 21, 2026
opencode plugins are JavaScript/TypeScript modules that hook into agent events and customize behavior — add tools, transform tool calls, inject context, react to session events. The official docs list a growing plugin ecosystem; this is how you join it.
Where plugins live
Two loading paths:
- Local files —
~/.config/opencode/plugins/(global) or.opencode/plugins/(project). Loaded directly. - npm packages — listed in
opencode.json; installed automatically with Bun at startup and cached under~/.cache/opencode/node_modules/:
{ "plugin": ["opencode-copilot-plugin", "@my-org/custom-plugin"] }
The module shape
A plugin exports one or more plugin functions. Each receives a context object and returns a hooks object:
export const MyPlugin = async ({ project, client, $, directory, worktree }) => {
console.log("Plugin initialized!")
return {
// hook implementations
}
}
The context gives you:
project— current project infodirectory— current working directoryworktree— git worktree pathclient— an opencode SDK client$— Bun’s shell API for running commands
Hooks and events
Hooks include tool interception points like tool.execute.before — e.g. sanitize a shell command before it runs:
import { escape } from "shescape"
export const Escape = async (ctx) => ({
"tool.execute.before": async (input, output) => {
if (input.tool === "shell") output.args.command = escape(output.args.command)
},
})
An event hook subscribes to lifecycle events — command.executed, file.edited, file.watcher.updated, installation.updated, session/permission events and more (full list in the plugins doc; newer events include lsp.*, message.*, tui.* and tool.execute.after).
Dependencies and TypeScript
Local plugins can use npm packages: drop a package.json in your config directory (.opencode/package.json) and opencode runs bun install at startup.
For types, import Plugin from the official package:
import type { Plugin } from "@opencode-ai/plugin"
export const MyPlugin: Plugin = async ({ project, client, $, directory, worktree }) => ({
// type-safe hooks
})
Publishing
- A minimal plugin is a single
.ts/.jsfile exporting aPluginfunction — no scaffolding required; browse a small published plugin on the ecosystem page for a working skeleton. - Ship on npm as
opencode-*(or a scoped name) so users can add it via thepluginconfig array — no manual install step. - Real examples to study:
opencode-pty,opencode-dynamic-context-pruning,opencode-supermemoryon the ecosystem page.