创见博客
opencode Hooks 与 Plugins:把 Agent 工作流变成可编程系统
七崽爱吃小饼干2026/07/21阅读 1专栏 Trellis 与 AI Agent 工程化

opencode 不只是一个能调用工具的 AI 编程助手。真正让它适合团队长期使用的,是它的 Plugins 与 Hooks 机制。

如果说普通配置解决的是“默认用什么模型、允许哪些工具”,那么 Plugin 解决的是另一个问题:当 Agent 运行到某个关键节点时,我能不能插入自己的逻辑?答案是可以。

你可以在用户发消息时注入项目上下文,在模型请求前调整参数,在工具执行前做安全检查,在权限询问时自动处理低风险操作,也可以把整个过程记录到本地日志里做审计。换句话说,opencode 的 Plugin 机制让 Agent 从一个通用助手,变成一个可以适配项目流程的工程系统。

Hooks 是什么

Hook 是 opencode 在特定生命周期节点触发的函数。

一个 Plugin 本质上就是一个默认导出的函数,这个函数返回一组 hook:

js
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 更新、文件编辑、权限变更等事件。

js
event({ event }) {
  console.log(event.type)
}

chat.message

用户消息进入聊天流程时触发。

这个 hook 非常实用,因为它可以修改用户消息的内容。常见用法包括:

  • 自动注入项目规范
  • 自动注入当前任务状态
  • 给子 Agent 补充背景信息
  • 在每轮对话前追加工作流提示

例如:

js
"chat.message": async (input, output) => {
  output.parts.unshift({
    type: "text",
    text: "请优先遵守本项目的编码规范。",
  })
}

chat.params

模型请求参数生成后触发。

适合统一调整模型调用参数,例如限制 temperature,设置 provider options,或者根据模型类型动态调整参数。

js
"chat.params": async (input, output) => {
  output.temperature = Math.min(output.temperature, 0.7)
}

tool.execute.before

工具执行前触发。

这是安全控制和工具增强最常用的 hook。它可以看到即将执行的工具名,也可以修改工具参数。

适合做:

  • 清理或改写 bash 命令
  • 阻止危险操作
  • 给 Task/subagent 注入上下文
  • 记录工具调用审计日志
js
"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

工具执行后触发。

适合记录工具输出、统计工具调用、做简单后处理。

js
"tool.execute.after": async (input, output) => {
  console.log(input.tool, output.title)
}

permission.ask

opencode 准备向用户请求权限时触发。

它适合把团队里的权限策略自动化。例如自动允许低风险命令,自动拒绝危险命令,或者把所有权限请求记录下来。

js
"permission.ask": async (input, output) => {
  if (input.type === "bash" && input.pattern === "date") {
    output.status = "allow"
  }
}

如何编写一个 Plugin

推荐把项目级 Plugin 放到:

text
.opencode/plugins/example-plugin.js

然后在 .opencode/opencode.json 里显式注册:

json
{
  "$schema": "https://opencode.ai/config.json",
  "plugin": ["./plugins/example-plugin.js"]
}

注意这里的路径是相对 .opencode/opencode.json 所在目录解析的。

也就是说:

json
"plugin": ["./plugins/example-plugin.js"]

实际指向:

text
.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 这类低风险命令

创建文件:

text
.opencode/plugins/example-plugin.js

内容如下:

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"
      }
    },
  }
}

再创建或修改:

text
.opencode/opencode.json
json
{
  "$schema": "https://opencode.ai/config.json",
  "plugin": ["./plugins/example-plugin.js"]
}

重启后,如果插件加载成功,会出现日志文件:

text
.opencode/example-plugin.log

里面每一行都是一条 JSON 记录:

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 时代的工程基础设施:它把“应该怎么做”变成“系统自动这样做”。

评论
0/100