Skip to content

OpenCode 插件系统允许你通过 JavaScript/TypeScript 模块钩入各种事件,扩展 OpenCode 的默认行为。插件可以添加自定义工具、保护敏感文件不被读取、发送桌面通知、注入环境变量,以及自定义会话压缩(Compaction)提示。

OpenCode 插件系统让你通过监听事件、添加工具或修改默认行为来扩展 OpenCode。可以用插件集成外部服务、加强安全控制,或适配特定的工作流。

社区已有大量插件,详见生态系统


加载插件

有两种方式加载插件:

本地文件

将 JavaScript 或 TypeScript 文件放入以下目录,启动时自动加载:

目录范围
.opencode/plugins/项目级
~/.config/opencode/plugins/全局

npm 包

opencode.json 中指定 npm 包名:

json
{
  "$schema": "https://opencode.ai/config.json",
  "plugin": ["opencode-helicone-session", "opencode-wakatime", "@my-org/custom-plugin"]
}

支持普通包和 scoped 包。npm 插件在启动时由 Bun 自动安装,缓存在 ~/.cache/opencode/node_modules/


插件加载顺序

所有来源的插件均会加载,Hooks 按以下顺序执行:

  1. 全局配置(~/.config/opencode/opencode.json
  2. 项目配置(opencode.json
  3. 全局插件目录(~/.config/opencode/plugins/
  4. 项目插件目录(.opencode/plugins/

相同名称和版本的 npm 包只加载一次;本地插件和同名 npm 插件会分别独立加载。


创建插件

插件是一个导出一个或多个插件函数的 JS/TS 模块:

js
export const MyPlugin = async ({ project, client, $, directory, worktree }) => {
  return {
    // 在这里放 Hook 实现
  }
}

插件函数接收的上下文:

参数说明
project当前项目信息
directory当前工作目录
worktreeGit worktree 路径
clientOpenCode SDK 客户端
$Bun Shell API,用于执行命令

TypeScript 类型支持

ts
import type { Plugin } from "@opencode-ai/plugin"

export const MyPlugin: Plugin = async ({ project, client, $, directory, worktree }) => {
  return {
    // 类型安全的 Hook 实现
  }
}

外部依赖

本地插件可以使用外部 npm 包,在配置目录中添加 package.json

json
{
  "dependencies": {
    "shescape": "^2.1.0"
  }
}

OpenCode 启动时会自动运行 bun install


可用事件

命令事件

  • command.executed

文件事件

  • file.editedfile.watcher.updated

安装事件

  • installation.updated

LSP 事件

  • lsp.client.diagnosticslsp.updated

消息事件

  • message.part.removedmessage.part.updatedmessage.removedmessage.updated

权限事件

  • permission.askedpermission.replied

服务器事件

  • server.connected

会话事件

  • session.createdsession.compactedsession.deletedsession.diff
  • session.errorsession.idlesession.statussession.updated

工具事件

  • tool.execute.beforetool.execute.after

Shell 事件

  • shell.env

TUI 事件

  • tui.prompt.appendtui.command.executetui.toast.show

示例

桌面通知

会话完成时发送系统通知(macOS):

js
export const NotificationPlugin = async ({ project, client, $, directory, worktree }) => {
  return {
    event: async ({ event }) => {
      if (event.type === "session.idle") {
        await $`osascript -e 'display notification "Session completed!" with title "opencode"'`
      }
    },
  }
}

保护 .env 文件

防止 OpenCode 读取 .env 文件:

js
export const EnvProtection = async ({ project, client, $, directory, worktree }) => {
  return {
    "tool.execute.before": async (input, output) => {
      if (input.tool === "read" && output.args.filePath.includes(".env")) {
        throw new Error("禁止读取 .env 文件")
      }
    },
  }
}

注入环境变量

为所有 Shell 执行注入环境变量(包括 AI 工具调用和用户终端):

js
export const InjectEnvPlugin = async () => {
  return {
    "shell.env": async (input, output) => {
      output.env.MY_API_KEY = "secret"
      output.env.PROJECT_ROOT = input.cwd
    },
  }
}

插件中添加自定义工具

插件也可以直接注册自定义工具:

ts
import { type Plugin, tool } from "@opencode-ai/plugin"

export const CustomToolsPlugin: Plugin = async (ctx) => {
  return {
    tool: {
      mytool: tool({
        description: "这是一个自定义工具",
        args: {
          foo: tool.schema.string(),
        },
        async execute(args, context) {
          const { directory, worktree } = context
          return `Hello ${args.foo} from ${directory}`
        },
      }),
    },
  }
}

自定义 Context 压缩行为

在会话压缩(Compaction)时注入额外上下文:

ts
import type { Plugin } from "@opencode-ai/plugin"

export const CompactionPlugin: Plugin = async (ctx) => {
  return {
    "experimental.session.compacting": async (input, output) => {
      output.context.push(`
## 自定义上下文

压缩后需要保留的状态:
- 当前任务状态
- 重要决策记录
- 正在处理的文件
`)
    },
  }
}

也可以完全替换压缩提示(替换时 output.context 数组会被忽略):

ts
export const CustomCompactionPlugin: Plugin = async (ctx) => {
  return {
    "experimental.session.compacting": async (input, output) => {
      output.prompt = `
你正在为多 Agent 协作会话生成延续提示。

摘要:
1. 当前任务及其状态
2. 哪些文件正在被修改及由谁修改
3. Agent 之间的阻塞和依赖关系
4. 完成工作的下一步骤
`
    },
  }
}

日志记录

在插件中使用 client.app.log() 进行结构化日志(推荐使用 log() 而不是 console.log()):

ts
export const MyPlugin = async ({ client }) => {
  await client.app.log({
    body: {
      service: "my-plugin",
      level: "info",
      message: "Plugin initialized",
      extra: { foo: "bar" },
    },
  })
}

日志级别:debuginfowarnerror


常见问题

Q: 插件和自定义工具有什么区别?

A: 插件功能更全面,可以监听所有事件、注册工具、修改系统行为。自定义工具(在 .opencode/tools/ 目录中)只是单纯提供 LLM 可调用的函数,实现更简单。如果只需要给 LLM 加工具,用自定义工具就够了;需要拦截事件或修改系统行为,用插件。

Q: 有安全性风险吗?

A: 插件代码有完整的系统访问权限(可以执行任意命令、读写文件等),请只加载来源可信的插件,并在使用社区插件前审查代码。

Q: 如何调试插件?

A: 使用 client.app.log() 记录日志,在启动 OpenCode 时加 --print-logs 参数可以在 stderr 看到日志输出。