name: tmux description: 在tmux中运行长生命周期进程的模式。适用于启动开发服务器、文件监视器、tilt或任何预期会持续运行的进程。
tmux 进程管理
会话复用规则
这些是硬性要求,而非建议:
- 必须在调用
tmux new-session前检查tmux has-session - 必须从
git rev-parse --show-toplevel派生会话名称,切勿硬编码 - 必须向现有项目会话添加窗口,切勿创建并行会话
- 必须使用
send-keys运行命令,切勿向new-session传递内联命令 - 切勿为当前项目创建新会话(如果已存在)
一个项目 = 一个tmux会话。多个进程 = 该会话中的多个窗口。
交互式Shell要求
使用send-keys模式确保可靠的Shell初始化。 创建会话时会自动生成一个交互式Shell。使用 send-keys 在该Shell内运行命令,确保PATH、direnv和其他初始化正确执行。
# 错误 - 内联命令绕过Shell初始化,破坏PATH/direnv
tmux new-session -d -s "$SESSION" -n main 'tilt up'
# 正确 - 检查会话是否存在,然后在交互式Shell中使用send-keys
if ! tmux has-session -t "$SESSION" 2>/dev/null; then
tmux new-session -d -s "$SESSION" -n main
fi
tmux send-keys -t "$SESSION:main" 'tilt up' Enter
会话命名约定
始终从项目派生会话名称:
SESSION=$(basename $(git rev-parse --show-toplevel 2>/dev/null) || basename $PWD)
对于一个项目中的多个进程,使用窗口而非独立会话:
- 会话:
myapp - 窗口:
server,tests,logs
启动进程
单个进程
SESSION=$(basename $(git rev-parse --show-toplevel 2>/dev/null) || basename $PWD)
if ! tmux has-session -t "$SESSION" 2>/dev/null; then
tmux new-session -d -s "$SESSION" -n main
tmux send-keys -t "$SESSION:main" '<命令>' Enter
else
echo "会话 $SESSION 已存在"
fi
向现有会话添加窗口
SESSION=$(basename $(git rev-parse --show-toplevel 2>/dev/null) || basename $PWD)
# 如果窗口不存在则添加新窗口
if ! tmux list-windows -t "$SESSION" -F '#{window_name}' | grep -q "^server$"; then
tmux new-window -t "$SESSION" -n server
tmux send-keys -t "$SESSION:server" 'npm run dev' Enter
else
echo "窗口 'server' 已存在"
fi
多个进程(窗口)
SESSION=$(basename $(git rev-parse --show-toplevel 2>/dev/null) || basename $PWD)
# 根据需要创建会话,然后添加窗口
if ! tmux has-session -t "$SESSION" 2>/dev/null; then
tmux new-session -d -s "$SESSION" -n server
tmux send-keys -t "$SESSION:server" 'npm run dev' Enter
fi
# 添加更多窗口(幂等操作)
for win in tests logs; do
if ! tmux list-windows -t "$SESSION" -F '#{window_name}' | grep -q "^${win}$"; then
tmux new-window -t "$SESSION" -n "$win"
fi
done
tmux send-keys -t "$SESSION:tests" 'npm run test:watch' Enter
tmux send-keys -t "$SESSION:logs" 'tail -f logs/app.log' Enter
监控输出
SESSION=$(basename $(git rev-parse --show-toplevel 2>/dev/null) || basename $PWD)
# 从第一个窗口获取最后50行
tmux capture-pane -p -t "$SESSION" -S -50
# 从特定窗口获取
tmux capture-pane -p -t "$SESSION:server" -S -50
# 检查错误
tmux capture-pane -p -t "$SESSION" -S -100 | rg -i "error|fail|exception"
# 检查就绪指示器
tmux capture-pane -p -t "$SESSION:server" -S -50 | rg -i "listening|ready|started"
生命周期管理
SESSION=$(basename $(git rev-parse --show-toplevel 2>/dev/null) || basename $PWD)
# 列出所有会话(查看存在哪些)
tmux ls
# 列出当前会话中的窗口
tmux list-windows -t "$SESSION"
# 仅终止此项目的会话
tmux kill-session -t "$SESSION"
# 终止特定窗口
tmux kill-window -t "$SESSION:tests"
# 向窗口发送按键(例如,Ctrl+C停止)
tmux send-keys -t "$SESSION:server" C-c
隔离规则
- 切勿使用
tmux kill-server - 切勿终止与当前项目不匹配的会话
- 始终从git根目录或pwd派生会话名称
- 始终在终止操作前验证会话名称
- 其他Claude Code实例可能运行着自己的会话
何时使用tmux
| 场景 | 使用tmux? |
|---|---|
tilt up |
是,始终使用 |
开发服务器 (npm run dev, rails s) |
是 |
文件监视器 (npm run watch) |
是 |
测试监视器 (npm run test:watch) |
是 |
| 数据库服务器 | 是 |
一次性构建 (npm run build) |
否 |
| 快速命令 (<10秒) | 否 |
| 需要在对话中直接查看stdout | 否 |
检查进程状态
SESSION=$(basename $(git rev-parse --show-toplevel 2>/dev/null) || basename $PWD)
# 检查会话是否存在
tmux has-session -t "$SESSION" 2>/dev/null && echo "会话存在" || echo "无会话"
# 列出窗口及其状态
tmux list-windows -t "$SESSION" -F '#{window_name}: #{pane_current_command}'
# 检查特定窗口是否存在
tmux list-windows -t "$SESSION" -F '#{window_name}' | grep -q "^server$" && echo "服务器窗口存在"
重启进程
SESSION=$(basename $(git rev-parse --show-toplevel 2>/dev/null) || basename $PWD)
# 发送Ctrl+C然后重启命令
tmux send-keys -t "$SESSION:server" C-c
sleep 1
tmux send-keys -t "$SESSION:server" 'npm run dev' Enter
常见模式
如果未运行则启动开发服务器
SESSION=$(basename $(git rev-parse --show-toplevel 2>/dev/null) || basename $PWD)
if ! tmux has-session -t "$SESSION" 2>/dev/null; then
tmux new-session -d -s "$SESSION" -n server
tmux send-keys -t "$SESSION:server" 'npm run dev' Enter
echo "在tmux会话中启动开发服务器: $SESSION"
elif ! tmux list-windows -t "$SESSION" -F '#{window_name}' | grep -q "^server$"; then
tmux new-window -t "$SESSION" -n server
tmux send-keys -t "$SESSION:server" 'npm run dev' Enter
echo "向会话添加服务器窗口: $SESSION"
else
echo "服务器已在会话中运行: $SESSION"
fi
等待服务器就绪
SESSION=$(basename $(git rev-parse --show-toplevel 2>/dev/null) || basename $PWD)
# 轮询就绪消息
for i in {1..30}; do
if tmux capture-pane -p -t "$SESSION:server" -S -20 | rg -q "listening|ready"; then
echo "服务器就绪"
break
fi
sleep 1
done