一、三种扩展方式

OpenCode 提供了三种扩展方式,适应不同粒度的需求:

方式 适用场景 复杂度
自定义工具 让 AI 调用特定函数(如查询数据库、调用 API)
Agent Skill 封装领域知识供 AI 按需加载
Plugin 通过事件钩子扩展 OpenCode 行为

二、自定义工具(Custom Tools)

2.1 创建工具

工具是 TypeScript/JavaScript 文件,放在以下目录:

  • 项目级:.opencode/tools/
  • 全局:~/.config/opencode/tools/

文件名就是工具名。

// .opencode/tools/database.ts
import { tool } from "@opencode-ai/plugin"

export default tool({
  description: "Query the project database",
  args: {
    query: tool.schema.string().describe("SQL query to execute"),
  },
  async execute(args) {
    // 你的数据库查询逻辑
    return `Executed query: ${args.query}`
  },
})

2.2 参数定义(Zod Schema)

使用 tool.schema(基于 Zod)定义参数:

export default tool({
  description: "Search user by ID or email",
  args: {
    id: tool.schema.number().optional().describe("User ID"),
    email: tool.schema.string().optional().describe("User email"),
    limit: tool.schema.number().default(10).describe("Max results"),
  },
  async execute(args) {
    // 至少需要一个参数
    if (!args.id && !args.email) {
      return "Please provide id or email"
    }
    return `Searching for user: ${args.id || args.email}`
  },
})

2.3 多个工具在一个文件

导出多个工具,工具名格式为 文件名_导出名

// .opencode/tools/math.ts
import { tool } from "@opencode-ai/plugin"

export const add = tool({
  description: "Add two numbers",
  args: {
    a: tool.schema.number().describe("First number"),
    b: tool.schema.number().describe("Second number"),
  },
  async execute(args) {
    return (args.a + args.b).toString()
  },
})

export const multiply = tool({
  description: "Multiply two numbers",
  args: {
    a: tool.schema.number().describe("First number"),
    b: tool.schema.number().describe("Second number"),
  },
  async execute(args) {
    return (args.a * args.b).toString()
  },
})

此文件会创建 math_addmath_multiply 两个工具。

2.4 工具上下文

工具可以访问当前会话的上下文信息:

export default tool({
  description: "Get project information",
  args: {},
  async execute(args, context) {
    const { agent, sessionID, messageID, directory, worktree } = context
    return `Agent: ${agent}, Session: ${sessionID}, Dir: ${directory}`
  },
})

2.5 用 Python 写工具逻辑

工具定义必须是 TS/JS,但执行逻辑可以是任何语言:

# .opencode/tools/add.py
import sys
a = int(sys.argv[1])
b = int(sys.argv[2])
print(a + b)
// .opencode/tools/python-add.ts
import { tool } from "@opencode-ai/plugin"
import path from "path"

export default tool({
  description: "Add two numbers using Python",
  args: {
    a: tool.schema.number().describe("First number"),
    b: tool.schema.number().describe("Second number"),
  },
  async execute(args) {
    const script = path.join(context.worktree, ".opencode/tools/add.py")
    const result = await Bun.$`python3 ${script} ${args.a} ${args.b}`.text()
    return result.trim()
  },
})

2.6 覆盖内置工具

自定义工具与内置工具同名时,自定义工具优先:

// .opencode/tools/bash.ts — 替换内置 bash 工具
import { tool } from "@opencode-ai/plugin"

export default tool({
  description: "Restricted bash wrapper",
  args: {
    command: tool.schema.string(),
  },
  async execute(args) {
    return `blocked: ${args.command}`
  },
})

三、Agent Skill

3.1 什么是 Skill?

Skill 是 SKILL.md 文件,封装了特定领域的知识。AI 按需加载,而非预置到上下文中。

3.2 创建 Skill

目录结构:.opencode/skills/<name>/SKILL.md

---
name: git-release
description: Create consistent releases and changelogs
license: MIT
compatibility: opencode
metadata:
  audience: maintainers
  workflow: github
---

## What I Do
- Draft release notes from merged PRs
- Propose a version bump
- Provide a copy-pasteable `gh release create` command

## When to Use Me
Use this when you are preparing a tagged release.
Ask clarifying questions if the target versioning scheme is unclear.

3.3 Skill 发现机制

OpenCode 搜索以下位置:

  • 项目:.opencode/skills/<name>/SKILL.md
  • 全局:~/.config/opencode/skills/<name>/SKILL.md
  • 兼容:.claude/skills/<name>/SKILL.md
  • 兼容:.agents/skills/<name>/SKILL.md

3.4 Skill 的 Frontmatter

字段 必需 说明
name 1-64 字符,小写字母数字和单连字符
description 1-1024 字符
license 许可证
compatibility 兼容性说明
metadata 字符串键值对

3.5 Skill 权限控制

{
  "permission": {
    "skill": {
      "*": "allow",
      "pr-review": "allow",
      "internal-*": "deny",
      "experimental-*": "ask"
    }
  }
}

四、Plugin(插件)

4.1 加载插件

三种方式:

  1. 本地文件.opencode/plugins/~/.config/opencode/plugins/
  2. npm 包
{
  "plugin": ["opencode-helicone-session", "@my-org/custom-plugin"]
}

注意:npm 插件通过 Bun 自动安装和缓存到 ~/.cache/opencode/node_modules/。如果使用 npm 插件,需要安装 Bun。

4.2 插件加载顺序

插件按以下顺序加载:

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

所有钩子按此顺序依次执行。

4.3 插件依赖管理

本地插件和自定义工具可以使用外部 npm 包。在配置目录中添加 package.json

// .opencode/package.json
{
  "dependencies": {
    "shescape": "^2.1.0"
  }
}

OpenCode 启动时会自动运行 bun install 安装依赖。然后插件中可以导入:

// .opencode/plugins/my-plugin.ts
import { escape } from "shescape"

4.4 创建插件

// .opencode/plugins/example.js
export const MyPlugin = async ({ project, client, $, directory, worktree }) => {
  console.log("Plugin initialized!")

  return {
    // 钩子实现
  }
}

插件函数接收:

  • project:当前项目信息
  • directory:工作目录
  • worktree:Git worktree 路径
  • client:OpenCode SDK 客户端
  • $:Bun shell API(仅在有 Bun 时可用)

TypeScript 类型支持:

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

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

4.5 事件钩子

插件可以订阅多种事件:

Session 事件

  • session.created / session.deleted / session.error
  • session.idle / session.updated
  • session.compacted

Tool 事件

  • tool.execute.before / tool.execute.after

Message 事件

  • message.updated / message.removed

Permission 事件

  • permission.asked / permission.replied

File 事件

  • file.edited / file.watcher.updated

4.6 实用示例

通知插件
// .opencode/plugins/notification.js
export const NotificationPlugin = async ({ $ }) => {
  return {
    event: async ({ event }) => {
      if (event.type === "session.idle") {
        await $`osascript -e 'display notification "Session completed!" with title "opencode"'`
      }
    },
  }
}
.env 保护插件
// .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("Do not read .env files")
      }
    },
  }
}
压缩钩子(高级)

在会话压缩时向上下文中注入自定义上下文:

// .opencode/plugins/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(`## Custom Context
- Current task status
- Important decisions made
- Files being actively worked on`)
    },
  }
}
注入环境变量
// .opencode/plugins/inject-env.js
export const InjectEnvPlugin = async () => {
  return {
    "shell.env": async (input, output) => {
      output.env.MY_API_KEY = "secret"
      output.env.PROJECT_ROOT = input.cwd
    },
  }
}
插件中添加自定义工具
// .opencode/plugins/custom-tools.ts
import { type Plugin, tool } from "@opencode-ai/plugin"

export const CustomToolsPlugin: Plugin = async (ctx) => {
  return {
    tool: {
      mytool: tool({
        description: "This is a custom tool",
        args: {
          foo: tool.schema.string(),
        },
        async execute(args, context) {
          const { directory, worktree } = context
          return `Hello ${args.foo} from ${directory} (worktree: ${worktree})`
        },
      }),
    },
  }
}
结构化日志
export const MyPlugin = async ({ client }) => {
  await client.app.log({
    body: {
      service: "my-plugin",
      level: "info",
      message: "Plugin initialized",
      extra: { foo: "bar" },
    },
  })
}

五、扩展方式选择指南

需求 推荐方式
AI 需要调用特定函数/API 自定义工具
封装领域知识供 AI 参考 Skill
在事件发生时执行操作 Plugin
修改 OpenCode 默认行为 Plugin
添加新的交互命令 Plugin (command 事件)

六、总结

本文覆盖了 OpenCode 三种扩展方式:

  • 自定义工具:让 AI 调用自定义函数,开发成本最低
  • Agent Skill:封装领域知识按需加载,适合分享和复用
  • Plugin:通过事件钩子深度定制,功能最强大

下一篇文章将介绍 OpenCode 的高阶玩法:CLI 自动化、CI/CD 集成与远程协作。

Logo

小龙虾开发者社区是 CSDN 旗下专注 OpenClaw 生态的官方阵地,聚焦技能开发、插件实践与部署教程,为开发者提供可直接落地的方案、工具与交流平台,助力高效构建与落地 AI 应用

更多推荐