Appearance
OpenCode 插件系统允许你通过 JavaScript/TypeScript 模块钩入各种事件,扩展 OpenCode 的默认行为。插件可以添加自定义工具、保护敏感文件不被读取、发送桌面通知、注入环境变量,以及自定义会话压缩(Compaction)提示。
OpenCode 插件系统让你通过监听事件、添加工具或修改默认行为来扩展 OpenCode。可以用插件集成外部服务、加强安全控制,或适配特定的工作流。
社区已有大量插件,详见生态系统。
加载插件
有两种方式加载插件:
本地文件
将 JavaScript 或 TypeScript 文件放入以下目录,启动时自动加载:
| 目录 | 范围 |
|---|---|
.opencode/plugins/ | 项目级 |
~/.config/opencode/plugins/ | 全局 |
npm 包
在 opencode.json 中指定 npm 包名:
json
{
"$schema": "https://opencode.ai/config.json",
"plugin": ["opencode-helicone-session", "opencode-wakatime", "@my-org/custom-plugin"]
}支持普通包和 scoped 包。npm 插件在启动时由 Bun 自动安装,缓存在 ~/.cache/opencode/node_modules/。
插件加载顺序
所有来源的插件均会加载,Hooks 按以下顺序执行:
- 全局配置(
~/.config/opencode/opencode.json) - 项目配置(
opencode.json) - 全局插件目录(
~/.config/opencode/plugins/) - 项目插件目录(
.opencode/plugins/)
相同名称和版本的 npm 包只加载一次;本地插件和同名 npm 插件会分别独立加载。
创建插件
插件是一个导出一个或多个插件函数的 JS/TS 模块:
js
export const MyPlugin = async ({ project, client, $, directory, worktree }) => {
return {
// 在这里放 Hook 实现
}
}插件函数接收的上下文:
| 参数 | 说明 |
|---|---|
project | 当前项目信息 |
directory | 当前工作目录 |
worktree | Git worktree 路径 |
client | OpenCode SDK 客户端 |
$ | Bun Shell API,用于执行命令 |
TypeScript 类型支持
ts
import type { Plugin } from "@opencode-ai/plugin"
export const MyPlugin: Plugin = async ({ project, client, $, directory, worktree }) => {
return {
// 类型安全的 Hook 实现
}
}外部依赖
本地插件可以使用外部 npm 包,在配置目录中添加 package.json:
json
{
"dependencies": {
"shescape": "^2.1.0"
}
}OpenCode 启动时会自动运行 bun install。
可用事件
命令事件
command.executed
文件事件
file.edited、file.watcher.updated
安装事件
installation.updated
LSP 事件
lsp.client.diagnostics、lsp.updated
消息事件
message.part.removed、message.part.updated、message.removed、message.updated
权限事件
permission.asked、permission.replied
服务器事件
server.connected
会话事件
session.created、session.compacted、session.deleted、session.diffsession.error、session.idle、session.status、session.updated
工具事件
tool.execute.before、tool.execute.after
Shell 事件
shell.env
TUI 事件
tui.prompt.append、tui.command.execute、tui.toast.show
示例
桌面通知
会话完成时发送系统通知(macOS):
js
export const NotificationPlugin = async ({ project, client, $, directory, worktree }) => {
return {
event: async ({ event }) => {
if (event.type === "session.idle") {
await $`osascript -e 'display notification "Session completed!" with title "opencode"'`
}
},
}
}保护 .env 文件
防止 OpenCode 读取 .env 文件:
js
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("禁止读取 .env 文件")
}
},
}
}注入环境变量
为所有 Shell 执行注入环境变量(包括 AI 工具调用和用户终端):
js
export const InjectEnvPlugin = async () => {
return {
"shell.env": async (input, output) => {
output.env.MY_API_KEY = "secret"
output.env.PROJECT_ROOT = input.cwd
},
}
}插件中添加自定义工具
插件也可以直接注册自定义工具:
ts
import { type Plugin, tool } from "@opencode-ai/plugin"
export const CustomToolsPlugin: Plugin = async (ctx) => {
return {
tool: {
mytool: tool({
description: "这是一个自定义工具",
args: {
foo: tool.schema.string(),
},
async execute(args, context) {
const { directory, worktree } = context
return `Hello ${args.foo} from ${directory}`
},
}),
},
}
}自定义 Context 压缩行为
在会话压缩(Compaction)时注入额外上下文:
ts
import type { Plugin } from "@opencode-ai/plugin"
export const CompactionPlugin: Plugin = async (ctx) => {
return {
"experimental.session.compacting": async (input, output) => {
output.context.push(`
## 自定义上下文
压缩后需要保留的状态:
- 当前任务状态
- 重要决策记录
- 正在处理的文件
`)
},
}
}也可以完全替换压缩提示(替换时 output.context 数组会被忽略):
ts
export const CustomCompactionPlugin: Plugin = async (ctx) => {
return {
"experimental.session.compacting": async (input, output) => {
output.prompt = `
你正在为多 Agent 协作会话生成延续提示。
摘要:
1. 当前任务及其状态
2. 哪些文件正在被修改及由谁修改
3. Agent 之间的阻塞和依赖关系
4. 完成工作的下一步骤
`
},
}
}日志记录
在插件中使用 client.app.log() 进行结构化日志(推荐使用 log() 而不是 console.log()):
ts
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。
常见问题
Q: 插件和自定义工具有什么区别?
A: 插件功能更全面,可以监听所有事件、注册工具、修改系统行为。自定义工具(在 .opencode/tools/ 目录中)只是单纯提供 LLM 可调用的函数,实现更简单。如果只需要给 LLM 加工具,用自定义工具就够了;需要拦截事件或修改系统行为,用插件。
Q: 有安全性风险吗?
A: 插件代码有完整的系统访问权限(可以执行任意命令、读写文件等),请只加载来源可信的插件,并在使用社区插件前审查代码。
Q: 如何调试插件?
A: 使用 client.app.log() 记录日志,在启动 OpenCode 时加 --print-logs 参数可以在 stderr 看到日志输出。