安装插件
理解 OpenCode 插件什么时候该用,以及如何安全扩展运行行为。
Plugin 是 OpenCode 的运行时扩展。它不是提示词,也不是 Agent 角色,而是在 OpenCode 运行过程中监听事件、注入环境、修改工具调用、发送通知、写日志,或者添加自定义工具。
这一篇用 10 分钟换什么:你会知道什么时候需要 Plugin,什么时候应该用 Rules、Agent、Skill、MCP 或 custom tool,以及写第一个插件时怎么把风险收住。
先给结论:大多数新手暂时不需要插件
Plugin 站得很底层。它能改变 OpenCode 的运行过程,所以不要把它当成“高级提示词”使用。
先按这个顺序判断:
| 你想解决的问题 | 优先用什么 | 原因 |
|---|---|---|
| 让 Agent 长期遵守项目规则 | Rules / AGENTS.md | 这是上下文约束,不是运行时扩展 |
| 复用一套操作流程 | Skill | Skill 按需加载,不会常驻改变运行时 |
| 给模型一个项目动作 | Custom tool | 只增加可调用能力,不必接管生命周期 |
| 接外部系统 | MCP | 外部服务接入更适合用标准协议 |
| 监听事件、改工具调用、注入环境 | Plugin | 这才是插件的职责 |
插件越全局,影响面越大。新插件先放项目级目录,先做只读日志或通知,确认稳定后再考虑拦截工具调用。
Plugin 在扩展层里的位置
OpenCode 的扩展不是一层东西。把层级分清,后面才不会越配越乱。
flowchart TB
Rules[Rules / AGENTS.md<br/>项目长期约束]
Agent[Agents<br/>角色和权限边界]
Skill[Skills<br/>可复用流程说明]
Tool[Custom tools / MCP<br/>模型可调用能力]
Plugin[Plugins<br/>运行时事件和行为扩展]
Rules --> Agent
Agent --> Skill
Agent --> Tool
Plugin -.监听和改变.-> Tool
Plugin -.注入或记录.-> Agent
一句话判断:如果你只是想让模型“知道怎么做”,不要写插件;如果你要在 OpenCode 运行时“发生某事时自动做某事”,才考虑插件。
插件放在哪里
OpenCode 支持本地插件和 npm 插件。
| 来源 | 路径或配置 | 适合场景 |
|---|---|---|
| 项目级本地插件 | .opencode/plugins/ | 当前仓库专属行为 |
| 全局本地插件 | ~/.config/opencode/plugins/ | 所有项目都需要的通用行为 |
| npm 插件 | opencode.json 的 plugin 数组 | 已有成熟社区插件或团队私有包 |
项目级插件只影响当前仓库,更适合试错。全局插件会影响所有 OpenCode 会话,除非它已经很稳定,否则不要默认放全局。
npm 插件什么时候用
如果社区已有成熟插件,可以在配置里引用 npm 包:
{
"$schema": "https://opencode.ai/config.json",
"plugin": ["opencode-wakatime"]
}OpenCode 会在启动时用 Bun(一个比 Node.js 快得多的 JavaScript 运行时和包管理器,OpenCode 内部用它跑插件代码)自动安装 npm 插件,并把依赖缓存到本机。使用前至少检查三件事:
- 插件源码做了什么,有没有读写文件、执行 shell、上传数据。
- 插件是否仍在维护,是否和当前 OpenCode 版本匹配。
- 是否真的需要全局启用,还是只在某个项目启用。
不理解的 npm 插件不要直接放进全局配置。插件能接触运行过程,风险比普通文档依赖高。
加载顺序怎么理解
OpenCode 会从多个来源加载插件,并按顺序运行 hooks。官方加载顺序是:
| 顺序 | 来源 |
|---|---|
| 1 | 全局配置:~/.config/opencode/opencode.json |
| 2 | 项目配置:opencode.json |
| 3 | 全局插件目录:~/.config/opencode/plugins/ |
| 4 | 项目插件目录:.opencode/plugins/ |
如果同名同版本的 npm 包重复出现,只会加载一次;本地插件和 npm 插件即使名字相近,也会分别加载。
先写一个只记录日志的最小插件
第一个插件不要拦截工具,也不要改 shell 环境。先验证它能被加载,并能写结构化日志。
文件:.opencode/plugins/audit-events.ts
export const AuditEventsPlugin = async ({ client }) => {
await client.app.log({
body: {
service: "audit-events",
level: "info",
message: "Plugin loaded",
},
})
return {}
}这类插件失败时影响面小,适合作为“插件链路是否正常”的第一步。
事件怎么选
你不需要背完整事件表。先按风险选择:
| 目标 | 常见事件 | 风险 |
|---|---|---|
| 观察会话状态 | session.*、message.*、todo.updated | 低 |
| 记录权限交互 | permission.asked、permission.replied | 中 |
| 注入 shell 环境 | shell.env | 中 |
| 拦截工具执行 | tool.execute.before、tool.execute.after | 高 |
| 改变 TUI 行为 | tui.toast.show、tui.prompt.append、tui.command.execute | 中到高 |
| 处理文件或 LSP 事件 | file.edited、lsp.client.diagnostics | 中 |
选事件前先问一句:我是观察发生了什么,还是要改变它?观察型插件风险低;拦截和修改型插件要有测试仓库和禁用方案。
依赖怎么管理
本地插件需要第三方 npm 包时,在配置目录放 package.json。OpenCode 启动时会运行 bun install。
{
"dependencies": {
"shescape": "^2.1.0"
}
}依赖越多,启动、缓存和排障成本越高。插件依赖只放真正必要的包;如果只是几行字符串处理,不要引入新依赖。
插件和 Custom Tool 的关系
Plugin 也可以添加 custom tool。这个能力很强,但也更容易误用。
适合:
- 工具需要和插件上下文绑定。
- 工具要配合事件监听、日志或权限逻辑。
- 团队希望用插件包统一分发工具。
不适合:
- 只是封装一个简单项目命令。
- 只是让模型多一个 API 调用入口。
- 没有测试参数 schema 和错误输出。
如果插件提供的 tool 和内置工具重名,插件工具会优先生效。不要随便覆盖内置工具名。
安全写法
插件可以影响 OpenCode 行为,所以默认按高风险扩展处理:
- 不在插件里硬编码 API Key。
- 不把完整环境变量写进日志。
- 拦截
bash时,不拼接未经校验的命令。 - 只在确实必要时修改工具参数。
- 插件出错时返回清楚错误,不静默吞掉。
- 给每个插件保留禁用路径,例如移出目录或清空配置里的
plugin数组。
如果你的目标只是阻止模型读 .env,优先用权限或内置敏感文件保护;只有需要更细粒度逻辑时才写插件。
怎么判断插件写对了
验证插件不要直接上真实任务。按这个顺序验收:
- 插件能被加载,没有启动错误。
- 只读日志或通知能正常触发。
- 如果拦截工具调用,先在测试仓库验证。
- 插件失败时,错误信息能定位到原因。
- 禁用插件后,OpenCode 能恢复默认行为。
一个好插件应该可关闭、可解释、可定位问题。否则它会让排障变得更难。
新手常见坑
- 把插件当成提示词增强器。提示词规则应放 Rules、Agent、Command 或 Skill。
- 在全局目录放项目专属插件,导致其他项目出现异常。
- 插件里直接执行危险 shell。
- 日志里打印完整环境变量。
- 本来只需要 custom tool,却写了一个会修改 OpenCode 生命周期的插件。
- 没有禁用方案,一出问题只能猜是不是插件导致。
接下来去哪
配置 Agents
先把角色、权限和主/子代理边界理清,再考虑运行时扩展。
使用 Agent Skills
把可复用流程沉淀成 Skill,避免把流程逻辑写进插件。
创建自定义工具
如果只是给模型一个可调用动作,custom tool 通常比 plugin 更合适。
Agents、Skills、Plugins 怎么分
用完整扩展层级判断什么时候该升级到插件。