主题
第五章 OmO 插件架构
← 返回目录 | 上一章:工具链与会话模型 | 下一章:OmO Agent 体系 →
本章合并原报告 §6(插件架构)、§10(Hook 与生命周期)、§22(Features 模块与 Hook 完整目录),全面展示 OmO 的结构设计。
5.1 "不改一行代码"的增强哲学
OmO 的核心设计约束是:作为纯插件运行,不修改 Opencode 的任何源代码。这意味着 OmO 所有的能力——12 个 Agent、26 个工具、48 个 Hook、3 个 MCP 服务器——全部通过 Opencode 暴露的 8 个插件接口实现。
这个约束带来了显著的工程优势:
- 独立升级:Opencode 和 OmO 可以分别更新,不会互相破坏
- 可选增强:用户可以选择使用或不使用 OmO
- 清晰边界:出问题时容易定位是平台问题还是插件问题
但也带来了工程挑战:
- 需要通过有限的 Hook 接口实现复杂的编排逻辑
- 某些功能(如后台任务)在原生 Opencode 中完全不存在,需要从零构建
5.2 初始化流程
OmO 的入口文件 (src/index.ts) 执行以下初始化序列:
loadConfig() ← 加载多层配置(项目/用户/默认)
↓
createManagers() ← 初始化核心管理器
├── BackgroundManager ← 后台任务调度器
├── SessionHistoryManager ← 会话历史搜索
├── McpManager ← MCP 服务器生命周期
└── SkillManager ← Skill 发现与加载
↓
createTools() ← 注册 26 个工具
↓
createHooks() ← 组装 48 个生命周期 Hook
↓
createPluginInterface() ← 返回符合 Opencode 插件接口的对象关键实现细节:
- 配置注入:OmO 通过
configHook 将自己的 Agent 定义、工具列表、模型绑定全部注入 Opencode 的配置系统。Opencode 在启动时加载插件配置,"认为"这些 Agent 和工具是自己原生的。 - 工具注入:通过
toolHook 返回 26 个工具定义,Opencode 的工具注册表会把它们和原生工具一起注册。 - 消息拦截:通过
chat.message和experimental.chat.messages.transformHook 拦截和修改消息流,实现后台任务通知、上下文注入等功能。 - 事件监听:通过
eventHook 监听 Opencode 的事件流(会话空闲、消息完成等),驱动后台任务轮询和续航机制。
5.3 多层配置系统
OmO 的配置采用三层合并策略:
项目级配置 (.opencode/oh-my-opencode.jsonc)
↓ 覆盖
用户级配置 (~/.config/opencode/oh-my-opencode.jsonc)
↓ 覆盖
默认配置 (OmO 内置)合并规则:
- 简单字段:项目级 > 用户级 > 默认(覆盖)
- Agent/Category:深度合并(可以只覆盖某个 Agent 的模型,保留其他配置)
- disabled_ 数组*:Set 并集(项目和用户级的禁用列表合并)
配置示例:
jsonc
// .opencode/oh-my-opencode.jsonc
{
"agents": {
"sisyphus": {
"model": "anthropic/claude-opus-4-6" // 只覆盖模型,保留其他配置
}
},
"categories": {
"quick": {
"model": "anthropic/claude-sonnet-4-6" // 修改 quick 类别的默认模型
}
},
"disabled_agents": ["librarian"], // 禁用特定 Agent
"disabled_tools": ["interactive_bash"] // 禁用特定工具
}5.4 五层 Hook 架构
OmO 将 48 个 Hook 组织为 5 个层级,每层负责不同的关注点:
层级 1: Session Hooks(23 个)—— 会话生命周期管理
层级 2: Tool-Guard Hooks(12 个)—— 工具执行拦截与增强
层级 3: Transform Hooks(4 个)—— 消息序列变换
层级 4: Continuation Hooks(7 个)—— 任务续航与自动恢复
层级 5: Skill Hooks(2 个)—— Skill 动态加载5.4.1 Session Hooks(会话层)
这一层处理会话级别的事件和状态管理:
关键 Hook:
| Hook | 触发时机 | 功能 |
|---|---|---|
session-idle-detector | 会话空闲时 | 检测父 session 空闲,触发后台任务通知注入 |
background-task-notifier | 后台任务完成时 | 将完成通知组装为 system-reminder 消息 |
ultrawork-detector | 用户消息包含关键词时 | 检测 "ultrawork"/"ulw" 关键词,激活 Ultrawork 模式 |
session-type-tracker | 会话创建/切换时 | 追踪会话类型(主会话/子任务/后台任务) |
model-override | LLM 调用前 | Ultrawork 模式下覆盖模型为最高能力版本 |
5.4.2 Tool-Guard Hooks(工具守卫层)
这一层在工具执行前后插入逻辑,实现增强和保护:
| Hook | 触发时机 | 功能 |
|---|---|---|
task-delegation-guard | Task 工具执行前 | 拦截原生 TaskTool 调用,路由到 OmO 的后台任务系统 |
lsp-tool-router | LSP 工具执行前 | 将 OmO 的 6 个 LSP 工具路由到 Opencode 的底层 LSP 服务 |
bash-safety-guard | Bash 执行前 | 检测危险命令(rm -rf, dd 等),要求确认 |
tool-output-truncator | 工具执行后 | 截断过长的工具输出(默认 50K tokens,webfetch 10K) |
edit-validation | 编辑工具执行后 | 验证文件编辑结果,检测潜在问题 |
task-delegation-guard 是最关键的 Hook——它是 OmO 后台任务系统(BackgroundManager,负责异步任务的排队、并发控制与生命周期管理)与 Opencode 的桥梁。当任何 Agent 调用 task 工具时:
Agent 调用 task(run_in_background=true, ...)
↓
tool.execute.before Hook 拦截
↓
task-delegation-guard 接管:
├─ 如果 run_in_background=true → 路由到 BackgroundManager
├─ 如果有 category → 解析为 Sisyphus-Junior + 对应模型
├─ 如果有 subagent_type → 路由到对应 Agent
└─ 如果有 session_id → 续接已有会话
↓
返回 task_id 给调用者(不等待完成)5.4.3 Transform Hooks(消息变换层)
这一层通过 Opencode 的 experimental.chat.messages.transform 接口,在 LLM 调用前变换整个消息序列:
| Hook | 功能 |
|---|---|
system-prompt-injector | 将 OmO 的动态系统提示注入到消息序列开头 |
queue-message-injector | 将队列消息(后台任务通知等)注入到消息序列末尾 |
context-recovery | 上下文窗口溢出时执行多策略恢复 |
skill-context-injector | 将已加载 Skill 的指令注入到系统提示中 |
5.4.4 Continuation Hooks(续航层)
这是 OmO 最有特色的 Hook 层——确保长时间运行的任务不会因为 Agent"忘记"或"放弃"而中断。
Atlas Hook(核心续航器):
Atlas 是一个"任务续航守护者"。当 Sisyphus 完成一轮对话但 Todo 列表中还有未完成的任务时,Atlas 会注入一条系统提醒,强制 Agent 继续工作:
Sisyphus 完成回复 → session 进入 idle 状态
↓
Atlas 检查决策门控:
├─ 会话类型是否正确?(只在主会话中工作)
├─ 是否有中止信号?(用户手动停止)
├─ 连续失败次数?(超过阈值则暂停)
├─ 后台任务是否仍在运行?(等待结果)
├─ 当前 Agent 是否匹配?(只对 Sisyphus/Atlas 生效)
├─ Todo 是否全部完成?
└─ 冷却时间是否满足?
↓
如果有未完成 Todo → 注入续航提醒:
"你还有 N 个待办任务未完成。请继续工作。"
↓
Sisyphus 收到提醒 → 继续处理下一个 TodoBoulder 机制(防无限循环):
"Boulder"(巨石)是 Atlas 的防护机制,用指数退避防止 Agent 陷入无限循环:
首次提醒: 等待 30 秒后注入
第二次: 60 秒
第三次: 120 秒
第四次: 240 秒
第五次: 5 分钟暂停
→ 之后重新评估是否继续5.4.5 Skill Hooks(技能层)
| Hook | 功能 |
|---|---|
skill-discovery | 从多个路径发现 SKILL.md 文件 |
skill-mcp-lifecycle | 管理 Skill 内嵌 MCP 服务器的启动/停止 |
5.5 Features 模块系统
OmO 将大量功能封装为独立的 Feature 模块(src/features/),每个模块自包含实现、类型和测试。这是 OmO 代码组织的核心模式——避免"上帝类"(god object),以 19 个聚焦的模块替代。
| 模块 | 复杂度 | 功能 |
|---|---|---|
| background-agent | 高(31 文件,~10k LOC) | 后台任务生命周期管理、并发控制(5/model)、FIFO 队列、轮询调度——详见后台任务系统 |
| opencode-skill-loader | 高(33 文件) | 4 层作用域的 Skill 发现与加载(项目 > opencode > 用户 > 全局),YAML frontmatter 解析 |
| tmux-subagent | 高(30 文件) | tmux 窗格管理、网格规划、会话编排——支持 interactive_bash 工具 |
| mcp-oauth | 高(18 文件) | OAuth 2.0 + PKCE + 动态客户端注册(RFC 7591),为 MCP 远程服务器提供认证 |
| builtin-skills | 低(17 文件) | 6 个内置 Skill:git-master、playwright、playwright-cli、agent-browser、dev-browser、frontend-ui-ux |
| skill-mcp-manager | 中(12 文件) | 管理 Skill 内嵌 MCP 服务器的生命周期(启动/停止/连接) |
| claude-code-plugin-loader | 中(10 文件) | 从 .opencode/plugins/ 发现和加载 Claude Code 兼容插件 |
| builtin-commands | 低(11 文件) | 内置斜杠命令模板(refactor、init-deep、handoff、start-work 等) |
| claude-tasks | 中(7 文件) | 持久化任务管理(文件存储 + Opencode todo 同步) |
| claude-code-mcp-loader | 中(6 文件) | 加载 .mcp.json 中定义的 Claude Code 兼容 MCP 服务器,支持 ${VAR} 环境变量展开 |
| context-injector | 中(6 文件) | 将 AGENTS.md 和 README.md 注入到会话上下文中 |
| run-continuation-state | 低(5 文件) | run 命令的跨会话持久化续航状态 |
| hook-message-injector | 中(5 文件) | 通用的系统消息注入框架,供各 Hook 使用 |
| boulder-state | 低(5 文件) | Atlas 巨石(Boulder)续航机制的持久化状态 |
| task-toast-manager | 中(4 文件) | 任务进度的 TUI Toast 通知 |
| tool-metadata-store | 低(3 文件) | 工具执行元数据缓存(记录工具调用历史供后续分析) |
| claude-code-session-state | 低(3 文件) | 子 Agent 会话状态追踪 |
| claude-code-command-loader | 低(3 文件) | 从 .opencode/commands/ 加载自定义命令 |
| claude-code-agent-loader | 低(3 文件) | 从 .opencode/agents/ 加载自定义 Agent 定义 |
Claude Code 兼容层:注意有 5 个 claude-code-* 模块——它们使 OmO 能够加载 Claude Code 格式的插件、MCP 配置、命令和 Agent 定义。这意味着为 Claude Code 编写的扩展可以直接在 Opencode + OmO 中使用。
5.6 Doctor 诊断系统
omo doctor 是一个环境健康检查命令(cli/doctor/,23 个检查文件),分 4 个类别自动检测常见问题:
| 类别 | 检查项 |
|---|---|
| System | 二进制文件存在、版本 ≥ 1.0.150、插件已注册、版本匹配 |
| Config | JSONC 语法有效、Zod Schema 验证通过、模型覆写语法正确 |
| Tools | AST-Grep 可用、注释检查器正常、LSP 服务器可启动、GitHub CLI 可用、MCP 服务器连接正常 |
| Models | 缓存存在、模型解析成功、Agent/Category 覆写有效、模型可用性 |
Doctor 的检查并行执行(runner.ts),支持三种输出格式:默认(人类可读)、详细(含修复建议)、JSON(机器可读)。这是一个优秀的运维实践——当用户报告问题时,omo doctor 的输出可以快速定位根因。
5.7 配置迁移
shared/migration/index.ts 实现了自动配置迁移:当配置文件中存在过时的键名(如旧版 Agent 名称、废弃的 Hook 名称、过时的模型版本标识)时,系统在加载配置时自动转换为新格式。这让用户无需手动更新配置文件即可升级到新版本。
5.8 Hook 完整目录
第 4 节介绍了 Hook 的五层架构和关键 Hook 的功能。以下是完整的 48+ 个 Hook 分类目录,基于 src/hooks/ 目录的逐文件分析:
5.8.1 Session Hooks(23 个)——会话生命周期
| Hook | 功能 |
|---|---|
context-window-monitor | 监控上下文窗口使用率,触发预防性压缩 |
preemptive-compaction | 在上下文窗口接近上限时主动执行消息压缩 |
preemptive-compaction-degradation-monitor | 监控压缩后模型能力是否退化 |
preemptive-compaction-no-text-tail | 压缩时去除尾部无意义文本 |
think-mode | 根据任务复杂度动态调整模型思维深度 |
ralph-loop | 自引用开发循环(14 文件,~1687 LOC) |
model-fallback | Provider 级别模型降级链 |
runtime-fallback | 实时错误捕获与自动重试 |
anthropic-context-window-limit-recovery | Anthropic 特定的上下文窗口溢出恢复 |
anthropic-effort | 调整 Anthropic 模型的 effort 级别 |
no-sisyphus-gpt | 限制 Sisyphus 不使用 GPT 系列模型 |
no-hephaestus-non-gpt | 限制 Hephaestus 仅使用 GPT 兼容模型 |
session-recovery | 会话崩溃后的恢复机制 |
session-notification | 会话状态通知(7 个辅助文件:内容、格式化、调度、发送等) |
background-notification | 后台任务完成通知注入 |
auto-update-checker | 插件更新检查与通知 |
non-interactive-env | 非交互环境(如 CI)的特殊处理 |
openclaw | OpenClaw 集成 |
legacy-plugin-toast | 旧版插件迁移提示 |
start-work | 工作会话启动(与 Prometheus 规划器配合) |
empty-task-response-detector | 检测并处理空任务响应 |
session-todo-status | 追踪会话中的 Todo 完成状态 |
agent-usage-reminder | 提醒 Agent 使用特定模式 |
5.8.2 Tool-Guard Hooks(12 个)——工具执行拦截与增强
| Hook | 功能 |
|---|---|
comment-checker | 检测并阻止 AI 生成的代码注释污染 |
rules-injector | 将 .sisyphus/rules/ 目录中的规则文件注入到上下文 |
write-existing-file-guard | 防止意外覆盖已有文件(要求先 read 才能 write) |
bash-file-read-guard | 阻止通过 bash 命令读取文件(强制使用 read 工具) |
hashline-read-enhancer | 为文件内容添加行哈希锚点 |
hashline-edit-diff-enhancer | 增强编辑操作的 diff 显示 |
json-error-recovery | JSON 解析错误的自动恢复 |
edit-error-recovery | 文件编辑错误的自动恢复(如 oldString 未找到时的重试策略) |
tool-output-truncator | 截断过长的工具输出(默认 50K tokens) |
question-label-truncator | 截断 question 工具中过长的选项标签 |
read-image-resizer | 缩小读取的图片尺寸以节省 token |
webfetch-redirect-guard | 防止 webfetch 陷入重定向循环 |
5.8.3 Transform Hooks(4 个)——消息序列变换
| Hook | 功能 |
|---|---|
claude-code-hooks | Claude Code 兼容的会话管理 Hook |
keyword-detector | 检测用户消息中的关键词(如 "ultrawork"/"ulw") |
context-injector | 将 AGENTS.md、README.md 等上下文注入到消息序列 |
thinking-block-validator | 验证和规范化模型的 thinking block |
5.8.4 Continuation Hooks(7 个)——任务续航与自动恢复
| Hook | 功能 |
|---|---|
todo-continuation-enforcer | 当 Todo 列表存在未完成项时强制续航 |
atlas | Atlas 核心续航器——详见本章第 4.4 节 |
stop-continuation-guard | 响应 /stop-continuation 命令,终止所有续航机制 |
compaction-context-injector | 压缩后向上下文注入必要的恢复信息 |
compaction-todo-preserver | 压缩时保留 Todo 列表不被裁剪 |
delegate-task-retry | 委派任务失败时的自动重试 |
task-reminder | 提醒 Agent 存在待处理的任务 |
5.8.5 Skill Hooks(2 个)——技能动态加载
| Hook | 功能 |
|---|---|
category-skill-reminder | 在委派时提醒 Agent 加载匹配的 Skill |
auto-slash-command | 自动检测并执行斜杠命令 |
5.8.6 其他辅助 Hooks
| Hook | 功能 |
|---|---|
unstable-agent-babysitter | 监控不稳定的 Agent 行为,防止失控 |
sisyphus-junior-notepad | Sisyphus Junior 的临时记事本功能 |
tasks-todowrite-disabler | 在 task 子 Agent 中禁用 TodoWrite 工具 |
todo-description-override | 覆写 Todo 项的描述内容 |
task-resume-info | 提供任务恢复所需的上下文信息 |
prometheus-md-only | 限制 Prometheus 规划器仅输出 Markdown |
interactive-bash-session | 管理 tmux 交互式终端会话的生命周期 |
设计哲学:48 个 Hook 可能看起来数量庞大,但这正是 OmO 的设计精髓——每个 Hook 只做一件事(单一职责),可以独立启用/禁用(通过配置的
disabled_hooks数组),也可以独立测试。相比一个巨大的"do everything"中间件,这种细粒度 Hook 架构提供了更好的可维护性和可调试性。