插件
插件允许你通过挂钩各种事件并自定义行为来扩展 OpenCode。你可以创建插件来添加新功能、与外部服务集成,或修改 OpenCode 的默认行为。
有关示例,请参阅社区创建的插件。
使用插件
有两种加载插件的方式。
从本地文件
将 JavaScript 或 TypeScript 文件放到插件目录中。
.opencode/plugins/- 项目级插件~/.config/opencode/plugins/- 全局插件
这些目录中的文件会在启动时自动加载。
从 npm
在配置文件中指定 npm 包。
{
"$schema": "https://opencode.ai/config.json",
"plugin": ["opencode-helicone-session", "opencode-wakatime", "@my-org/custom-plugin"]
}
普通包和带 scope 的 npm 包都受支持。
在 ecosystem 中浏览可用的插件。
插件的安装方式
npm 插件在启动时由 Bun 自动安装。包及其依赖会缓存在 ~/.cache/opencode/node_modules/ 中。
本地插件直接从插件目录加载。要使用外部包,你必须在配置目录中创建一个 package.json(见 Dependencies),或者将插件发布到 npm 并将其添加到你的配置中。
加载顺序
插件会从所有来源加载,所有 hooks 按顺序运行。加载顺序为:
- 全局配置(
~/.config/opencode/opencode.json) - 项目配置(
opencode.json) - 全局插件目录(
~/.config/opencode/plugins/) - 项目插件目录(
.opencode/plugins/)
同名同版本的重复 npm 包只会加载一次。但是,名称相似的本地插件和 npm 插件会作为独立的两个插件加载。
创建一个插件
插件是一个 JavaScript/TypeScript 模块,导出一个或多个插件函数。 每个函数接收一个 context 对象并返回一个 hooks 对象。
Dependencies
本地插件和自定义工具可以使用外部 npm 包。在你的配置目录中添加一个 package.json,并在其中声明你需要的依赖。
{
"dependencies": {
"shescape": "^2.1.0"
}
}
OpenCode 会在启动时运行 bun install 来安装这些依赖。之后你的插件和工具就可以导入它们了。
import { escape } from "shescape"
export const MyPlugin = async (ctx) => {
return {
"tool.execute.before": async (input, output) => {
if (input.tool === "bash") {
output.args.command = escape(output.args.command)
}
},
}
}
Basic structure
export const MyPlugin = async ({ project, client, $, directory, worktree }) => {
console.log("Plugin initialized!")
return {
// Hook implementations go here
}
}
插件函数会接收:
project:当前项目的信息。directory:当前工作目录。worktree:git worktree 路径。client:一个 opencode SDK 客户端,用于与 AI 交互。$:Bun 的 shell API,用于执行命令。
TypeScript support
对于 TypeScript 插件,你可以从插件包中导入类型:
import type { Plugin } from "@opencode-ai/plugin"
export const MyPlugin: Plugin = async ({ project, client, $, directory, worktree }) => {
return {
// Type-safe hook implementations
}
}
Events
插件可以订阅事件,订阅方式见下方 Examples 章节。下面是可用事件的列表。
Command Events
command.executed
File Events
file.editedfile.watcher.updated
Installation Events
installation.updated
LSP Events
lsp.client.diagnosticslsp.updated
Message Events
message.part.removedmessage.part.updatedmessage.removedmessage.updated
Permission Events
permission.askedpermission.replied
Server Events
server.connected
Session Events
session.createdsession.compactedsession.deletedsession.diffsession.errorsession.idlesession.statussession.updated
Todo Events
todo.updated
Shell Events
shell.env
Tool Events
tool.execute.aftertool.execute.before
TUI Events
tui.prompt.appendtui.command.executetui.toast.show
Examples
下面是一些你可以用来扩展 opencode 的插件示例。
Send notifications
在某些事件发生时发送通知:
export const NotificationPlugin = async ({ project, client, $, directory, worktree }) => {
return {
event: async ({ event }) => {
// Send notification on session completion
if (event.type === "session.idle") {
await $`osascript -e 'display notification "Session completed!" with title "opencode"'`
}
},
}
}
我们使用 osascript 在 macOS 上运行 AppleScript。这里我们用它来发送通知。
.env protection
阻止 opencode 读取 .env 文件:
export const EnvProtection = async ({ project, client, $, directory, worktree }) => {
return {
"tool.execute.before": async (input, output) => {
if (input.tool === "read" && output.args.filePath.includes(".env")) {
throw new Error("Do not read .env files")
}
},
}
}
Inject environment variables
向所有 shell 执行(AI 工具和用户终端)中注入环境变量:
export const InjectEnvPlugin = async () => {
return {
"shell.env": async (input, output) => {
output.env.MY_API_KEY = "secret"
output.env.PROJECT_ROOT = input.cwd
},
}
}
Custom tools
插件也可以向 opencode 添加自定义工具:
import { type Plugin, tool } from "@opencode-ai/plugin"
export const CustomToolsPlugin: Plugin = async (ctx) => {
return {
tool: {
mytool: tool({
description: "This is a custom tool",
args: {
foo: tool.schema.string(),
},
async execute(args, context) {
const { directory, worktree } = context
return `Hello ${args.foo} from ${directory} (worktree: ${worktree})`
},
}),
},
}
}
tool 辅助函数用于创建一个可被 opencode 调用的自定义工具。它接受一个 Zod schema 函数,并返回包含以下内容的工具定义:
description:工具的功能描述args:工具参数的 Zod schemaexecute:工具被调用时执行的函数
你的自定义工具会与内置工具一起在 opencode 中可用。
Logging
使用 client.app.log() 而不是 console.log 来进行结构化日志记录:
export const MyPlugin = async ({ client }) => {
await client.app.log({
body: {
service: "my-plugin",
level: "info",
message: "Plugin initialized",
extra: { foo: "bar" },
},
})
}
日志级别:debug、info、warn、error。详见 SDK 文档。
Compaction hooks
自定义在 session 被压缩(compact)时包含的上下文:
import type { Plugin } from "@opencode-ai/plugin"
export const CompactionPlugin: Plugin = async (ctx) => {
return {
"experimental.session.compacting": async (input, output) => {
// Inject additional context into the compaction prompt
output.context.push(`
## Custom Context
Include any state that should persist across compaction:
- Current task status
- Important decisions made
- Files being actively worked on
`)
},
}
}
experimental.session.compacting hook 会在 LLM 生成延续摘要之前触发。使用它可以注入默认压缩 prompt 可能会遗漏的领域特定上下文。
你也可以通过设置 output.prompt 来完全替换压缩 prompt:
import type { Plugin } from "@opencode-ai/plugin"
export const CustomCompactionPlugin: Plugin = async (ctx) => {
return {
"experimental.session.compacting": async (input, output) => {
// Replace the entire compaction prompt
output.prompt = `
You are generating a continuation prompt for a multi-agent swarm session.
Summarize:
1. The current task and its status
2. Which files are being modified and by whom
3. Any blockers or dependencies between agents
4. The next steps to complete the work
Format as a structured prompt that a new agent can use to resume work.
`
},
}
}
当设置了 output.prompt 时,它会完全替换默认的压缩 prompt。在这种情况下,output.context 数组会被忽略。