主权个人必看的 OpenCode 教程之第四课(2026版)
🎯 课程定位:本节课开始我们进入进阶课程,面向希望掌握 OpenCode 扩展开发的开发者,涵盖 Plugin 系统架构、Skills 工程化实践以及 Oh My OpenCode 多智能体协作的完整技术细节。
一、Plugin 系统深度解析
1.1 什么是 Plugin?为什么需要它?
在开始技术细节之前,让我们先理解 Plugin 的核心价值。OpenCode 是一个强大的 AI 编码助手,但每个团队和项目都有其独特的需求——安全策略、工作流程、工具链集成等。Plugin 系统正是为了解决这个问题而设计的:它让你能够在不修改 OpenCode 核心代码的情况下,扩展和定制其行为。
想象这些场景:
- 🔐 安全需求:你的公司禁止 AI 读取
.env文件 - 🔔 通知需求:任务完成时发送 Slack 或桌面通知
- 📊 审计需求:记录所有 AI 操作用于合规审查
- 🛠️ 工具集成:让 AI 能够查询你的内部数据库
所有这些都可以通过 Plugin 来实现,而无需等待官方支持。
1.2 架构原理与设计哲学
OpenCode 的 Plugin 系统采用 TypeScript-first 设计理念——插件不是 YAML 配置或 JSON 文件,而是真正的 TypeScript 模块。这意味着你可以获得:
| 特性 | 说明 |
|---|---|
| 完整的类型安全 | 通过 @opencode-ai/plugin 包获得 IntelliSense 支持 |
| Shell API 访问 | 通过 Bun 的 $ 模板字符串执行系统命令 |
| Agent 生命周期钩子 | 多个事件分类让你可以介入 AI 工作流的关键阶段 |
🏗️ 插件加载流程
OpenCode 在启动时会按照特定顺序加载插件。理解这个顺序对于避免插件冲突非常重要:
┌─────────────────────────────────────────────────────────┐
│ 插件加载顺序 │
├─────────────────────────────────────────────────────────┤
│ 1️⃣ 全局配置插件 (~/.config/opencode/opencode.json) │
│ ↓ │
│ 2️⃣ 项目配置插件 (./opencode.json) │
│ ↓ │
│ 3️⃣ 全局目录插件 (~/.config/opencode/plugins/) │
│ ↓ │
│ 4️⃣ 项目目录插件 (.opencode/plugins/) │
└─────────────────────────────────────────────────────────┘💡 提示:同名同版本的 NPM 包只会加载一次,但本地插件和 NPM 插件即使名称相似也会分别加载。
两种插件加载方式
1. 本地文件加载(适合开发和项目特定插件)
将 .ts 或 .js 文件放置在以下目录:
- 项目级:
.opencode/plugins/(注意是 plugins 而非 plugin) - 全局级:
~/.config/opencode/plugins/
2. NPM 包加载(适合共享和分发)
在 opencode.json 中配置:
{
"$schema": "https://opencode.ai/config.json",
"plugin": ["oh-my-opencode", "@your-org/custom-plugin"]
}
NPM 插件会在启动时通过 Bun 自动安装,依赖缓存在 ~/.cache/opencode/node_modules/。
1.3 Context API 完全指南
⚠️ 初学者常见错误:Plugin 函数接收的是一个 Context 对象,而非独立参数。很多新手会直接调用 ctx.send(),但这是错误的用法。
Context 结构详解
interface PluginContext {
/**
* OpenCode SDK 客户端
* 用于与 AI 核心交互
*/ client: OpenCodeClient;
/**
* 项目信息
*/ project: {
/** 项目标识符 */ id: string;
};
/**
* Bun Shell API
* 用于执行系统命令
*/ $: BunShell;
/**
* 当前工作目录
*/ directory: string;
/**
* Git worktree 路径
*/ worktree: string;
}
✅ 正确用法 vs ❌ 错误用法
// ❌ 错误:将 context 当作 client 使用 export const MyPlugin = async (ctx) => {
await ctx.send("Hello"); // TypeError: ctx.send is not a function }
// ✅ 正确:解构 context 对象 export const MyPlugin = async ({ client, project, $, directory, worktree }) => {
// 使用 client 进行 AI 交互 await client.app.log({
service: "my-plugin",
level: "info",
message: `Working in: ${directory}` });
}
Client API 详解
client 对象是你与 OpenCode 核心交互的主要接口:
// 结构化日志(推荐替代 console.log) await client.app.log({
service: "my-plugin", // 插件名称 level: "info", // debug | info | warn | error message: "操作完成",
extra: { key: "value" } // 可选的额外数据 });
Shell API 使用技巧
$ 是 Bun 的 Shell API,支持模板字符串语法,让命令执行变得优雅:
export const MyPlugin = async ({ $ }) => {
// 基本命令执行 const result = await $`git status`.text();
// 静默执行(不输出到控制台) await $`npm install`.quiet();
// 获取退出码 const { exitCode } = await $`cargo test`;
// 管道操作 const files = await $`find . -name "*.ts" | head -10`.lines();
}
1.4 事件系统详解
OpenCode 提供了丰富的生命周期事件,让你可以在 AI 工作流的关键节点介入。以下是根据官方最新文档整理的完整事件列表:
📋 完整事件分类表
| 类别 | 事件名 | 触发时机 | 典型用途 |
|---|---|---|---|
| Command | command.executed | 命令执行后 | 命令审计、快捷键记录 |
| File | file.edited | 文件被编辑 | 自动格式化、备份 |
file.watcher.updated | 文件监听更新 | 热重载触发 | |
| Installation | installation.updated | 安装更新 | 版本检查 |
| LSP | lsp.client.diagnostics | LSP 诊断信息 | 错误高亮、问题面板 |
lsp.updated | LSP 状态更新 | 语言服务监控 | |
| Message | message.updated | 消息更新 | 内容过滤、翻译 |
message.removed | 消息删除 | 日志记录 | |
message.part.updated | 消息片段更新 | 流式处理 | |
message.part.removed | 消息片段删除 | 清理 | |
| Permission | permission.replied | 权限请求响应 | 权限审计 |
permission.updated | 权限更新 | 缓存刷新 | |
| Server | server.connected | 服务器连接 | 连接状态监控 |
| Session | session.created | 新会话创建 | 初始化状态 |
session.updated | 会话更新 | 同步状态 | |
session.compacted | 会话压缩完成 | 统计、日志 | |
session.deleted | 会话删除 | 清理资源 | |
session.idle | 会话空闲 | 自动保存、通知 | |
session.status | 状态变化 | UI 更新 | |
session.error | 会话错误 | 错误处理、重试 | |
session.diff | 会话差异 | 变更追踪 | |
| Todo | todo.updated | 待办更新 | 任务追踪 |
| Tool | tool.execute.before | 工具执行前 | 参数验证、安全检查 |
tool.execute.after | 工具执行后 | 结果处理、审计 | |
| TUI | tui.prompt.append | 提示追加 | 自定义提示 |
tui.command.execute | TUI命令执行 | 命令拦截 | |
tui.toast.show | 显示提示 | 自定义通知 |
1.5 工具执行钩子详解
tool.execute.before 和 tool.execute.after 是最常用的两个钩子,让我们深入了解它们的用法:
tool.execute.before:执行前拦截
export const SecurityPlugin = async ({ client }) => {
return {
"tool.execute.before": async (input, output) => {
// input 包含工具调用信息 console.log(`Tool: ${input.tool}`);
// 通过 output.args 修改参数 if (input.tool === "bash") {
// 将危险的 rm -rf 替换为更安全的 rm -i output.args.command = output.args.command.replace(/rm -rf/g, "rm -i");
}
// 通过 throw 中止执行 if (input.tool === "read" && output.args.filePath.includes(".env")) {
throw new Error("Security: Cannot read environment files");
}
}
}
}
tool.execute.after:执行后处理
export const FormatterPlugin = async ({ $ }) => {
return {
"tool.execute.after": async (input, output) => {
// 自动格式化编辑后的文件 if (input.tool === "edit" || input.tool === "write") {
const filePath = output.args.filePath;
const ext = filePath.split('.').pop();
if (["ts", "tsx", "js", "jsx"].includes(ext)) {
await $`prettier --write ${filePath}`.quiet();
}
}
}
}
}
1.6 自定义工具开发
Plugin 最强大的能力之一是注册自定义工具,让 AI Agent 获得全新能力。
💡 重要理解:自定义工具让你可以将公司内部系统、数据库、API 等暴露给 AI,使其能够执行原本无法完成的操作。
工具定义基本结构
import { tool } from "@opencode-ai/plugin"
export default tool({
// 工具描述(供 LLM 理解何时使用此工具) description: "Query the project database",
// 参数定义(使用 Zod schema) args: {
query: tool.schema.string().describe("SQL query to execute"),
},
// 执行函数 async execute(args) {
// 实现你的逻辑 return `Executed: ${args.query}`;
}
});
文件名即工具名:将上述代码保存为 .opencode/tools/database.ts,就会创建一个名为 database 的工具。
单文件多工具模式
你也可以在一个文件中导出多个工具:
// .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;
}
});
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;
}
});
这会创建两个工具:math_add 和 math_multiply(格式为 文件名_导出名)。
跨语言工具开发
工具定义必须用 TypeScript/JavaScript,但实际逻辑可以用任何语言实现:
// .opencode/tools/python-analyzer.ts import { tool } from "@opencode-ai/plugin"
export default tool({
description: "Analyze code using Python script",
args: {
filePath: tool.schema.string().describe("File to analyze"),
},
async execute(args) {
// 调用 Python 脚本 const result = await Bun.$`python3 .opencode/scripts/analyze.py ${args.filePath}`.text();
return result.trim();
}
});
1.7 实战示例
示例一:会话完成通知(macOS)
// .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"'`;
}
}
};
}
💡 提示:如果你使用 OpenCode 桌面应用,它可以自动发送系统通知,无需额外插件。
示例二:敏感文件保护
// .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 () => {
return {
"experimental.session.compacting": async (input, output) => {
// 注入额外上下文到压缩提示 output.context.push(`
## 项目特定上下文
请在压缩时保留以下信息:
- 当前任务状态
- 重要的设计决策
- 正在修改的文件列表
`);
}
};
}
第二章:Skills 工程化开发
2.1 什么是 Skills?
Skills 是 OpenCode 的按需加载指令系统。与 Plugin 不同,Skills 不是代码,而是 Markdown 文档——它们定义了 AI 在特定场景下应该如何行动。
形象比喻:如果把 AI Agent 比作一个员工,那么 Skills 就像是工作手册或 SOP(标准操作程序)。当员工需要处理特定任务时,就会查阅相应的手册。
| 特性 | Plugin | Skills |
|---|---|---|
| 本质 | TypeScript 代码 | Markdown 文档 |
| 加载时机 | 启动时全部加载 | 按需动态加载 |
| 作用 | 扩展系统能力 | 指导 AI 行为 |
| 典型用途 | 集成外部服务 | 定义工作流程 |
2.2 Skills 的工作机制
用户输入: "帮我做一次代码审查" │
▼
┌─────────────────┐
│ Agent 分析意图 │
└────────┬────────┘
│
▼
┌─────────────────┐
│ 调用 skill 工具 │ ← 查看可用的 Skills 列表
└────────┬────────┘
│
▼
┌─────────────────┐
│ 发现匹配 Skill │ ← 找到 "code-review" Skill │ "code-review" │
└────────┬────────┘
│
▼
┌─────────────────┐
│ 加载 SKILL.md │ ← 将内容注入到 System Prompt
└────────┬────────┘
│
▼
┌─────────────────┐
│ 按照指导执行任务 │ ← AI 遵循 SKILL.md 中的指导
└─────────────────┘
2.3 Skills 存放位置
OpenCode 会扫描以下位置的 Skills(按优先级排序):
| 优先级 | 位置 | 作用域 |
|---|---|---|
| 1 | .opencode/skills/<name>/SKILL.md | 项目级 |
| 2 | ~/.config/opencode/skills/<name>/SKILL.md | 全局(用户级) |
| 3 | .claude/skills/<name>/SKILL.md | 项目级(兼容 Claude Code) |
| 4 | ~/.claude/skills/<name>/SKILL.md | 全局(兼容 Claude Code) |
💡 重要:对于项目本地路径,OpenCode 会从当前工作目录向上遍历到 git worktree 根目录,加载沿途发现的所有匹配 Skills。
2.4 SKILL.md 规范详解
Frontmatter 字段(YAML 格式)
每个 SKILL.md 必须以 YAML frontmatter 开头,包含以下字段:
| 字段 | 必填 | 说明 |
|---|---|---|
name | ✅ | 技能标识符,1-64 字符,小写字母数字和连字符 |
description | ✅ | 技能描述,1-1024 字符 |
license | ❌ | 许可证信息 |
compatibility | ❌ | 兼容性说明 |
metadata | ❌ | 字符串到字符串的映射 |
name 命名规则:
- 必须是 1-64 个字符
- 只能包含小写字母、数字和单个连字符作为分隔符
- 不能以
-开头或结尾 - 不能包含连续的
-- - 必须与包含 SKILL.md 的目录名匹配
正则表达式:^[a-z0-9]+(-[a-z0-9]+)*$
完整示例
.opencode/skills/git-release/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.
2.5 Skills 权限配置
你可以通过配置控制哪些 Skills 可以被 Agent 访问:
{
"permission": {
"skill": {
"*": "allow",
"pr-review": "allow",
"internal-*": "deny",
"experimental-*": "ask" }
}
}
| 权限值 | 行为 |
|---|---|
allow | Skill 可以立即加载 |
deny | Skill 对 Agent 隐藏,访问被拒绝 |
ask | 加载前需要用户确认 |
💡 模式支持通配符:internal-* 会匹配 internal-docs、internal-tools 等。
按 Agent 配置权限
对于自定义 Agent(在 Agent frontmatter 中):
---
permission:
skill:
"documents-*": "allow"
---对于内置 Agent(在 opencode.json 中):
{
"agent": {
"plan": {
"permission": {
"skill": {
"internal-*": "allow" }
}
}
}
}
2.6 Prompt Engineering 最佳实践
编写高质量的 SKILL.md 是一门艺术。以下是经过验证的最佳实践:
原则一:结构化指令
使用清晰的层级结构,让 LLM 能够准确理解:
## 执行流程
### Phase 1: 信息收集
1. 读取目标文件内容
2. 分析文件类型和语言
3. 识别相关依赖
### Phase 2: 分析
1. 检查语法错误
2. 识别代码异味
3. 评估复杂度
### Phase 3: 报告
1. 汇总发现
2. 优先级排序
3. 生成建议
原则二:提供具体示例
Few-shot 示例帮助 LLM 理解预期输出格式:
## 输出示例
### 发现严重问题时
**位置**: `src/api/users.ts:45` **问题**: SQL 注入漏洞
**风险**: 攻击者可获取数据库内容
**修复建议**:
\```typescript
// 使用参数化查询
const result = await db.query('SELECT * FROM users WHERE id = $1', [userId]);
\``` 原则三:明确边界和限制
告诉 LLM 什么不应该做:
## ⛔ 禁止行为
1. **不要自动修改代码** - 只提供建议,除非用户明确要求修复
2. **不要审查以下内容**:
- `node_modules/` 目录
- 自动生成的文件(*.generated.*)
3. **不要给出模糊建议**:
- ❌ "代码可以更简洁"
- ✅ "将第 45-52 行的 for 循环替换为 Array.map()"
2.7 常见问题排查
如果你的 Skill 没有显示:
- ✅ 确认
SKILL.md是全大写 - ✅ 确认 frontmatter 包含
name和description - ✅ 确认 Skill 名称在所有位置中是唯一的
- ✅ 检查权限配置——
deny的 Skills 会对 Agent 隐藏 - ✅ 确认目录名与 frontmatter 中的
name一致
第三章:Oh My OpenCode 多智能体协作
3.1 什么是 Oh My OpenCode?
Oh My OpenCode (OMO) 是 OpenCode 的社区推荐插件,它将单一 AI Agent 升级为多智能体协作系统。
核心理念:模拟真实开发团队的协作方式——有人负责规划、有人负责执行、有人负责审查。每个 Agent 专注于自己擅长的领域,通过协作完成复杂任务。
| 设计理念 | 说明 |
|---|---|
| 团队协作 | 模拟真实开发团队,每个 Agent 扮演不同角色 |
| 成本优化 | 智能路由到成本最优的模型 |
| 并行执行 | 后台 Agent 异步运行,提高效率 |
| 专业分工 | 每个 Agent 专注特定领域,提高质量 |
安装方式
# 方式 1: 使用 bunx(推荐) bunx oh-my-opencode install
# 方式 2: 手动配置 # 在 opencode.json 中添加 {
"plugin": ["oh-my-opencode"]
}
3.2 Sisyphus 编排器
Sisyphus(西西弗斯)是 OMO 的核心编排器。它以希腊神话中那位不断推石上山的人物命名,象征着 Agent 不断迭代解决问题的工作方式。
核心职责
- 任务分析:理解用户意图,分解为子任务
- 智能路由:将任务委派给最合适的专家 Agent
- 进度跟踪:通过 TodoList 管理任务状态
- 结果整合:汇总各 Agent 输出,生成最终响应
委派策略优先级
优先级 1: Skills ↓ 如果有匹配的 Skill,直接加载使用 优先级 2: Direct Tools ↓ 范围明确的简单任务,使用内置工具 优先级 3: Background Agents ↓ 可并行执行的任务,异步返回结果 优先级 4: Blocking Agents ↓ 需要即时结果的复杂任务3.3 专业 Agent 矩阵
规划三人组 (Planning Triad)
| Agent | 角色 | 核心能力 |
|---|---|---|
| Prometheus | 规划者 | 战略规划、任务分解、架构设计 |
| Metis | 顾问 | 计划审查、风险识别、隐性需求挖掘 |
| Momus | 批评者 | 代码审查、质量把关、改进建议 |
Prometheus 的工作哲学:
"我是纯粹的战略家,从不直接写代码。我的工作是通过访谈和分析建立完美计划。"
Metis 的强制介入:
"在 Prometheus 制定任何计划之前,必须先咨询我。我会强制外化那些隐性知识。"
执行专家 (Execution Specialists)
| Agent | 专长 | 使用场景 |
|---|---|---|
| Librarian | 文档搜索 | 搜索文档、GitHub、知识库 |
| Explore | 代码搜索 | 快速代码搜索、定位 |
| Oracle | 技术咨询 | 技术咨询、调试帮助、方案评估 |
| Frontend | 前端开发 | React/Vue/UI 组件开发 |
| Backend | 后端开发 | API/数据库/服务开发 |
| QA | 测试 | 测试编写、Bug 验证 |
3.4 后台任务与并行执行
OMO 的核心优势之一是后台并行执行——多个 Agent 可以同时工作:
用户: 调研主流的状态管理方案
Sisyphus 执行计划:
├── 后台任务 1: @librarian → 搜索 Redux 文档
├── 后台任务 2: @librarian → 搜索 Zustand 文档
├── 后台任务 3: @librarian → 搜索 Jotai 文档
├── 后台任务 4: @explore → 搜索项目现有状态管理
└── 主线程: Sisyphus 继续规划后续步骤
(所有后台任务并行执行,2-5秒后)
↓
汇总所有结果,生成对比分析报告
任务调用方式
显式调用(通过 @ 提及):
@librarian 搜索一下 JWT 认证的最佳实践
@explore 找一下项目中现有的认证代码
@oracle 帮我分析一下这两个方案哪个更好
隐式调用(Sisyphus 自动委派):
用户: 帮我重构这个模块
Sisyphus: (自动分析后调用)
→ @explore 搜索相关代码
→ @prometheus 制定重构计划
→ @momus 审查方案
📎 附录
A. 常用命令速查
| 命令 | 说明 |
|---|---|
/init | 初始化项目配置 |
/connect | 配置 LLM Provider |
/models | 选择模型 |
/undo | 撤销上一步 |
/redo | 重做 |
/share | 分享会话 |
B. 配置文件位置汇总
| 类型 | 路径 |
|---|---|
| 全局配置 | ~/.config/opencode/opencode.json |
| 项目配置 | ./opencode.json |
| 全局插件 | ~/.config/opencode/plugins/ |
| 项目插件 | .opencode/plugins/ |
| 全局技能 | ~/.config/opencode/skills/ |
| 项目技能 | .opencode/skills/ |
| 全局工具 | ~/.config/opencode/tools/ |
| 项目工具 | .opencode/tools/ |