1. 从零认识 openrig:它到底解决什么问题
第一次看到 openrig 这个名字,很多人会以为是某个硬件支架项目,毕竟 rig 在英文里有“装配、支架”的意思。但如果你最近在折腾 Claude Code、Codex 这类命令行 AI 编程工具,就会明白它其实是一个多 AI 编码代理的统一编排层。简单说,openrig 做的事情就是:把你机器上散落各处的 AI 编程助手(Claude Code、Codex CLI 等)用一个统一的配置文件和一套会话管理机制串起来,让它们共享上下文、共享工作目录、共享终端会话,而不是每开一个工具就要重新配置一遍环境、重新解释一遍项目背景。
我最初接触这类需求,是因为同时用 Claude Code 写业务逻辑、用 Codex 做代码审查,两边都要各自维护一份项目说明和 API 配置,切换一次就要重新交代一遍“这个项目用的是什么框架、哪些目录不要动、测试怎么跑”。这种重复劳动在真实项目里非常消耗精力。openrig 的核心价值就在于把这些重复配置收敛到一份 YAML 里,再配合 tmux 做会话持久化,让多个代理在同一个工作区里协同。
它适合谁?如果你已经在用或者准备用 Claude Code、Codex 这类工具做日常开发,并且遇到过“配置散乱、会话丢失、多工具上下文不同步”的问题,那 openrig 就是为你准备的。哪怕你只是刚装好 Claude Code 的新手,理解 openrig 的设计思路也能帮你把工具链整理清楚。下面我会从整体设计、核心配置、实操流程到问题排查,完整拆一遍。
2. openrig 的整体设计与思路拆解
2.1 为什么需要一层“编排”而不是直接用原生工具
Claude Code 和 Codex CLI 各自都能独立工作,官方也提供了配置文件。但问题在于,它们是各自为政的。Claude Code 读自己的配置,Codex 读自己的配置,两者的会话状态、工作目录、环境变量互不相通。当你想让两个代理协作时,要么手动复制粘贴上下文,要么写一堆 shell 脚本去桥接。
openrig 的思路是把“代理怎么启动、读什么配置、在哪个会话里跑”抽象成声明式配置。你不再关心每个工具的具体启动参数,而是描述“我要一个跑 Claude Code 的会话,工作目录是 X,注入这些环境变量”,openrig 负责把它翻译成实际的启动命令并挂到 tmux 会话上。这种声明式的好处是可复现:换一台机器,把 YAML 拷过去,一条命令就能恢复整套环境。
这里有个关键的设计取舍:openrig 没有选择自己实现一个全新的代理运行时,而是复用现有 CLI 工具 + tmux。这个选择非常务实。因为 Claude Code、Codex 的模型能力和工具调用逻辑是它们自己的核心竞争力,重新实现一遍既没必要也不现实。openrig 只做编排层,把复杂度控制在配置管理和会话调度上,这样即使上游工具升级,openrig 也只需要适配启动参数,不会伤筋动骨。
2.2 tmux 在其中的角色:不只是“后台运行”
很多人以为 tmux 只是让程序在后台跑,关掉终端也不中断。但在 openrig 的架构里,tmux 承担的是会话状态容器的角色。每个 AI 代理跑在一个独立的 tmux window 或 pane 里,这意味着:
- 会话可以随时 attach 回去看历史输出,不会因为网络断开或终端关闭而丢失上下文;
- 多个代理可以在同一个 tmux session 的不同 window 里并行工作,互不干扰;
- 通过 tmux 的 send-keys 机制,openrig 可以向指定会话注入命令,实现代理之间的消息传递。
我实测下来,tmux 的send-keys配合capture-pane是做代理间通信最轻量的方案。不需要额外的消息队列或 socket 服务,直接操作终端缓冲区就行。当然这也有代价,就是输出解析依赖文本匹配,不如结构化 API 稳定。但对于个人开发场景,这个取舍是划算的。
2.3 YAML 配置驱动的核心逻辑
openrig 用 YAML 而不是 JSON 或 TOML,原因很直接:YAML 支持注释、支持多行字符串、层级表达清晰,适合写“给人看也给人改”的配置。一个典型的 openrig 配置大概长这样:
version: 1 workspace: ~/projects/myapp agents: claude: tool: claude-code args: - --model - claude-sonnet-4-5 env: ANTHROPIC_API_KEY: ${ANTHROPIC_API_KEY} session: rig-claude codex: tool: codex args: - --profile - review env: OPENAI_API_KEY: ${OPENAI_API_KEY} session: rig-codex这份配置里,workspace定义了共享工作目录,agents下面每个条目描述一个代理。tool指定用哪个 CLI,args是透传给该工具的启动参数,env是环境变量注入,session是 tmux 会话名。openrig 读取这份配置后,会为每个 agent 创建对应的 tmux 会话并启动工具。
注意:环境变量建议用
${VAR}形式引用系统环境变量,不要把密钥明文写进 YAML。我见过有人直接把 API key 写进配置文件然后提交到 Git,这是非常危险的操作。
2.4 与 Claude Code、Codex 的适配层设计
openrig 对每个工具做了一层薄适配。因为 Claude Code 和 Codex 的启动方式、配置路径、会话恢复机制都不一样。Claude Code 有自己的~/.claude配置目录,Codex 有~/.codex,两者的认证方式也不同。openrig 的适配层负责:
- 检查工具是否已安装(通过
which或版本命令); - 按配置组装启动命令;
- 处理工具特有的初始化逻辑,比如 Codex 需要先登录、Claude Code 需要确认订阅状态;
- 把工具输出重定向到 tmux 会话。
这层适配是 openrig 最需要维护的部分,因为上游工具更新频繁。但好在适配逻辑集中在少数几个文件里,改动可控。
3. 核心细节解析与实操要点
3.1 环境准备:先把基础工具装齐
在碰 openrig 之前,你得先确保底层工具都在。这一步很多人会跳过,结果后面报错找不到原因。我按顺序列一下需要的东西:
- tmux:会话管理的基础。Ubuntu 下
sudo apt install tmux,macOS 下brew install tmux。装完用tmux -V确认版本,建议 3.0 以上。 - Claude Code:官方安装方式是通过 npm,
npm install -g @anthropic-ai/claude-code。装完运行claude会引导你完成认证。如果你在 Windows 上,建议用 WSL,原生 Windows 支持一直不太稳定。 - Codex CLI:同样通过 npm 安装,
npm install -g @openai/codex。装完codex login完成认证。 - Node.js 18+:上面两个工具都依赖 Node,版本太低会直接报错。
- YAML 解析库:如果你要自己写脚本处理配置,Python 用
pyyaml,Node 用js-yaml。
提示:安装 Claude Code 时如果遇到 “your organization has disabled claude subscription access” 这类提示,通常是账号订阅类型的问题,需要确认你的账号是否有对应的访问权限。这不是 openrig 的问题,是上游工具的认证限制。
3.2 YAML 配置文件的字段详解
openrig 的配置文件字段设计得不复杂,但每个字段都有讲究。我把关键字段拆开讲:
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| version | int | 是 | 配置格式版本,目前是 1 |
| workspace | string | 是 | 所有代理共享的工作目录,支持~展开 |
| agents | map | 是 | 代理定义集合,key 是代理名 |
| agents.*.tool | string | 是 | 工具标识,如claude-code、codex |
| agents.*.args | list | 否 | 透传给工具的启动参数 |
| agents.*.env | map | 否 | 环境变量注入 |
| agents.*.session | string | 是 | tmux 会话名,需全局唯一 |
| agents.*.auto_start | bool | 否 | 是否在 openrig 启动时自动拉起,默认 true |
workspace字段特别重要,因为它决定了代理看到的文件系统范围。我建议把它设成具体项目目录,而不是用户主目录,避免代理误操作无关文件。session命名也要有规律,比如统一加rig-前缀,方便用tmux ls过滤。
3.3 会话隔离与共享的边界
openrig 里有个容易混淆的点:哪些东西是共享的,哪些是隔离的。我整理成一张表:
| 资源 | 是否共享 | 说明 |
|---|---|---|
| 工作目录 | 共享 | 所有代理看到同一个 workspace |
| 文件系统 | 共享 | 同上,代理可以读写同一批文件 |
| 环境变量 | 隔离 | 每个代理有独立的 env 注入 |
| tmux 会话 | 隔离 | 每个代理独立会话,互不干扰 |
| 终端历史 | 隔离 | 各自会话的 scrollback 独立 |
| API 凭证 | 隔离 | 各自读各自的密钥 |
这个设计的好处是文件层面协作、进程层面隔离。两个代理可以改同一个文件(当然要小心冲突),但一个代理崩溃不会影响另一个。我在实际使用中,会让 Claude Code 负责写代码,Codex 负责审查,两者共享工作目录但独立会话,配合起来很顺。
3.4 启动流程的时序细节
openrig 启动时的执行顺序是有讲究的,理解这个顺序能帮你排查很多问题:
- 读取并校验 YAML 配置,检查必填字段;
- 展开
workspace路径,确认目录存在; - 对每个 agent,检查
tool对应的 CLI 是否在 PATH 里; - 检查
session是否已存在,存在则跳过创建(幂等); - 创建 tmux 会话,设置工作目录;
- 注入环境变量,启动工具命令;
- 记录会话映射到状态文件,供后续操作查询。
第 4 步的幂等设计很关键。这意味着你可以反复运行 openrig 启动命令,不会重复创建会话。我经常在调试配置时反复跑启动命令,这个特性省了很多手动清理的麻烦。
4. 实操过程与核心环节实现
4.1 从零搭建一个双代理工作区
假设你有一个项目在~/projects/demo,想让 Claude Code 和 Codex 同时在这个项目上工作。完整流程如下。
第一步,创建配置文件~/.openrig/demo.yaml:
version: 1 workspace: ~/projects/demo agents: claude: tool: claude-code args: - --model - claude-sonnet-4-5 env: ANTHROPIC_API_KEY: ${ANTHROPIC_API_KEY} session: rig-demo-claude codex: tool: codex args: - --profile - default env: OPENAI_API_KEY: ${OPENAI_API_KEY} session: rig-demo-codex第二步,确认环境变量已经导出。在~/.bashrc或~/.zshrc里加上:
export ANTHROPIC_API_KEY="你的密钥" export OPENAI_API_KEY="你的密钥"改完记得source ~/.bashrc让配置生效。可以用echo $ANTHROPIC_API_KEY确认。
第三步,运行 openrig 启动命令。具体命令取决于你的 openrig 安装方式,假设是openrig up -c ~/.openrig/demo.yaml。执行后你会看到类似输出:
[openrig] loading config: /home/user/.openrig/demo.yaml [openrig] workspace: /home/user/projects/demo [openrig] agent claude -> session rig-demo-claude [created] [openrig] agent codex -> session rig-demo-codex [created] [openrig] 2 agents running第四步,验证会话。运行tmux ls,应该能看到两个会话:
rig-demo-claude: 1 windows (created ...) rig-demo-codex: 1 windows (created ...)第五步,attach 到某个会话看输出,比如tmux attach -t rig-demo-claude。你会看到 Claude Code 的交互界面已经在工作目录里启动了。
4.2 参数选择背后的计算与考量
配置里有几个参数值得展开说。--model选哪个模型,直接关系到成本和效果。以 Claude 为例,Sonnet 系列在代码任务上性价比高,Opus 系列更强但贵。我的经验是:日常写代码用 Sonnet,遇到复杂重构或架构设计再切 Opus。这个切换可以通过改 YAML 里的args实现,改完重启对应会话即可。
Codex 的--profile参数对应~/.codex/config.toml里的配置档。你可以定义多个 profile,比如一个用强模型做审查,一个用快模型做补全。openrig 的args透传机制让你不用改 openrig 本身就能切换这些行为。
环境变量注入这块,有个细节:openrig 注入的 env 会覆盖系统已有的同名变量。这意味着你可以在 YAML 里为不同代理指定不同的密钥或端点。比如你想让 Codex 走某个兼容端点,就在它的 env 里设OPENAI_BASE_URL,不影响 Claude Code。
4.3 代理间协作的实操模式
两个代理跑起来后,怎么让它们协作?我常用的模式是“生产者-审查者”:
- Claude Code 会话里,让它实现一个功能模块;
- 实现完成后,通过 tmux send-keys 把改动摘要发给 Codex 会话;
- Codex 审查代码,输出问题列表;
- 把问题列表发回 Claude Code 会话,让它修复。
第 2 步的 send-keys 命令大概是这样:
tmux send-keys -t rig-demo-codex "请审查 src/auth.py 的改动,重点关注边界条件" Enter第 3 步读取 Codex 输出:
tmux capture-pane -t rig-demo-codex -p | tail -50这套流程我实测下来很顺,关键是消息要简短明确。不要一次性发一大堆上下文,代理的上下文窗口有限,塞太多反而降低质量。我一般控制在 200 字以内的指令。
4.4 会话持久化与恢复
tmux 会话默认在机器重启后会丢失。如果你希望重启后还能恢复,需要配合 tmux 的插件或者自己写恢复脚本。我的做法是维护一个状态文件,记录每个会话的工作目录和启动命令,重启后读这个文件重新拉起。
openrig 本身如果实现了状态持久化,会把这个逻辑封装掉。如果没有,你可以用tmux-resurrect插件做基础恢复,再手动补上环境变量注入。这里要注意:API 密钥不会自动恢复,因为插件只保存会话结构不保存环境变量。所以重启后还是要确保 shell 里导出了密钥。
5. 常见问题与排查技巧实录
5.1 启动失败类问题速查
这类问题最让人头疼,因为报错信息往往不直接指向根因。我整理了一张速查表:
| 现象 | 可能原因 | 排查方法 |
|---|---|---|
| 提示 tool not found | CLI 未安装或不在 PATH | which claude/which codex |
| 会话创建后立即退出 | 工具启动参数错误 | 手动跑一次启动命令看报错 |
| 环境变量为空 | shell 未导出或 YAML 引用错误 | echo $VAR确认 |
| 工作目录不存在 | workspace 路径写错 | ls确认路径 |
| 认证失败 | 密钥无效或订阅限制 | 单独跑工具确认认证状态 |
| 会话名冲突 | 已有同名会话 | tmux ls检查并清理 |
我踩过最坑的一次是workspace用了相对路径,结果 openrig 在不同目录下启动时解析到了不同位置,代理看到的文件完全不对。后来统一改成绝对路径或~开头的路径,问题就没了。
5.2 代理输出异常的处理
有时候代理会话看起来在跑,但输出卡住或者乱码。常见原因有几个:
- 终端尺寸问题:tmux 会话的默认尺寸可能和工具预期不符,导致界面渲染错乱。解决方法是创建会话时指定尺寸,或者在 attach 后手动 resize。
- 编码问题:如果工具输出包含特殊字符,capture-pane 抓取时可能乱码。建议在 tmux 配置里设
set -g default-terminal "screen-256color"。 - 缓冲未刷新:工具输出有缓冲,capture-pane 抓到的可能是旧内容。可以加个短暂 sleep 再抓,或者用
-S -参数抓完整 scrollback。
提示:capture-pane 抓取的是渲染后的文本,不是原始输出流。如果工具用了复杂的 TUI 界面,抓取结果可能包含大量控制字符,需要额外清洗。
5.3 多代理并发冲突的规避
两个代理同时改同一个文件,冲突几乎必然发生。我的规避策略是按目录划分职责:Claude Code 负责src/,Codex 负责tests/,各自不越界。如果确实需要改同一个文件,就串行化——先让一个改完并提交,再让另一个基于最新版本工作。
另一个冲突点是 API 速率限制。如果两个代理同时高频调用同一个 API,可能触发限流。解决办法是给不同代理配不同的密钥,或者错开它们的活跃时间。我在配置里会给每个代理设一个rate_limit提示,虽然 openrig 不一定强制,但至少提醒自己注意。
5.4 配置热更新的注意事项
改完 YAML 后,openrig 通常需要重启对应会话才能生效。直接改文件不会自动重载。重启单个会话的命令大概是:
tmux kill-session -t rig-demo-claude openrig up -c ~/.openrig/demo.yaml --only claude--only参数(如果支持)可以只重启指定代理,不影响其他会话。如果没有这个参数,就得全部重启。重启前记得保存代理会话里的重要输出,因为 kill-session 会清掉 scrollback。
6. 我个人的实操心得与扩展思路
用了一段时间 openrig 这套模式后,我最大的体会是:编排层的价值不在于功能多,而在于把重复劳动收敛掉。以前每开一个新项目就要重新配一遍工具,现在复制一份 YAML 改几个字段就行。这种效率提升在长期项目里累积起来非常可观。
几个我踩过坑之后总结的小技巧:第一,YAML 里所有路径都用绝对路径或~开头,别用相对路径;第二,会话名统一加前缀,方便批量操作;第三,环境变量永远走 shell 导出,不写进配置文件;第四,定期清理僵尸会话,tmux ls看到不认识的会话先确认再杀。
这个模式后续还能往几个方向扩展。一是加一层健康检查,定期 ping 每个代理会话,挂了自动重启;二是把代理间的消息传递从 tmux send-keys 升级成结构化协议,减少文本解析的脆弱性;三是把配置拆成基础配置和项目配置两层,基础配置放通用设置,项目配置只写差异部分。这些扩展都不需要改动上游工具,纯粹在编排层做文章,风险可控。