opencode 不只是一个能调用工具的 AI 编程助手。真正让它适合团队长期使用的,是它的 Plugins 与 Hooks 机制。
如果说普通配置解决的是“默认用什么模型、允许哪些工具”,那么 Plugin 解决的是另一个问题:当 Agent 运行到某个关键节点时,我能不能插入自己的逻辑?答案是可以。
你可以在用户发消息时注入项目上下文,在模型请求前调整参数,在工具执行前做安全检查,在权限询问时自动处理低风险操作,也可以把整个过程记录到本地日志里做审计。换句话说,opencode 的 Plugin 机制让 Agent 从一个通用助手,变成一个可以适配项目流程的工程系统。
Hooks 是什么
Hook 是 opencode 在特定生命周期节点触发的函数。
一个 Plugin 本质上就是一个默认导出的函数,这个函数返回一组 hook:
export default async ({ directory }) => {
return {
"chat.message": async (input, output) => {
// 用户消息进入对话流程时触发
},
"tool.execute.before": async (input, output) => {
// 工具执行前触发
},
}
}
大多数 hook 都有两个参数:
input:当前事件的上下文,主要用于读取信息。output:opencode 接下来要使用的数据,很多时候可以原地修改它。
这点很重要。Plugin 不只是“旁路监听”,它也可以改变后续行为。例如在 tool.execute.before 里修改 output.args,工具最终收到的参数就会随之改变。
常见 Hook 的触发时机
event
event 会监听 opencode 内部事件。
适合做日志、调试、统计、会话状态追踪。例如记录 session 更新、文件编辑、权限变更等事件。
event({ event }) {
console.log(event.type)
}
chat.message
用户消息进入聊天流程时触发。
这个 hook 非常实用,因为它可以修改用户消息的内容。常见用法包括:
- 自动注入项目规范
- 自动注入当前任务状态
- 给子 Agent 补充背景信息
- 在每轮对话前追加工作流提示
例如:
"chat.message": async (input, output) => {
output.parts.unshift({
type: "text",
text: "请优先遵守本项目的编码规范。",
})
}
chat.params
模型请求参数生成后触发。
适合统一调整模型调用参数,例如限制 temperature,设置 provider options,或者根据模型类型动态调整参数。
"chat.params": async (input, output) => {
output.temperature = Math.min(output.temperature, 0.7)
}
tool.execute.before
工具执行前触发。
这是安全控制和工具增强最常用的 hook。它可以看到即将执行的工具名,也可以修改工具参数。
适合做:
- 清理或改写 bash 命令
- 阻止危险操作
- 给 Task/subagent 注入上下文
- 记录工具调用审计日志
"tool.execute.before": async (input, output) => {
if (input.tool === "bash" && typeof output.args?.command === "string") {
output.args.command = output.args.command.trim()
}
}
tool.execute.after
工具执行后触发。
适合记录工具输出、统计工具调用、做简单后处理。
"tool.execute.after": async (input, output) => {
console.log(input.tool, output.title)
}
permission.ask
opencode 准备向用户请求权限时触发。
它适合把团队里的权限策略自动化。例如自动允许低风险命令,自动拒绝危险命令,或者把所有权限请求记录下来。
"permission.ask": async (input, output) => {
if (input.type === "bash" && input.pattern === "date") {
output.status = "allow"
}
}
如何编写一个 Plugin
推荐把项目级 Plugin 放到:
.opencode/plugins/example-plugin.js
然后在 .opencode/opencode.json 里显式注册:
{
"$schema": "https://opencode.ai/config.json",
"plugin": ["./plugins/example-plugin.js"]
}
注意这里的路径是相对 .opencode/opencode.json 所在目录解析的。
也就是说:
"plugin": ["./plugins/example-plugin.js"]
实际指向:
.opencode/plugins/example-plugin.js
如果写成 ./.opencode/plugins/example-plugin.js,就可能被解析成 .opencode/.opencode/plugins/example-plugin.js,导致启动时报找不到模块。
修改 Plugin 后,需要重启 opencode 或封装它的 Agent。Plugin 通常不是热加载的。
Plugins 可以做什么
Plugin 最适合做“项目工作流增强”。它能把很多原本靠口头约定、文档提醒、手动检查的事情变成自动化机制。
常见用法包括:
- 自动注入项目规则和架构约定
- 自动注入当前任务、需求、设计文档
- 给 subagent 分发更完整的上下文
- 在模型请求前统一调参
- 对工具调用做审计日志
- 对 bash 命令做安全检查
- 自动允许低风险权限请求
- 自动拒绝危险命令
- 统计 Agent 的工具使用情况
- 连接内部系统,补充需求、工单、知识库信息
举个例子,团队可以写一个 Plugin,在每次用户发消息时读取 .project/rules.md,把关键规则注入到消息前面。这样每个 Agent 都会天然知道项目约定,而不是依赖用户反复提醒。
再进一步,Plugin 还可以在调用 Task 工具之前,根据子 Agent 类型自动注入不同上下文:实现 Agent 获得需求文档,Review Agent 获得 diff 和测试策略,Research Agent 获得代码结构索引。这类能力会明显提升多 Agent 协作的稳定性。
一个简单好用的例子:本地审计日志插件
下面这个插件做三件事:
- 记录 Plugin 是否成功加载
- 记录聊天、模型参数、工具调用、权限请求等关键节点
- 在工具执行前清理 bash 命令末尾空白,并自动允许
date这类低风险命令
创建文件:
.opencode/plugins/example-plugin.js
内容如下:
import { appendFileSync, mkdirSync } from "fs"
import { dirname, join } from "path"
function createLogger(directory) {
const logPath = join(directory, ".opencode", "example-plugin.log")
return function log(message, data = undefined) {
mkdirSync(dirname(logPath), { recursive: true })
appendFileSync(
logPath,
JSON.stringify({ time: new Date().toISOString(), message, data }) + "\n",
"utf8",
)
}
}
export default async ({ app, directory }) => {
const root = directory || app?.path?.root || process.cwd()
const log = createLogger(root)
log("plugin.loaded", {
root,
cwd: app?.path?.cwd,
hostname: app?.hostname,
})
return {
event({ event }) {
log("event", { type: event?.type })
},
"chat.message": async (input, output) => {
log("chat.message", {
sessionID: input?.sessionID,
agent: input?.agent,
parts: output?.parts?.map((part) => part.type) || [],
})
},
"chat.params": async (input, output) => {
log("chat.params", {
provider: input?.provider?.id,
model: input?.model?.id,
})
if (typeof output.temperature === "number") {
output.temperature = Math.min(output.temperature, 0.7)
}
output.options = {
...(output.options || {}),
examplePlugin: true,
}
},
"tool.execute.before": async (input, output) => {
log("tool.execute.before", {
tool: input?.tool,
sessionID: input?.sessionID,
callID: input?.callID,
})
if (input?.tool === "bash" && typeof output?.args?.command === "string") {
output.args.command = output.args.command.replace(/\s+$/, "")
}
},
"tool.execute.after": async (input, output) => {
log("tool.execute.after", {
tool: input?.tool,
title: output?.title,
})
},
"permission.ask": async (input, output) => {
log("permission.ask", {
type: input?.type,
pattern: input?.pattern,
})
if (input?.type === "bash" && input?.pattern === "date") {
output.status = "allow"
}
},
}
}
再创建或修改:
.opencode/opencode.json
{
"$schema": "https://opencode.ai/config.json",
"plugin": ["./plugins/example-plugin.js"]
}
重启后,如果插件加载成功,会出现日志文件:
.opencode/example-plugin.log
里面每一行都是一条 JSON 记录:
{"time":"2026-07-21T10:00:00.000Z","message":"plugin.loaded","data":{"root":"/path/to/project"}}
{"time":"2026-07-21T10:00:05.000Z","message":"chat.message","data":{"sessionID":"...","parts":["text"]}}
{"time":"2026-07-21T10:00:08.000Z","message":"tool.execute.before","data":{"tool":"bash","callID":"..."}}
这个例子虽然简单,但很实用。它能帮你确认 hook 是否触发,也能让你理解 Agent 实际经过了哪些执行节点。等你确认机制稳定后,就可以把日志插件扩展成项目上下文注入、权限策略、安全审计或多 Agent 工作流系统。
结语
opencode 的 Hooks 与 Plugins 机制,本质上是把 Agent 的运行过程开放给开发者。
它让我们不必把所有规则都写进提示词,也不必依赖每次手动提醒。项目规范、上下文注入、权限策略、工具审计、子 Agent 协作,都可以通过 Plugin 固化下来。
对于个人使用,Plugin 可以提升效率。对于团队使用,Plugin 更像是 Agent 时代的工程基础设施:它把“应该怎么做”变成“系统自动这样做”。