openrig:多AI编码代理的本地编排与终端会话管理实践
1. openrig 到底在解决什么问题第一次看到 openrig 这个名字很多人会以为是某个硬件项目毕竟 “rig” 这个词在装机圈里太常见了。但如果你最近在折腾 Claude Code、Codex 这类终端 AI 编程助手大概率已经隐约感觉到它要解决的是什么问题了——多 AI 编码代理的本地编排与终端会话管理。我自己的日常工作流里同时开着 Claude Code 和 Codex 是常态。一个负责大范围重构和代码审查一个负责快速补全和命令行操作。用久了就会发现几个特别烦人的点每个工具都要单独开一个终端窗口切来切去容易乱会话状态没法统一管理关掉终端再回来上下文就断了不同工具的配置散落在各自的家目录里想统一改个模型端点要翻好几个文件。openrig 这个项目本质上就是冲着这些痛点来的。它做的事情可以概括成三句话把多个 AI 编码代理统一到一个可管理的终端会话体系里用 tmux 作为底层会话承载用 Node.js 做编排层让 Claude Code、Codex 这些工具能在同一个 “工作台” 里协同工作。说白了它想当的是你本地 AI 编程工具的 “调度中心”而不是再做一个新的 AI 助手。适合谁来参考这篇文章如果你已经在用或者准备用 Claude Code、Codex并且遇到了多会话管理混乱、配置分散、终端切换成本高的问题那 openrig 的思路值得你花时间研究。如果你只是偶尔用一下 AI 补全还没到多代理协同的阶段可以先收藏等需求上来了再回头看。下面我会从设计思路、核心细节、实操落地到问题排查把整个东西拆开讲清楚。2. 整体设计思路与方案选型拆解2.1 为什么是 tmux 而不是自己造会话层openrig 选择 tmux 作为底层会话承载这个决定我认为是整个项目里最务实的一步。很多人第一反应可能是 “为什么不自己写一个会话管理模块”毕竟 Node.js 生态里做进程管理并不难。但真做过终端工具的人都知道终端会话的持久化、分离重连、窗口分屏、滚动缓冲这些能力自己实现一遍就是几个月的工作量而且稳定性很难保证。tmux 在这里扮演的角色类似于一个 “终端操作系统”。它天然支持会话分离detach和重连attach这意味着你关掉 SSH 或者合上笔记本AI 代理的会话还在后台跑着。它还支持窗口和面板切分你可以左边跑 Claude Code 做代码审查右边跑 Codex 执行命令下面再挂一个日志窗口。这些能力如果让 openrig 自己实现代码量会膨胀好几倍而且大概率没有 tmux 稳定。提示tmux 的会话是独立于终端进程存在的。理解这一点很关键它意味着 openrig 管理的不是 “窗口”而是 “会话”窗口只是会话的一个视图。从编排层的角度看openrig 用 Node.js 做胶水通过子进程调用 tmux 命令来创建、切换、销毁会话。这个选择也有讲究。Node.js 的 child_process 模块处理这类 “调用外部命令并解析输出” 的场景非常顺手而且 npm 生态里有大量现成的终端字符串处理库。更重要的是Claude Code 和 Codex 本身很多就是 Node.js 写的或者通过 npm 分发的用同一套运行时环境可以减少很多环境变量和路径上的坑。2.2 多代理协同的核心矛盾隔离还是共享openrig 在设计上要回答一个根本问题多个 AI 编码代理之间应该是完全隔离的还是共享某些状态这个问题没有标准答案取决于你的使用场景。完全隔离的好处是干净。每个代理有自己的工作目录、自己的配置、自己的会话互不干扰。但坏处也很明显你没法让 Claude Code 审查 Codex 刚写的代码也没法让两个代理看到同一份上下文。共享状态则相反灵活但容易乱一个代理改了文件另一个可能不知道。openrig 的做法我理解是 “会话隔离、工作区共享”。每个 AI 代理跑在独立的 tmux 窗口或面板里拥有独立的进程空间和配置加载路径但它们默认指向同一个项目工作目录。这样你可以在一个窗口里让 Codex 生成代码切到另一个窗口让 Claude Code 直接审查刚生成的文件不需要手动复制粘贴。这个设计取舍很符合实际工作流——大多数时候你要的是 “同一个项目上的多个视角”而不是 “多个互不相干的项目”。2.3 配置层为什么要做统一抽象Claude Code 和 Codex 的配置格式、环境变量、模型端点设置方式都不一样。Claude Code 有自己的 settings 文件和环境变量体系Codex 也有自己的 config 文件。如果你同时用多个模型提供商比如本地跑的 LM Studio、远程的 DeepSeek、或者官方端点每个工具的配置方式都要单独学一遍。openrig 在配置层做了一层抽象把 “模型端点”、“API 密钥”、“工作目录”、“启动参数” 这些共性配置抽出来再映射到各个工具自己的配置格式上。这个思路类似于 Docker Compose 对多个容器的编排——你写一份声明式的配置由编排层负责翻译成各个工具能理解的参数。这样做的好处是当你需要切换模型端点时只改一个地方所有代理同步生效。坏处是抽象层本身需要维护如果某个工具更新了配置格式抽象层要跟着改。但对于同时用多个工具的人来说这个维护成本远低于每次手动改多个配置文件。3. 核心细节解析与实操要点3.1 Node.js 环境准备版本选择与安装避坑openrig 跑在 Node.js 上所以第一步是把 Node.js 环境弄好。这里有个很常见的坑网上很多教程让你直接装最新版但 AI 编码工具链对 Node.js 版本往往有要求。比如有些工具要求 Node.js 18 以上有些在 Node.js 22 上会有兼容性问题。我的建议是优先用 LTS 版本。截至我写这篇文章的时候Node.js 20 LTS 和 22 LTS 是比较稳妥的选择。如果你在 Ubuntu 上不要直接用 apt 里的 Node.js那个版本通常很旧。推荐用 NodeSource 的仓库或者 nvm 来管理版本。# 用 nvm 安装和管理 Node.js 版本推荐 curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash source ~/.bashrc nvm install 22 nvm use 22 node -v如果你在 Windows 上直接从 Node.js 官网下载 LTS 版本的安装包就行。安装时注意勾选 “Add to PATH”否则后面在终端里调 node 命令会找不到。安装完成后开一个新的终端窗口运行node -v和npm -v确认版本。注意如果你看到类似 “error installing 24.21.0: node.js v24.21.0 is not yet released” 这样的报错说明你指定的版本号不存在或者还没发布。去 Node.js 官网确认当前可用的 LTS 版本号不要凭记忆写版本。3.2 tmux 的安装与基础会话管理tmux 在大多数 Linux 发行版的仓库里都有Ubuntu 上直接sudo apt install tmux就行。macOS 上用 Homebrew 安装。Windows 上原生没有 tmux但如果你用 WSL可以在 WSL 里装。装好之后先熟悉几个最基础的命令这些是 openrig 底层会调用的# 创建一个名为 work 的会话 tmux new-session -d -s work # 列出所有会话 tmux ls # 连接到 work 会话 tmux attach -t work # 在 work 会话里创建一个新窗口 tmux new-window -t work -n claude # 向指定窗口发送命令 tmux send-keys -t work:claude claude Enter理解 tmux 的 “会话-窗口-面板” 三层结构很重要。一个会话可以包含多个窗口一个窗口可以切分成多个面板。openrig 通常会为每个 AI 代理创建一个窗口然后在窗口里跑对应的命令。你可以在会话之间自由切换而所有代理进程都在后台持续运行。提示tmux 的默认前缀键是 Ctrlb。所有 tmux 快捷键都要先按前缀键再按功能键。如果你觉得别扭可以在 ~/.tmux.conf 里改成 Ctrla。3.3 Claude Code 与 Codex 的安装要点Claude Code 和 Codex 的安装方式各有不同这里分别说一下我实测下来比较稳的路径。Claude Code 通常通过 npm 全局安装npm install -g anthropic-ai/claude-code安装完成后在项目目录下运行claude就能启动。第一次启动会引导你完成认证。如果你在 VS Code 里用也可以装对应的扩展然后在 VS Code 的终端里直接调用。Codex 的安装类似也是 npm 全局包npm install -g openai/codex安装完成后运行codex启动。Codex 的配置通常在~/.codex/config或者项目目录下的配置文件里。如果你要接入第三方模型端点比如 DeepSeek 或者本地 LM Studio需要在这里配置 base URL 和 API key。注意安装全局 npm 包时如果遇到权限错误不要直接用 sudo。正确做法是配置 npm 的全局目录到用户目录下或者用 nvm 管理 Node.js这样全局包会装在用户空间里不需要提权。3.4 配置统一抽象的具体做法openrig 的配置抽象层我理解核心是一份 YAML 或 JSON 格式的声明文件里面定义了每个代理的启动参数、环境变量、工作目录和模型端点。然后由 Node.js 脚本读取这份配置生成对应的 tmux 命令和工具配置文件。一个简化的配置结构大概长这样agents: claude: tool: claude-code workdir: ~/projects/myapp model_endpoint: http://localhost:1234/v1 env: ANTHROPIC_BASE_URL: http://localhost:1234/v1 codex: tool: codex workdir: ~/projects/myapp model_endpoint: https://api.deepseek.com/v1 env: OPENAI_BASE_URL: https://api.deepseek.com/v1这个配置的好处是当你需要把 Claude Code 从本地 LM Studio 切到远程端点时只改model_endpoint和对应的环境变量就行不需要去翻 Claude Code 自己的配置文件。Codex 那边同理。实际操作中要注意不同工具对环境变量的读取时机不一样。有些工具在启动时读一次有些在每次请求时都读。如果你在会话运行中改了配置可能需要重启对应的代理进程才能生效。4. 实操过程与核心环节实现4.1 从零搭建 openrig 工作流的完整步骤假设你现在什么都没有想从零把 openrig 这套工作流跑起来下面是我实测下来比较顺的步骤。第一步确认系统环境。你需要一个类 Unix 终端环境Linux、macOS、WSL 都行。Windows 原生终端虽然也能跑 Node.js但 tmux 支持不好建议用 WSL。第二步安装 Node.js LTS 和 tmux。前面已经讲过具体命令这里不重复。装完后确认node -v、npm -v、tmux -V都能正常输出版本号。第三步安装 Claude Code 和 Codex。用 npm 全局安装确认claude --version和codex --version能正常输出。第四步创建 openrig 的工作目录和配置文件。我习惯在~/openrig下放配置在~/projects下放实际项目。mkdir -p ~/openrig cd ~/openrig npm init -y npm install js-yaml第五步写一个最简的编排脚本。这个脚本读取配置创建 tmux 会话为每个代理开一个窗口并启动对应命令。// openrig.js const { execSync } require(child_process); const yaml require(js-yaml); const fs require(fs); const config yaml.load(fs.readFileSync(./agents.yaml, utf8)); const sessionName openrig; // 创建会话如果已存在则跳过 try { execSync(tmux new-session -d -s ${sessionName}); } catch (e) { // 会话已存在 } // 为每个代理创建窗口并启动 Object.entries(config.agents).forEach(([name, agent]) { const cmd agent.tool claude-code ? claude : codex; const envStr Object.entries(agent.env || {}) .map(([k, v]) ${k}${v}) .join( ); execSync(tmux new-window -t ${sessionName} -n ${name}); execSync(tmux send-keys -t ${sessionName}:${name} cd ${agent.workdir} Enter); execSync(tmux send-keys -t ${sessionName}:${name} ${envStr} ${cmd} Enter); }); console.log(openrig 会话已启动运行 tmux attach -t ${sessionName} 进入);第六步运行脚本并进入会话。node openrig.js tmux attach -t openrig进入后你应该能看到多个窗口每个窗口里跑着一个 AI 代理。用 Ctrlb 加数字键可以在窗口之间切换。4.2 模型端点接入的实操细节接入本地 LM Studio 或者远程模型端点是很多人用 openrig 的核心诉求。这里以 LM Studio 为例说一下关键点。LM Studio 启动本地服务后默认监听http://localhost:1234/v1。你需要在 Claude Code 和 Codex 的配置里把 base URL 指过去。Claude Code 通过环境变量ANTHROPIC_BASE_URL控制Codex 通过OPENAI_BASE_URL控制。但这里有个容易踩的坑不同工具对 API 格式的要求不一样。Claude Code 用的是 Anthropic 的 API 格式Codex 用的是 OpenAI 的 API 格式。如果你的本地模型只支持其中一种另一个工具可能连不上。LM Studio 通常两种格式都支持但你要确认加载的模型和配置的端点路径匹配。注意如果你看到 “cc switch local proxy failed while handling codex endpoint /responses” 这类报错通常是代理层在转发请求时路径或格式不对。检查你的 base URL 是否包含了正确的路径前缀以及代理是否支持目标 API 格式。4.3 会话持久化与断线重连的实操openrig 用 tmux 做会话承载最大的好处就是持久化。你可以在笔记本上跑着代理合上盖子去开会回来打开终端tmux attach就能接着用。但有几个细节要注意。第一tmux 会话默认在服务器重启后会丢失。如果你需要跨重启保留得用 tmux 的插件或者自己写脚本在启动时恢复。第二长时间运行的会话里AI 代理的上下文可能会变得很大响应变慢。定期重启代理进程是个好习惯。第三如果你通过 SSH 连到远程机器上跑 openrig确保 SSH 配置里没有设置过短的超时否则连接断了虽然 tmux 会话还在但重连体验会受影响。# 在 ~/.ssh/config 里加长超时 Host myserver ServerAliveInterval 60 ServerAliveCountMax 104.4 多代理协同的实际工作流示例说一个我日常用得最多的场景。假设我在开发一个新功能需要先让 Codex 根据需求生成代码骨架然后让 Claude Code 审查代码质量最后我自己在终端里跑测试。在 openrig 会话里我切到 codex 窗口输入需求描述让它生成代码。生成完成后切到 claude 窗口让它读取刚生成的文件并给出审查意见。两个窗口共享同一个工作目录所以 Claude Code 能直接看到 Codex 写的文件不需要我手动传递。如果审查发现问题我再切回 codex 窗口让它修改。整个过程都在一个 tmux 会话里完成窗口切换用 Ctrlb 加数字键非常快。这比开多个终端窗口然后 AltTab 切换要顺手得多尤其是在全屏终端环境下。5. 常见问题与排查技巧实录5.1 安装与启动阶段的典型报错这个阶段的问题大多和环境有关。我整理了一个速查表覆盖了我遇到过和社区里反馈比较多的几种情况。报错信息可能原因排查方向node.js v24.21.0 is not yet released版本号不存在或未发布去官网确认可用 LTS 版本npm install 权限错误全局目录权限问题用 nvm 或配置 npm prefixclaude: command not found全局 bin 目录不在 PATH检查 npm bin -g 输出并加入 PATHcodex is ignoring 1 unrecognized configuration setting配置文件里有拼写错误或未知字段逐行检查配置文件对照官方文档your organization has disabled claude subscription access账号权限或订阅问题检查账号状态和订阅计划提示遇到 “command not found” 时先运行npm bin -g看看全局 bin 目录在哪然后确认这个目录在 PATH 里。这是最高频的问题没有之一。5.2 模型接入阶段的连接问题模型接入的问题通常表现为请求超时、返回格式错误、或者认证失败。排查顺序建议是先确认端点本身可达再确认 API 格式匹配最后确认认证信息正确。# 测试端点是否可达 curl http://localhost:1234/v1/models # 测试 API 格式以 OpenAI 格式为例 curl http://localhost:1234/v1/chat/completions \ -H Content-Type: application/json \ -d {model:your-model,messages:[{role:user,content:hi}]}如果 curl 能通但工具连不上大概率是工具侧的配置问题。检查环境变量是否在正确的时机被读取以及是否有其他配置文件覆盖了你的设置。5.3 会话管理中的常见坑tmux 会话管理这块我踩过的坑主要有几个。一是窗口命名冲突如果你用同一个名字创建多个窗口tmux 会自动加后缀导致脚本里按名字定位窗口时找不到。二是 send-keys 发送命令时如果命令里有特殊字符可能被 tmux 解释成快捷键。三是会话里的工作目录不会自动继承每个新窗口都要手动 cd。针对第一个问题我的做法是在脚本里用窗口索引而不是名字来定位。针对第二个问题发送复杂命令时用send-keys -l参数让 tmux 按字面量处理。针对第三个问题可以在创建窗口时直接用-c参数指定起始目录。# 创建窗口时指定工作目录 tmux new-window -t openrig -n codex -c ~/projects/myapp # 按字面量发送命令避免特殊字符被解释 tmux send-keys -t openrig:codex -l echo hello world tmux send-keys -t openrig:codex Enter5.4 性能与资源占用的观察同时跑多个 AI 代理资源占用是绕不开的话题。我的实测是两个代理同时空闲时内存占用大概在几百 MB 级别主要看 Node.js 运行时本身的开销。但如果代理正在处理大文件或者长上下文内存会明显上升。如果你在资源有限的机器上跑建议不要同时开太多代理。另外tmux 的滚动缓冲默认是 2000 行如果你跑了很多输出可以适当调大但也会占内存。在~/.tmux.conf里设置set-option -g history-limit 10000可以调到一万行。还有一个容易被忽略的点AI 代理的日志文件。有些工具会把详细日志写到磁盘上跑久了可能占几个 GB。定期清理日志目录是个好习惯或者配置日志轮转。5.5 我个人的几条避坑经验第一条不要在生产环境的机器上直接跑 openrig 的实验性配置。先在本地或者测试机上跑通再迁移到常用环境。第二条配置文件一定要纳入版本管理这样改坏了能回滚。第三条tmux 会话名和窗口名用有意义的命名别用默认的 0、1、2过两天你自己都忘了哪个是哪个。第四条如果某个工具更新后 openrig 的编排脚本失效了先去看工具的更新日志大概率是启动参数或者配置格式变了。第五条遇到问题先看日志AI 代理工具通常会把详细错误写到日志文件里比终端上显示的那一行信息有用得多。6. 后续可以怎么扩展这套工作流openrig 这套思路跑通之后能扩展的方向其实不少。比如你可以加一个 “任务队列” 层把需要 AI 处理的任务写到一个队列里让多个代理轮流消费。也可以加一个简单的 Web 界面用浏览器查看各个会话的状态和输出。还可以把常用的提示词模板化在启动代理时自动注入。我目前在做的一个扩展是给 openrig 加一个 “健康检查” 功能定期检查每个代理进程是否还活着如果挂了就自动重启。这个用 Node.js 的定时任务加 tmux 的会话检测就能实现代码量不大但很实用。另一个想法是把 openrig 的配置和 dotfiles 管理结合起来这样换机器的时候一套配置直接同步过去不用重新搭环境。这套东西的价值不在于它有多复杂而在于它把多个 AI 编码代理的日常使用体验理顺了。你不用再记每个工具各自的启动方式和配置位置也不用在多个终端窗口之间反复横跳。一个 tmux 会话几个窗口所有代理各就各位该干活干活该审查审查。这种 “工作台” 式的体验用惯了之后很难回去。