用tmux统一管理多个终端AI工具:macOS下的可控工作台方案
开头先交代一下背景我最近很长一段时间都在同一个仓库里反复横跳 Claude Code、Codex、OpenCode、pi 和 Grok 这几个终端 AI 工具。最初我以为这只是“多开几个标签页”的事实际跑下来才发现根本不是。五个工具各有各的会话状态、登录方式、启动参数和工作目录偏好桌面上终端窗口叠成一摞等你想从 A 工具切到 B 工具去问同一个报错时刚才 A 工具里的对话已经滚到找不着了B 工具还不知道这个仓库的背景。“四个终端对不上”这个说法确实很形象——不是数量问题是它们之间完全没有被组织起来。这篇文章不聊哪个模型更强只聊怎么在 macOS 上把这些 CLI 形态的 AI 工具收进同一个可控工作台。我会直接给出一套我天天在用的 tmux 方案包括配置、启动脚本、窗口切换逻辑以及真正跑起来之后容易翻车的几个点。无论你是刚接触 CLI agent还是已经用了一段时间但觉得桌面失控都可以照着我这套思路改。1. “四个终端对不上”到底卡在哪我先拆了几个症状先说结论这类工具要求的不是“多开几个终端标签”而是会话级的组织。如果你只是把五个 Terminal 标签并列排开等于把五份各自为政的对话现场摊在桌面上时间一长必然失控。我在实际使用中总结了三个典型症状。第一个症状是“不知道当前焦点在哪”。五个工具都跑着同一个任务的不同阶段Claude Code 在帮我重构函数Codex 在生成测试OpenCode 里挂着设计评审pi 在分析日志Grok 在准备提交说明。每个窗口看起来都重要但谁也说不清哪个才是当下的主线。每次切窗口都要先上下翻滚动历史来恢复记忆非常浪费精力。第二个症状是“会话状态丢得莫名其妙”。终端标签页一旦被关掉对应的 CLI 进程通常也就结束了。如果那会儿 agent 正好跑到一半比如还在生成一个长文件你手一抖关掉标签整个上下文都可能丢。更麻烦的是如果中途要重启电脑五个标签里的状态一个都留不下来只能重新开始。第三个症状也是标题里说的“对不上”就是工具之间没有统一的项目语境。你在 Claude Code 里已经说了十分钟需求切到 Codex 之后它对你的意图一无所知只能从零开始把前因后果再讲一遍。旧的全覆盖新的不知道五个工具反复“复制粘贴需求”效率反而比单工具更低。问题的根源不在终端软件而在于你缺少一层跨窗口的会话管理层。传统终端的大多数标签页功能只帮你开了多个窗口并没有帮你把窗口里的活动进程收拾起来。所以第一步不是去找更多“AI 驱动终端”而是先把终端会话收纳好。1.1 别把五个工具当成同一种软件来处理在进入工作台之前先要认清这五个工具的脾气。我的观察如下当然各个项目更新很快具体命令以你安装版本的 README 和--help为准CLI 命令典型形态需要留意的点claudeClaude Code面向代码仓库的终端 agent登录方式和配置项可能和传统ANTHROPIC_API_KEY不完全一致启动后能维护较长上下文codexOpenAI 的 Codex CLI终端里的编码代理强调“可执行命令前先征求同意”交互比较重会话恢复后要确认目录状态opencode开源终端 AI 编码工具可配置多类模型配置文件通常和各家 provider 的 key 有关装好后要先跑 auth 类命令pi终端 AI 对话/编码工具命令名就叫pi这名字通用性太强不同仓库的pi不是一回事先确认你真实装的哪个版本grokxAI 的终端入口也提供编码和问答能力大概率需要自己的 API 或账号体系别指望和 Claude Code 复用同一组环境变量这张表想表达的意思是它们不是同一家公司出的登录体系不同、配置目录不同、会话文件也互不相同。很多人的“对不上”其实是误以为所有工具都读同一套~/.config或者同一个环境变量实际上完全不通用。1.2 工作台真正要对齐的不是窗口而是“会话”你想要的终极状态应该是在任意时刻进入某一个项目的工作台五个 agent 都已经在那个项目的上下文里等着你而你不需要重新讲一遍背景。要实现这个状态必须抓住“会话”这个关键概念。tmux里有一个常被忽略的点它可以脱离终端窗口持续运行。CLI agent 本质是一个长时间运行的前台进程它需要终端提供输入和输出通道。只要把进程放进 tmux 的 session 里哪怕关掉 macOS 的 Terminal 窗口进程也不会结束。下一次输入tmux attach就能回到刚才那个界面对话历史还在、上下文还在、agent 刚才执行到哪个状态也都在。这和“把五个终端标签一直挂着”最大的差别是标签页是终端软件层面的视觉分组关了窗口就什么都没有而 tmux 的 session 是进程级的收纳容器和某一个具体的窗口是否打开无关。1.3 为什么我不建议用 iTerm2 或终端原生分屏硬凑iTerm2 的标签页和分屏其实做得很好但它解决的问题是“在屏幕上同时看多个终端”而不是“在项目维度管理多个长时间运行的 agent 会话”。举个例子你开了五个 iTerm2 标签页确实能切来切去。可一旦某个标签页因为误操作被关掉或者整台 Mac 重启你就得手动重建五个标签、重新 cd 到项目目录、重新登录、重新把这些 agent 一个个拉起来。这并没有解决组织问题只是把原始状态铺开。更别提如果你想通过 SSH 从另一台机器连回来或者同一台机器在另一次登录里想进入同一套会话iTerm2 标签页完全做不到tmux 只需要一条命令。所以我要搭的工作台不是“再装一个花哨终端模拟器”而是在普通终端外面套一层 tmux 会话管理。2. 工作台的设计一个项目一条 session五个 agent 各占一个 window很多教程上来就是让人把终端均分成几个 pane让 Claude Code 在左边、Codex 在右边、下面再开一个日志窗口。我实际用下来觉得这种排列对这类 CLI agent 并不友好。原因在于 agent 工具的输出方式很特殊。它们既不是普通命令行工具那种“滚完就结束”的日志也不是可以稳定缩在窄面板里的静态界面。很多终端 agent 会渲染结构化内容会输出大段代码 diff还会动态响应用户输入。如果窗格宽度不足这些内容很容易被折行视觉上非常混乱。所以我把工作台做成“一窗口一个 agent”而不是“一窗格一个 agent”。具体结构是这样一个 tmux session 代表一个项目比如webapp、api-service、blog。这个 session 下面有五个 window固定命名对应五个工具。这样一来你要做某个项目时输入一个命令就能拉起整套环境window 1claudewindow 2codexwindow 3opencodewindow 4piwindow 5grok我之所以不把五个 agent 塞进几个 pane 里同屏显示还有一个原因这些 AI 工具的交互通常需要你完整阅读它输出的上下文频繁切 pane 并不能帮你并行处理反而会把有限注意力切碎。2.1 一个项目对应一个 session而不是全局一个 session还要注意按照“项目”区分 session不要把所有工作都塞进一个 session。假设你同时在维护两个仓库那 A 仓库和 B 仓库里跑 agent 的目标可能背道而驰。如果都放在同一个 session切到claude窗口后还得确认当前目录是哪个项目非常容易搞混。我的约定是每个仓库单独一个 session比如tmux new -s blog-ai和tmux new -s api-ai。切换项目就是从blog-aiattach 到api-ai完全不会混淆。2.2 那要不要在 agent 窗口旁边再开一个命令 pane要但不是在 agent 窗口里。建议单独分配一个 window 用来干“杂活”比如改配置文件、跑 git diff、查看进程、执行 agent 帮你生成的命令。我的习惯是每个 session 里再加一个 window 叫shell专门用来手动确认 agent 产出的代码是否能编译、测试是否能通过。如果确实需要在看 agent 输出的同时执行另一条命令我临时按 tmux 的拆分键开一个 pane用完就关。但长期布局保持“一个 agent 一个完整 window”避免折行和误触。3. 可直接抄的 macOS 配置安装、按键、一键启动脚本讲了这么多下面给出我目前在用的实际配置。这套配置只依赖 tmux 和 zsh不需要额外安装什么重型工具。3.1 安装 tmuxmacOS 上通常用 Homebrew 装brew install tmux tmux -V如果你之前没装过 tmux这几条命令会帮你搞定。装完先别急还需要往~/.tmux.conf里写配置。3.2 一份适合 AI 终端会话的~/.tmux.conf这是重点。我建议不要用 tmux 默认的Ctrl-b作为前缀键。原因很实际Ctrl-b在很多 CLI 工具和 shell 操作里已经被占用特别是一些 agent 工具会读取行编辑快捷键。为了避免按一下Ctrl-b触发 tmux 窗口跳转而不是输入给 agent我把前缀改成了Ctrl-Space。# 把前缀改成 Ctrl-Space避免和常见 shell/AI CLI 快捷键冲突 unbind C-b set -g prefix C-Space bind-key C-Space send-prefix # 窗口编号从 1 开始而不是 0 set -g base-index 1 setw -g pane-base-index 1 # 窗口被关闭后自动重新编号避免出现空洞 set -g renumber-windows on # escape 时间调短避免按 ESC 时卡顿 set -g escape-time 10 # 终端类型 set -g default-terminal tmux-256color # 在状态栏显示窗口名和会话名方便快速确认当前在哪个 agent set -g set-titles on set -g set-titles-string #S:#W set -g status-left AI set -g status-right #S:#W | %H:%M # 用数字键直接跳到对应窗口符合我“每窗口一个 agent”的设计 bind-key 1 select-window -t 1 bind-key 2 select-window -t 2 bind-key 3 select-window -t 3 bind-key 4 select-window -t 4 bind-key 5 select-window -t 5 # 开启窗口活动提示agent 在某个窗口悄悄跑完时能快速发现 setw -g monitor-activity on set -g visual-activity on # 退出 copy mode 时用 vi 风格方便回看历史输出 set -g mode-keys vi写完后让配置生效tmux kill-server 2/dev/null tmux new-session -d -s init tmux kill-session -t init这里kill-server会清掉所有旧配置和残留 session如果你已经有正在工作的 tmux session请慎用。更温和的方式是tmux source-file ~/.tmux.conf。3.3 一键拉起五个工具的工作台脚本这是整个配置里最核心的部分。我把下面的函数放到~/.zshrc之后只需要敲一个命令就能在当前项目目录里创建或者重新连接到工作台。# 打开/连接 AI 工作台参数 1 是目录默认当前目录 aiwork() { local dir${1:-$PWD} local session_name$(basename $dir)-ai # 如果 session 已经存在直接连接 if tmux has-session -t $session_name 2/dev/null; then exec tmux attach-session -t $session_name return fi # 按顺序创建五个 agent 窗口以及一个手动 shell 窗口 tmux new-session -d -s $session_name -c $dir -n claude claude tmux new-window -t $session_name -c $dir -n codex codex tmux new-window -t $session_name -c $dir -n opencode opencode tmux new-window -t $session_name -c $dir -n pi pi tmux new-window -t $session_name -c $dir -n grok grok tmux new-window -t $session_name -c $dir -n shell # 回到 claude 窗口并连接 tmux select-window -t $session_name:claude tmux attach-session -t $session_name }这个脚本做了几件关键的事。第一session 名称根据当前目录名生成比如你在~/code/website目录下执行就会得到website-ai这个 session。第二每个 agent 启动时都使用-c $dir把工作目录固定为当前项目目录避免 agent 启动后落在错误的目录。第三如果 session 已经存在你不会重复开出一堆新窗口而是直接连接回原来的会话现场。3.4 为什么用exec tmux attach-session而不是普通调用脚本里我写了exec。这么做的原因是当你退出 tmux 时当前 shell 也会直接退出不会留下一层多余的嵌套 shell。如果你只是在.zshrc里写tmux attach-session而不加exec退出时容易多停留在一个空 shell 里心理上总觉得没退干净。这个exec是细节但能显著提升使用体验。4. 使用这套工作台的日常流切换、登录、恢复状态配置好之后有一批实际操作层面的技巧。这些技巧是我反复用之后沉淀下来的比配置本身更重要。4.1 用prefix 数字快速跳 agent进入 attach 状态后按Ctrl-Space然后按数字键就能在 claude、codex、opencode、pi、grok、shell 这几个窗口之间切换。之所以给每个 agent 一个独立 window就是为了让“跳到某个工具”这个动作成本非常低。你不需要用鼠标点某个窗口也不需要在一堆标签里辨认哪个是哪个。Control-Space 1永远是 ClaudeControl-Space 2永远是 Codex时间长了手部肌肉记忆自然建立。每切到一个窗口状态栏左侧会显示当前 session:window 名。例如blog:claude一眼就知道自己在哪。即便你开了四个项目、二十个窗口也不会迷路。4.2 每个 agent 第一次登录最好在当前窗口完成Claude Code、Codex、OpenCode、pi、Grok 各自有独立的登录或鉴权流程。第一次打开对应窗口时我建议先在该窗口内完成认证而不是在临时 shell 里登完再启动 agent。原因是 agent 进程会记住终端交互状态很多 CLI 在启动阶段会检查会话有效期直接让它在工作窗口里跑第一次认证最干净。登录时如果某个 agent 要你访问外部地址完成授权流程通常会在对应窗口里给出提示确认后正常走完即可。完成一次认证之后后续重新拉起 agent 一般不需要再重复登录。4.3 会话恢复后如何确认 agent 真的“活着”用 tmux 管理 agent 还有一个好处如果你工作到一半要合上 Mac回来之后打开终端随便执行tmux attach应该能看到所有窗口还保留着离开时的样子。但有一点要注意有些终端 agent 在长时间无输入、或网络重新连接后可能会进入等待状态。它们不是死了只是在等你按一下回车或者重新发一条命令。所以恢复会话后的第一件事不是盲目继续输入而是看窗口里最新的输出状态是否需要重新登录。可以按一下回车让 agent 重新感知到终端在线再从输出内容判断会话是否有效。5. 我最常遇到的三个坑以及绕开方式这套工作台我用了大概两个月日常非常舒服但过程中也踩了几次坑写出来给你提个醒。5.1 换终端宽度后 agent 输出折行混乱最开始我把 agent 窗口和其他工具拆成左右 pane小宽度情况下 Claude Code 的输出经常被折得七零八落代码 diff 根本没法看。后来我改成全窗口模式才真正解决。如果你确实需要同时看两个 agent 的输出建议临时拆窗格不要让它成为长期布局。agent 输出内容通常需要足够宽度才能正确渲染宁可多按几次切换键也别把字挤在一起。查看一个 pane 是否过窄可以执行tmux display -p #{pane_width}一般低于 100 列时带表格和代码块的输出就很容易乱。我的经验是每个 agent 窗口至少保持 120 列以上。5.2 几个 agent 同时改同一个文件产生互相覆盖这是一个比操作层面更危险的坑。Claude Code 和 Codex 在同一个项目目录里同时工作两边如果都在改同一个文件哪怕有 tmux 也不会自动解决冲突。你以为一个在重构、一个在补测试可能它们改的是同一段代码。我的解法是给五个 agent 约定明确的职责边界。每个工作流只让一个 agent 负责写代码另一个负责 review 或查询。比如 Claude Code 负责核心模块重构Codex 只负责写测试文件OpenCode 用来检查第三方 API 用法。如果你发现两个 agent 都在主动改动同一批文件就要停下来给其中一个发布停手指令而不是让它们继续并行。5.3 在 macOS 睡眠唤醒后键盘输入偶尔失灵有一个小概率问题Mac 合盖几个小时后再唤醒tmux 里的某个 agent 窗口看起来正常但键盘按下去没反应。这不是 agent 坏了大概率是终端进程暂时没有重新获得焦点或输入通道卡住。遇到这种情况先按一次Ctrl-Spaced脱离会话再重新tmux attach回到会话。这个方法通常能解决绝大多数“输入假死”问题。如果仍然卡住再检查当前 pane 是不是停留在某个正在 running 的进度任务里比如某个阻塞式命令还没结束这时候需要先中断它再输入。6. 扩展思路同一套工作台还能怎么加钟这个工作台成立后不仅能管理标题里那五个工具还能融合更多终端 AI 能力。比如你现在想用某个新出的 agent只需要把安装好的命令作为新的 window 加进脚本。我日常会为临时测试命令专门开一个窗口执行一些不常用但需要观察的脚本而不是直接塞进 agent 对话。可以让 agent 专注推理而把“手动验证”的活交给旁边的 shell 窗口。如果要带团队交付你也可以把启动脚本分发给同事。每个成员进入仓库后执行同一个aiwork函数就能进入各自独立命名的 session不会互相干扰但所有人都用同一套习惯降低了沟通成本。我个人还有一个使用习惯把每天的最终上线检查放在shellwindow 里手动跑一遍不全部丢给 agent。原因很简单工具可以做不错的技术活但最后的“生产环境是否真的符合预期”这种检查我倾向于亲眼看看实际日志和状态。tmux 工作台把多个 AI 工具聚拢后反而让你保留了人工介入的空间。若某个 agent 需要持续跑几分钟你可以切到别的窗口继续干活等状态栏出现活动提示再回来这才是“工作台”该有的体验。