jixiaxue 知识库
← blog-write

当 AI 替你写代码之后,你需要一个好的终端管理工具

2026-04-12 已发布

当 AI 替你写代码之后,你需要一个好的终端管理工具

一个正在发生的变化

AI agent 的编程能力到了一个临界点。越来越多开发者的日常变成了:在终端里打开 Claude Code,用自然语言告诉它要做什么,它自己去读代码、改代码、跑测试、修 bug。描述需求、看它做、追问、确认、下一个任务——编辑器几乎不碰,文件树几乎不翻。

IDE 那个大窗口开始闲置了。真正在用的就是终端,里面跑着和 AI 的对话。

当一整天都在终端里工作,同时跑着 3-5 个项目的 AI 对话,“管理终端窗口”就变成了一个真实的需求

tmux 就是干这个的——终端多路复用器,在一个终端里管理多个会话、多个窗口、多个分屏。下面是用下来觉得最有用的几段配置,按实际遇到问题的顺序来聊。


开了 5 个项目的对话,切来切去找不到哪个是哪个

这是我切到终端工作流之后最先遇到的问题。

我通常同时开着 engineeringcreationresearchskills 等十来个 session,每个对应一个工作台。但 tmux 默认状态栏只显示当前 session——[engineering] 0:ai-brain*。其他 session 在哪、在干什么,一概看不到

pane 也一样——开了 3 个 pane,一个跑着 Claude Code,一个跑着 dev server,一个是空 shell,外表上分不清。

解法是把状态栏改成一排”session 标签页”,鼠标点哪个切哪个,当前 session 金色高亮。pane 顶部边框显示当前在跑什么命令、在哪个目录:

tmux 状态栏效果:底部一排 session 标签页,当前 engineering 金色高亮;pane 顶部显示命令和路径

核心是两个小脚本 + 状态栏配置。脚本放在 ~/.config/tmux/scripts/ 下,chmod +x

session_list.sh — 生成状态栏 session 标签:

#!/bin/bash
SLOT_WIDTH=14
NAME_WIDTH=$((SLOT_WIDTH - 2))
current=$(tmux display-message -p '#S' 2>/dev/null)

tmux list-sessions -F "#{session_name}" 2>/dev/null | while IFS= read -r name; do
    short="${name:0:$NAME_WIDTH}"
    if [ "$name" = "$current" ]; then
        printf "#[bold,fg=colour235,bg=colour220] %-${NAME_WIDTH}s #[default]" "$short"
    else
        printf "#[fg=colour245,bg=colour235] %-${NAME_WIDTH}s #[default]" "$short"
    fi
done

session_click.sh — 鼠标点击切换 session:

#!/bin/bash
# 整除计算假设 status-left 从终端最左端 x=0 开始
# 如果状态栏有额外左侧 padding,可能偏移一个 session
MOUSE_X="$1"
SLOT_WIDTH=14
index=$((MOUSE_X / SLOT_WIDTH))
session=$(tmux list-sessions -F "#{session_name}" 2>/dev/null | awk "NR==$((index + 1))")
[ -n "$session" ] && tmux switch-client -t "$session"

tmux.conf

set -g status-interval 2
set -g status-left-length 200
set -g status-left "#(~/.config/tmux/scripts/session_list.sh)"
set -g status-right "#{?client_prefix,#[bold,fg=colour235,bg=colour220] PREFIX #[default] ,} %H:%M "
setw -g window-status-current-format '#[bold,fg=colour220] #I:#W #[default]'
setw -g window-status-format ' #I:#W '

set -g pane-border-status top
set -g pane-border-format ' #{pane_current_command}  #{b:pane_current_path} '
set -g pane-active-border-style 'fg=colour220'
set -g pane-border-style 'fg=colour240'

bind -n MouseDown1StatusLeft run-shell "~/.config/tmux/scripts/session_click.sh #{mouse_x}"

还有一个小问题:Claude Code 在后台跑任务时你切去了别的 window,跑完了你不知道。所以我在 window 状态栏上加了红点通知——任务完成时对应 window 名前会亮一个 ,切过去红点自动消:

# Claude Code 完成通知:window 名前显示红点
setw -g window-status-format '#{?#{==:#{@claude_notify},1},#[fg=colour196]● #[fg=colour245], }#I:#W '

# 切到对应 window 时自动清除
set-hook -g after-select-window 'set-option -w @claude_notify 0'
set-hook -g client-session-changed 'set-option -w @claude_notify 0'

改完之后,一眼就能看到所有 session、当前在哪、每个 pane 在跑什么、哪个 AI 任务刚跑完。


tmux 默认配置的一堆历史遗留问题

状态栏搞定之后,接下来就是被 tmux 的默认行为反复绊。

没有鼠标支持——不能点击切 pane,不能拖拽调大小。回滚缓冲区只有 2000 行——Claude Code 跑一个复杂任务的输出轻松超过这个数。ESC 延迟 500ms——在终端里用 Vim 编辑什么东西时按 ESC 要等半秒。窗口编号从 0 开始——键盘最左边是 1 不是 0。不支持真彩色——Vim 主题颜色偏移。

这组设置基本是”装完 tmux 第一件事”,一次性解决:

set -g mouse on                         # 开鼠标
set -g history-limit 200000             # 回滚 20 万行(AI 输出很长,这个很有必要)
set -s escape-time 5                    # ESC 延迟降到 5ms
set -s focus-events on                  # 让 Vim 感知焦点变化
set -g base-index 1                     # window 从 1 编号
setw -g pane-base-index 1              # pane 也从 1
set -g renumber-windows on              # 关窗口后重编号
setw -g automatic-rename on             # window 名跟随进程
set -g set-titles on
set -g display-time 2000
set -g default-terminal "tmux-256color"
# RGB 真彩色——如果不生效,检查 echo $TERM 是否匹配 *256col*
# 不匹配的话改成具体值如 ",xterm-256color:RGB"
set -as terminal-features ",*256col*:RGB"
# 个人偏好:复制模式 vim 键位,命令行 emacs 键位
# 不用 vim 的删掉 mode-keys 这行
set -g mode-keys vi
set -g status-keys emacs

改完之后这些绊脚石就没了。


Prefix 键跟 Vim 抢键

tmux 默认 Prefix 是 Ctrl+b。问题是 Vim 里 Ctrl+b 是翻页。在 tmux 内的 Vim 里按 Ctrl+b,tmux 会先拦截这个键作为 Prefix——Vim 收不到,什么都没发生。

我换成了 Ctrl+\

unbind C-b
set -g prefix 'C-\'
bind 'C-\' send-prefix

这个键 Vim 和 Bash 都不用,在键盘右手区单手就能按。顺便加个 bind r 重载配置,改完不用重启 tmux:

bind r source-file ~/.tmux.conf \; display '✓ 配置已重载'

一个细节

Ctrl+\ 在终端里默认是 SIGQUIT 信号。绑定为 Prefix 后 tmux 会拦截它,SIGQUIT 不再生效。日常几乎用不到 SIGQUIT,但如果你的工作流依赖这个信号,需要换一个 Prefix。


最常用的操作每次要两步,太慢了

tmux 的默认设计是所有操作先按 Prefix。切窗口 Prefix + 1,分屏 Prefix + %,新建窗口 Prefix + c

当你一天的工作就是在几个 AI 对话之间切来切去,这个”每次多按一步 Prefix”的成本很快就累积起来了。更烦的是 Prefix + % 是左右分割、Prefix + " 是上下分割——谁能记得住。

我把高频操作全部绑到 Alt+X,一键直达:

macOS 用户注意

macOS 终端默认不发送 Alt 键。需要在终端设置里把 Option 改为 Meta/Alt(iTerm2: Profiles → Keys → Left Option → Esc+),否则以下快捷键全部不生效。

# ── Session ──
bind -n M-s choose-session                                           # Alt+s session 列表
bind -n M-n command-prompt -p "新建 session:" "new-session -s '%%'"  # Alt+n 新建
bind -n M-, switch-client -p                                         # Alt+, 上一个
bind -n M-. switch-client -n                                         # Alt+. 下一个

# ── Window ──
# Alt+1~9 直接跳到对应窗口(下面只列 1~5,6~9 同理)
bind -n M-1 select-window -t 1
bind -n M-2 select-window -t 2
bind -n M-3 select-window -t 3
bind -n M-4 select-window -t 4
bind -n M-5 select-window -t 5
bind -n M-'{' previous-window     # Alt+{ / } 前后切
bind -n M-'}' next-window
bind -n M-o new-window -c "#{pane_current_path}"  # Alt+o 新建(继承路径)

# ── Pane ──
bind -n M-f resize-pane -Z                                # Alt+f 缩放/还原
bind -n 'M-\' split-window -h -c "#{pane_current_path}"  # Alt+\ 左右分(\ 像竖线)
bind -n M-- split-window -v -c "#{pane_current_path}"     # Alt+- 上下分(- 像横线)

Alt+1 直接跳窗口 1,Alt+\ 左右分割,Alt+- 上下分割。键位本身就是助记符——竖线分左右,横线分上下。


偶尔要做管理操作,但记不住命令

有些操作不常用但用到时很头疼:关 pane 没有确认提示(误按直接杀)、想把 pane 拆成独立窗口得 Google break-pane、想同时向多个 pane 发命令得 Google synchronize-panes

这些放在 Prefix 后面,低频操作不需要一键直达:

bind q confirm-before -p "关闭 pane?(y/n)" kill-pane
bind '\' command-prompt -p "重命名 window:" "rename-window '%%'"
bind / command-prompt -p "重命名 session:" "rename-session '%%'"
bind Space next-layout
bind w choose-tree -Z
bind ! break-pane                         # pane 拆成独立 window
bind @ command-prompt -p "合并到 window:" "join-pane -t ':%%'"
bind m command-prompt -p "移动到 session:" "move-window -t '%%'"

# 同步输入:同时向所有 pane 发命令,开启时边框变红提醒
bind g if-shell '[[ $(tmux showw synchronize-panes | cut -d\  -f2) == "on" ]]' \
  'setw synchronize-panes off; set -g pane-active-border-style fg=colour220; display "同步输入:关闭"' \
  'setw synchronize-panes on;  set -g pane-active-border-style fg=red;      display "同步输入:开启(边框变红)"'

Prefix + g 开启同步输入后,你在一个 pane 里打的字会同时发到所有 pane。边框变红提醒你别忘了关。


电脑重启后所有对话窗口全丢

这是最痛的一个。

你花了一个小时精心布好了 5 个 session 的窗口布局——每个项目的 Claude Code 对话在哪个 window、dev server 在哪个 pane、日志在哪个 pane。然后电脑更新重启了,或者 tmux server 意外退出。

打开 tmux——空的。所有布局消失,得从头重建。

# 先装 TPM(只需要一次):
# git clone https://github.com/tmux-plugins/tpm ~/.tmux/plugins/tpm

set -g @plugin 'tmux-plugins/tpm'
set -g @plugin 'tmux-plugins/tmux-resurrect'
set -g @plugin 'tmux-plugins/tmux-continuum'

set -g @continuum-save-interval '15'          # 每 15 分钟自动保存
set -g @continuum-restore 'on'                # 启动时自动恢复
set -g @resurrect-capture-pane-contents 'on'  # 保存 pane 输出快照

run '~/.tmux/plugins/tpm/tpm'
# 安装插件:tmux 内按 Prefix + I(大写 i)

一个重要限制

resurrect 恢复的是布局、路径和输出快照,但正在运行的进程不会恢复。比如之前跑着 npm run dev,重启后目录对了但进程需要手动重启。这是终端进程的本质限制,不是 bug。

最耗时的”建 session、开 window、分 pane、cd 到正确目录”全自动了,剩下的”重启几个命令”很快。


一个锦上添花的小功能

有时候想临时跑个 git logls 看一眼什么东西,但不想为此新建一个 pane 打乱现有布局。

bind -n M-e display-popup -w 80% -h 40% -d "#{pane_current_path}" -E

Alt+e 弹出一个浮动终端,继承当前路径,exit 后自动消失。用完即走,零残留。