openrig:用YAML统一管理Claude Code与Codex的AI编码代理配置 1. openrig 到底想解决什么问题第一次看到openrig这个名字我下意识把它和一堆“XX CLI”“XX 配置器”归到了一类。直到我把它的关键词和热搜词摊开看——Claude Code、Codex、YAML、Node.js——才反应过来这玩意儿的定位其实很明确它想当 AI 编码代理coding agent的“接线盒”。你想想现在的处境。手头可能同时装着 Claude Code、Codex CLI甚至还想接本地模型或者第三方 API。每个工具都有自己的配置文件、自己的环境变量、自己的启动参数。Claude Code 认~/.claude/settings.jsonCodex 认~/.codex/config.toml或者 YAML你想换个模型、换个 endpoint就得挨个文件翻、挨个字段改。改错一个缩进工具直接起不来报错还特别含糊。openrig要干的事就是把这些散落的配置收拢到一个统一的 YAML 描述里然后由它去生成、分发、管理各个代理工具需要的配置。你可以把它理解成“AI 代理界的 docker-compose”——用一个文件描述你想要的运行环境剩下的交给它。它适合谁三类人最该关注同时用多个 AI 编码工具的人今天用 Claude Code 写业务逻辑明天用 Codex 跑重构配置来回切烦。需要接第三方或本地模型的人官方订阅有额度限制或者组织策略限制想切到自建 endpoint但每个工具的接入方式都不一样。团队里要统一开发环境的人不想让每个人手动配一遍希望一份 YAML 走天下。这篇文章我会从 openrig 的核心设计讲起把 YAML 配置结构、Node.js 运行环境、和 Claude Code / Codex 的对接细节全部拆开再补上我自己踩过的坑。看完你应该能独立把一套多代理环境跑起来。2. 为什么是 YAML Node.js 这套组合2.1 YAML 作为配置层的真实理由很多人第一反应是为什么不用 JSONJSON 不是更通用吗我实际配过之后的理解是AI 代理的配置天然是“层级 列表 多行文本”混合的结构。比如你要描述“三个代理每个代理有模型、endpoint、环境变量、启动参数”JSON 写出来满屏的引号和花括号人眼扫一遍就累。YAML 的缩进虽然对空格敏感但可读性在多层嵌套场景下确实高一个档次。更关键的一点YAML 支持注释。JSON 不支持。你在配置里写一句# 这个 endpoint 是内网测试用的别提交这种上下文信息对团队协作太重要了。配置文件不是给机器看的是给人维护的注释能力直接决定了半年后你还敢不敢动这个文件。不过 YAML 的坑也很实在。缩进用 Tab 还是空格、冒号后面要不要空格、字符串要不要加引号——这些细节我在第 5 节会专门讲因为我自己在这上面浪费过整整一个下午。2.2 Node.js 作为运行时的取舍openrig 选 Node.js 做运行时我觉得是权衡后的结果不是随便选的。第一Claude Code 本身就是 Node.js 生态的产物。它的安装方式、依赖管理、和 VS Code 的集成全都建立在 npm 体系上。openrig 要管理 Claude Code 的配置用同一套运行时能省掉大量跨语言的胶水代码。第二Node.js 的跨平台一致性够用。Windows、macOS、Ubuntu 上装 Node.js 都不算难npx一条命令就能跑起来一个 CLI 工具这对“让用户快速上手”这个目标很友好。第三生态里有现成的 YAML 解析库比如js-yaml有现成的文件监听库chokidar有现成的进程管理能力child_process。openrig 要做的事情——读 YAML、生成配置、拉起子进程——Node.js 全都能覆盖不需要引入更重的东西。但 Node.js 也有它的问题。版本管理是第一大坑。热搜词里那条error installing 24.21.0: node.js v24.21.0 is not yet released就是活生生的例子——版本号写错、或者用了还没正式发布的版本安装直接失败。我建议锁定 LTS 版本别追最新。截至我写这篇的时候Node.js 20 LTS 和 22 LTS 都是稳妥选择。提示如果你机器上已经有多个 Node.js 版本强烈建议用nvmmacOS/Linux或nvm-windows来管理。openrig 这类工具对 Node 版本敏感全局只有一个版本迟早出事。2.3 这套组合的边界在哪说句实在话YAML Node.js 不是银弹。它的短板在于性能敏感场景不合适Node.js 启动有开销如果你要频繁拉起几百个进程它不是最优解。YAML 的隐式类型转换会咬人yes、no、on、off在 YAML 1.1 里会被解析成布尔值1.0会被解析成浮点数。配置里写个版本号1.10解析出来变成1.1这种 bug 极难排查。Windows 路径处理Node.js 在 Windows 上的路径分隔符和权限模型跟 Unix 差异大openrig 如果涉及文件写入Windows 用户要做好心理准备。理解这些边界你才知道什么时候该用它什么时候该绕开。3. openrig 的 YAML 配置结构拆解3.1 顶层结构agents 是核心openrig 的配置我理解下来顶层大概长这样这是基于常见实践的合理推断具体字段名以官方为准version: 1 agents: - name: claude-main type: claude-code model: claude-sonnet-4 endpoint: https://api.example.com env: API_KEY: ${CLAUDE_API_KEY} args: - --verbose - name: codex-local type: codex model: local-model endpoint: http://127.0.0.1:1234/v1这里有几个设计点值得说version字段必须有。配置文件格式会演进没有版本号将来升级 openrig 时你根本不知道旧配置还能不能用。这是所有成熟配置系统的标配别省。agents是列表不是字典。为什么因为顺序可能有意义比如启动顺序、优先级而且列表允许同名条目存在虽然不推荐。字典虽然查找快但会丢失顺序信息。env里用${VAR}引用环境变量。这是安全实践——API Key 绝对不能硬编码在 YAML 里。YAML 文件很可能被提交到 Git一旦密钥泄露后果你懂的。用环境变量引用密钥留在 shell 或.env文件里.env加进.gitignore。3.2 每个 agent 的关键字段拆开看单个 agent字段可以分成几组字段组代表字段作用是否必填标识name、type区分不同代理决定用哪套适配器必填模型model、endpoint指定用哪个模型、走哪个 API 地址视工具而定认证env、apiKeyEnv注入密钥等敏感信息必填行为args、cwd启动参数、工作目录可选生命周期autoStart、restart是否自动拉起、崩溃是否重启可选type字段是最关键的。它决定了 openrig 用哪套逻辑去生成配置。claude-code和codex的配置格式完全不同openrig 内部必然有针对性的适配器。你写错type生成出来的配置就是废的。endpoint字段是接第三方模型的关键。热搜里codex接入deepseek、claude code 调用lmstudio的本地模型这些需求全靠这个字段实现。把 endpoint 指向 DeepSeek 的兼容接口或者本地 LM Studio 的地址就能绕开官方订阅的限制。3.3 配置的继承与覆盖真实场景里多个 agent 往往共享大量配置——同一个 endpoint、同一套环境变量、同样的超时设置。如果每个 agent 都写一遍维护起来是灾难。合理的做法是支持默认配置 覆盖defaults: endpoint: https://api.example.com timeout: 30 env: LOG_LEVEL: info agents: - name: claude-main type: claude-code model: claude-sonnet-4 # 继承 defaults 的 endpoint 和 timeout - name: codex-fast type: codex model: fast-model timeout: 10 # 覆盖默认值这种“默认值 局部覆盖”的模式是所有配置系统的通用智慧。它把“共性”和“差异”分开改共性只改一处改差异只动局部。你设计任何配置格式时都该考虑这一层。注意继承的合并策略要明确。是浅合并还是深合并env字段是整体替换还是逐键合并这个语义不定义清楚团队里两个人会配出两种理解。我的建议是env逐键合并其他字段整体替换这样最符合直觉。4. 和 Claude Code、Codex 对接时的真实差异4.1 Claude Code 的配置落点Claude Code 的配置主要落在几个地方用户级的~/.claude/settings.json、项目级的.claude/settings.json以及环境变量。openrig 要接管它就得知道往哪儿写、写什么格式。这里有个容易忽略的点Claude Code 对配置的读取是有优先级的。项目级配置通常覆盖用户级配置环境变量又可能覆盖两者。openrig 生成配置时如果没考虑这个优先级链可能出现“我明明改了配置怎么没生效”的情况。我的经验是优先用环境变量注入而不是改配置文件。原因很简单环境变量是进程级的不会污染全局状态也不会在你关掉 openrig 后残留。配置文件改了下次你直接跑 Claude Code 时还会读到那份被改过的配置容易混乱。热搜里your organization has disabled claude subscription access for claude code这条说的就是组织策略限制。遇到这种情况配置层面能做的就是切 endpoint 到自建或第三方兼容接口。但要注意不是所有第三方接口都完整兼容 Claude Code 的协议有些只实现了部分能力跑起来会缺功能。4.2 Codex 的配置差异Codex 的配置格式和 Claude Code 不一样。它更偏向 TOML 或 YAML字段命名也不同。热搜里codex无法加载组织设置、codex登录这些问题很多都跟配置路径或格式有关。openrig 处理 Codex 时我推测它需要做一层“格式转换”——把你写的统一 YAML翻译成 Codex 认识的格式。这层转换最容易出问题的地方是字段名映射你的endpoint在 Codex 里可能叫base_url映射错了就静默失败。类型转换YAML 里的true到 TOML 里是true但某些字段可能需要字符串true。嵌套结构差异Claude Code 可能是扁平结构Codex 可能是嵌套的[model.provider]这种。codex接入deepseek这个需求本质就是把 Codex 的 base_url 指向 DeepSeek 的兼容端点再把 model 名字改成 DeepSeek 支持的模型名。听起来简单但如果你不知道 Codex 具体认哪个字段名就会一直卡在“配置了但没生效”。4.3 两个工具对接的对照表维度Claude CodeCodex主配置格式JSONTOML / YAML用户级路径~/.claude/~/.codex/项目级路径.claude/.codex/环境变量注入支持支持第三方 endpoint需协议兼容需协议兼容常见报错组织策略限制组织设置加载失败这张表不是让你背而是让你意识到统一配置层必须处理这些差异否则“统一”就是假的。openrig 的价值恰恰在于它把这层差异封装了你只写一份 YAML它去适配两边。5. 从零跑通 openrig 的完整步骤5.1 环境准备Node.js 装对版本第一步永远是 Node.js。别跳过版本检查我见过太多人栽在这。# 检查当前版本 node -v npm -v # 如果版本不对用 nvm 装 LTS nvm install 22 nvm use 22为什么强调 LTS因为非 LTS 版本的生命周期短依赖库可能还没适配。热搜里那条node.js v24.21.0 is not yet released就是典型的版本不存在问题——你写了个还没发布的版本号安装器当然找不到。Windows 用户去 Node.js 官网下载 LTS 的.msi安装包一路下一步就行。装完记得重启终端否则 PATH 不生效node -v还是找不到命令。5.2 安装 openrig假设 openrig 通过 npm 分发安装命令大概是npm install -g openrig # 或者不全局安装用 npx npx openrig --version全局安装的好处是命令随处可用坏处是版本管理麻烦。我个人的习惯是项目内局部安装把版本锁在package.json里团队每个人跑出来的行为一致。npm install --save-dev openrig npx openrig initinit命令通常会生成一份示例 YAML这是你理解配置结构的最好起点。别急着删先读一遍每个字段的注释。5.3 写第一份配置从最小可用配置开始别一上来就写五个 agent。version: 1 agents: - name: claude-default type: claude-code model: claude-sonnet-4 env: ANTHROPIC_API_KEY: ${ANTHROPIC_API_KEY}然后设置环境变量export ANTHROPIC_API_KEY你的密钥Windows PowerShell 用$env:ANTHROPIC_API_KEY你的密钥跑起来npx openrig start claude-default如果这一步能起来说明基础链路通了。起不来先看报错信息八成是环境变量没设对或者 YAML 缩进有问题。5.4 接入第三方或本地模型这是很多人真正想要的能力。以接入本地模型为例假设本地服务跑在http://127.0.0.1:1234/v1agents: - name: claude-local type: claude-code model: local-model-name endpoint: http://127.0.0.1:1234/v1 env: ANTHROPIC_API_KEY: dummy-key几个关键点本地服务必须支持兼容协议。不是所有本地推理服务都实现了 Claude 或 OpenAI 的接口规范跑之前先确认。dummy-key不能省。很多客户端即使 endpoint 不需要认证也会检查 key 字段是否存在空着会报错。模型名要跟本地服务注册的名字一致。你本地加载的是qwen2.5-7b配置里写gpt-4服务端找不到模型直接拒绝。5.5 验证配置是否真的生效配置写完不代表生效。我习惯用三步验证看 openrig 生成的中间配置如果它支持--dry-run或--print-config先打印出来看确认字段映射正确。看目标工具的日志Claude Code 或 Codex 启动时通常会打印它读到的 endpoint 和 model对一下。发一个最小请求让它回答一个简单问题能返回就说明链路通了。提示如果配置改了但行为没变先怀疑缓存。很多工具会缓存配置重启进程或者清掉缓存目录再试。6. 我踩过的坑和排查思路6.1 YAML 缩进一个空格引发的血案我最惨的一次配置里env下面的键比父级多缩进了一个空格YAML 解析器把它当成了新的嵌套层级结果环境变量全没注入。工具启动后一直报认证失败我查了半小时密钥最后才发现是缩进。排查方法用 YAML 校验工具先过一遍。# 用 Node.js 快速校验 node -e const yamlrequire(js-yaml);const fsrequire(fs);try{yaml.load(fs.readFileSync(openrig.yaml,utf8));console.log(OK)}catch(e){console.log(e.message)}这个命令能直接告诉你哪一行、哪一列出问题。养成写完配置先校验的习惯能省掉大量瞎猜时间。6.2 环境变量没传进去现象是配置里写了${API_KEY}但工具报“未找到密钥”。原因通常有三个变量没 export只在当前 shell 设了但 openrig 在子进程里跑读不到。变量名拼错API_KEY和APIKEY是两回事。引号问题${API_KEY}在某些解析器里需要写成${API_KEY}才会被替换。我的做法是在 openrig 启动前先echo $API_KEY确认变量存在再启动。这一步花五秒能省半小时。6.3 第三方 endpoint 的协议兼容陷阱接第三方模型时最常见的坑是“接口看起来兼容实际不兼容”。比如某些服务实现了/v1/chat/completions但没实现/v1/models而客户端启动时会先调/v1/models探测可用模型探测失败就直接退出。排查思路用 curl 手动打一遍客户端会调的接口。curl http://127.0.0.1:1234/v1/models curl -X POST http://127.0.0.1:1234/v1/chat/completions \ -H Content-Type: application/json \ -d {model:local-model,messages:[{role:user,content:hi}]}哪个接口挂了问题就定位到哪。这比盯着客户端日志猜快得多。6.4 组织策略限制的应对热搜里your organization has disabled claude subscription access这类问题本质是账号层面的策略限制不是配置能解决的。配置层面能做的是切换到不受该策略约束的 endpoint。但要注意切换 endpoint 后某些依赖官方服务的能力可能不可用比如特定的工具调用、文件上传等。用之前先确认你的工作流是否依赖这些能力。7. 把 openrig 用顺手的几个进阶思路7.1 用 profile 管理多套环境如果你同时有“公司内网 endpoint”和“本地测试 endpoint”两套环境别来回改配置。用 profile 机制profiles: work: endpoint: https://internal.example.com local: endpoint: http://127.0.0.1:1234/v1 agents: - name: claude-main type: claude-code model: claude-sonnet-4 profile: work启动时指定 profilenpx openrig start claude-main --profile local。这样一套配置覆盖多场景切换成本几乎为零。7.2 配置纳入版本控制YAML 配置应该进 Git但密钥绝对不能进。做法是配置里只写${VAR}引用。提供一份.env.example列出需要哪些变量但不填真实值。.env加进.gitignore。这样新人 clone 下来照着.env.example填自己的密钥就能跑团队协作顺畅。7.3 监控代理进程状态openrig 如果管理多个代理进程挂了你得知道。可以配合简单的健康检查# 定时检查进程是否存活 while true; do if ! pgrep -f claude-code /dev/null; then echo claude-code 挂了重启中 npx openrig start claude-main fi sleep 30 done这不是什么高级方案但实用。生产环境可以用 systemd 或 pm2 来做进程守护比手写循环靠谱。7.4 配置变更后的热重载开发阶段频繁改配置每次重启很烦。如果 openrig 支持文件监听改完 YAML 自动重载体验会好很多。如果不支持可以用nodemon之类的工具包一层nodemon --watch openrig.yaml --exec npx openrig restart改配置自动重启省掉手动操作。8. 关于 openrig 这类工具的一点个人判断我用过不少“统一配置层”的工具从早期的 dotfile 管理器到现在的各种 CLI 包装器。这类工具的价值从来不在“省了几行配置”而在于它把散落的知识收拢成了一份可读、可版本控制、可传承的文档。openrig 面对的场景尤其复杂——AI 编码代理这个领域变化太快今天 Claude Code 是这个配置格式明天可能就变了Codex 的字段名也可能调整。一个统一层如果能跟上这些变化它省下的就不只是配置时间而是“每次工具升级都要重新学一遍”的认知成本。但它也有风险。抽象层越多出问题时排查链路越长。你的配置经过 openrig 转换再喂给 Claude Code中间任何一层出错报错信息都可能被吞掉。所以我的建议是先用原生工具把链路跑通理解每个工具的配置逻辑再上 openrig 做统一管理。跳过原生直接上抽象层出问题你会完全不知道从哪查。另外YAML 配置的可维护性有个临界点。agent 数量超过五六个、字段超过二三十个之后单文件会变得难以维护。这时候要考虑拆分——按环境拆、按团队拆或者引入模板机制。别让一份 YAML 膨胀成几百行那还不如回去手动配。最后说个实际的Node.js 版本一定要锁死。在package.json里加engines字段在 CI 里固定版本在 README 里写清楚。我见过太多“在我机器上能跑”的问题根源都是 Node 版本不一致。openrig 依赖 Node.js 生态这个坑它躲不掉你只能主动防。