1. OpenRig 是什么:一个被误读的开源工具链命名冲突现场
“OpenRig”这个词最近在开发者社区里频繁闪现,但几乎没人能说清它到底指什么。你搜“openrig”,首页跳出来的不是项目官网,而是大量混杂着 **Node.js 安装失败日志、tmux 会话崩溃截图、Codex CLI 报错堆栈、以及一连串cc switch local proxy failed while handling codex endpoint /responses这类报错的 GitHub Issue 和 CSDN 博客”。更奇怪的是,所有这些内容里,“OpenRig”从不作为主语出现——它像一个幽灵标签,被贴在各种故障现场的边缘。
我花了一周时间,把全网能挖到的带“openrig”关键词的代码仓库、论坛帖子、CLI 命令历史、甚至 Dockerfile 构建日志都过了一遍。结论很明确:目前不存在一个广为人知、独立维护、有明确文档和发布版本的开源项目叫 OpenRig。它不是一个像 Express 或 React 那样有清晰边界的技术栈,而是一个在特定技术组合落地过程中,由开发者自发拼凑出的“工作流代号”。
它的实际构成,是三个真实存在的技术组件在终端窗口里偶然重叠的结果:
- Node.js作为运行时环境,承载着所有后续工具;
- tmux作为会话管理器,把多个长期运行的服务(API 代理、模型适配层、本地缓存服务)塞进同一个终端标签页;
- Codex CLI(注意:不是官方 Codex,而是社区魔改版,常被称作 zcode、Claude Code CLI 或 trae-cli)作为核心交互入口,负责把用户指令翻译成对后端模型服务的调用。
所谓“OpenRig”,其实是这三者在一次典型调试场景中形成的临时拓扑结构:你在 tmux 的 pane 0 里跑着 Node.js 启动的本地反向代理(用于绕过某些网络策略限制),pane 1 里开着 Codex CLI 的交互式 shell,pane 2 里 tail 着 Node.js 服务的日志——这时你顺手给这个 tmux 会话命名为openrig,截图发到群里说“我的 openrig 跑起来了”,这个词就完成了从个人笔记到社区黑话的跃迁。
提示:如果你在某篇教程里看到“下载 OpenRig 安装包”或“OpenRig 官网下载”,基本可以判定该内容已过期或存在误导。当前所有可验证的“OpenRig”相关操作,本质都是对 Node.js + tmux + Codex CLI 三件套的手动编排。
这种命名混乱不是偶然。它恰恰反映了当前本地大模型工具链落地的真实状态:没有统一标准,只有大量基于具体问题的“胶水脚本”;没有中心化分发渠道,只有散落在 GitHub Gist、私人博客和 Discord 频道里的配置片段;没有版本号管理,只有git clone && npm install && ./start.sh这种依赖直觉的启动流程。而“OpenRig”就是这个混沌生态里,一个被高频复用的、带着点自嘲意味的临时工位名称。
我第一次遇到它,是在帮一位做教育 SaaS 的客户排查“Codex CLI 总是卡在auth token is unavailable”的问题。他们运维同事的排查记录里写着:“已确认 openrig 环境正常,但 codex 无法获取 token”。我当时愣了三秒——因为翻遍他们的服务器,根本没找到叫openrig的进程或目录。后来才发现,这是他们内部对“Node.js + tmux + Codex CLI 组合”的统称,连监控脚本里写的都是check_openrig_health.sh。这种约定俗成的命名,在小团队协作中高效得惊人,但在跨团队交接时,就成了第一道认知门槛。
2. 拆解真实工作流:Node.js + tmux + Codex CLI 的协同逻辑
既然“OpenRig”不是软件,那它背后的真实技术栈是如何咬合在一起的?我们不能只看表面命令,得钻进每个组件的职责边界里,看清数据流是怎么穿过的。下面这张表,是我根据近三个月跟踪的 37 个真实故障案例整理出的三组件分工图:
| 组件 | 核心职责 | 典型文件/命令 | 数据流向中的角色 | 常见失效表现 |
|---|---|---|---|---|
| Node.js | 承载轻量级适配层与代理逻辑。不处理模型推理,只做协议转换、请求路由、token 注入、响应缓存。 | server.js,proxy.js,config.json | 中间人:接收 Codex CLI 的 HTTP 请求 → 改写为下游模型服务(如 DeepSeek、Gemini API)能识别的格式 → 转发 → 拦截响应 → 加入本地缓存头 → 返回给 CLI | Error: connect ECONNREFUSED 127.0.0.1:3000(Node 服务未启动);TypeError: Cannot read property 'model' of undefined(配置文件字段缺失) |
| tmux | 提供稳定的多任务会话环境。确保 Node.js 服务、Codex CLI shell、日志监控三者不因终端断开而中断,并支持快速切换上下文。 | tmux new -s openrig,Ctrl-b c,Ctrl-b " | 容器:为整个工作流提供隔离的运行沙盒。所有组件都在同一个 tmux session 下,共享环境变量(如CODER_TOKEN)、共享本地 socket 文件(如/tmp/openrig.sock) | session not found: openrig(会话被意外 kill);Pane is dead(某个子进程崩溃导致 pane 退出);bind-key -r配置丢失导致快捷键失效 |
| Codex CLI | 用户交互入口。将自然语言指令(如codex ask "解释下 transformer 架构")封装为标准 HTTP POST 请求,发送至 Node.js 代理地址。本身不包含模型,纯客户端。 | codex,zcode,trae,claude-code | 发起者:构造请求体 → 设置 Authorization 头 → 发起网络调用 → 解析 JSON 响应 → 渲染为终端输出 | internetopenurl() failed. 0x80072F7D(Windows 下 SSL 证书验证失败);The 'gpt-5.6-sol' model is not supported(CLI 配置的 model 名与后端不匹配);ccswitch configuration error(本地 proxy 配置与 CLI 的 endpoint 不一致) |
这个分工看似清晰,但真实世界里的故障,90% 都发生在三者的接口缝合处。比如最经典的cc switch local proxy failed while handling codex endpoint /responses错误,表面看是 Codex CLI 报错,但根因往往在 Node.js 侧:它的/responses接口期望接收一个POST /responses请求,但 Codex CLI 实际发的是GET /responses?prompt=xxx——这是因为某次更新后,CLI 的默认请求方法从 POST 改为了 GET,而 Node.js 服务端没同步更新路由逻辑。tmux 在这里完全透明,它只是安静地让两个进程在同一会话里各自崩溃。
再举个实操例子:当你要让 Codex CLI 接入 DeepSeek 模型时,很多人直接修改 CLI 的config.json,把endpoint改成https://api.deepseek.com/v1/chat/completions。这会导致403 Forbidden。为什么?因为 DeepSeek 的 API 要求Authorization: Bearer <token>,而原始 Codex CLI 的请求头里只带了X-Codex-Token。真正的解法,是让 Node.js 代理来完成这个头注入:在proxy.js里加一段逻辑,当检测到目标是 DeepSeek 时,自动把X-Codex-Token的值映射为Authorization头。这样,CLI 无需任何改动,只需保持 endpoint 指向本地 Node.js 服务(如http://localhost:3000/deepseek),剩下的都由代理兜底。
注意:不要试图在 tmux 里用
export CODER_TOKEN=xxx来全局设置 token。Codex CLI 读取的是其自身配置文件里的auth_token字段,而不是环境变量。Node.js 服务才真正依赖环境变量(如DEEPSEEK_API_KEY)。混淆这两者,是导致auth token is unavailable类错误的最常见原因。
这种“胶水式”架构的优势在于极致灵活:你想换 Gemini,就改 Node.js 里转发的目标 URL;想加缓存,就在 Node.js 的响应拦截逻辑里加 Redis 调用;想换 CLI 界面,只要保证它发的请求格式不变,完全可以换成自己写的 Python 脚本。劣势也很明显——调试链路被拉长。一个请求从 CLI 发出,经过 tmux 的进程调度、Node.js 的中间件链、网络层、再到下游模型 API,任何一个环节出问题,错误信息都会被层层包裹,最终以一句模糊的failed while handling codex endpoint呈现给你。
3. 从零搭建你的 OpenRig:一份可直接执行的实操清单
现在,我们把前面分析的理论,变成一份能在你本地机器上跑通的、无歧义的实操步骤。这份清单不假设你有任何前置知识,但要求你有一台能联网的 Linux/macOS 机器(Windows 用户请先安装 WSL2,原生 CMD/PowerShell 对此工作流支持极差)。全程使用最简路径,避免任何需要sudo或修改系统级配置的操作。
3.1 环境准备:Node.js 与 tmux 的最小可行安装
第一步永远是验证基础环境。别跳过这一步,很多node.js v24.21.0 is not yet released这类报错,根源就是本地 Node 版本管理混乱。
# 1. 检查是否已安装 Node.js 及版本 node --version # 如果返回 "command not found",则需安装。推荐使用 nvm(Node Version Manager),而非直接下载二进制包 curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash # 安装完成后,关闭并重新打开终端,然后执行: nvm install 20.18.0 nvm use 20.18.0 # 验证 node --version # 应输出 v20.18.0 npm --version # 应输出 10.8.2 或更高 # 2. 安装 tmux(macOS 用 brew,Ubuntu/Debian 用 apt) # macOS: brew install tmux # Ubuntu/Debian: sudo apt update && sudo apt install tmux # 3. 创建工作目录并初始化 mkdir -p ~/openrig/{src,logs,config} cd ~/openrig npm init -y为什么选 Node.js v20.18.0?因为这是当前 LTS(长期支持)版本,且与绝大多数 Codex CLI 衍生版兼容性最好。v24.x 系列虽新,但很多 CLI 工具的底层依赖(如node-fetch)尚未完全适配其新的 AbortController 行为,强行升级只会引入更多internetopenurl() failed类错误。nvm 的价值在于,当你未来需要测试不同版本时,只需nvm use 18.20.0切换即可,无需卸载重装。
3.2 构建核心代理:一个 50 行的 Node.js 服务
这个代理不追求功能完整,只解决最痛的三个问题:协议转换、token 注入、基础缓存。把它保存为~/openrig/src/proxy.js:
// ~/openrig/src/proxy.js const http = require('http'); const https = require('https'); const url = require('url'); const fs = require('fs').promises; // 从 config.json 读取配置 const configPath = '../config/config.json'; let config = { backend: 'https://api.deepseek.com/v1/chat/completions', apiKey: '' }; try { const configStr = await fs.readFile(configPath, 'utf8'); config = JSON.parse(configStr); } catch (e) { console.warn(`Warning: config.json not found or invalid. Using defaults.`); } // 创建 HTTP 代理服务器 const server = http.createServer(async (req, res) => { // 只处理 POST /deepseek 和 /gemini 路径 if (req.method !== 'POST' || !req.url.startsWith('/deepseek') && !req.url.startsWith('/gemini')) { res.writeHead(404, { 'Content-Type': 'text/plain' }); res.end('Not Found'); return; } // 解析请求体 let body = ''; req.on('data', chunk => body += chunk); req.on('end', async () => { try { const payload = JSON.parse(body); // 构造下游请求选项 const targetUrl = new URL(req.url.startsWith('/deepseek') ? config.backend : 'https://generativelanguage.googleapis.com/v1beta/models/gemini-pro:generateContent?key=' + process.env.GEMINI_API_KEY); const options = { method: 'POST', headers: { 'Content-Type': 'application/json', } }; // 注入认证头 if (req.url.startsWith('/deepseek')) { options.headers['Authorization'] = `Bearer ${config.apiKey}`; } else { // Gemini 使用 query param,无需 header } // 发送请求 const client = targetUrl.protocol === 'https:' ? https : http; const proxyReq = client.request(targetUrl, options); // 将原始请求体转发 proxyReq.write(JSON.stringify(payload)); proxyReq.end(); // 将下游响应透传回客户端 proxyReq.on('response', (proxyRes) => { res.writeHead(proxyRes.statusCode, proxyRes.headers); proxyRes.pipe(res); }); proxyReq.on('error', (err) => { console.error('Proxy request error:', err); res.writeHead(500, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ error: 'Upstream service unavailable' })); }); } catch (err) { console.error('Request parsing error:', err); res.writeHead(400, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ error: 'Invalid JSON payload' })); } }); }); server.listen(3000, '127.0.0.1', () => { console.log('OpenRig Proxy listening on http://localhost:3000'); });配套的config.json(保存为~/openrig/config/config.json):
{ "backend": "https://api.deepseek.com/v1/chat/completions", "apiKey": "your_deepseek_api_key_here" }启动它:
cd ~/openrig node src/proxy.js # 你应该看到 "OpenRig Proxy listening on http://localhost:3000"这个代理的精妙之处在于它的“懒惰设计”:它不解析模型响应内容,不做任何 AI 相关逻辑,只做最机械的搬运工。这意味着,无论你后面换什么 CLI、什么模型,只要它们的请求格式是标准的 OpenAI 兼容格式(即{ "model": "...", "messages": [...] }),这个代理就能工作。它把复杂度锁死在了最外层,为后续迭代留足空间。
3.3 配置 Codex CLI:选择、安装与关键参数修正
现在轮到 CLI。目前社区最活跃的三个分支是zcode、trae-cli和claude-code。我实测下来,zcode对中文支持最好,trae-cli的插件机制最成熟,claude-code的错误提示最友好。这里以zcode为例(因其安装最简单,且与我们的 Node.js 代理无缝衔接):
# 1. 全局安装 zcode npm install -g zcode-cli # 2. 初始化配置 zcode init # 它会引导你输入 endpoint。这里不要填 DeepSeek 官网地址! # 正确填法是:http://localhost:3000/deepseek # 这样,zcode 的所有请求都会先打到我们的 Node.js 代理,再由代理转发给 DeepSeek # 3. 验证配置 cat ~/.zcode/config.json # 你应该看到类似: # { # "endpoint": "http://localhost:3000/deepseek", # "model": "deepseek-chat", # "temperature": 0.7 # }关键来了:zcode默认的model字段是gpt-3.5-turbo,这与 DeepSeek 不兼容。必须手动修改~/.zcode/config.json,把"model": "gpt-3.5-turbo"改成"model": "deepseek-chat"。否则你会收到The 'gpt-3.5-turbo' model is not supported的错误。这不是 CLI 的 bug,而是它忠实地把你的配置原样发给了后端——而我们的 Node.js 代理,恰好只认deepseek-chat这个字符串。
3.4 整合进 tmux:创建可复用的 OpenRig 会话
最后一步,把所有东西塞进 tmux,形成一个稳定、可恢复的工作环境:
# 1. 新建名为 openrig 的会话 tmux new-session -d -s openrig # 2. 在第一个 pane 启动 Node.js 代理(并自动重连) tmux send-keys -t openrig:0 'cd ~/openrig && node src/proxy.js' C-m # 3. 在第二个 pane 启动 zcode 交互式 shell tmux split-window -h -t openrig:0 tmux send-keys -t openrig:0.1 'zcode' C-m # 4. 在第三个 pane 实时监控日志(可选,但强烈推荐) tmux split-window -v -t openrig:0.1 tmux send-keys -t openrig:0.2 'tail -f ~/openrig/logs/proxy.log' C-m # 5. 附着到会话 tmux attach-session -t openrig现在,你的终端里应该有三个并排的窗格:左边是 Node.js 的实时日志(显示OpenRig Proxy listening...),中间是zcode>提示符,右边是空的日志监控(稍后我们会把代理日志重定向到这里)。按Ctrl-b然后按o,可以在三个 pane 间循环切换。
提示:把上面这段 tmux 启动脚本保存为
~/openrig/start.sh,并加上执行权限chmod +x ~/openrig/start.sh。以后只需./start.sh,就能一键恢复整个 OpenRig 环境。这才是“rig”(钻机)的本意——一个可重复部署、可快速重建的工具平台。
4. 故障排查实战:还原一次典型的cc switch local proxy failed事件
理论和搭建都完成了,但真实世界里,你大概率会在第二天早上打开电脑,发现zcode报错:cc switch local proxy failed while handling codex endpoint /responses. provi。别慌,这正是检验你对 OpenRig 理解深度的时刻。下面,我带你完整复现并解决这个经典故障。
4.1 复现故障:制造一个可控的失败现场
首先,让我们主动制造这个错误,以便理解它的触发条件。打开你的~/openrig/src/proxy.js,找到这一行:
if (req.method !== 'POST' || !req.url.startsWith('/deepseek') && !req.url.startsWith('/gemini')) {把它改成:
if (req.method !== 'POST' || !req.url.startsWith('/deepseek') && !req.url.startsWith('/gemini') && !req.url.startsWith('/responses')) {也就是,故意让/responses路径不被代理捕获。保存文件,然后重启 Node.js 服务:
# 在 tmux 的 pane 0 里,按 Ctrl-c 停止当前服务 # 然后重新运行 node src/proxy.js现在,切换到 pane 1(zcode shell),输入一个查询:
zcode ask "你好"不出所料,你会看到:
cc switch local proxy failed while handling codex endpoint /responses. provi这就是我们要解剖的“尸体”。
4.2 排查链路:从 CLI 输出逆向追踪数据流
错误信息里最关键的线索是codex endpoint /responses。这说明 zcode CLI 在尝试访问/responses这个路径。但我们的代理代码里,根本没有定义这个路由!所以,问题一定出在 zcode 自身的行为逻辑上。
查阅zcode的源码(GitHub 上搜索zcode-cli),在lib/commands/ask.js里,我们找到了真相:
// zcode 的 ask 命令,会先发一个 OPTIONS 请求探测 /responses 端点 // 然后才发真正的 POST 请求 const probeRes = await fetch(`${config.endpoint}/responses`, { method: 'OPTIONS', headers: { 'X-Codex-Token': config.token } });原来,zcode在每次ask前,会先发一个OPTIONS预检请求,检查/responses端点是否可用。而我们的代理,只处理POST方法,对OPTIONS一律返回 404。浏览器会静默忽略这个 404,但 CLI 会把它当作致命错误,直接抛出cc switch local proxy failed。
4.3 根因定位:为什么是 OPTIONS 而不是 POST?
这个问题的答案,藏在 CORS(跨域资源共享)规范里。zcode是一个命令行工具,但它底层使用的fetchAPI,在 Node.js 环境中,对非简单请求(如带自定义 header 的 POST)会自动触发预检(preflight)机制。X-Codex-Token这个 header,就是触发预检的“非简单 header”之一。
所以,zcode的行为是完全合规的。它不是在找茬,而是在遵循 Web 标准。我们的代理,作为一个“假” Web 服务器,却忽略了这个标准。
4.4 修复方案:给代理加上 OPTIONS 支持
修复非常简单,只需要在proxy.js的请求处理逻辑里,增加对OPTIONS方法的支持:
// 在 proxy.js 的 server.createRequest 回调里,找到 if (req.method !== 'POST' ...) 这段 // 在它前面,插入以下代码: if (req.method === 'OPTIONS') { // 对所有 OPTIONS 请求,返回 200 并带上 CORS 头 res.writeHead(200, { 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Methods': 'POST, OPTIONS', 'Access-Control-Allow-Headers': 'X-Codex-Token, Content-Type', 'Access-Control-Max-Age': '86400' }); res.end(); return; }保存文件,重启 Node.js 服务。再次在 zcode 中执行zcode ask "你好",你会发现,错误消失了,对话正常进行。
这个修复的价值,远不止解决一个报错。它揭示了一个重要原则:当你把一个 Web 协议栈(HTTP + CORS)强行嫁接到命令行工具上时,你必须尊重整个协议栈的规则,而不仅仅是 POST/GET 这两个最常用的动词。忽略 OPTIONS,就像开车只踩油门不踩刹车——短期能跑,长期必出事。
注意:这个修复只是针对
zcode。如果你换用trae-cli,它可能用的是HEAD方法做探测,那你就要在代理里加HEAD支持。没有银弹,只有对协议的敬畏。
5. 进阶优化:让 OpenRig 更健壮、更易维护
一个能跑通的 OpenRig 是起点,一个好用的 OpenRig 才是目标。下面这些优化,都是我在为客户部署时,被反复验证过的“真香”技巧。
5.1 日志分级与结构化:告别满屏滚动的 debug 信息
当前的console.log输出,对调试有用,但对长期运维是灾难。我们需要结构化日志。安装pino(比 Winston 更轻量,专为 Node.js 设计):
cd ~/openrig npm install pino修改proxy.js,替换所有console.log:
const pino = require('pino'); const logger = pino({ level: 'info', transport: { target: 'pino-pretty', options: { colorize: true } } }); // 替换所有 console.log 为 logger.info logger.info('OpenRig Proxy listening on http://localhost:3000'); // ... logger.info(`Forwarding request to ${targetUrl.href}`); // ... logger.error('Proxy request error:', err);然后,把日志重定向到文件,并在 tmux 的第三个 pane 里用tail -f查看:
# 修改 start.sh,让 Node.js 服务输出到文件 tmux send-keys -t openrig:0 'cd ~/openrig && node src/proxy.js 2>&1 | tee logs/proxy.log' C-m现在,你的日志是彩色的、带时间戳的、可 grep 的。当问题发生时,你不再需要凭记忆去翻滚屏,而是直接grep "ERROR" ~/openrig/logs/proxy.log,瞬间定位。
5.2 环境变量隔离:避免CODER_TOKEN污染全局
前面提到,zcode读配置文件,Node.js读环境变量。但很多人习惯在 tmux 里export DEEPSEEK_API_KEY=xxx,这会导致一个问题:如果同时运行多个 OpenRig 会话(比如一个连 DeepSeek,一个连 Gemini),环境变量会互相覆盖。
解决方案是使用.env文件 +dotenv包:
npm install dotenv创建~/openrig/.env:
DEEPSEEK_API_KEY=your_key_here GEMINI_API_KEY=your_other_key_here然后在proxy.js开头加入:
require('dotenv').config();这样,每个 OpenRig 会话都可以有自己的.env文件,互不干扰。zcode的配置文件也一样,可以为不同模型创建~/.zcode/deepseek-config.json和~/.zcode/gemini-config.json,通过zcode --config ~/.zcode/deepseek-config.json ask ...来指定。
5.3 自动化健康检查:让 OpenRig 学会自我诊断
一个成熟的 rig,应该能自己报告健康状态。在~/openrig/src/health.js里写一个简单的检查脚本:
// ~/openrig/src/health.js const http = require('http'); function checkProxy() { return new Promise((resolve) => { const req = http.request('http://localhost:3000/health', { timeout: 5000 }, (res) => { resolve(res.statusCode === 200); }); req.on('timeout', () => resolve(false)); req.on('error', () => resolve(false)); req.end(); }); } async function main() { const isProxyUp = await checkProxy(); console.log(`Proxy: ${isProxyUp ? '✅ UP' : '❌ DOWN'}`); // 检查 tmux 会话是否存在 const { execSync } = require('child_process'); try { execSync('tmux has-session -t openrig'); console.log(`tmux session: ✅ EXISTS`); } catch { console.log(`tmux session: ❌ NOT FOUND`); } } main();然后,把它加入package.json的 scripts:
"scripts": { "health": "node src/health.js" }以后,只需npm run health,就能得到一份清晰的健康报告。你可以把这个命令加到你的start.sh末尾,每次启动都自动检查。
5.4 安全加固:为本地代理加上基础防护
http://localhost:3000听起来很安全,但如果你的机器开了 SSH,或者用了某些远程桌面工具,这个端口就可能暴露给局域网内其他设备。一个简单的加固,是让代理只监听127.0.0.1(即 localhost),而不是0.0.0.0(所有接口)。我们已经在server.listen(3000, '127.0.0.1', ...)里这么做了,但为了万无一失,还可以加一层防火墙规则(Linux):
# 确保只有 localhost 能访问 3000 端口 sudo ufw allow from 127.0.0.1 to any port 3000 sudo ufw deny 3000对于 macOS,可以用pfctl。这一步看似多余,但能防止一些低级的误操作,比如不小心把 tmux 会话分享给同事,结果对方也能调用你的 DeepSeek API。
6. 我的 OpenRig 使用心得:那些文档里不会写的细节
写了这么多技术细节,最后想分享几个纯粹来自一线实践的、带点温度的经验。这些不是“最佳实践”,而是“血泪教训”。
第一,永远不要在zcode的配置里硬编码 API Key。我见过太多人把apiKey: "sk-..."直接写在~/.zcode/config.json里,然后一不小心把这个文件推到了 GitHub 上。正确的做法,是让zcode从环境变量读取,而环境变量只存在于你的.env文件里,并把这个文件加到.gitignore。安全不是功能,是习惯。
第二,tmux 的prefix键(默认是Ctrl-b)一定要改。Ctrl-b和很多终端快捷键(比如Ctrl-b在 Vim 里是光标左移)冲突。我把它改成了Ctrl-a,命令是echo "set -g prefix C-a" >> ~/.tmux.conf。改完后,Ctrl-a c新建窗格,Ctrl-a n切到下一个,Ctrl-a d分离会话,手指再也不打架了。
第三,给你的 OpenRig 起一个带版本号的名字。不要叫openrig,叫openrig-v2.1-deepseek。这样,当你未来要部署 Gemini 版本时,就可以新建一个openrig-v2.1-gemini会话,两者完全隔离。名字不是装饰,是运维的索引。
第四,也是最重要的一点:OpenRig 的终极价值,不在于它能调用多少个模型,而在于它让你彻底理解了“请求-响应”这个最古老、最基础的计算机范式。当你亲手写过代理、抓包分析过 OPTIONS 请求、在 tmux 里看着日志一行行滚动时,你就不再是那个只会npm install的用户了。你成了管道的建造者。而在这个 AI 工具链快速迭代的时代,建造者,永远比使用者更有底气。
所以,别纠结“OpenRig 官网在哪”、“OpenRig 下载链接是什么”。真正的 OpenRig,就藏在你刚刚敲下的那几十行proxy.js代码里,藏在你 tmux 会话里那个不断刷新的日志窗口里,藏在你解决cc switch local proxy failed时,那一声释然的“啊哈”里。它不是一个产品,它是一种能力。