乐于分享
好东西不私藏

oh-my-opencode 源码架构解析:OpenCode 外挂系统到底在外挂什么

oh-my-opencode 源码架构解析:OpenCode 外挂系统到底在外挂什么

oh-my-opencode 这类项目,读 README 很容易被带偏。

它的表达很猛,功能列表也长。真要判断有没有价值,不能看它喊了什么,得看它到底把能力挂在了 OpenCode / Codex 的哪些运行点上。

我读下来,最值得看的不是“它让 Agent 更强”,而是它暴露了一个现实:很多 AI Coding Harness 还缺一层工程运行时。规则怎么注入,工具怎么接,长任务怎么恢复,编辑怎么防旧上下文,这些都不能靠一句 prompt 解决。

它不是一个普通插件,而是一套外挂运行层

oh-my-opencode 这种项目,最容易被两种方式误读。

一种是把它当“更强的 OpenCode 配置”。

另一种是被 README 里的激进表达带跑,直接把它当成玄学提效神器。

这两种看法都不太工程。

仓库正在从 oh-my-opencode 过渡到 oh-my-openagent,npm 包名和 CLI binary 仍然兼容旧名,Codex Light edition 通过 lazycodex-ai 安装。

把宣传话术先放一边,源码里值得看的地方是:

它在试图补齐一个 Coding Agent Harness 的运行层。

这个运行层包括:

规则注入AGENTS.md 层级上下文生命周期 hooksMCP 工具LSP 诊断AST 级搜索和改写hashline 编辑校验长任务 loop state多模型/多 agent 路由Codex 轻量适配层

如果只看“它让 Agent 更猛”,就看不到真正的技术点。

更准确的问题应该是:

一个 AI Coding Harness 到底缺什么,才会需要这么重的外挂系统?

先看包结构:不是一个包,是一组运行组件

根目录 package.json 里能看到 workspaces:

{  "workspaces": [    "packages/rules-engine",    "packages/ast-grep-core",    "packages/ast-grep-mcp",    "packages/git-bash-mcp",    "packages/model-core",    "packages/prompts-core",    "packages/comment-checker-core",    "packages/hashline-core",    "packages/boulder-state",    "packages/agents-md-core",    "packages/shared-skills",    "packages/omo-codex"  ]}

packages/AGENTS.md 又把这些包分成几类:

Platform binariesMCP packagesCore packagesCodex adapterSkillsWeb

所以它不是一个单点功能插件。

它更像一组 agent harness extension runtime:

OpenCode Ultimate edition:重型运行层Codex Light edition:可移植组件包共享 core packages:规则、prompt、model、hashline、comment checker、stateMCP packages:LSP、AST-grep、Git Bash

我把它单独拎出来写,也是因为这个。

它把 AI Coding 工具缺的运行能力拆成独立包,再通过 plugin / hooks / MCP / CLI 注入到宿主。

第一层:规则不是靠记忆,靠查找和匹配

规则注入是 oh-my-opencode 最基础的一层。

packages/rules-engine/src/finder.ts 负责找规则文件。它会从当前文件目录向上扫描项目规则,也会扫描用户级规则目录。

它支持的规则来源包括:

项目规则目录项目单文件规则用户规则目录OpenCode 用户规则目录Claude 用户规则目录

packages/rules-engine/src/matcher.ts 再决定某条规则是否适用于当前文件。

逻辑大概是:

if (metadata.alwaysApply === true) return { applies: true };const patterns = normalizeGlobs(metadata);const pathBases = [  relative(projectRoot, currentFilePath),  basename(currentFilePath)];for (const pattern of patterns) {  if (matcherFor(pattern)(pathBase)) {    return { applies: true, reason: `glob: ${pattern}` };  }}

这段代码说明规则注入不是“全部塞进去”。

它做了两件很具体的事:

发现规则:当前文件附近有哪些规则文件?匹配规则:这些规则是不是适用于当前文件?

这比全局 AGENTS.md 更细。

比如一个 monorepo:

apps/web/AGENTS.mdservices/order/AGENTS.mdpackages/ui/AGENTS.md

修改 services/order/refund.ts 时,Agent 应该看到订单服务的规则,不应该被前端组件规则污染。

规则引擎存在的理由也在这里:少一点全局噪声,多一点局部上下文。

规则系统还有一层更细的东西:优先级。

packages/rules-engine/src/constants.ts 里把规则来源排了顺序:

.omo/rules.claude/rules.cursor/rules.github/instructions.github/copilot-instructions.md.sisyphus/rules~/.omo/rules~/.opencode/rules~/.claude/rules~/.sisyphus/rules

项目内规则优先于用户级规则,.omo/rules 又排在最前面。测试里还有一个场景:当用户 home 里的规则和插件 bundled 规则有同一个 description 时,用户 home 文件胜出,bundled 文件不会出现在格式化结果里。

这个设计很工程。

插件可以提供默认纪律,但不能压过项目和用户自己的规则。否则插件越强,越容易变成新的全局污染源。规则系统必须允许覆盖、禁用和优先级排序,不然最后一定变成“所有规则都注入,模型自己看着办”。

所以 oh-my-opencode 的规则层不是简单收集 Markdown。它在做三件事:

发现:从当前文件向上找项目规则,也找用户规则排序:按距离、来源和优先级决定谁更靠前去重:同类规则冲突时保留更贴近当前项目的版本

这也是重型插件能不能落地的分界线。没有这层,插件越多,Agent 越乱。

第二层:AGENTS.md 不是只读一次,而是沿文件路径向上找

packages/agents-md-core/src/injector.ts 负责 AGENTS.md 注入。

它的核心流程是:

拿到当前文件路径解析成绝对路径从文件所在目录向上找 AGENTS.md去重已注入目录读取文件内容截断追加到工具输出里保存 session cache

其中 findAgentsMdUp() 负责从文件目录往项目根向上找。

这和普通“启动时读根目录 AGENTS.md”不一样。

它更像 IDE 里的 scoped config:

根目录 AGENTS.md:全局约束src/AGENTS.md:源码层约束src/payments/AGENTS.md:支付领域约束

当 Agent 读到 src/payments/refund.ts,它才应该知道支付目录的特殊规则。

这类机制解决的是上下文工程里的老问题:

规则太少,Agent 不知道边界。规则太多,Agent 被噪声污染。

按路径注入,是折中方案。

第三层:Hook 把 Agent 行为接到生命周期事件上

Codex Light edition 的 manifest 很清楚。

packages/omo-codex/plugin/.codex-plugin/plugin.json 声明:

{  "name": "omo",  "skills": "./skills/",  "hooks": "./hooks/hooks.json",  "mcpServers": "./.mcp.json",  "capabilities": [    "Hooks",    "MCP Tools",    "Code Intelligence",    "Workflow",    "Context Injection"  ]}

hook 配置在 packages/omo-codex/plugin/hooks/hooks.json

它挂了这些生命周期:

SessionStartUserPromptSubmitPreToolUsePostToolUsePostCompactStopSubagentStop

每个事件都对应一个或多个组件 CLI。

例如:

SessionStart -> rules / telemetry / auto-updateUserPromptSubmit -> rules / ultrawork / ulw-loopPreToolUse(Bash) -> git-bash reminderPostToolUse(edit/apply_patch) -> comment-checker + lsp diagnosticsPostCompact -> reset rules / lsp / git-bash cachesStop -> start-work continuation

这比 prompt 硬很多。

Prompt 只能影响模型“怎么想”。

Hook 可以影响系统“在什么事件发生时执行什么检查”。

AI Coding 工具越来越像 IDE 插件系统,原因就在这里。

把这些 hook 放进一次编辑流程里,效果更直观:

SessionStart:先装载规则、恢复缓存、做 telemetry / auto-updateUserPromptSubmit:根据用户输入注入规则,判断是否进入 ultrawork / loopPreToolUse:在 Bash 这类高风险工具前提醒或改写执行环境PostToolUse:编辑完成后跑 comment-checker、LSP diagnosticsPostCompact:上下文压缩后重置规则、LSP、git-bash cacheStop:如果目标没收口,触发 continuation

这就不是“模型多想一步”的问题了。

它把 Agent 的行为拆成事件,再把检查挂在事件上。只要宿主愿意执行 hook,模型就很难完全绕过这些检查。Prompt 只能劝模型认真一点,hook 能在模型已经动手以后检查现场。

第四层:MCP 把代码智能补成工具,而不是塞进 prompt

Codex Light edition 的 .mcp.json 里注册了:

{  "ast_grep": {    "command": "node",    "args": ["../../ast-grep-mcp/dist/cli.js", "mcp"]  },  "grep_app": {    "url": "https://mcp.grep.app"  },  "context7": {    "url": "https://mcp.context7.com/mcp"  },  "git_bash": {    "command": "node",    "args": ["../../git-bash-mcp/dist/cli.js", "mcp"]  },  "lsp": {    "command": "node",    "args": ["../../lsp-daemon/dist/cli.js", "mcp"]  }}

这几个工具很典型:

ast_grep:结构化代码搜索和替换grep_app:GitHub 代码搜索context7:官方文档检索git_bash:Windows Git Bash 兼容lsp:诊断、定义跳转、引用、符号、重命名

这些能力不该写进 prompt。

Prompt 里写一万句“请准确理解代码”,也不如给 Agent 一个 LSP diagnostics 工具。

Prompt 里写“请谨慎修改函数”,也不如给它 AST-grep 和 hashline 编辑校验。

MCP 在这里的作用是:

把模型不擅长凭空完成的代码智能,变成可调用工具。

这是外挂系统的第二个价值。

不是让模型记更多,而是让模型查得更准、改得更稳。

第五层:hashline 解决的是“我读到的行还是不是那一行”

README 里提到 hashline edit。

它给读取结果加上内容 hash,编辑时再校验目标行有没有变。

普通 Agent 编辑代码有一个很隐蔽的问题:

它读到第 120 行。中间别的修改发生了。它还按旧上下文改第 120 行。

这是很典型的 stale-line error。

oh-my-opencode 把它抽成 hashline-core,README 里描述为 LINE#ID 内容 hash。

这个设计其实就是乐观并发控制。

数据库里常见做法是:

读取记录时拿 version更新时带 versionversion 不匹配就拒绝

hashline 做的是:

读取文本时拿内容 hash编辑时带 hashhash 不匹配就拒绝

这类机制很适合 Coding Agent:

因为 Agent 最大的问题不是不会生成 diff,而是在长任务、多工具、多轮编辑里,上下文经常过期。

hashline 把“你是不是还在改同一段文本”变成了可检查条件。

更完整一点看,oh-my-opencode 想要的是一个“读、诊断、改、复查”的闭环:

rules / AGENTS.md:告诉 Agent 当前文件该遵守什么规则MCP / LSP:告诉 Agent 代码现在真实报什么错hashline:告诉 Agent 目标文本有没有被别人改过PostToolUse hook:告诉 Agent 改完以后还剩什么问题loop state:告诉 Agent 长任务做到哪一步了

这里每一层都在补模型的一个短板。

规则补的是项目边界,LSP 补的是静态诊断,hashline 补的是编辑一致性,hook 补的是时机,loop state 补的是长任务记忆。

所以我不太愿意把它叫“提示词增强”。它更像是在给 Coding Agent 补一套简化版 IDE runtime。

第六层:ulw-loop 不是魔法,是把长任务状态外置

packages/omo-codex/plugin/skills/ulw-loop/SKILL.md 写得很直接:

Use the ulw-loop CLI state under .omo/ulw-loop; do not hand-edit goal state.After any compaction or context loss, re-read brief + goals + ledger FIRST.Every success criterion needs observable evidence.

ulw-loop 不是一句“继续做直到完成”的咒语。

它做的是三件事:

把目标状态写到文件系统把执行证据写到 ledger把 compaction 后的恢复路径固定下来

长任务最怕的不是模型不会努力。

最怕的是:

做到一半上下文爆了做过的事情没证据失败路径没人记录下一个会话重新规划

ulw-loop 把这些状态外置到 .omo/ulw-loop。Agent 恢复时先读状态,而不是重新猜。

这和我们前面讲 memory、spec、harness 是同一个方向:

不要把重要状态只放在模型上下文里。

Ultimate 和 Light 的分层,能看出它的野心

README 里把产品分成两种:

Ultimate Edition:OpenCodeLight Edition:Codex CLI

Ultimate 更重,有 agent orchestration、Team Mode、更多 hooks、更多内置 MCP、hashline edits 等。

Light 更克制,主要把可移植组件放进 Codex 插件系统:

rulescomment-checkergit-bashlspultraworkulw-loopstart-work-continuationtelemetry

这个分层很现实,也说明作者并没有只押一个宿主。

不同 Harness 能支持的能力边界不一样。

OpenCode 插件系统可以承载更重的多 agent、hook、tool 编排。

Codex Light edition 则把能移植的组件打成 omo@sisyphuslabs 插件,通过 ~/.codex/plugins/cache/sisyphuslabs/omo/<version>/~/.codex/config.toml、本地 marketplace snapshot、agent TOML 和 component CLIs 接入。

这里能看到一个趋势:

未来 AI Coding 插件不一定只服务一个宿主。能力会被拆成 harness-neutral core,再通过 adapter 投递到不同工具。

oh-my-opencode 这套结构已经很接近这个趋势。

为什么 LSP 和 hook 比“请仔细检查”有用

假设 Agent 在 TypeScript 项目里改退款状态机。

它修改了:

RefundStatus.Pending -> RefundStatus.Approved

但还有某个地方引用旧枚举。

如果只靠 prompt,你只能写:

请仔细检查有没有遗漏引用。

模型可能 grep,也可能不 grep。

如果有 LSP MCP,流程可以更硬:

编辑文件  ↓PostToolUse 触发 lsp diagnostics  ↓发现旧枚举引用报错  ↓Agent 根据诊断定位文件  ↓修复后再次检查

如果有 hashline,编辑目标还能校验旧上下文是否过期。

如果有 rule injector,Agent 在改 services/refund 时能看到退款目录规则。

如果有 comment checker,可以在编辑后检查 AI 味注释。

这才是外挂系统补的东西:

把“请认真”变成事件、工具和校验。

它的风险也很明显

oh-my-opencode 这种重型外挂系统有吸引力,但风险也不小。

第一是复杂度。

rules、hooks、MCP、agent、model routing、loop state、platform binary、Codex adapter、telemetry、installer 都在一个生态里。能力越多,排障越难。

第二是权限。

Codex Light edition 的安装文档提到可以配置 autonomous full-permissions mode,比如 approval_policy = "never"sandbox_mode = "danger-full-access"network_access = "enabled"

这对重度 agent 工作流很方便,但不适合所有人。

一旦工具链能写文件、跑 shell、访问网络,插件就不只是“增强体验”,而是进入了真实副作用边界。

第三是过度自动化。

ultraworkulw-loop 这种模式适合长任务,但如果没有清晰验收标准,Agent 可能会产生大量看起来忙碌的操作。

所以我更建议把这类工具当成工程系统看,而不是效率神药。

要看:

状态在哪里?证据在哪里?权限怎么控?失败怎么恢复?能不能禁用某些 hook?能不能只装轻量组件?

这些问题比“它能不能一键干活”重要。

怎么判断这种项目值不值得装

如果你在评估 oh-my-opencode 或类似项目,不要先看 README 里的爽文截图。

先看源码里的四个面:

1. manifest:插件到底暴露了什么入口?2. hooks:它在哪些生命周期拦截?3. MCP:它把哪些能力变成工具?4. state:长任务和恢复状态放在哪里?

再看它有没有测试。

oh-my-opencode 的仓库里有大量针对 installer、Codex plugin、hooks、rules、LSP、hashline、model resolution 的测试文件。这个信号比 star 数更重要。

重型插件最怕“能跑 demo,不能升级”。

测试比 star 数更能说明它是不是工程化项目。

外挂系统火,是因为 Harness 还不够完整

oh-my-opencode 的源码给我的最大启发,不是某个具体功能,而是一个判断:

AI Coding 的竞争正在从模型输出,转到 Harness 运行层。

模型当然重要。

但只靠模型,你很难解决这些问题:

项目规则怎么按目录注入?工具调用后怎么自动检查?代码诊断怎么回流给 Agent?编辑目标怎么防 stale?长任务怎么跨 compact 恢复?不同宿主怎么共享同一套能力?

这些都不是一句 prompt 能解决的。

它们需要插件系统、hook 系统、MCP、LSP、状态机、installer、测试和权限策略。

oh-my-opencode 正好把这些东西放在了一个高热度仓库里。

它不一定是所有团队都该装的工具。

但它很适合作为源码样本。看懂它,基本就能看懂下一代 AI Coding Harness 还缺哪些能力。

资料来源

  • • code-yeongyu/oh-my-opencode,源码快照:64acd646fe943451eeaba38e8486cb202ee06613,2026-06-09。
  • • README.md:OpenCode Ultimate / Codex Light edition、功能面和安装路径。
  • • package.json:workspaces、CLI binary、package files、测试脚本。
  • • packages/AGENTS.md:monorepo role map、MCP packages、core packages、Codex adapter。
  • • packages/omo-codex/AGENTS.md:Codex Light edition 结构、安装、telemetry、deploy 说明。
  • • packages/omo-codex/plugin/.codex-plugin/plugin.json:Codex plugin manifest。
  • • packages/omo-codex/plugin/hooks/hooks.json:Codex hook 生命周期和组件挂载。
  • • packages/omo-codex/plugin/.mcp.json:AST-grep、grep.app、Context7、Git Bash、LSP MCP 注册。
  • • packages/rules-engine/src/finder.tsmatcher.ts:规则发现和匹配。
  • • packages/agents-md-core/src/injector.ts:AGENTS.md 路径向上发现和注入。
  • • packages/omo-codex/plugin/skills/ulw-loop/SKILL.md:长任务 loop state 和证据规则。