OpenCode 作为一个开源的 AI 编程助手,其核心设计理念之一就是可扩展性。除了内置的丰富功能外,OpenCode 提供了强大的插件系统(Plugin System),允许开发者通过编写 JavaScript 或 TypeScript 代码来 hook 到 OpenCode 的各种生命周期事件,从而实现自定义行为。无论你想在特定操作前后执行逻辑、添加自定义工具、保护敏感文件,还是集成外部通知服务,插件系统都能帮你实现。
本文将从插件的基础概念讲起,涵盖插件的加载方式、创建方法、事件系统,以及多个实战案例,帮助你全面掌握 OpenCode 插件开发。
OpenCode 插件本质上是一个 JavaScript 或 TypeScript 模块,它导出一个或多个函数。每个函数接收一个上下文对象,并返回一个包含各种事件钩子(hooks)的对象。当 OpenCode 运行时发生特定事件(如执行工具、创建会话、修改文件等),插件中注册的钩子函数会被自动调用。
插件的核心优势在于:
将你的插件文件放在以下目录,OpenCode 会自动加载:
.opencode/plugins/ — 项目级插件,仅在该项目中生效~/.config/opencode/plugins/ — 全局插件,所有项目生效文件可以是 .js 或 .ts 格式,直接放置在目录中即可。
你也可以通过配置 opencode.json 的 plugin 字段来加载 npm 包:
{
"$schema": "https://opencode.ai/config.json",
"plugin": [
"opencode-helicone-session",
"opencode-wakatime",
"@my-org/custom-plugin"
]
}
OpenCode 在启动时会自动使用 Bun 安装这些 npm 包并缓存到 ~/.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 客户端,用于与 AI 交互$ — Bun 的内置 Shell API,用于执行命令如果你偏好 TypeScript,可以从 @opencode-ai/plugin 包中导入类型定义:
import type { Plugin } from "@opencode-ai/plugin"
export const MyPlugin: Plugin = async ({ project, client, $, directory, worktree }) => {
return {
// 类型安全的钩子实现
}
}
OpenCode 插件可以订阅多种事件,覆盖了从工具执行到会话管理的方方面面。
最常用的事件钩子,允许你在工具执行前后插入逻辑:
tool.execute.before — 工具执行前触发tool.execute.after — 工具执行后触发file.edited — 文件被编辑时file.watcher.updated — 文件监听器更新时session.created — 新会话创建时session.compacted — 会话上下文被压缩时session.deleted — 会话被删除时session.error — 会话发生错误时session.idle — 会话空闲时session.status — 会话状态变化时permission.asked / permission.replied — 权限请求与响应command.executed — 命令执行完成shell.env — Shell 环境变量注入tui.prompt.append — TUI 提示信息追加tui.toast.show — TUI 通知显示完整的事件列表可参考官方文档的 Events 章节。
在长时间运行的任务完成时,你可能希望收到系统通知:
// .opencode/plugins/notification.js
export const NotificationPlugin = async ({ $ }) => {
return {
event: async ({ event }) => {
if (event.type === "session.idle") {
await $`osascript -e 'display notification "OpenCode 会话已完成!" with title "opencode"'`
}
},
}
}
在 macOS 上使用 osascript 发送通知;Linux 用户可以使用 notify-send,Windows 用户可以使用 msg 命令。
防止 AI 意外读取敏感的环境变量文件:
// .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("禁止读取 .env 文件")
}
},
}
}
当 AI 尝试读取包含 .env 的文件路径时,插件会抛出错误,阻止该操作。
为所有 Shell 执行注入自定义环境变量:
// .opencode/plugins/inject-env.js
export const InjectEnvPlugin = async () => {
return {
"shell.env": async (input, output) => {
output.env.MY_API_KEY = "your-api-key"
output.env.PROJECT_ENV = "development"
},
}
}
这些环境变量会同时注入到 AI 工具执行的命令和用户终端中。
插件不仅能监听事件,还可以注册全新的工具供 AI 调用:
// .opencode/plugins/custom-tools.ts
import { type Plugin, tool } from "@opencode-ai/plugin"
export const CustomToolsPlugin: Plugin = async (ctx) => {
return {
tool: {
getWeather: tool({
description: "获取指定城市的天气信息",
args: {
city: tool.schema.string({ description: "城市名称" }),
},
async execute(args, context) {
const { directory } = context
// 这里可以调用外部天气 API
return `${args.city} 的天气:晴朗,25°C`
},
}),
},
}
}
自定义工具使用 tool 辅助函数创建,包含描述、参数定义和执行函数。AI 会像调用内置工具一样调用它们。如果插件工具与内置工具同名,插件工具会优先执行。
使用结构化日志替代 console.log:
// .opencode/plugins/my-plugin.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。
当长会话被压缩时,注入额外的上下文信息:
import type { Plugin } from "@opencode-ai/plugin"
export const CompactionPlugin: Plugin = async (ctx) => {
return {
"experimental.session.compacting": async (input, output) => {
output.context.push(`## 自定义上下文
需要在压缩后保留的状态信息:
- 当前任务状态
- 已做出的重要决策
- 正在处理的文件列表`)
},
}
}
你也可以通过设置 output.prompt 完全替换默认的压缩提示词。
如果你的本地插件需要使用外部 npm 包,需要在配置目录中创建 package.json:
// .opencode/package.json
{
"dependencies": {
"shescape": "^2.1.0"
}
}
OpenCode 会在启动时自动运行 bun install 安装这些依赖,插件中可以直接 import 使用:
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)
}
},
}
}
单一职责:每个插件只做一件事,保持代码简洁
错误处理:始终用 try-catch 包裹可能出错的逻辑,避免影响 OpenCode 主流程
性能敏感:钩子函数应尽量轻量,避免在 tool.execute.before 等高频事件中执行耗时操作
使用 TypeScript:类型安全能显著降低插件开发中的错误率
版本管理:将项目级插件提交到 Git 仓库,团队共享
OpenCode 的插件系统为用户提供了极大的灵活性和扩展能力。无论是简单的通知提醒、环境变量注入,还是复杂的自定义工具开发,插件都能让你按需定制 AI 编程助手的行为。通过掌握事件机制和插件 API,你可以将 OpenCode 打造成完全符合个人或团队工作流的专属工具。
如果你开发了有用的插件,不妨提交到 OpenCode 的生态系统(Ecosystem)页面,与社区分享你的成果。