按智能体自动切换模型并配置推理参数
29.8/100
综合分
0
GitHub 星标
—
npm 周下载
—/5
用户评分
数据截至 2026/10/11 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。
安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add hugefiver/ocmm该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)
状态速览
判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态信任档位:待复验
是什么
dsh 原生插件 · model
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
活跃:最近一次提交在 22 天前
档位由哪些信号合成
本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。
社区实装还没有人打卡 · 装过的第一个就是你
安全扫描自动 · 静态分析源码v2.7.0🔵 扫描:含敏感能力尚无人工评估展开查看扫描说明与证据 ↓
安全扫描自动 · 静态分析源码
v2.7.0静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。
可执行外部命令读写/删除本地文件读取剪贴板或密钥环境变量
扫描于 2026/10/31(1 天前) · 范围 全包扫描(包内未声明入口) · 来源 GitHub 仓库
静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。
给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个
功能亮点
- 按智能体切换模型
- 配置推理参数
README
由 DeepSeek 最新模型翻译生成ocmm — OpenCode 多模型自动路由
一个小巧的 OpenCode 插件:按智能体自动路由模型,把单个「variant」开关翻译成各服务商专属的推理设置,在配置阶段以声明方式挂载工作流专属提示词,并在运行时当前模型失败时,反应式地回退到链条中的下一个模型。
其中的理念(模型分层、按模型定制提示词、意图门控、主动 + 反应式回退)受 oh-my-opencode 启发;命名与代码均为独立实现。
它能做什么
| 钩子 | ocmm 做什么 |
| config | 注册 11 个智能体 + 10 个分类子代理,带上各自偏好的服务商/模型、共享技能路径和斜杠命令。给内置智能体挂载功能性智能体提示词,以及工作流/模型家族 deepwork 提示词;给分类子代理挂载分类提示词。用户配置可以新增、覆盖或禁用其中任意一项。 |
| chat.params | 为当前智能体/模型解析 variant(4 级优先级:用户配置 -> 智能体默认 -> 分类默认 -> 输入 variant),尊重用户显式选择,并且只应用 ocmm 对该模型支持的模型家族参数。内置默认值会把分类工作归一为模型适配的高/最高推理档(在支持的前提下),并避免隐式的 Opus 4.7+ thinking 预算。
展开完整文档(README 剩余 1 节)
ocmm — OpenCode 多模型自动路由
一个小巧的 OpenCode 插件:按智能体自动路由模型,把单个「variant」开关翻译成各服务商专属的推理设置,在配置阶段以声明方式挂载工作流专属提示词,并在运行时当前模型失败时,反应式地回退到链条中的下一个模型。
其中的理念(模型分层、按模型定制提示词、意图门控、主动 + 反应式回退)受 oh-my-opencode 启发;命名与代码均为独立实现。
它能做什么
| 钩子 | ocmm 做什么 |
| config | 注册 11 个智能体 + 10 个分类子代理,带上各自偏好的服务商/模型、共享技能路径和斜杠命令。给内置智能体挂载功能性智能体提示词,以及工作流/模型家族 deepwork 提示词;给分类子代理挂载分类提示词。用户配置可以新增、覆盖或禁用其中任意一项。 |
| chat.params | 为当前智能体/模型解析 variant(4 级优先级:用户配置 -> 智能体默认 -> 分类默认 -> 输入 variant),尊重用户显式选择,并且只应用 ocmm 对该模型支持的模型家族参数。内置默认值会把分类工作归一为模型适配的高/最高推理档(在支持的前提下),并避免隐式的 Opus 4.7+ thinking 预算。 |
| chat.message | v1 工作流:在每个会话的首条消息上排队 superpowers 技能内容。还会在非交互式 opencode run 输入里展开裸 ocmm 斜杠命令,这样即使 TUI 的斜杠解析器被绕过,/ralph-loop ... 和共享技能命令也能拿到命令上下文。 |
| experimental.chat.system.transform | 把排队的 v1 技能内容和一次性斜杠命令上下文前置到 output.system。 |
| event | 在 session.deleted / session.idle 时清理按会话划分的状态。在 session.error 时:对错误分类,如果可重试,就通过 client.session.prompt 派发智能体回退链中的下一个模型。当 idleContinuation.enabled 为 true 时,在 session.idle 且存在未完成的 todo、之前也没有 ESC 中止的情况下,重新提示模型继续。ESC 中止(通过 session.error 上的 abort 错误检测)会抑制继续。 |
| command.execute.before | 处理 /idle-continuation 斜杠命令,按会话切换空闲自动继续(on / off / status)。会话级覆盖优先于全局 idleContinuation.enabled 配置。 |
插件不会通过 chat.params 按调用逐个切换模型。OpenCode 的 chat.params 输出 schema 里没有 model 字段。按智能体路由通过 config 钩子完成(这是模型选择唯一安全的切入点),响应式重路由则通过 event 钩子 + client.session.prompt 完成。
工作流
OpenCode 默认使用技能驱动的 v1 工作流。配置/路径标签仍写作 v1,但面向模型的提示词文本称它为 deepwork。默认提示词是一个简洁的本地控制器,技能在每个会话的第一条消息时通过 chat.message + system.transform 注入。
Codex 适配器是另一套独立生成的接口。它打包 Codex 原生的提示词、技能、智能体和 MCP 配置,但不改动 OpenCode 运行时。
{ "workflow": "v1" }
安装
从 npmjs.org 安装
主包 ocmm 发布在 npmjs.org 上,包名就是 ocmm。原生 LSP 二进制文件是按平台划分的可选依赖 —— npm 会自动为你的系统安装匹配的平台包。如果你只需要插件逻辑,可以用 --omit=optional 跳过原生二进制文件:
pnpm add ocmm
or: npm install ocmm
npm tarball 不包含原生 LSP 二进制文件,以保持平台无关。用默认选项安装时,会从 npmjs.org 拉取匹配的 ocmm-lsp-<platform> 可选包,与主包一起安装。运行时解析顺序:先找可选的平台包,再回退到打包的 dist/bin(仅限 GitHub Release/Codex tarball),最后是本地构建 / PATH。
// opencode.json
{ "plugin": ["./node_modules/ocmm/dist/index.js"] }
对 Codex,把已安装的包根目录添加为本地 marketplace:
codex plugin marketplace add ./node_modules/ocmm --json
codex plugin add deepwork@deepwork-local --json
从 GitHub Release 安装
主包发布(vX.Y.Z)会发布自包含的 OpenCode/Codex 插件 tarball 及其校验和。独立的原生 ocmm-lsp- 可执行文件和平台包 .tgz 产物属于另一条发布线 ocmm-lsp-vA.B.C。
一个主包 vX.Y.Z 发布包含:
- ocmm-opencode-plugin-<version>.tgz —— OpenCode 插件的包管理器安装包,含 CLI 包装器、Codex bundle 和打包的原生二进制文件。
- deepwork-codex-plugin-<version>.tgz — Codex 插件包根目录,用于本地市场安装。
- SHA256SUMS.txt — 每个发布产物的校验和。
OpenCode 用包管理器安装发布 tarball 的资产 URL:
VERSION=0.6.5
pnpm add "https://github.com/<owner>/ocmm/releases/download/v${VERSION}/ocmm-opencode-plugin-${VERSION}.tgz"
发布 tarball 打包了 OpenCode 插件、ocmm、ocmm-profiles、ocmm-lsp 命令行包装器,以及 dist/bin/ 下带平台后缀的原生 ocmm-lsp 二进制文件。
它还包含 Codex 市场文件和一份自包含的生成插件包,位于 .agents/plugins/marketplace.json 和 plugins/deepwork/;Codex 包自带插件本地的 dist/cli、dist/shared、dist/bin 运行时,因此 Codex 的插件缓存可以运行默认的 lsp MCP。
// opencode.json
{ "plugin": ["./node_modules/ocmm/dist/index.js"] }
Codex 这边,可以把已安装的包根目录添加为本地市场:
codex plugin marketplace add ./node_modules/ocmm --json
codex plugin add deepwork@deepwork-local --json
也可以直接从 Codex 发布包安装。tarball 是包根目录结构,解压到 .codex-plugins/deepwork 这样的目录,再让市场指向该目录:
VERSION=0.6.5
curl -L -o "deepwork-codex-plugin-${VERSION}.tgz" "https://github.com/<owner>/ocmm/releases/download/v${VERSION}/deepwork-codex-plugin-${VERSION}.tgz"
mkdir -p .codex-plugins/deepwork
tar -xzf "deepwork-codex-plugin-${VERSION}.tgz" -C .codex-plugins/deepwork
codex plugin marketplace add ".codex-plugins/deepwork" --json
codex plugin add deepwork@deepwork-local --json
从 GitHub Packages 安装
发布工作流也能把同样的包内容发布到 GitHub Packages,包名为 @<owner>/ocmm。这样依然避开 npmjs.org,但安装走 npm.pkg.github.com,通常需要在 .npmrc 里配置带 read:packages 权限的 GitHub 个人访问令牌:
@<owner>:registry=https://npm.pkg.github.com
//npm.pkg.github.com/:_authToken=<github_pat_with_read:packages>
pnpm add @<owner>/ocmm
// opencode.json
{ "plugin": ["./node_modules/@<owner>/ocmm/dist/index.js"] }
Codex 这边,用带作用域的包根目录作为市场根目录:
codex plugin marketplace add ./node_modules/@<owner>/ocmm --json
codex plugin add deepwork@deepwork-local --json
在 GitHub Actions 里,如果工作流有包读取权限,可以用 ${GITHUB_TOKEN} 代替个人令牌。
原生 LSP 支持
ocmm 以多种形式提供 ocmm-lsp 原生二进制文件:
- npm 可选平台包:8 个按平台拆分的包发布到 npmjs.org(ocmm-lsp-linux-x64-gnu、ocmm-lsp-linux-arm64-gnu、ocmm-lsp-linux-x64-musl、ocmm-lsp-linux-arm64-musl、ocmm-lsp-darwin-x64、ocmm-lsp-darwin-arm64、ocmm-lsp-windows-x64、ocmm-lsp-windows-arm64)。npm 会根据你的操作系统、CPU 和 libc 自动安装匹配的那个。
- 打包进 GitHub Release tarball,放在 dist/bin/ 和 plugins/deepwork/dist/bin/ 下;
- 独立发布资产,命名为 ocmm-lsp-,可直接下载,也可用于自定义 OCMM_LSP_COMMAND 配置。
运行时解析优先级(先匹配到的胜出):
1. 可选的 npm 平台包(node_modules/ocmm-lsp-<platform>/bin/ocmm-lsp-<target>)
2. 打包进 release 的二进制文件(dist/bin/ocmm-lsp-<target>)——仅限 GitHub Release tarball
3. 本地 Cargo release/debug 构建
4. 从 crates/ocmm-lsp/ 执行 cargo run
5. PATH 中的 ocmm-lsp
Linux 构建同时覆盖 glibc(GNU)和 musl libc 目标,所以 Alpine 以及其他基于 musl 的发行版现在开箱即用,完全支持。
原生二进制文件针对以下平台构建:
| 平台 | npm 包 | 资产 |
| Linux x64 glibc | ocmm-lsp-linux-x64-gnu | ocmm-lsp-x86_64-unknown-linux-gnu |
| Linux arm64 glibc | ocmm-lsp-linux-arm64-gnu | ocmm-lsp-aarch64-unknown-linux-gnu |
| Linux x64 musl | ocmm-lsp-linux-x64-musl | ocmm-lsp-x86_64-unknown-linux-musl |
| Linux arm64 musl | ocmm-lsp-linux-arm64-musl | ocmm-lsp-aarch64-unknown-linux-musl |
| macOS x64 | ocmm-lsp-darwin-x64 | ocmm-lsp-x86_64-apple-darwin |
| macOS arm64 | ocmm-lsp-darwin-arm64 | ocmm-lsp-aarch64-apple-darwin |
| Windows x64 | ocmm-lsp-windows-x64 | ocmm-lsp-x86_64-pc-windows-msvc.exe |
| Windows arm64 | ocmm-lsp-windows-arm64 | ocmm-lsp-aarch64-pc-windows-msvc.exe |
ocmm 默认注册内置的 OpenCode MCP,名为 lsp,使用项目自有的 ocmm-lsp mcp 服务器。解析时优先用可选的 npm 平台包,然后是 dist/bin/ 里打包进 release 的二进制文件,接着是本地 Cargo release/debug 构建,再从 crates/ocmm-lsp/ 执行 cargo run,最后是 PATH 中的 ocmm-lsp。设置 OCMM_LSP_COMMAND 可强制使用自定义命令,添加 disabledMcps:["lsp"] 可禁用它,或者定义 mcp.servers.lsp 覆盖内置配置。
如果要在外部程序里直接使用,从 ocmm-lsp-vA.B.C release 下载匹配的独立资产,然后把 OCMM_LSP_COMMAND 指向它:
LSP_VERSION=0.3.2
curl -L -o ~/.local/bin/ocmm-lsp "https://github.com/<owner>/ocmm/releases/download/ocmm-lsp-v${LSP_VERSION}/ocmm-lsp-x86_64-unknown-linux-gnu"
chmod +x ~/.local/bin/ocmm-lsp
OCMM_LSP_COMMAND="$HOME/.local/bin/ocmm-lsp" opencode run "check diagnostics"
OCMM_LSP_COMMAND 填普通值时,会自动补上 mcp 参数。只有需要精确控制参数时,才用 JSON 数组,例如 ["/path/to/ocmm-lsp","mcp"]。
从源码构建
pnpm install
pnpm run build
然后把 OpenCode 配置指向构建好的插件:
// opencode.json
{ "plugin": ["./node_modules/ocmm/dist/index.js"] }
或者用 ocmm 垫片二进制(见下文)启动 opencode,自动加载插件并隔离配置。
Nix
不用把 ocmm 加进配置档就能运行,也可以构建两个主包中的任意一个:
nix run github:hugefiver/ocmm
nix build github:hugefiver/ocmm#ocmm
nix build github:hugefiver/ocmm#ocmm-lsp
默认包和应用都包装了 nixpkgs 的 OpenCode 包,所以垫片总能拿到一个已知的 OpenCode 可执行文件。ocmm-unwrapped 只包含插件和原生 LSP;OpenCode 的选择则交给命令行、配置、环境变量或 PATH。
Unfree 策略
flake 里的直接包和应用只带一条很窄的内部 AAAPL allowUnfreePredicate 许可,仅覆盖 ocmm 自己的 derivation,所以普通的 nix run github:hugefiver/ocmm 不需要环境里预先有 NIXPKGS_ALLOW_UNFREE。由于 AAAPL 是非自由协议,下游的 overlay、factory、Home Manager 和 NixOS 使用者必须在自己的 pkgs 里配置同样这条窄许可:
nixpkgs.config.allowUnfreePredicate = package:
builtins.elem (lib.getName package) [
"ocmm-lsp"
"ocmm-unwrapped"
"ocmm"
];
Overlay
把 overlay 加进安装 ocmm 的那个包集合。下面这个完整的 NixOS flake 示例让 ocmm 和使用者共用同一个 nixpkgs 输入,并在选中 pkgs.ocmm 之前应用这条窄许可:
{
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
ocmm = {
url = "github:hugefiver/ocmm";
inputs.nixpkgs.follows = "nixpkgs";
};
};
outputs = inputs@{ nixpkgs, ... }: {
nixosConfigurations.example = nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
modules = [
({ lib, pkgs, ... }: {
nixpkgs.config.allowUnfreePredicate = package:
builtins.elem (lib.getName package) [
"ocmm-lsp"
"ocmm-unwrapped"
"ocmm"
];
nixpkgs.overlays = [ inputs.ocmm.overlays.default ];
environment.systemPackages = [ pkgs.ocmm ];
system.stateVersion = "24.11";
})
];
};
};
}
包工厂
lib.mkOcmmPackage 围绕选定的基础 ocmm 包创建一个包装。可以选一个 OpenCode derivation:
inputs.ocmm.lib.mkOcmmPackage {
inherit pkgs;
opencodePackage = pkgs.opencode;
}
也可以选一个可执行命令:
inputs.ocmm.lib.mkOcmmPackage {
inherit pkgs;
opencodeCommand = "/opt/opencode/bin/opencode";
}
opencodePackage 和 opencodeCommand 互斥。在传给工厂的 pkgs 里配置上面那条窄许可。
垫片按下面这个确切顺序解析 OpenCode:
1. --opencode
2. non-empty OCMM_OPENCODE
3. ocmm.json or ocmm.jsonc shim.opencode
4. non-empty OCMM_NIX_OPENCODE
5. non-empty OCMM_PROGRAMS_OPENCODE
6. opencode from PATH
Home Manager
独立使用 Home Manager 时,传给 homeManagerConfiguration 的 pkgs 要用同样窄的谓词构造。配置导入默认模块,并启用两个程序:
{
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
home-manager.url = "github:nix-community/home-manager";
home-manager.inputs.nixpkgs.follows = "nixpkgs";
ocmm = {
url = "github:hugefiver/ocmm";
inputs.nixpkgs.follows = "nixpkgs";
};
};
outputs = inputs@{ nixpkgs, home-manager, ocmm, ... }:
let
system = "x86_64-linux";
lib = nixpkgs.lib;
pkgs = import nixpkgs {
inherit system;
config.allowUnfreePredicate = package:
builtins.elem (lib.getName package) [
"ocmm-lsp"
"ocmm-unwrapped"
"ocmm"
];
};
in {
homeConfigurations."user@example" = home-manager.lib.homeManagerConfiguration {
inherit pkgs;
modules = [
{
imports = [ ocmm.homeManagerModules.default ];
home.username = "user";
home.homeDirectory = "/home/user";
home.stateVersion = "24.11";
programs.ocmm.enable = true;
programs.opencode.enable = true;
}
];
};
};
}
两个程序都启用、且 programs.opencode.package 非空时,wrapper 会复用那个包,并把 ocmm 的 store 插件路径追加到现有 OpenCode 插件列表末尾。
两个模块也都接受 programs.ocmm.opencode.command,用来显式指定 OpenCode 可执行文件路径或命令名。programs.ocmm.opencode.package 与 programs.ocmm.opencode.command 互斥;在 Home Manager 里,两者都不设置时,模块会复用已启用的 programs.opencode.package。
NixOS 模块
在 NixOS 包集合里配置同样的谓词之后,导入默认 NixOS 模块,并显式设置 OpenCode 包:
{
imports = [ inputs.ocmm.nixosModules.default ];
programs.ocmm = {
enable = true;
opencode.package = pkgs.opencode;
};
}
NixOS 模块只安装包和 wrapper。它从不创建服务或用户配置。
CI 缓存
仓库的 Nix 工作流始终使用 GitHub Actions 的 Nix store 缓存。Cachix 是可选的:设置仓库变量 CACHIX_CACHE_NAME 即可启用,设置仓库密钥 CACHIX_AUTH_TOKEN 即可认证写入。没有该变量时,Cachix 不配置;没有该 token 时,它只读。Pull request 永远拿不到 token,只有对 master 的可信推送或手动运行工作流,才能用它推送。
Codex 适配器
ocmm 还附带一个 Codex 插件包,由同一份本地工作流数据生成:
.agents/plugins/marketplace.json
plugins/deepwork/
.codex-plugin/plugin.json
.mcp.json
package.json
agents/.toml
dist/{cli,shared,bin}/
skills/
改动提示词、技能、智能体、分类或 MCP 配置逻辑后,重新生成或刷新:
pnpm run gen:codex-plugin
生成器刻意与 OpenCode 运行时分离。它先读项目配置 <project>/.codex/ocmm.jsonc,再读 <project>/.opencode/ocmm.jsonc;默认不读用户全局配置,所以本地服务商名称或密钥不会写进提交的 Codex 包。项目配置不存在时,用 ocmm 默认值。
装到隔离的 Codex home 里测试:
$env:CODEX_HOME = "$env:LOCALAPPDATA\Temp\codex\ocmm-test"
mkdir.exe -p $env:CODEX_HOME
codex plugin marketplace add . --json
codex plugin add deepwork@deepwork-local --json
codex plugin list --available --json
Codex 插件暴露这些内容:
- 复制过来的 ocmm 共享技能,加上从 skills/v1/ 展平的 deepwork- 技能;
- deepwork 技能,把 ocmm 的规划/委派语义映射到 Codex 工具;
- 插件作用域的 MCP 服务器,由 ocmm 的 MCP 配置生成,包括默认的 lsp MCP,由插件本地的 ocmm-lsp wrapper 提供;
- 生成的 dw- Codex 智能体 TOML 文件,放在 plugins/deepwork/agents/ 下,供安装器或本地智能体注册使用,包括 dw-oracle、dw-oracle-2nd、dw-creative 这类功能性智能体;配置了 review variants 时,还能输出 dw-oracle-high、dw-oracle-2nd-low 这类逻辑层级配置档。
OpenCode 仍然用 dist/index.js 和它的 OpenCode 钩子接口。Codex 适配器在运行时不会导入或改动 OpenCode 插件模块。
配置
把配置文件放到下面任一位置(冲突时项目配置优先):
- <project>/.opencode/ocmm.jsonc
- ~/.config/opencode/ocmm.jsonc(所有平台,包括 Windows —— 沿用 opencode 的约定)
Schema(Zod 校验;未知对象键会被剥掉)。声明为非法的字段会让直接 schema 解析失败,运行时加载会在本地剪掉它们,好让合法的同级字段和低优先级值活下来。所有字段都可选:
{
"workflow": "v1", // OpenCode default
"disabledAgents": ["media-reader"],
"disabledSkills": ["debugging"],
"disabledCommands": ["ralph-loop"],
"disabledMcps": [],
"skills": {
"sources": [],
"enable": [],
"disable": []
},
// Opt in per provider before --fast / OCMM_FAST can promote a route.
"fastModels": {
"defaultRules": true,
"providers": ["openai"],
"mappings": {
"openai/<original-model>": "<provider-local-fast-model>"
},
// Rules are a fallback after model promotion. Later matches override earlier ones.
"rules": [
{
"match": { "provider": "openai" },
"options": { "telemetry": { "fast": true } }
},
{
"match": { "model": "gpt-5.", "sdk": "@ai-sdk/openai" },
"options": { "serviceTier": "priority", "telemetry": { "sampled": true } }
},
{
"match": { "model": "gpt-5.", "sdk": "@ai-sdk/openai-compatible" },
"options": { "service_tier": "priority", "telemetry": { "sampled": true } }
}
]
},
"agents": {
"reviewer": {
"model": "<provider>/<primary-reasoning-model>",
"variant": "max",
},
"orchestrator": {
"reasoning": "high",
"models": [
"openai/gpt-5.6-sol:high",
{
"model": "anthropic/claude-sonnet-4-6:max",
"reasoning": "max",
"temperature": 0.2,
"top_p": 0.8,
"max_tokens": 8192
}
],
},
"builder": {
"requirement": {
"variant": "high",
"requiresProvider": ["<provider>"],
"fallbackChain": [
{ "providers": ["<provider>"], "model": "<implementation-model>", "variant": "high" },
],
},
},
},
"categories": {
"hard-reasoning": {
"models": ["openai/gpt-5.6-sol:xhigh"],
},
},
"runtimeFallback": {
"enabled": true,
"dispatch": true,
"maxAttempts": 3,
"cooldownSeconds": 60,
"retryOnStatusCodes": [402, 429, 500, 502, 503, 504],
"retryOnPatterns": [
"rate.?limit",
"too.?many.?requests",
"usage.?quota.{0,20}?(?:exceeded|exhausted|reached)",
"quota.?exceeded",
"(?:exceeded|exhausted|reached).{0,20}?quota",
"free.?usage.{0,20}?(?:exceeded|exhausted|limit)",
"usage.?exceeded",
"(?:usage|quota)\\s+limit\\s+exhausted",
"exhausted\\s+your\\s+capacity",
"all\\s+credentials\\s+for\\s+model",
"cool(?:ing)?\\s+down",
"model.{0,20}?not.{0,10}?supported",
"model_not_supported",
"service.?unavailable",
"temporarily.?unavailable",
"overloaded",
"internal server error",
"gateway timeout",
"bad gateway",
"try\\s+again\\s+(?:later|shortly|in\\s+\\d+\\s(?:seconds?|minutes?))",
"\\b429\\b",
"\\b503\\b",
"\\b529\\b",
"使用上限", "频率限制", "请求过于频繁", "暂时不可用", "服务不可用", "请稍后重试", ],
"subagent429": {
"enabled": true,
"maxRetries": 5,
"providerScopes": {
"anthropic": "provider",
"openai": "model"
}
}
},
"subagent": {
"maxDepth": 3
},
"idleContinuation": {
"enabled": false,
"maxContinuations": 20,
"prompt": "Your todo list has unfinished items. Continue with the next pending or in-progress task. Do not ask for confirmation — proceed." },
"mcp": {
"enabled": true,
"envAllowlist": ["EXA_API_KEY", "CONTEXT7_API_KEY"],
"websearch": { "provider": "exa" }, // "exa" or "tavily"
"servers": {
// Explicit entries override built-ins. Use this to replace or pin lsp.
// "lsp": { "type": "local", "command": "custom-lsp", "args": ["mcp"] }
}
},
"shim": {
"mode": "none", // none|inline|config-file|config-dir|xdg (default: none)
"configDir": "/custom", // target dir for config-dir/xdg modes
"configFile": "/path.json", // target file for config-file mode
"opencode": "/usr/local/bin/opencode",
"keepOmo": false,
"noProviders": false,
"noPlugins": false,
},
"registerBuiltinAgents": true,
"debug": false,
}
OpenCode 宿主子代理深度兼容性
OpenCode 提交 285d315b4e5355e0a94608acc0678a11b720079e 新增了顶层 subagent_depth 设置。它的隐式默认值是 1。ocmm 的 subagent.maxDepth 默认值仍是 3。
两个守卫都生效时,实际 Task 上限取较小的那个值。ocmm 从不把自己的值写进宿主配置,也从不改动任何一方的默认值。如果插件配置钩子里能读到宿主字段,OCMM_DEBUG=1 会记录一次宿主与本地组合的结果:两者一致时输出 info 消息,不一致时输出 warn 消息并指出更严格的那个守卫。如果 ocmm 的守卫被禁用,同样的调试设置会针对仅宿主的上限输出 info 消息。
subagent_depth 字段缺失并不能说明宿主版本。它可能意味着较旧的宿主没有这个能力,也可能意味着较新的宿主正在使用隐式默认值 1,这两种运行时情况都不会产生兼容性日志。在较新的宿主上省略该字段时,实际宿主上限是 1,本地上限是 3,实际生效上限是 1;运行时想解释这种情况,只能靠本文档。
| 宿主情况 | 宿主上限 | 本地守卫 | 实际 Task 上限 | OCMM_DEBUG=1 时的诊断 |
| 提交之前,字段不可用 | 不可用 | 启用,本地 3 | 3 | 无 |
| 新宿主,字段省略 | 隐式 1 | 启用,本地 3 | 1 | 无 |
| 显式 subagent_depth: 1 | 1 | 启用,本地 3 | 1 | warn,宿主更严格 |
| 显式 subagent_depth: 3 | 3 | 启用,本地 3 | 3 | info,上限一致 |
| 显式 subagent_depth: 5 | 5 | 启用,本地 3 | 3 | warn,ocmm 更严格 |
| 显式 subagent_depth: 1 | 1 | 禁用 | 1 | info,仅宿主 |
两个控制项都只作用于 OpenCode 的 task 派发。ocmm 不会把名为 execute 的工具归类为 task,所以两个深度守卫都不作用于 execute。
标准评审槽位配置
{
"agents": {
"oracle": {
"model": "openai/gpt-5.6-terra",
"variant": "xhigh",
"variants": {
"low": "high",
"high": "max",
"max": { "model": "openai/gpt-5.6-sol", "variant": "max" }
}
},
"oracle-2nd": {
"model": "anthropic/claude-opus-4-7",
"variant": "xhigh",
"variants": { "max": "max" }
},
"oracle-3rd": { "model": "google/gemini-3.1-pro" },
"reviewer": {
"model": "openai/gpt-5.6-sol",
"variants": { "high": { "variant": "max" } }
},
"planner": {
"variants": {
"low": { "model": "openai/gpt-5.5", "variant": "high" },
"high": "max",
"max": { "model": "openai/gpt-5.6-sol", "variant": "max" }
}
},
"plan-critic": {
"variants": {jsonc
"low": { "model": "openai/gpt-5.5", "variant": "low" },
"high": "xhigh",
"max": { "model": "openai/gpt-5.6-sol", "variant": "max" }
}
}
}
}
- 不带后缀的槽位名(oracle、oracle-2nd、oracle-3rd、reviewer)表示逻辑上的 normal 档。
- 逻辑档(-low/-high/-max)与服务商原生模型 variant 是两个独立的控制项。
- 评审槽位是优先级顺序,不是能力排名。
- 槽位 oracle-3rd 到 oracle-9th 需要显式配置。
- 配置了多个评审配置档也不会自动并行分发;派发时仍然只用一个选定的配置档。
- reviewer 没有序号槽位命名。
- reviewer 是主模型或主通道自审;Oracle 槽位默认是外部模型交叉检查。用户显式配置模型后,这种异构性可能消失。
- Reviewer 和 Oracle 配置档只用于软件实现验收,或在实现补丁已存在后做针对性的代码质量验证,不用于调研、构思、架构设计、根因调试、通用答案校验或日常信心确认。
- 即使选了逻辑 low 档,xhigh 等效的评审下限依然生效。
- 不带后缀的 planner 和 plan-critic 是它们逻辑上的 normal 配置档。它们的 -low、-high、-max 后缀配置档只在显式配置了 variants 时才实体化;示例或生成的文件不能证明某个配置档当前可调用。
- 派发规划角色之前,先查看当前可调用/已注册的名称,再选第一个可用候选:显式要求成本/延迟时用 low 再 normal;小而清晰的任务用 normal;复杂/跨模块用 high 再 normal;安全/性能/数据丢失/发布安全/运行时安全/关键迁移类工作用 max 再 high 再 normal。绝不凭空造一个不存在的后缀。
- 每个生成的规划档都继承其规范角色的提示词、模式、权限、注册策略、路由行为和回执语义。档位只改变配置的模型路由。
- plan-critic-low 可以选成本更低或延迟更低的模型,但它不是更低强度的评审:xhigh 等效下限依然强制生效。
- agents.oracle-high 是已废弃的配置写法,会迁移到 agents.oracle-2nd;而运行时的 oracle-high 仍是第一槽位的逻辑 high 档。
- 别名与规范名冲突会导致校验失败。
- schema.json 和直接解析 OcmmConfigSchema 仍然严格。运行时 loadConfig() 是宽容的:某个评审字段或条目与 schema 不匹配时,只在本地丢弃它,有效的同级项和低优先级值仍会加载。只有别名/规范名迁移冲突这种歧义情况才回退到默认值。
禁用评审槽位与中断恢复 jsonc {
"disabledAgents": ["oracle-2nd", "oracle-high"],
"disabledHooks": ["subagent-interruption-recovery"]
}
- oracle-2nd 会禁用整个第二评审槽位,包括它的逻辑档配置档。
- oracle-high 只禁用第一槽位的逻辑 high 档配置档,不会禁用 oracle normal 或其他槽位。
- subagent-interruption-recovery 是可选的证据关联 + 恢复提示行为,叠加在现有回退流程之上。
中断恢复行为:
1. 复用现有的专用 429/通用回退控制器与重试预算。
2. 按子会话关联证据,并对父级 message.part.updated 证据去重。
3. 把子级 session.error 当作服务商错误证据。
4. 绝不重试显式中止、权限拒绝、未知智能体、删除,或普通空输出结果。
5. 只有在任务输入/输出或关联的父级 part 证据中观察到显式任务标识符时,才可追加一条手动续跑通知;它绝不会用 childSessionID 替代 task_id,不会从 tool.execute.after 派发,也不会合成父级提示词。
Shorthand vs full form
Both agents. and categories. accept either shape:
| Field | Type | Meaning |
| models | non-empty array of string \| { model, reasoning?, temperature?, top_p?, max_tokens? } | Preferred canonical fallback chain. Objects validate temperature 0..2, top_p 0..1, and positive integer max_tokens; unknown keys are stripped. |
| model | "provider/model" string | Legacy primary shorthand. Split into providers: [provider] plus model. |
| variant | "low" \| "medium" \| "high" \| "xhigh" \| "max" \| "minimal" \| "none" \| "auto" \| "thinking" | Requirement default; with legacy model, also promoted onto the first chain entry. |
| reasoning | "off" \| "minimal" \| "low" \| "medium" \| "high" \| "xhigh" \| "max" \| "auto"; deprecated input alias "none" | Canonical requirement default. An individual models object value is entry-local and wins its model suffix. |
| fallbackModels | array of string \| FallbackEntry | Legacy fallback shorthand appended after legacy model; its ordinary user/project accumulation behavior is unchanged. |
| requirement | full ModelRequirement object | Full guards/defaults. With models, only its chain is replaced; otherwise it outranks legacy model/fallbackModels. |
| disabled | true | (Agents only.) Removes the agent from registration. |
| description | string | Overrides the built-in description (used in agent registration). |
models[0] is the primary model; the remaining entries are ordered runtime fallbacks. Internally, ocmm normalizes the array to the existing route/fallback chain. Direct model-source precedence is models → requirement chain → model plus fallbackModels → alias; chains are never merged. When models and requirement coexist, ocmm replaces only fallbackChain while preserving cloned requirement guards and defaults. Explicit top-level reasoning/variant overrides requirement defaults; per-entry fields remain local. provider_options is unsupported and, like other unknown object fields, is stripped before runtime. Legacy forms remain supported.
Hook defaults
disabledHooks in config controls which hooks are active. Default: ["directory-readme-injector"] — only the directory README injector is disabled out of the box; all other hooks are enabled. The full list:
| Hook name | Default | Purpose |
| directory-readme-injector | Disabled | Read tool output appends the nearest README.md once per directory/session; disabled by default. |
| directory-agents-injector | Enabled | Read tool output appends AGENTS.md directory context found upward from the read file, within project root, once per directory/session. |
| rules-injector | Enabled | Appends configured rule blocks to matching Read/Write/Edit tool output when rules are enabled. |
| write-existing-file-guard | Enabled | Tracks Read permissions; blocks write overwriting existing files and edit/multiedit/patch-style edits without prior read where applicable. |
| notepad-write-guard | Enabled | Blocks write/edit/multiedit under .omo/notepads/ and .sisyphus/notepads/. |
| bash-file-read-guard | Enabled | Warns when a Bash command appears to be a simple file read (cat, head, tail); does not block. |
| bash-file-write-guard | Enabled | Blocks Bash commands that write to existing project files through redirects, tee/dd/install/truncate, in-place editors, copy/move overwrites, or nested shell scripts. |
| question-label-truncator | Enabled | Truncates ask-user-question option labels over 30 chars. |
| tasks-todowrite-disabler | Enabled | Blocks todoread while the task system is active, making todowrite the source of truth. |
| webfetch-redirect-guard | Enabled | Resolves HTTP redirects and rewrites the WebFetch URL to the final URL. |
| empty-task-response-detector | Enabled | Replaces empty Task tool output with a warning/notice. |
| comment-checker | Enabled | Warns on AI-attribution comments in write/edit/multiedit content unless a bypass marker is present. |
| plan-format-validator | Enabled | Warns on malformed checklist lines in .omo/plans/.md writes/edits. |
| read-image-resizer | Enabled | Appends a dependency-free build notice for image Read outputs; does not resize. |
| json-error-recovery | Enabled | Appends recovery instructions when tool output contains JSON parse errors. |
| fsync-skip-warning | Enabled | Appends drained fsync skip warnings from the fsync tracker. |
| tool-output-truncator | Enabled | Truncates very large selected tool outputs. |
| history-cache-mitigation | Disabled | Optional cache workaround that truncates older completed tool outputs in configured model histories before model-message conversion. Prefer OpenCode's native tool_output truncation for stable prefixes. |
| todo-description-override | Enabled | Overrides the todowrite tool description with ocmm’s structured todo format. |
| commit-guard-injector | Enabled | Injects the no-autonomous-git-write constraint into the system prompt. |
| subagent-git-guard | Enabled | Blocks git write commands in subagent sessions except allowed temp-repo cases. |
| subagent-interruption-recovery | Enabled | Correlates child-session interruption evidence (session.error + message.part.updated) and lets the output adapter append at most one manual continuation notice without owning retry dispatch. |
| subagent-depth-guard | Enabled | Blocks task dispatches that would exceed local subagent.maxDepth (default 3); when host subagent_depth is observable, the effective limit is the lower active value and OCMM_DEBUG logs compatibility once per combination. Never treats execute as task. |
Variant policy
variant is a routing hint, not a portable provider API. ocmm normalizes it by model family before writing chat.params:
| Model family | ocmm behavior |
| Explicit user config or request | Respected as written except for review/plan-review floors: reviewer, Oracle review profiles (oracle, oracle-high, oracle-2nd, etc.), and plan-critic are raised to the model family's xhigh-equivalent/highest-supported review effort when possible. |
| GPT-like non-mini built-in defaults | Older GPT defaults retain the high floor. GPT-6.1+ Sol preserves low/medium and maps unsupported minimal/canonical off to low; explicit neutral none remains a no-op. Category defaults from coding upward resolve to max. GPT-5.6+ supports native reasoningEffort=max; other families use their supported maximum effort. |
| GPT-like mini | Keeps the provider's full low-effort ladder, including minimal, low, and no-op none when supported. |
| Claude Opus 4.7+ / Fable | Built-in defaults do not emit an ocmm-owned thinking budget or reasoningEffort; explicit non-review user config is passed through as written, while review/plan-review agents still receive the xhigh-equivalent floor when possible. |
| Older Claude | Uses Anthropic thinking budgets for non-none variants. |
| Gemini | Uses reasoningEffort; high and above also enable provider thinking. |
| Latest GLM / DeepSeek | Built-in defaults normalize low/medium-style local variants to canonical high/max controls where the provider family supports them; non-review explicit user config or request variants are left as written. |
| Category defaults | quick stays lightweight. Built-in category defaults from coding upward resolve to max; explicit user category config or input variants are respected as written. |
| Kimi / MiniMax / unknown | Uses the existing temperature shaping fallback when no better family-specific knob exists. |
History cache mitigation
historyCacheMitigation is disabled by default. It is an opt-in workaround for existing long OpenCode histories where large completed tool outputs were already persisted before OpenCode's native tool_output truncation limits were configured. It uses OpenCode's experimental.chat.messages.transform hook to truncate older completed tool outputs before history is converted to model messages, while preserving recent tool results intact.
jsonc
{
"historyCacheMitigation": {
"enabled": false,
"models": ["gpt-5.6-sol"],
"maxToolOutputChars": 16000,
"preserveRecentToolResults": 24
}
}
Enable it explicitly with "historyCacheMitigation": { "enabled": true } only when native tool_output truncation and compaction pruning are insufficient for old long sessions. Increase preserveRecentToolResults or maxToolOutputChars if a workflow depends on large older tool outputs staying verbatim in model history.
Built-in agents
orchestrator primary reasoning lane variant=max main coordinator
builder implementation lane variant=high autonomous implementer
reviewer primary review lane xhigh floor implementation self-review
oracle review slot 1 (logical normal) xhigh floor external-model cross-check
oracle-high review slot 1 logical high derived profile runtime tier profile (from variants)
oracle-2nd review slot 2 (logical normal) xhigh floor second-priority external cross-check
doc-search lightweight lookup lane (none) external docs / OSS lookup
code-search lightweight lookup lane (none) internal codebase grep
planner primary reasoning lane variant=max work-plan author
clarifier analysis lane (none) pre-plan analysis
plan-critic primary review lane variant=xhigh plan QA
media-reader multimodal-capable lane variant=high multimodal analysis
Built-in categories (also registered as subagents)
frontend UI/multimodal-capable lane variant=high UI/UX, layout, styling, visual QA
creative creative-capable lane variant=high concepts, naming, narrative, framing
hard-reasoning primary reasoning lane variant=xhigh ultrabrain-style decisions and tradeoffs
research research-capable lane variant=high missing-fact investigation and evidence gathering
quick lightweight lane (none) fully specified mechanical edits
coding implementation lane (none) determined code edits and bug fixes
normal-task implementation lane (none) ordinary bounded tasks
complex coordinated-work lane variant=high coordinated multi-step ordinary tasks
deep primary reasoning lane variant=max autonomous system development and delivery
documenting prose-capable lane (none) standalone documentation and prose
Rows above describe built-in selection lanes, not required provider channels or model IDs. Example model names elsewhere in the repository are references only; explicit user configuration and the currently available model catalog decide the actual model. Agent rows show source defaults or enforced review floors; category rows show the raw source values from src/data/categories.ts. At runtime the variant policy normalizes categories from coding upward to model-appropriate max unless the user explicitly overrides them; see the variant policy table above. Entries marked (none) carry no built-in variant and rely on this normalization.
New GPT defaults use GPT-6.1 Sol for former Terra and high/xhigh Sol assignments, GPT-6 Astra for maximum-tier assignments, and GPT-6 Luna for lightweight lookup roles. Existing Astra heads remain Astra-first; GPT-5.5 and GPT-5.4 (including mini) remain compatibility fallbacks rather than new primary defaults. Runtime upgrades use only observed provider catalog keys in the declared lane: newer Astra versions such as 6.1/6.2 are eligible, but Sol, Luna, and unlabelled GPT models are not Astra successors. Provider tie order and fallback tuning are preserved.
Codex generation is offline: its confirmed-model table and project .codex/ocmm.jsonc are build inputs, not a live release monitor. Future Codex defaults require an explicit configuration/table update and regeneration; user-selected models are never globally migrated. This checkout's local Codex config was explicitly updated to GPT-6.1 Sol while retaining its variants and existing Astra/Luna selections. Codex preserves Sol/Luna low/medium effort in the new assignments, with the existing reviewer/Oracle/plan-critic xhigh floors still enforced.
The primary review structure is primary-model or primary-lane self-review through reviewer, plus external-model cross-checks through canonical Oracle slots (oracle, oracle-2nd, optional oracle-3rd ... oracle-9th when explicitly configured). Runtime logical tier names such as oracle-high and oracle-max are derived from configured variants and stay within slot 1; they are not separate slot registrations. oracle is the first external cross-check slot and shares implementation-review semantics via promptSource: "reviewer"; oracle-2nd is the second-priority external slot. Explicit user model configuration remains authoritative and may remove model heterogeneity. agents.oracle-high is a deprecated config spelling migrated to agents.oracle-2nd during config load so legacy config keeps working while canonical keys remain slot-based. Supporting utility agents (builder, doc-search, code-search, media-reader) still use the workflow/model-family deepwork prompt without an additional role prompt. builder is registered with mode:"primary"; planner is registered with mode:"all" so it can be selected directly and used as a delegated task agent. Each category has a prompt under prompts/<workflow>/category/<name>.md that is set as the category-subagent's system prompt. Callers invoke categories via task(category="deep", ...) or direct subagent names such as @deep and @quick. The upstream-style compatibility alias @explore maps to local code-search; @oracle selects the independent local oracle agent rather than aliasing reviewer.
Category model-availability diagnostics
With OCMM_DEBUG=1, the config hook emits one deduplicated availability diagnostic for each successfully registered built-in or custom category and each distinct observed diagnostic state. Every message includes the category name, requirement/primary provenance, selected model, candidate summaries, and routePreserved=true.
| Status | Meaning |
| available | The current host catalog contains an exact eligible provider/model key, or requiresAnyModel is active and an eligible observed provider exposes at least one model. |
| dead | The normalized fallback chain is empty, or every candidate is structurally impossible because it conflicts with requiresModel or requiresProvider. |
| unknown | At least one candidate is structurally eligible, but the host catalog is missing, malformed, incomplete, or does not currently show the provider/model. |
These diagnostics are read-only. target.provider[].models is observation evidence, not proof of credentials or runtime access, and catalog absence never disables a category. A dead or unknown category remains registered; diagnostics do not change selected primaries, catalog upgrades, provider defaults, canonical models[], effective-route snapshots, or runtime fallback. Messages contain provider IDs and model keys only—never provider options, API keys, URLs, response bodies, or the full host config. The existing logger keeps all of this output silent unless OCMM_DEBUG is enabled.
Prompt architecture
OpenCode sources and the independent Codex adapter are organized separately:
prompts/
v1/ # OpenCode deepwork prompts
deepwork/{default,gpt,claude-opus-5,gemini,glm,codex,planner,kimi-k27,swe-2}.md
agents/{orchestrator,reviewer,planner,clarifier,plan-critic}.md
category/.md (11 sources; 10 default categories, cross-cutting opt-in)
codex/ # Codex adapter sources
deepwork/ agents/ category/
skills/
ast-grep/ # shared skills registered as OpenCode skills + slash commands
coding-agent-sessions/ # local session-history finder shared skill
debugging/
frontend/
git-master/
init-deep/
v1/ # forked superpowers skills (v1 only)
brainstorming/SKILL.md
writing-plans/SKILL.md
subagent-driven-development/SKILL.md
requesting-code-review/SKILL.md
receiving-code-review/SKILL.md
Model-family variant selection (pickDeepworkVariantForAgent):
- planner agent -> planner.md
- GPT family -> gpt.md
- Gemini family -> gemini.md
- GLM family -> glm.md
- Codex family -> codex.md
- others (Claude/Kimi/Minimax/unknown) -> default.md
Variant is selected at config time using the final selected agent model after explicit user configuration, inherited aliases, and catalog-confirmed upgrades are considered. Built-in functional agents compose their authoritative agents/<name>.md role before subordinate workflow/model calibration. Each adapter's deepwork/gpt.md is the sole GPT/Codex behavioral calibration, applied once to detected GPT/Codex models, including planners and categories. Planner retains its planning doctrine; codex.md contains only host tool compatibility. Category roles remain authoritative, with no Astra-only inline addenda. Opus calibration remains orchestrator-only; Kimi/SWE keep their separate additive layers. Explicit prompt overrides retain priority.
Codex profiles carry one guarded shared GPT layer ahead of runtime selection: GPT/Codex-family models apply it, non-GPT models ignore it without ignoring their role, planner, embedded skills, or adapter tool instructions. GPT generations share prompt behavior, not parameter capabilities: runtime model detection, native max support, effort translation, and review floors remain model-dependent. Generated profiles are refreshed only through the generator. Prompts are attached declaratively, not selected by conversation keywords.
For OpenCode, v1 skills are injected on the first message per session via chat.message (queue) + system.transform (prepend).
Slash Commands
ocmm registers OpenCode config.command entries for:
- Shared skills under skills/, available as /git-master, /ast-grep, /coding-agent-sessions, /frontend, /debugging, and /init-deep by default.
- v1 injected deepwork skills when workflow:"v1" is active, available as /brainstorming, /writing-plans, /subagent-driven-development, /requesting-code-review, and /receiving-code-review. In v1, ocmm also adds skills/v1 to OpenCode skill paths so native skill slash resolution works without "skill not found" noise.
- Loop protocol commands /ralph-loop, /audit-loop, and /dwloop (/dwloop is the deepwork-loop alias for /audit-loop).
Interactive OpenCode uses its native slash-command parser. For noninteractive opencode run "/command args" calls, OpenCode 1.17.9 passes the first message directly and does not parse project commands; ocmm compensates by expanding bare ocmm command text during chat.message and injecting the expanded command once through system.transform.
The loop commands are command-template entry points only. They explicitly tell the model to run the loop in the current session and not claim hidden auto-continuation. The Ralph Loop runtime and related hooks are tracked as follow-up work in docs/kb/omo-features/loops.md.
ocmm does not ship a separate /lsp-setup command. OpenCode already provides LSP setup guidance, while ocmm's responsibility is to register and distribute the default lsp MCP backed by ocmm-lsp. Configure external language servers through .opencode/ocmm-lsp.json, .opencode/lsp.json, or .codex/lsp-client.json when overrides are needed.
Coding-agent session search
/coding-agent-sessions searches local coding-agent session stores, including Aside, through its bundled finder. It supports JSON list, search/find, and get/read output with child-session linkage; it reads local stores only and implies no network request. Runtime needs Python 3.11+ and the standard library only; the source retains pytest development tests, but they are not distributed.
Use explicit platform and root constraints when reading history. Omitting either broadens known-store discovery and may inspect local session history:
powershell
$sessionRoot = "C:\exports\coding-agent-session-fixture"
python skills/coding-agent-sessions/scripts/find-agent-sessions.py find "ambassador" --platform aside --root "$sessionRoot"
The imported subtree has its separate license in skills/coding-agent-sessions/LICENSE-UPSTREAM.md.
Profiles
A profile is a named partial overlay on the base config. It can override any top-level field (agents, categories, runtimeFallback, subagent, debug, etc.) except profiles and activeProfile themselves. At load time, after merging user + project configs, the active profile is deep-merged over the result — profile wins over both.
Selecting a profile
Ambient selection remains, in priority order: OCMM_NO_PROFILE, then OCMM_PROFILE, then config activeProfile.
1. OCMM_NO_PROFILE=1 or OCMM_NO_PROFILE=true disables profile selection for that process.
2. OCMM_PROFILE env var selects a profile for the shell without persisting it:
bash
OCMM_PROFILE=gpu opencode run "..."
Empty string is treated as unset — falls back to the config's activeProfile.
3. activeProfile in the config file is the persisted fallback:
jsonc
{ "activeProfile": "gpu" }
If the named profile doesn't exist, the OpenCode plugin facade warns and preserves the base config.
OpenCode plugin profile facade and qualified aliases
Directory profile descriptors and qualified aliases are an OpenCode plugin facade feature. Only loadOpenCodePluginConfig materializes them; ordinary programmatic loadConfig calls — including loadConfig({ host: "opencode" }) — and the Codex adapter remain non-materializing.
For each profile name, descriptor precedence is inline profiles.<name> < user ocmm-profiles/ directory < project .opencode/ocmm-profiles/ directory. When both extensions exist for one basename, .jsonc wins before parsing. An invalid inactive descriptor is inert. An invalid selected descriptor at higher precedence makes the plugin atomically use defaults; it does not fall through to a lower-precedence descriptor.
An alias containing a colon uses first-colon grammar, <profile>:<agent>. For example, a base agent can import the reviewer requirement from the precision profile while retaining its own behavior:
jsonc
{
"agents": {
"oracle": {
"alias": "precision:reviewer",
"description": "Local Oracle behavior remains local",
"promptAppend": "Use this role's local review instructions."
}
}
}
The import is requirement-only: it copies the normalized ModelRequirement — fallbackChain; its requirement-level native variant; each fallback entry's providers, model, native variant, and model-control metadata; and requiresModel, requiresAnyModel, and requiresProvider. Agent-level logical review variants remain local and are not imported. Permissions, prompts, tools, description, other agent controls, and profile-wide fields also stay on the source agent.
When a profile agent specifies alias without a direct model, models, fallbackModels, or requirement, the alias replaces inherited model selectors and inherited requirement-level reasoning/variant from the base agent. An explicit reasoning or variant beside the alias overrides the imported requirement default (reasoning wins when both are present); entry-local controls inside the imported fallback chain remain unchanged. Other inherited and profile-local controls remain merged normally. If the same profile agent explicitly supplies both an alias and a direct selector, the existing direct-selector precedence is preserved and the alias is not materialized.
Profile merge semantics
| Field type | Behavior under profile overlay |
| Scalars (debug, workflow, ...) | Replaced |
| Objects (agents, categories, runtimeFallback, subagent) | Deep-merged (profile field wins per-key) |
| Alias-only agents.<name> entries | Replace inherited model selectors and requirement-level intensity; retain other controls |
| Nested agents..models, categories..models | Replaced (the overlay owns the complete canonical chain; no index merge or union) |
| fallbackModels, disabledAgents | Replaced (profile fully owns these arrays) |
| Other arrays (retryOnStatusCodes, ...) | Replaced |
Nested canonical models arrays replace across both ordinary user/project layers and profiles. Root fallbackModels and disabledAgents remain unioned across user/project configs and replaced by profiles.
Fast model routing
Fast routing is opt-in and applies only to OCMM-managed routes. It never mutates unmanaged OpenCode agents or provider catalogs. Use the OpenCode shim:
bash
ocmm --fast run "Review this change"
Before an explicit -- separator, the shim consumes --fast; ocmm -- --fast instead passes --fast to OpenCode verbatim. The shim sets OCMM_FAST=1 in its child environment only when it consumes that flag; otherwise it clears any inherited child value. For direct plugin activation, only the exact ambient values OCMM_FAST=1 and OCMM_FAST=true enable fast routing; every other value is false.
fastModels.providers is an explicit, case-sensitive provider allowlist. Omitting it or leaving it empty disables promotion. For an allowlisted selected model, fastModels.mappings looks up the qualified original key provider/model; its value is a provider-local model ID (it may itself contain /), and the already-selected provider is retained. An explicitly owned mapping key is authoritative, including a self-map no-op.
providers plus mappings are always the first-priority fast-model promotion path. Without an explicit mapping, ocmm tries ${modelID}-fast only when that exact model exists in the selected provider's catalog. An explicit self-mapping and a selected model already ending in -fast are authoritative no-ops; neither falls through to option rules.
fastModels.defaultRules defaults to false. When enabled on an options-only fast path, ocmm applies a best-effort OpenAI Priority Processing default based on the exact, case-sensitive runtime model.api.npm and model ID: @ai-sdk/openai receives serviceTier: "priority", while @ai-sdk/openai-compatible receives the wire-compatible service_tier: "priority". Other or missing SDK metadata is unchanged. It performs no network probe.
The model must start with lowercase gpt- followed immediately by numeric major version 4 or newer. Standard, mini, snapshot, and future numeric GPT generations are eligible; IDs containing an exact ., _, or - delimited token from nano, pro, realtime, audio, transcribe, image, search, tts, vision, or codex are excluded. GPT 3.5, non-GPT, fine-tuned, and case-mismatched IDs are excluded. This heuristic is intentionally best-effort: OpenAI can change Priority support, and an OpenAI-compatible backend remains the final authority and may reject service_tier.
fastModels.rules
When --fast / OCMM_FAST=1|true is active and an OCMM-managed route has no eligible mapping or catalog-backed -fast promotion, fastModels.rules provides an options-only fallback. It does not change the selected model, and it does not use fastModels.providers as an allowlist; use match.provider to scope a rule. off and model-promoted routes, plus unmanaged routes, never apply rules.
Each rule has match and options. match must declare at least one of optional provider, model, or sdk; omitted fields are unrestricted and all present fields use AND semantics. Values are matched against the runtime providerID, provider-local runtime modelID, and OpenCode model.api.npm (for example @ai-sdk/openai or @ai-sdk/anthropic). Patterns are case-sensitive whole-string globs: matches any number of characters, including /, and ? matches exactly one character. A rule with sdk does not match when SDK metadata is absent.
For an options path, ordinary route/hook options are the base, enabled built-ins overlay that base, matching user rules overlay the built-ins in declaration order, and protected reviewer/plan-critic reasoning floors write last. A user rule can therefore override a built-in field or reset the official provider with serviceTier: "default"; the two SDK-specific names are not emitted together unless a user rule explicitly adds the other name. Plain objects deep-merge, while arrays, scalars, and null replace the earlier value, so later rules win. Runtime fallback requests are re-matched against their actual fallback provider, model, and SDK on every chat.params call.
Profile fastModels.defaultRules is a scalar: omission inherits the root value, while explicit true or false overrides it. Profile-declared fastModels.rules continues to replace the root array wholesale; omission continues to inherit the root rules.
ocmm shim
The ocmm binary launches opencode with configurable config isolation. It merges providers from your global opencode.json, adds the ocmm plugin, and optionally strips the oh-my-openagent plugin to avoid collision.
bash
ocmm # start opencode (no isolation by default)
ocmm -p work run "hello" # select profile + run
ocmm --fast run "Review this change" # opt into fast model routing
ocmm --background-subagents run "Delegate this work" # experimental OpenCode background subagents
ocmm --mode xdg run "hello" # full config isolation
ocmm --mode config-file -c run x # config-file mode + continue
ocmm --help
Flags
-p, --profile <name> Select ocmm profile (sets OCMM_PROFILE)
--fast Enable opt-in fast model routing
--background-subagents
Experimental, OpenCode-only background subagents
(sets child-process env OPENCODE_EXPERIMENTAL_BACKGROUND_SUBAGENTS=true)
--mode <m> Isolation: none|inline|config-file|config-dir|xdg (default: none)
--no-providers Don't merge providers from global config
--no-plugins Don't merge plugins from global config
--ocmm-only Shorthand for --no-providers --no-plugins
--config-dir <path> Target dir for config-dir/xdg modes
--config-file <path> Target file for config-file mode
--opencode <path> Custom opencode binary path
--keep-omo Keep oh-my-openagent plugin (stripped by default in xdg)
--reset Clear isolated dir before starting
-h, --help Show help
-- Separator; everything after passes to opencode verbatim
All non-ocmm args (including -c, --continue, --model, run, etc.) pass through to opencode. Before the explicit -- separator, --fast is an ocmm shim flag; after it, ocmm -- --fast passes that token through to OpenCode.
Experimental OpenCode background subagents
Use the CLI-only switch when launching a new OpenCode process:
bash
ocmm --background-subagents ...
The experimental, OpenCode-only switch sets OPENCODE_EXPERIMENTAL_BACKGROUND_SUBAGENTS=true only in the spawned child process. Without it, the shim removes any ambient inherited value for that variable so background subagents cannot activate accidentally. Before the first exact --, ocmm consumes the switch; ocmm -- --background-subagents ... forwards it unchanged to OpenCode and does not set the child environment variable.
This is a startup opt-in: direct opencode use or direct plugin loading bypasses it, and an existing process needs to be restarted through ocmm --background-subagents ... to activate it. OpenCode owns its background child sessions, jobs, completion, and cancellation. It automatically injects completion into the parent conversation, so ocmm does not poll. Jobs are process-local and non-durable; after a restart they are gone. Use OpenCode's returned task_id to continue the related session.
Isolation modes
| Mode | Env var | Isolation | Notes |
| none (default) | OPENCODE_CONFIG_CONTENT | No config-dir isolation | Inline config is additive; it cannot remove an already-loaded global plugin. |
| inline | OPENCODE_CONFIG_CONTENT | No config-dir isolation | Explicit form of none. |
| config-file | OPENCODE_CONFIG | Generated single config file | Writes <config-dir>/opencode.json. |
| config-dir | OPENCODE_CONFIG_DIR | Generated config directory | Uses ~/.config/opencode/ocmm-opencode/ unless --config-dir overrides it. |
| xdg | XDG_CONFIG_HOME | Full OpenCode config-dir isolation | Uses the same default isolated directory and can strip global plugins. |
Supported config defaults can be set in the shim section of ocmm.jsonc. CLI flags override config values; --background-subagents is CLI-only.
ocmm-profiles CLI
Manage profiles without editing JSON:
bash
ocmm-profiles list # list all ( = active)
ocmm-profiles use claude # set active profile (persisted)
ocmm-profiles show [name] # print a profile
ocmm-profiles add gpu ./gpu.json # add/replace from JSON file
ocmm-profiles rm gpu # delete a profile
ocmm-profiles clear # clear activeProfile
ocmm-profiles current # print active profile name
The CLI reads/writes the user config file at ~/.config/opencode/ocmm.json[c]. Comments are not preserved on write.
Runtime fallback
When a model call falls through to generic runtime fallback (a configured HTTP status, or a message matching retryOnPatterns), ocmm:
1. Resolves the failing agent's ModelRequirement (user config -> built-in defaults).
2. Marks the just-failed model as failed with a timestamp.
3. Finds the next entry in the fallback chain that is not in cooldown (default 60s).
4. Dispatches a new client.session.prompt call with the next model, reusing the latest contiguous user-message block.
5. Aborts the original session first (best-effort).
The default status list is 402, 429, 500, 502, 503, and 504. A name-based provider AbortError or DOMException carrying status 402 may use this fallback path; an explicit user abort remains terminal and never dispatches a fallback prompt.
Subagent 429 recovery
New child sessions have a dedicated recovery path only for retryable errors with an explicit HTTP status of 429. It recognizes the OpenCode parent-session fields parentID, parentId, parentSessionID, and parentSessionId when the child is created; root sessions, untracked sessions, and regex-only matches remain on generic fallback. A non-429 error before the child enters the dedicated path leaves it on the generic path.
Each dedicated 429 waits for two signals before retrying or switching: its delay timer and the idle event owned by that error. Dedicated dispatches do not abort the child session; generic fallback continues to use a best-effort abort. Recovery hints longer than 10 minutes become a zero-delay probe, while hints of 10 minutes or less wait in full. With no hint, the wait uses capped equal-jitter exponential backoff (1-second base, 30-second cap).
subagent429.maxRetries defaults to 5 and is scoped to a model by default. Set it to 0 to prepare a switch immediately (the two signals still gate dispatch). A configured provider scope blocks every model of that provider, but only in the current child session. Every newly selected model starts with a fresh retry budget; runtimeFallback.maxAttempts counts only committed model switches, not same-model dedicated retries.
While a dedicated dispatch is active, the first queued provider outcome takes priority over idle. A queued 429 continues the dedicated flow after the active dispatch settles; a queued non-429 error hands off to generic fallback after settlement; and a bare false dispatch result with no queued outcome stops the dedicated flow. With runtimeFallback.dispatch: false, ocmm is observe-only and dispatches neither dedicated retries nor generic fallback. Dedicated state is never shared between child sessions.
jsonc
"runtimeFallback": {
"enabled": true,
"dispatch": true,
"maxAttempts": 3,
"cooldownSeconds": 60,
"retryOnStatusCodes": [402, 429, 500, 502, 503, 504],
"retryOnPatterns": [
"rate.?limit",
"too.?many.?requests",
"usage.?quota.{0,20}?(?:exceeded|exhausted|reached)",
"quota.?exceeded",
"(?:exceeded|exhausted|reached).{0,20}?quota",
"free.?usage.{0,20}?(?:exceeded|exhausted|limit)",
"usage.?exceeded",
"(?:usage|quota)\\s+limit\\s+exhausted",
"exhausted\\s+your\\s+capacity",
"all\\s+credentials\\s+for\\s+model",
"cool(?:ing)?\\s+down",
"model.{0,20}?not.{0,10}?supported",
"model_not_supported",
"service.?unavailable",
"temporarily.?unavailable",
"overloaded",
"internal server error",
"gateway timeout",
"bad gateway",
"try\\s+again\\s+(?:later|shortly|in\\s+\\d+\\s(?:seconds?|minutes?))",
"\\b429\\b",
"\\b503\\b",
"\\b529\\b",
"使用上限", "频率限制", "请求过于频繁", "暂时不可用", "服务不可用", "请稍后重试" ],
"subagent429": {
"enabled": true,
"maxRetries": 5,
"providerScopes": {
"anthropic": "provider",
"openai": "model"
}
}
}
Explicit user aborts are never retried. Name-based provider AbortError and DOMException events remain terminal except for the configured status-402 recovery path described above. Generic retries acquire a lifecycle-generation, route-snapshot, and target-model reservation before prompt I/O; accepted or possibly accepted prompts remain pending until explicit target evidence or lifecycle cleanup, while the dispatcher retains an in-flight Set<sessionID> for the active prompt call.
Subagent interruption recovery
The subagent-interruption-recovery hook is enabled by default and layers evidence correlation over the existing fallback ownership model:
- It reuses the existing 429/generic fallback controller and budget accounting.
- Correlation is keyed by child session and deduplicates parent message.part.updated task-part evidence.
- Child session.error events are treated as provider-error evidence in that correlation record.
- It never retries explicit abort, permission denial, unknown agent, deletion, or ordinary empty-output outcomes.
- The task-output adapter may append at most one manual continuation notice only when an explicit task identifier is observed in tool input/output or correlated parent-part evidence. It never substitutes childSessionID for task_id, dispatches from tool.execute.after, or synthesizes a parent prompt.
Develop
bash
pnpm run typecheck
pnpm test
pnpm run build
Tests use node --test --experimental-strip-types (Node 22+) plus cargo test for the native ocmm-lsp MCP server in crates/ocmm-lsp/. pnpm run build emits TypeScript into dist/ and copies the Rust release binary into dist/bin/ as both the target-triple release name and the local fallback name.
Release
ocmm publishes through two independent release lanes.
ocmm-lsp release
1. Bump crates/ocmm-lsp/Cargo.toml version.
2. Tag ocmm-lsp-vA.B.C and push.
3. CI builds 8 native binaries (Linux glibc x64/arm64, Linux musl x64/arm64, macOS x64/arm64, Windows x64/arm64).
4. CI publishes 8 npm platform packages to npmjs.org through npm Trusted Publishing (GitHub Actions OIDC).
5. CI publishes standalone native binaries, platform package tarballs (ocmm-lsp-<platform-package>-<version>.tgz), and SHA256SUMS.txt to the GitHub Release.
ocmm release
1. Set package.json.version and package.json.ocmm.lspVersion (must match an already-published ocmm-lsp-vA.B.C release).
2. Regenerate the Codex plugin bundle: pnpm run build:ts && pnpm run gen:codex-plugin.
3. Tag vX.Y.Z and push.
4. CI downloads pinned ocmm-lsp-v<lspVersion> release assets, bundles them into GitHub Release tarballs.
5. CI publishes to npmjs.org as ocmm through npm Trusted Publishing (GitHub Actions OIDC).
6. On tag pushes, CI also publishes @<owner>/ocmm to GitHub Packages (optional for manual dispatch).
7. CI publishes self-contained tarballs (ocmm-opencode-plugin-X.Y.Z.tgz, deepwork-codex-plugin-X.Y.Z.tgz) and SHA256SUMS.txt to the GitHub Release.
The npm tarball excludes native LSP binaries (platform-agnostic, relies on optional dependency resolution). GitHub Release tarballs are self-contained with bundled native binaries for all 8 platforms.
Required npm configuration:
- Configure npm Trusted Publishing for ocmm and each ocmm-lsp- platform package, with GitHub repository hugefiver/ocmm, workflow filename release.yml (the file at .github/workflows/release.yml), and publish permission enabled. The workflow uses GitHub Actions OIDC (id-token: write) and does not require an npm token for npmjs.org publishes.
Completion proof
Workflow terminal success is an intermediate signal, not release completion. The post-run checker is the completion authority: report a release complete only when its JSON receipt has outcome: "COMPLETED" and the command exits 0.
For a main tag push, run this from the exact released checkout after the tag and matching run exist. This is a release-stage command, not a feature-development command:
powershell
pnpm --silent run check:release-completion -- --mode remote --repository hugefiver/ocmm --tag v0.6.6 --deadline-ms 5400000 --poll-ms 15000
Use the authorized later tag in place of v0.6.6. A manually dispatched run also requires its numeric --run-id.
No local GITHUB_TOKEN is needed to bump, tag, push, or trigger CI. npmjs and GitHub Packages are not completion checks or proof surfaces, so the checker does not request either registry. Registry publish jobs remain in CI and their workflow job conclusions remain part of the completion contract.
| Exit | Receipt outcome | Meaning |
| 0 | COMPLETED | Every required surface is proven; this is the only completion outcome. |
| 1 | FAILED | At least one definite identity, workflow, asset, checksum, or required content invariant failed. |
| 2 | UNRESOLVED | No definite failure won, but a required surface could not be proven before the deadline. |
| Lane | Required surfaces | Explicitly non-applicable surfaces |
| Main vX.Y.Z tag push | Peeled tag commit; fixed release.yml run/attempt and exact job conclusions; exact nonempty GitHub Release assets with downloaded SHA-256 verification; and the non-draft pinned ocmm-lsp Release. | npmjs and GitHub Packages completion checks are skipped. |
| LSP ocmm-lsp-vA.B.C | Peeled tag commit; fixed release.yml run/attempt and exact job conclusions; exact nonempty GitHub Release assets with downloaded SHA-256 verification. | npmjs, GitHub Packages, and pinned-LSP-release proof are skipped. |
Registry publication still runs in CI, but registry metadata is outside completion proof for every lane. Keep tokens, authorization headers, registry bodies, and signed asset URLs out of terminal captures, receipts, and chat.
After any partial publication, the tag is immutable: never move, delete, or recreate it, and never overwrite packages or Release assets from a workstation. Report the FAILED or UNRESOLVED receipt, preserve its bound identity, and use a separately authorized new commit/version/tag or an explicitly authorized same-identity rerun.
Live integration test
See AGENTS.md for the full live test procedure using isolated XDG dirs.
License
Licensed under the Anti American AI Public License (AAAPL) — see LICENSE (English), LICENSE.zh.md (Chinese), or LICENSE.bilingual.md (authoritative bilingual reference).
SPDX identifier: LicenseRef-AAAPL.
Architecture & internals
For design rationale, hook flow, the 4-tier variant resolution pipeline, two-layer fallback system, and config schema overview, see docs/architecture.md.
Authoritative agent and category definitions live in src/data/agents.ts and src/data/categories.ts. For OpenCode deepwork prompt and skill provenance, see docs/v1-maintenance.md.预览分享卡片长什么样 ↓
分享 · DeepSeek Harness Hub
hugefiver/ocmm
按智能体自动切换模型并配置推理参数
相关插件 · 模型接入
API 中继安全审计toby-bridges/api-relay-audit
面向 AI API 中转与 LLM 代理的本地安全审计。
★ 897已汉化DSH
69.4
免费搜索插件DDDMUC/dsh-free-search
DeepSeek Harness 免费搜索插件 —— 无需 API key,零成本,多引擎可切换。 一个给…
★ 761已汉化DSH
68.7
免费联网搜索liustack/modsearch
在官方 App 里模型能联网,切到 API 就不能了。ModSearch 把联网补回来:网页搜索、X…
★ 863已汉化DSH
68.5
OpenCode 免费模型FishBottle7/opencode2dsh
在 DSHDeepSeek Harness里原生使用 OpenCode Zen 的免费匿名模型。
★ 379已汉化DSH
67.8
AI 模型网关tingly-dev/tingly-box
Tingly Box Web UI 演示
★ 373已汉化DSH
67.4
WorkBuddy 账号池XDTrees/dsh-xdpool
把你能白嫖的模型额度接进 DSH 同一个池:WorkBuddy 多账号自动容错、十三家扫码登录、76…
★ 359已汉化DSH
67.1