OpenCode 的插件系统允许开发者通过 JavaScript 或 TypeScript 编写插件,挂钩到 OpenCode 的各种事件中,实现功能扩展、外部服务集成和默认行为修改。无论是发送系统通知、保护敏感文件,还是添加自定义工具,插件都能帮你轻松实现。
OpenCode 插件本质上是一个 JS/TS 模块,导出一个异步函数,该函数接收上下文对象并返回一个 hooks 对象。插件可以响应 OpenCode 生命周期中的各种事件,从会话创建到文件编辑,从工具执行到会话压缩。
插件加载方式有两种:本地文件和 npm 包。
将 JS/TS 文件放入以下目录,OpenCode 启动时会自动加载:
.opencode/plugins/ —— 项目级插件~/.config/opencode/plugins/ —— 全局插件在 opencode.json 中声明 npm 包:
{
"$schema": "https://opencode.ai/config.json",
"plugin": [
"opencode-helicone-session",
"opencode-wakatime",
"@my-org/custom-plugin"
]
}
npm 插件在启动时由 Bun 自动安装,缓存到 ~/.cache/opencode/node_modules/。
插件按以下顺序加载,所有钩子依次执行:
全局配置 ~/.config/opencode/opencode.json
项目配置 opencode.json
全局插件目录 ~/.config/opencode/plugins/
项目插件目录 .opencode/plugins/
一个基础插件结构如下:
// .opencode/plugins/example.js
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 客户端 |
| $ | Bun 的 Shell API |
使用 TypeScript 可以获得类型提示和编译检查:
import type { Plugin } from "@opencode-ai/plugin"
export const MyPlugin: Plugin = async ({ project, client, $, directory, worktree }) => {
return {
// Type-safe hook implementations
}
}
插件可以订阅 OpenCode 生命周期中的各类事件。
session.created —— 会话创建session.compacted —— 会话压缩session.deleted —— 会话删除session.idle —— 会话空闲session.error —— 会话出错tool.execute.before —— 工具执行前tool.execute.after —— 工具执行后file.edited —— 文件被编辑file.watcher.updated —— 文件监听更新permission.asked —— 权限被询问permission.replied —— 权限被响应完整的事件列表还包括命令事件、消息事件、Shell 事件、LSP 事件、TUI 事件等,涵盖 OpenCode 运行的方方面面。
当会话完成时发送系统通知:
// .opencode/plugins/notification.js
export const NotificationPlugin = async ({ $ }) => {
return {
event: async ({ event }) => {
if (event.type === "session.idle") {
await $`osascript -e 'display notification "Session completed!" with title "opencode"'`
}
},
}
}
防止 OpenCode 读取敏感文件:
// .opencode/plugins/env-protection.js
export const EnvProtection = async () => {
return {
"tool.execute.before": async (input, output) => {
if (input.tool === "read" && output.args.filePath.includes(".env")) {
throw new Error("Do not read .env files")
}
},
}
}
为所有 Shell 执行注入环境变量:
// .opencode/plugins/inject-env.js
export const InjectEnvPlugin = async () => {
return {
"shell.env": async (input, output) => {
output.env.MY_API_KEY = "secret"
output.env.PROJECT_ROOT = input.cwd
},
}
}
插件可以注册全新的工具供 OpenCode 调用:
import { type Plugin, tool } from "@opencode-ai/plugin"
export const CustomToolsPlugin: Plugin = async (ctx) => {
return {
tool: {
mytool: tool({
description: "A custom tool example",
args: {
name: tool.schema.string(),
},
async execute(args, context) {
const { directory } = context
return `Hello ${args.name} from ${directory}`
},
}),
},
}
}
tool 辅助函数接收 description、args(Zod schema)和 execute 函数,返回的工具定义会与内置工具一同呈现给 AI。如果插件工具与内置工具同名,插件工具将优先生效。
会话压缩时注入额外上下文:
import type { Plugin } from "@opencode-ai/plugin"
export const CompactionPlugin: Plugin = async (ctx) => {
return {
"experimental.session.compacting": async (input, output) => {
output.context.push(`## Custom Context
Include any state that should persist across compaction:
- Current task status
- Important decisions made
- Files being actively worked on`)
},
}
}
也可以完全替换压缩提示词:
export const CustomCompactionPlugin: Plugin = async (ctx) => {
return {
"experimental.session.compacting": async (input, output) => {
output.prompt = `You are generating a continuation prompt for a multi-agent 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`
},
}
}
使用 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 四个级别。
本地插件需要外部 npm 包时,在配置目录创建 package.json:
// .opencode/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)
}
},
}
}
事件选择 —— 只在需要的时机挂钩,避免不必要的性能开销。例如文件保护用 tool.execute.before 而不是全局 event。
错误处理 —— 插件中的异常不会影响 OpenCode 核心功能,但建议用 try/catch 妥善处理。
日志记录 —— 使用 client.app.log() 而非 console.log,便于集中查看和管理。
TypeScript —— 使用 TypeScript 编写插件可以获得编译期类型检查,减少运行时错误。
测试 —— 在独立项目中进行插件测试,确认事件触发和行为符合预期后再部署到生产项目。
OpenCode 插件系统为你提供了强大的扩展能力。通过几十个事件钩子、自定义工具注册和灵活的生命周期管理,你可以将 OpenCode 无缝集成到自己的工作流中。无论是简单的通知提醒,还是复杂的自定义工具链,插件系统都能满足你的需求。
浏览 OpenCode 插件生态 可以发现社区贡献的更多插件,也可以将自己的插件发布到 npm 分享给他人。