AI 时代的程序员,如果只学一样东西,我建议是 tmux
上个月我做一个项目,Claude Code 跑了 20 分钟,生成了一套完整的认证系统。我看着屏幕上一行行代码往下滚动,测试覆盖率 89%,API 设计干净,甚至自己写了 README。然后我的 SSH 断了。
重连回去,终端一片空白。那个 Claude Code 进程死在了断连的那一刻。20 分钟的工作,什么都没留下。重跑一遍,prompt 一样,但结果不一样了——换了种实现方式,少了一个边缘情况处理,多了一层没必要抽象。
这时候我才意识到一个问题:你把最贵的模型、最长的上下文、最精心设计的 system prompt 都给了 AI,但你和 AI 之间隔着一层脆弱到一碰就碎的东西——你的终端。
这不是 SSH 的问题,也不是 Claude Code 的问题。是你根本没想过"工作流的物理层"这件事。
一、AI 和你的连接,比你想的脆弱得多
我问过很多同事一个问题:你用 AI 写代码的时候,最常遇到什么麻烦?
答案出奇一致。不是模型不够聪明,不是上下文窗口太小,而是——“跑着跑着就没了”。
你开着 Claude Code 在终端里改一个模块,切出去查个文档,回来发现 Terminal 标签页不知道什么时候被你误关了。你在远程服务器上跑 Codex CLI,WiFi 抖了一下,SSH 断了。你在 iTerm2 里同时开着三个 AI 会话,一个在改后端,一个在写测试,一个在生成配置文件——然后你的 Mac 因为内存不足强制重启了。
每一个场景的结果都一样:你的 AI 会话死在了路上。进度归零。上下文丢失。重来一遍,但这次 AI 的思路完全不一样了。
这不是个别现象。身边的开发者大多用上了 AI 编程工具,但很少有人意识到"终端会话管理"是这套工具链的物理底座——直到某一次重要的 AI 任务跑了 20 分钟、然后没了,才会回头补这一课。
你花了 200 美金一个月的 Claude 订阅,但你让它跑在一个随时可能被风吹灭的蜡烛上。
二、tmux 解决的,根本不是"多窗口"那点事
如果你对 tmux 的印象还停留在"分屏",那你低估了它 90% 的价值。
tmux 的核心能力只有三个词:detach, persist, multiplex。
Detach 的意思是,你可以从一个 tmux 会话里"脱身",关掉终端窗口、断开 SSH、甚至关机睡觉——你的会话还活着,所有进程继续跑。第二天早上打开电脑,tmux attach,一切都在。
这不是"方便",这是质变。你不再需要担心 Claude Code 跑了二十分钟因为网络波动白费。你不再需要在脑子里维护"终端里正在跑什么"的清单。你让 AI 跑一个重构任务,detach,去写文档。一个小时后 attach 回来,AI 已经完成了——或者在中间某一步卡住了等你决策。无论是哪种结果,你都省下了一个小时的等待时间。
Persist 是 detach 的背面。你的 AI 会话不是"run once"的临时进程,而是一个持续存在的环境。你在 tmux 窗口里执行过的命令、设置的环境变量、安装的依赖,全都在。不用每次重连都 cd 到项目目录、source .env、重新构建上下文。
Multiplex 才是你熟悉的"分屏"。但它真正的威力不是"同时看两个东西",而是"AI 在干活的时候你不用盯着"。
为什么 tmux 能做到这些?一句话:它是 client-server 架构
这里有必要讲一下 tmux 是怎么做到的,因为理解了它的架构,你才能理解它为什么跟其他所有终端工具都不一样。
你在终端里输入 tmux 的时候,实际上启动了三个东西:一个 tmux server(后台守护进程,只有一个),一个 session(你看到的窗口集合),和一个 tmux client(连接到 server 的显示界面)。
所有的 session、window、pane 都活在 server 里。你关掉的只是 client。server 还在,里面的 AI 进程还在,一切都在。
这意味着你的 Claude Code 不是跑在 iTerm2 的标签页里——是跑在 tmux server 的 session 里。关掉 iTerm2、断开 SSH、甚至重启你的笔记本(只要 server 进程没被杀),你的 AI 就还在工作。你用任何一个终端、任何一台机器,tmux attach 连回这个 server,就能回到刚才那个 AI 会话里——屏幕输出原样还在,命令历史原样还在,正在执行的进程原样还在。
看一下你的机器上跑着哪些 tmux server:tmux ls。你会看到所有活着的 session,每个 session 可能包含多个 window。tmux attach -t {session名} 就能接回去。
这个架构差别,是把 AI 工作流从"即抛型"变成"持久型"的关键。你的 Claude Code session 不再是一个"跑完就消失的临时任务",而是一个"持续存在的、可以随时接入的开发环境"。
顺带提一句:tmux 根据 $TMUX_TMPDIR 或 /tmp 下的 socket 文件来管理 server。默认 socket 是 /tmp/tmux-{uid}/default。如果你需要为不同项目隔离 tmux server(比如一个项目跑一堆 AI agent,另一个项目另一堆,互不干扰),用 -L 指定不同的 socket 名:tmux -L project-a new -s agent1、tmux -L project-a new -s agent2。这样 project-a 和 project-b 的 agent 跑在不同的 server 上,各自的 session 列表完全隔离。
三、我每天真正在用的工作流
先把骨架画清楚,因为这跟大部分人想象的"开几个 tmux 分屏"完全不是一回事:
iTerm2 单窗口
└── 本机 tmux session: main
├── window 1: 本地代码
├── window 2: ssht <服务器A> → 远端 tmux: work
├── window 3: ssht <服务器B> → 远端 tmux: agents
├── window 4: logs / 监控
└── window 5: deploy
三条规矩:
- iTerm2 永远只开一个窗口。 默认 Profile 的启动命令直接设置成
tmux new -A -s main——开窗即进 tmux,没有"裸 shell"这一步。 - 每台远端机器对应一个本机 tmux window。 进远端不是手敲
ssh xxx,是ssht <host>——一个 helper,自动ssh -t进去然后tmux new -A -s main接到远端 tmux。本地一个 tmux,每台远端一个 tmux,两层 tmux 串起来。 - AI 会话跑在远端 tmux 里,不是本地 iTerm2 的 pane 里。 远端 tmux detach 后,AI 进程不依赖你本地这台机器的存活——你把笔记本合上、SSH 断了、iTerm2 崩了,AI 都还在远端继续跑。
一个具体的下午
举一个我前几天的下午。要给一个后端模块加一组新接口,前端组件也得跟着改。
打开 iTerm2,自动落到本机 tmux main。Ctrl+b c 开新 window,敲 ssht backend-server work——一秒后我在远端的 tmux session 里了。claude "实现新接口,参考 spec/v2.md",让它跑着。
Ctrl+b c 再开一个 window,ssht frontend-server work,又一个 Claude Code 跑前端改动。
Ctrl+b c 第三个 window,留在本地,写集成测试,准备等会两边都改完了拿来对。
切换全靠 Ctrl+b 1/2/3。哪个 AI 卡了进哪个 window 看一眼。哪个 AI 写跑偏了 Ctrl+c 打断,重新追加一句 prompt。
中间我去开了个会,回来 iTerm2 里 SSH 已经被 macOS 切到睡眠的时候断了——重新激活窗口,连接自己续上来了(靠的是 ServerAliveInterval + tmux 双保险),两边的 Claude Code 还在远端 tmux 里继续输出。如果连接没自己续上,那就再敲一次 ssht backend-server work——tmux new -A 的 -A 意味着"有就 attach,没有才新建",进去就回到了原来那个 session。
晚上下班合上笔记本走人。第二天早上在家用另一台电脑打开 iTerm2,依然是 tmux new -A -s main、ssht backend-server work——昨天的 AI 输出原样在屏幕上,commit 也都打好了。
这个流程里没有"备份 prompt"、没有"重连后重跑一遍"、没有"丢了 20 分钟"。因为 AI 从来不在我本地这台机器上跑。
为什么不用本地 pane 分屏跑 AI
很多 tmux 教程喜欢秀"Ctrl+b % 左右分屏,左边 AI 右边自己看"。我试过,很快就放弃了:
- AI 输出一长就把右边挤得很窄,看代码看不全。
- 分屏后两个 pane 共享 history,复制粘贴跨 pane 容易切错。
- 最关键的:本地 pane 没有解决"网络断了 AI 死了"——pane 跑在你本地终端的子进程里,iTerm2 一关就完。
正确的做法是把"垂直关系"换成"水平关系"——AI 不是跟你并排坐在同一个 pane,而是住在另一台机器的另一个 tmux 里。你用 window 切换过去看它干什么,看完 Ctrl+b 0 切回来。AI 死活跟你的本地终端解耦。
几个用得最多的快捷键
不是凑命令清单,是这些每天按得手指起茧:
Ctrl+b c:新 window(每开一台远端机器都用一次)Ctrl+b 数字:跳到第 N 个 windowCtrl+b ,:给 window 改名(开多了不改名根本分不清谁是谁)Ctrl+b d:detach(合电脑前不需要按,崩溃了也不会丢;但养成习惯有好处)Ctrl+b z:当前 pane 全屏切换(AI 输出一大段时要看清)Ctrl+b R:重载~/.tmux.conf(自定义键,下面 §八 会讲)Ctrl+b C-s:切换 synchronize-panes(同一句命令同时打到所有 pane,多机器排障神器)
四、ssht 和 ControlMaster:让"两层 tmux"丝滑起来的两个工具
上面那个工作流听起来很轻量,但你照搬过去会很快踩两个坑:
- 每开一个新 window 进远端机器,都要敲一遍
ssh xxx && tmux new -A -s main,麻烦。 - 同一台机器开三四个 window,每个 window 一条 SSH,几秒钟之内三四次握手——慢,且远端 sshd 看到一堆并发连接。
下面这两个工具解决这两个问题。它们都不是 tmux 自己的,但少了它们 tmux 工作流就不成立。
4.1 ssht:远端 tmux 的快捷入口
写一个简单的 shell helper,叫 ssht:
#!/usr/bin/env bash
set -euo pipefail
usage() {
cat <<'USAGE'
Usage:
ssht <ssh-config-host> [tmux-session]
Examples:
ssht lighthouse
ssht backend-server work
USAGE
}
if [[ $# -lt 1 || "${1:-}" == "-h" || "${1:-}" == "--help" ]]; then
usage; exit 0
fi
host="$1"
session="${2:-main}"
if [[ ! "$session" =~ ^[A-Za-z0-9_.-]+$ ]]; then
echo "Invalid tmux session name: $session" >&2; exit 2
fi
exec ssh -t "$host" "tmux new -A -s '$session'"
放到 ~/.local/bin/ssht,chmod 755 一下,再确认 ~/.local/bin 在你的 PATH 里。
它做的事就一句:ssh -t <host> 进去,立刻 tmux new -A -s <session>。-A 的意思是"有就 attach,没有才新建"——不管这是你今天第一次连还是第十次,结果都是回到同一个 session。
为什么这事必须做成 helper 而不是手敲?因为人手敲会偷懒。你赶时间的时候会直接 ssh xxx,跑个命令,断了——没在 tmux 里,进程没了。把进 tmux 这一步固化进 ssht,断网就不再是问题,因为你根本进不了一个不在 tmux 里的远端 shell。
4.2 ControlMaster:让 N 个 SSH tab 共享一条 TCP
这是 SSH 自己的特性,跟 tmux 无关,但配合 tmux 多 window 用爆炸性提升体验。
在 ~/.ssh/config 末尾加:
Host *
IgnoreUnknown UseKeychain
AddKeysToAgent yes
UseKeychain yes
ServerAliveInterval 30
ServerAliveCountMax 3
ControlMaster auto
ControlPath ~/.ssh/controlmasters/%C
ControlPersist 10m
记得先建目录:mkdir -p ~/.ssh/controlmasters && chmod 700 ~/.ssh/controlmasters。
四件事:
ControlMaster auto+ControlPath:第一次连 host A 建立一条 TCP master 连接,后续所有连 host A 的 SSH 都共享这条 TCP,不再握手。ControlPersist 10m:你最后一个 SSH session 退出后,master 连接还保留 10 分钟。十分钟内重连,秒进。ServerAliveInterval 30/CountMax 3:每 30 秒发一个心跳,连续 3 次没响应才认为断了——大部分"中午合上电脑下午打开断了"的场景靠这一条自动续上。UseKeychain把 SSH key 的密码缓存到 macOS Keychain,开机后第一次用 key 输一次密码,之后不用再输。
加完之后效果有多明显?你 Ctrl+b c 开第二个 window 再 ssht backend-server work ——几乎瞬间就进去了,因为复用了第一个 window 的 TCP。十个 window 连同一台机器,就是一次握手 + 九次复用。
4.3 验证一下
# SSH 配置生效
ssh -G backend-server | egrep '^(controlmaster|controlpersist|serveraliveinterval) '
# 期望看到
# controlmaster auto
# controlpersist 600
# serveraliveinterval 30
# helper 可用
ssht --help
ssht + ControlMaster 两件事加起来不到 50 行配置,但它们是把"iTerm2 单窗 → 多 window → 每 window 一台远端 → AI 在远端 tmux 里跑"这套架构变成真的能用的关键。少了任一件,要么打字累,要么连接抖。
五、更狠的玩法:让 AI 自己跟 AI 对话
前面说的,本质还是你和一个 AI 之间的协作。但 tmux 真正让我觉得"回不去了"的,是下面这个模式:不同 tmux session 里的 AI agent 可以互相通信。
你开三个 tmux session:
architect:AI 做架构设计,输出 spec 文件builder:AI 读 spec 写实现reviewer:AI 自动跑测试、做 code review
让它们自己串起来,靠的是 tmux 的四个命令:send-keys、capture-pane、pipe-pane、wait-for。
send-keys:跨 session 发指令
最基本的用法你已经看到了:tmux send-keys -t builder "claude '根据 /tmp/spec.md 实现用户模块'" Enter。
但它的能力远不止"打字"。完整格式是三层定位:
tmux send-keys -t {session}:{window}.{pane} "内容" Enter
比如一个 backend session,第二个 window 左边那个 pane(编号 0),你要往那里精确打命令:
tmux send-keys -t backend:2.0 "npm test -- --coverage 2>&1 | tee /tmp/test-output.log" Enter
用 Ctrl+b q 可以快速查看当前所有 pane 的编号——每个 pane 会闪现一个数字。
还有一个极其实用但被忽略的技巧:你可以用 send-keys 发送控制字符。 AI agent 有时候会跑飞——陷入无限循环、输出一个不收敛的方向。你不用 attach 进去打断它,直接从当前 session 发信号:
tmux send-keys -t builder C-c
这意味着你可以在任何地方——另一个 tmux session 里、SSH 的另一端、甚至一个 cron job 里——远程管理和干预你的 AI agent。
更进一步的,你可以用它给 agent 发送多行 prompt。AI 程序通常读取终端输入直到遇到某个结束符,send-keys 可以精确控制每一行:
tmux send-keys -t architect "claude '分析以下代码库:'" Enter
tmux send-keys -t architect "$(cat /tmp/context.md)" Enter
capture-pane:跨 session 抓输出
capture-pane 是 send-keys 的反向操作——读取另一个 session 的屏幕内容:
tmux capture-pane -t reviewer -p -S -30 -E -1
参数解释:
-t reviewer:目标 session-p:输出到 stdout(方便管道给其他命令)-S -30:从当前光标位置往上 30 行开始-E -1:截到当前光标前一行(也就是最后一行输出)
所以你可以这样用:reviewer 跑完测试报错,你把失败日志抓出来,解析后喂回给 builder:
ERROR_LOG=$(tmux capture-pane -t reviewer -p -S -40)
tmux send-keys -t builder "claude '修复这个测试失败:$ERROR_LOG'" Enter
pipe-pane:给 AI 会话装黑匣子
send-keys 解决了往 agent 发指令,capture-pane 解决了抓当前屏幕。但如果你的 AI 跑了三个小时,你中间不在,你怎么知道它整个过程都干了什么?
pipe-pane 实时同步一个 pane 的全部输出到文件:
tmux pipe-pane -t builder -o 'cat >> /tmp/ai-builder-$(date +%Y%m%d-%H%M).log'
-o 表示"open",开始记录。AI 在 builder session 里输出的每一行,都被实时追加到日志文件。你可以 detach 去开会、去吃饭、去睡觉,回来后看这个 log——完整回放 AI 在这段时间里的全部思考和操作。
我一般在启动 AI agent 之后,第一件事就是 pipe-pane。它相当于给你的 AI 装了一个黑匣子。Agent 崩溃了、跑偏了、或者你只是想复盘它为什么做了某个决策——log 里有完整的上下文。
关掉 pipe 也很简单:
tmux pipe-pane -t builder
不加 -o 就是关闭。
wait-for:让 AI agent 学会排队
上面的流水线有一个时序问题:如果 builder 在 architect 还没写完 spec 的时候就去读文件,读到的是空文件或旧版本。
tmux 的 wait-for 是一个轻量的进程间信号机制。architect 完成后通知,builder 收到通知后才开始:
# architect 完成,发信号
tmux wait-for -S arch-done
# builder 等待信号,收到后才继续
tmux wait-for arch-done
-S 是发送(Signal),不加 -S 是等待。Builder 里的进程会一直阻塞,直到 architect 发出信号。
三个 agent 就自然形成了严格流水线:
# Stage 1: architect 跑完,发信号
tmux wait-for -S stage1-done
# Stage 2: builder 收到 stage1-done,跑完,发信号
tmux wait-for -S stage2-done
# Stage 3: reviewer 收到 stage2-done,开始审查
一个完整的自动修复闭环
把这四个命令组合起来,你可以实现一个"自动修复循环"——AI 写代码,AI 跑测试,测试失败自动喂回去修,修完再跑,直到通过。
具体流程:
- Builder 生成代码,运行后输出结果,跑测试
- Reviewer 用 capture-pane 抓 builder 的测试输出
- 如果测试失败,reviewer 把失败日志喂回 builder:
tmux send-keys -t builder "claude '修复以下测试失败:$(cat /tmp/error.log)'" Enter - Builder 修复,重新跑测试
- Reviewer 再次抓输出
- 循环直到测试通过,或者达到最大迭代次数
我做过的一个实际案例:一组单元测试初始有十几个失败,搭了 builder + reviewer 两个 session,pipe-pane 全程记日志。睡觉前启动,第二天早上看日志——builder 在 reviewer 不断回喂失败堆栈的引导下,迭代了几轮把测试逐步压绿了。整个过程中我没有介入,但醒来第一件事是看 pipe-pane 日志,确认它每一步都没有为了"让测试通过"而把测试本身改错。
整个过程中我一次都没有介入。不是我不管,是我用 tmux 搭的这套东西让它自己管了自己。
当然,自动修复有风险——AI 可能把代码越修越歪,甚至会"作弊"地把测试本身改了让它通过。所以 pipe-pane 日志至关重要:你醒来后第一件事不是看代码,是看日志,看 AI 在每轮迭代里做了什么决策。如果方向不对,git log --oneline 找到正确的那个 commit,从那里恢复。tmux 不替你规避风险,但它给你提供了完整的可回溯性。
六、把流水线写进脚本:让 AI agent 在你睡觉的时候干活
前面所有操作都是手动的——你开 tmux session,你发 send-keys,你检查输出。但一旦你理解了这些命令的组合方式,下一步是不可避免的:把它们写成一个脚本,放在 cron 里,让它们在你睡觉的时候自动跑。
下面这个脚本是一个模板,不是我每天原样跑的版本——日常我只跑其中很小的一部分(一个 omx team 加 pipe-pane)。完整版我会在重构前晚或验证某个新 agent prompt 时拿出来用:
#!/bin/bash
# nightly-ai-pipeline.sh — 夜间自动开发管线
set -e
PROJECT=~/code/myapp
DATE=$(date +%Y%m%d)
LOG_DIR=/tmp/ai-logs/$DATE
mkdir -p $LOG_DIR
cd $PROJECT
# 拉最新代码
git pull origin main
# ── Stage 1: 分析 ──
tmux -L nightly new-session -d -s analyze -c $PROJECT
tmux -L nightly pipe-pane -t analyze -o "cat >> $LOG_DIR/01-analyze.log"
tmux -L nightly send-keys -t analyze \
"claude '深度分析 src/ 目录的代码架构。
输出到 /tmp/arch-$DATE.md,包含:
1. 模块依赖图(标注循环依赖)
2. 超过 200 行的函数列表
3. 缺少测试的核心模块
4. 硬编码的配置/密钥/URL
5. 可以抽取为公共逻辑的重复代码
对每个问题标注严重程度:CRITICAL / WARNING / INFO'" Enter
# ── Stage 2: 重构 ──
tmux -L nightly new-session -d -s refactor -c $PROJECT
tmux -L nightly pipe-pane -t refactor -o "cat >> $LOG_DIR/02-refactor.log"
tmux -L nightly send-keys -t refactor \
"while [ ! -f /tmp/arch-$DATE.md ]; do sleep 30; done
claude '根据 /tmp/arch-$DATE.md,按严重程度依次修复问题。
规则:
- 每个修复完成后立即跑一次完整测试
- 任一测试不通过,回滚该修改(git checkout -- .)
- 通过的修改立刻 git add + git commit,commit message 包含问题编号
- 只修复 CRITICAL 和 WARNING 级别的问题'" Enter
# ── Stage 3: 审查 ──
tmux -L nightly new-session -d -s review -c $PROJECT
tmux -L nightly pipe-pane -t review -o "cat >> $LOG_DIR/03-review.log"
tmux -L nightly send-keys -t review \
"sleep 60
claude '审查 $(git log --oneline origin/main..HEAD | wc -l) 个新 commit。
输出到 /tmp/review-$DATE.md,每个 commit 评估:
1. 逻辑变更是否正确(有没有意外改掉业务逻辑)
2. 是否引入新的外部依赖
3. 安全影响(认证/授权/输入校验/SQL注入)
4. 测试覆盖率变化
末尾给一个总体判断:SAFE_TO_MERGE / NEEDS_REVIEW / BLOCKED'" Enter
echo "[$(date)] Pipeline started — 3 agents running"
echo " Analyze → tmux -L nightly attach -t analyze"
echo " Refactor → tmux -L nightly attach -t refactor"
echo " Review → tmux -L nightly attach -t review"
echo " Logs → $LOG_DIR"
这个脚本干了什么?凌晨,三个 AI agent 在各自的 tmux session 里醒来。一个读你的代码写架构分析,第二个根据分析结果逐个修复问题(修一个、测一个、commit 一个),第三个审查所有变更出报告。
你早上 8 点打开电脑:
tmux -L nightly attach -t review看审查报告——agent 标记了一个 SQL WHERE 条件被意外简化,你再确认一遍git log --oneline origin/main..HEAD看这一夜产出了几个 commitcat /tmp/review-$DATE.md读完整审查报告- 如果审查结果是
SAFE_TO_MERGE,直接 push,开 PR
从你的角度看,你只是睡了一觉。代码自己重构完了,测试跑了,review 也做了。
几个关键设计点:
-
tmux -L nightly:用独立的 socket,不和你的日常 tmux session 混在一起。tmux ls看不到 nightly 的 session,tmux -L nightly ls才能看到。干净隔离。 -
-d参数:new-session -d创建 session 但不 attach。脚本里跑的所有 session 都是后台的,不需要打开终端窗口。 -
pipe-pane:每个 agent 启动后立即绑定日志。出任何问题,日志里有完整的时间线。 -
while 等待:refactor 在 architect 输出文件之前不会开始。review 给了 60 秒缓冲让 refactor 先 commit。这不是最好的同步方式(
wait-for更好),但 shell 原生的while+sleep在任何环境下都能跑。 -
回滚规则:refactor 里的 prompt 明确写了"测试不通过立即回滚"。这是你防止 AI 把代码改坏的最关键约束。没有这条规则,AI 可能在 14 个 commit 里埋了 14 个隐患——有这条规则,每个 commit 至少是能通过测试的。
crontab 配置
把脚本放进 crontab:
# 每天凌晨 2 点自动跑
0 2 * * * /Users/yourname/scripts/nightly-ai-pipeline.sh >> /tmp/ai-pipeline-cron.log 2>&1
你也可以在工作日晚上手动触发:
bash ~/scripts/nightly-ai-pipeline.sh
然后关电脑,明天早上验收。
这跟一个完整的 CI/CD pipeline 的区别在哪?你的 CI 只能跑测试和 lint。而这个 pipeline 里的 agent 在写代码——它在分析、重构、审查。它不是检查你的代码质量,是提升你的代码质量。
而且跟 CI 不同,这一切跑在你的机器上。没有 pipeline 分钟数限制,没有 runner 排队。你有一台空闲的电脑 + tmux + Claude Code,你就有一个 7×24 的开发团队。
七、你可能已经在用的"替代品",以及它们为什么替代不了
“我用 VS Code 内置的 terminal。”
VS Code 会崩。插件冲突、内存泄漏、全量索引崩溃——任何一个都能让你的 terminal session 消失。更关键的,VS Code 的 terminal 是"客户端"——关掉 VS Code,terminal 就没了。tmux 是"服务端"——只要你的机器还在跑,tmux 会话就在。
“我用 screen。”
screen 是 tmux 的前辈,但维护停滞了十年。tmux 的 pane 布局、鼠标支持、256 色终端、插件生态,screen 都没有。不是偏执——在 AI 工作流里你需要频繁地复制粘贴大段代码和 prompt,screen 的复制模式会让你崩溃。
“我用 Warp / Tabby / Kitty。”
这些是现代终端模拟器,做的是 UI 层的优化。它们和 tmux 不冲突,甚至应该一起用。Warp 给你好看的渲染,tmux 给你 session 持久化。你把 tmux 跑在 Warp 里面,断网了 Warp 废了,但 tmux 还在。
“我用 zellij。”
zellij 是 tmux 的新对手,Rust 写的,默认带 floating pane 和 WASM 插件系统。它确实在某些方面更现代。但目前 zellij 的生态和社区远远不及 tmux——大多数 AI coding agent 文档里的 tmux 集成示例、Stack Overflow 上的排障贴、同事之间的工作流分享,全是 tmux。在"AI 工作流"这个具体场景下,生态兼容性比技术先进性重要。你用 zellij 做 ai agent pipeline,遇到 bug,Google 不到答案——这就够了。
八、十分钟就能掌握的进阶命令
如果你从没用过 tmux,先把这些基础命令刻进肌肉记忆:
tmux new -s work # 新建会话
Ctrl+b d # detach(后台继续跑)
tmux attach -t work # 重新接入
Ctrl+b % # 左右分屏
Ctrl+b " # 上下分屏
Ctrl+b c # 新建窗口
Ctrl+b 0/1/2 # 切换窗口
Ctrl+b [ # 滚动/复制模式
Ctrl+b z # 当前 pane 全屏/还原
Ctrl+b , # 重命名窗口
Ctrl+b :resize-pane -D 10 # pane 向下扩展 10 行
基础 ~/.tmux.conf(如果你用的是 gpakosz/oh-my-tmux,应该写到 ~/.tmux.conf.local,别动主配置):
# 终端类型与真彩色
set -g default-terminal "tmux-256color"
set -as terminal-overrides ",xterm-256color:RGB,tmux-256color:RGB,iTerm2*:RGB"
# 体验
set -g focus-events on # 编辑器能感知 tmux 内 pane 失焦/获焦
set -g mouse on # 鼠标支持(滚动/选择/调整 pane 大小)
set -g history-limit 100000 # 滚动历史,AI 一次输出几千行也接得住
set -g set-clipboard on # tmux 选中即写入系统剪贴板
set -g detach-on-destroy off # session 内最后一个 window 关掉时不退出,跳到下一个 session
setw -g aggressive-resize on # 多 client 同时 attach 时按当前最大可用尺寸重排
# 自定义键
bind-key R source-file ~/.tmux.conf \; display-message "tmux config reloaded"
bind-key C-s setw synchronize-panes \; display-message "synchronize-panes: #{?pane_synchronized,on,off}"
最不显眼但最有用的是 detach-on-destroy off:你跑 AI agent 的 session 跑完最后一个 window 时,tmux 不会把你拽出去,而是跳到下一个 session——多个 agent 并行跑、有的早有的晚结束的时候,这条让 client 始终待在 tmux 里不被踢出来。
set-clipboard on 让你在 tmux 里鼠标选中一段 AI 输出就直接进系统剪贴板,省掉一步"先 Ctrl+b [ 再 vi 模式选"。这条在公司机器上需要终端模拟器配合(iTerm2 默认支持),一般不用额外配。
AI 工作流专用的进阶命令
当你开始跑多 agent pipeline 后,这些命令的出场率会急剧上升:
创建和销毁:
tmux new-session -d -s agent1 -c /path/to/project # detached 创建
tmux kill-session -t agent1 # 销毁 session
tmux kill-server # 销毁所有 session(慎用)
跨 session 通信:
tmux send-keys -t agent2 "command" Enter # 发送指令
tmux send-keys -t agent3 C-c # 发送 Ctrl+C(打断 AI)
tmux send-keys -t agent3 C-d # 发送 Ctrl+D(EOF)
tmux capture-pane -t agent2 -p -S -50 # 抓取最近 50 行输出
tmux capture-pane -t agent2 -p -S - -E - > /tmp/out # 抓取全部历史输出
日志与监控:
tmux pipe-pane -t agent1 -o 'cat >> /tmp/agent1.log' # 开始记录输出
tmux pipe-pane -t agent1 # 停止记录
tmux list-sessions # 查看所有 session
tmux list-windows -t agent1 # 查看 session 内所有 window
独立 socket(项目隔离):
tmux -L project-a new -s agent1 # 用独立 socket 创建
tmux -L project-a ls # 只看这个 socket 的 session
tmux -L project-a attach -t agent1 # 接入
几个可选的小调整
如果你想再压一压日常摩擦,可以加:
# ── 状态栏左侧显示 session 名(多 session 来回切时一眼分清) ──
set -g status-left '#[fg=green]#S '
# ── 新建 window 默认继承当前 pane 的目录 ──
bind c new-window -c "#{pane_current_path}"
# ── 一键切回上一个 window(在两台远端机器之间反复切时手指会感谢你) ──
bind Tab last-window
# ── window/pane 编号从 1 开始(数字键位排布跟你的 1234 行一致) ──
set -g base-index 1
setw -g pane-base-index 1
这些都是体验层调整,加不加不影响 tmux 工作流跑得通;但每一条都来自真实场景里"敲多了觉得烦"的痛点。
九、AI 时代的竞争力,不只在"会不会用 AI"
现在有一种流行叙事:AI 时代,程序员的核心竞争力是"会不会用 AI"。怎么用 Claude Code、怎么写 system prompt、怎么 chain 多个 agent。
这没错,但不全对。
真正拉开差距的,是你和 AI 之间那一层——工作流的基础设施。
同样的 Claude 账号,同样的 prompt,一个人用 tmux + 远端 session + ssht + pipe-pane 日志 + 脚本化流水线,另一个人在 iTerm2 里单窗口裸跑。一段时间下来,前者的 AI 实际产出会显著高于后者——不是因为前者更聪明,不是因为前者 prompt 更好,而是前者的 AI 可以连续工作很长时间不停:不需要人盯着,不会因为网络波动丢进度,不同 agent 之间有明确的输入输出契约。
聊到这个话题时我经常问一个偏题:“你怎么保证你的 AI 编程 session 不会丢?” 大部分人的第一反应是"在 commit 之前不关 terminal"或者"把 prompt 存进笔记"。这两种答案背后都是同一件事——把 AI session 看成一次性的;session 一断,就只剩一段静态记录。
而真正用 tmux 工作流的人会反过来想:AI 不是魔法,它跑在一个具体的进程里。进程会死,你得为它建一艘不会沉的船。 detach 了去吃饭、远端 tmux 配 pipe-pane 留全程日志,session 本身就是可以被随时 attach 回来继续推进的活物。这个心智模型一旦切换过去就回不去了。
现在就能看到的分叉
未来一两年,程序员的 AI 工作流大概率会分化成两种典型形态:
一种是 “iTerm2 里开一个标签页,跑一个 Claude Code,等它跑完,手动检查,复制粘贴到下一个标签页”。
另一种是 “早上打开电脑,ssht 到昨晚那台机器的 tmux session,几个 agent 已经跑完,pipe-pane 日志和 commit 历史都在,看几分钟判断要不要 merge,然后 push”。
前者的瓶颈是 AI 速度。后者的瓶颈是自己的判断力。
这不是学不学 tmux 的问题。是你有没有意识到:AI 时代的生产力单位正在从"人"变成"人 + AI agent 集群"。你的工作不再是写代码——是在多个 AI agent 之间做架构决策、质量控制、方向校准。tmux 是你指挥这个集群的操作系统。
一个你可能已经具备、但还没用上的能力
如果你用过 Docker Compose,你对这种思维模型已经熟悉了——你把多个服务定义在一个 yaml 里,docker-compose up -d,它们就互相协作跑起来。你可以随时 docker-compose logs -f service-name 看某个服务的日志,可以随时 docker-compose restart service-name 重启某个出问题的组件。
tmux 对 AI agent 做的,本质上就是这件事。只不过"服务"变成了 AI agent,"docker-compose.yml"变成了 bash 脚本,"docker-compose logs"变成了 pipe-pane 日志。但思维模型完全一样——声明一组互相协作的进程,让它们在后台持续运行,你只出现在需要做决策的节点。
这个能力你已经有了,只是工具还不熟。花一个下午把上面的脚本跑通一遍,你就回不去了。
tmux 的 man page 写了快二十年了。但它在 AI 时代的真正价值,大部分人还没注意到。不是因为难,是因为他们还没丢过 AI 会话。别等丢的那天。
现在就学。