agentleFS
Spoon94Spoon94/skill-vault/tmux/SKILL.md

tmux

Skill5 starsChanged 3 months agoMITView on GitHub

以脚本方式驱动 tmux:创建后台会话、用 send-keys 向运行中的程序发命令、用 capture-pane 读输出。用于自动化 REPL/SSH/调试器、并发跑多个长生命周期服务、跨调用保持 shell 状态、或让用户 attach 到自动化现场——普通 Bash 拿不到 PTY 时使用。

69 other projects use a version of this.

Adopted by

Most recently taken up by

Used with

Projects with it also use taskflow-inbox-triage, session-logs and 10 more.

Other files people use alongside this one.

Files found in the same public projects as a version of this one, more often than they turn up anywhere else. Each project counts once, large collections count for less, and this file's own repository is left out.
  • AtomicBot-aiSkill

    taskflow-inbox-triage

    Also in 6 projects that use this

  • seedprodSkill

    session-logs

    Search and analyze your own session logs (older/parent conversations) using jq.

    Also in 20 projects that use this

  • seedprodSkill

    voice-call

    Start voice calls via the OpenClaw voice-call plugin.

    Also in 18 projects that use this

  • AtomicBot-aiSkill

    taskflow

    Also in 7 projects that use this

  • jiulingyunSkill

    BlueBubbles

    为Clawdbot构建或更新BlueBubbles外部通道插件(扩展包,REST发送/探测,webhook入站)。

    Also in 16 projects that use this

  • hkyutongSkill

    openclaw-release-maintainer

    Maintainer workflow for OpenClaw releases, prereleases, changelog release notes, and publish validation. Use when Codex needs to prepare or verify stable or beta release steps, align version naming, assemble release notes, check release auth requirements, or validate publish-time commands and artifacts.

    Also in 4 projects that use this

  • +5 more from seedprod

The file

Files
SKILL.md

tmux 自动化技能

本技能教 Claude 如何用 tmux 在自动化场景里驱动交互式程序。重点不是手按键绑定,而是用 tmux 子命令以脚本方式创建会话、发命令、读输出。

心智模型

程序  ⊂  面板 (pane, %X)  ⊂  窗口 (window, @X)  ⊂  会话 (session, $X)  ⊂  客户端
  • 一个面板里跑一个程序,提供完整 PTY。
  • 窗口是一组面板的容器,占满终端。
  • 会话是一组窗口,可被多个客户端 attach 共享。
  • 服务器进程在后台维护所有状态;只要服务器没被 kill,会话就一直在。

每种对象都有稳定的唯一 ID:会话 $N、窗口 @N、面板 %N。永远用 ID 定位——索引 (0、1.2) 在窗口被创建/关闭时会变,ID 不会。


何时该用本技能

满足下列任一条即可:

  1. 要向已经启动的程序发命令(python REPL、psql、gdb、ssh 远端 shell、claude/codex CLI 等)。普通 Bash 启动后无法再向 stdin 投递输入,tmux 可以。
  2. 程序拒绝在非 TTY 下工作,或在管道里行为变差(丢色、不刷新、缓冲变怪、curses 错乱)。tmux 提供真 PTY。
  3. 需要多个并发长生命周期服务,且要分别向它们发命令、分别读输出(前端 dev、后端、worker、日志监控)。
  4. 想让用户随时 attach 看 Claude 当前操作的现场,或在 Claude 离开后接管。
  5. 需要在跨多次 Claude 工具调用之间保留同一个 shell/程序的状态(环境变量、cd 后的目录、virtualenv、登录的 ssh 连接)。

不满足以上任何一条时,普通的 Bash 调用就够了,没必要套 tmux。


黄金法则

永远先抓 ID,再用 ID 操作。 创建任何对象时都加 -d -P -F '#{...}',把 stdout 拿到的 ID 存进 shell 变量,后续命令一律用 -t $ID。

# 幂等防御:同名会话已存在则先清掉,避免 new-session 失败
tmux has-session -t '=claude-work' 2>/dev/null && tmux kill-session -t '=claude-work'

# -d 不 attach;-P 打印目标;-F 指定打印格式
S=$(tmux new-session -d -P -F '#{session_id}' -s claude-work)
W=$(tmux new-window  -d -P -F '#{window_id}'  -t "$S")
P=$(tmux split-window -d -P -F '#{pane_id}'   -t "$W")

这之后 $S、$W、$P 是稳定句柄,重命名/重排都不影响。-t '=name' 的 = 前缀强制精确匹配,避免误命中名字相近的别的会话。


五个核心模板

模板 1:创建一个后台会话,跑一个程序

# 创建会话,在第一个面板里启动 python,并拿到面板 ID
PANE=$(tmux new-session -d -s repl -P -F '#{pane_id}' 'python3 -i')

-i 是给 python 的:让它启动后进入 REPL 而不是执行完命令就退出(tmux 已经提供了真 PTY,所以 stdin 一定是 tty;-i 解决的是 python 的行为而非 tty 检测)。

本节模板为简化起见省略了 has-session 幂等检查。脚本要可重复运行时,按"黄金法则"那段代码先做 has-session && kill-session 清理,或改用 tmux new-session -A -d ...(已存在则复用、不存在才建)。

模板 2:向运行中的程序发命令

tmux send-keys -t "$PANE" 'import os; print(os.getcwd())' Enter
  • 解析按位置参数为单位:每个独立参数先整体匹配键名(Enter、Tab、C-c、F1 等),匹配上就发那个键的转义序列;匹配不上就把整个参数作为字面字符串逐字符发送。注意:不会把"参数里的某些子串"再去匹配键名——'cmd Enter' 是六个字符(c, m, d, 空格, E...)一起发,不会触发回车。
  • 因此命令文本和回车要分成两个参数:'cmd' Enter,不要写成 'cmd\n' 或 'cmd Enter'。
  • 要发的字面量恰好等于某个键名(比如真要键入 "Enter" 这个词),加 -l 关闭键名识别:tmux send-keys -lt "$PANE" 'Enter'。
  • 取消正在跑的程序:tmux send-keys -t "$PANE" C-c。

模板 3:读取面板输出

# 读当前可见内容(包含已滚出屏幕之前的最后一屏)
tmux capture-pane -p -t "$PANE"

# 读完整历史(含 scrollback)
tmux capture-pane -p -t "$PANE" -S -

# 保留尾随空格 + 重新拼接折行(适合解析结构化输出)
tmux capture-pane -p -t "$PANE" -S - -J

-p 表示 print 到 stdout(不加 -p 则存到 paste buffer)。-S 是起始行,- 表示历史最早一行;-E 是结束行,默认到可见区末尾。

模板 4:发命令后等程序就绪

程序处理输入需要时间,盲目立刻 capture 容易拿到旧画面。轮询 capture 直到看到稳定的提示符:

tmux send-keys -t "$PANE" 'long_running_thing()' Enter

ok=0
for _ in $(seq 1 30); do
  # 范围设大一点:覆盖命令本身的输出加上提示符所在行
  out=$(tmux capture-pane -p -t "$PANE" -S -200 -J)
  # 用两个分支匹配提示符:
  #   1) "<换行>>>>" — 提示符前有更早的输出(绝大多数情况)
  #   2) ">>>"      — 极少数边界:捕获区起点恰好就是提示符所在行(无前导换行)
  # 不依赖提示符末尾的尾随空格——不同环境(python "> "、shell "$ ")习惯不同,
  # 而且 capture 在不带 -J/-N 时会吃掉它们。
  case $out in
    *"
>>>"*|">>>"*) ok=1; break ;;
  esac
  sleep 1
done

if [ "$ok" -ne 1 ]; then
  echo "timeout waiting for prompt; last capture:" >&2
  echo "$out" >&2
  exit 1
fi
echo "$out"

要点:

  • 在 send-keys 后不要不 sleep 直接 capture,至少留一个轮询循环;用面板里独有的提示符当结束信号,比"等固定秒数"可靠得多。
  • case 模式里嵌入的是真实换行符(双引号内回车换行),不是 \n 转义——后者在 case 里会被当成两个字符 \ 和 n。"换行+提示符"模式锁定的是"提示符出现在某行行首",避免误匹配字符串里偶然出现的 >>>;附加 ">>>"* 兜底新会话刚启动、捕获区第一行就是提示符的边界情况。
  • 永远显式判定超时,不要让脚本在没看到提示符时静默继续。
  • -J 同时拼接折行并保留尾随空格——长命令被终端宽度切断时仍能正确解析。

模板 5:并发跑多个服务

S=$(tmux new-session -d -s services -P -F '#{session_id}')

# 第一个面板/窗口已经存在但 new-session 没 -P 出来——单独取 ID
W0=$(tmux display -p -t "$S" -F '#{window_id}')
BACKEND=$(tmux display -p -t "$W0" -F '#{pane_id}')
tmux rename-window -t "$W0" services
tmux send-keys -t "$BACKEND" 'cd backend && npm run dev' Enter

# 再起一个窗口跑前端
FRONTEND=$(tmux new-window -d -P -F '#{pane_id}' -t "$S" -n frontend)
tmux send-keys -t "$FRONTEND" 'cd frontend && npm run dev' Enter

# 同窗口里再分一个面板跑日志
LOGS=$(tmux split-window -d -P -F '#{pane_id}' -t "$FRONTEND")
tmux send-keys -t "$LOGS" 'tail -F /tmp/app.log' Enter

之后任何时候都能用 $BACKEND / $FRONTEND / $LOGS 各自发命令、各自 capture。所有定位均用 ID,与黄金法则一致。

让用户接管 / Claude 离开

  • 用户想看:让 Ta 跑 tmux attach -t =services(= 前缀强制精确匹配,避免被名字相近的别的会话抢去)。-d 选项可顺便把其他客户端踢掉以避免大小冲突。
  • Claude 不能在自己的工具调用里 attach(会卡住前台),但可以在创建会话时不 attach,让会话留在后台供用户 attach。
  • 完事清理:tmux kill-session -t =services。一个孤立的会话不会自己消失。

关键陷阱(自动化场景最常翻车的几个)

  1. send-keys 不带 Enter 等于没按回车。 几乎所有"命令发了但没反应"都是这个。检查最后一个参数是不是 Enter。
  2. 键名 vs 字面量的歧义。 要发的字符串里如果有 Enter、Tab、Space 这种英文单词,加 -l 强制字面量,否则会被当成按键。引号里的特殊 shell 字符($、反引号)也要按 shell 规则转义。
  3. capture 时机。 紧跟 send-keys 之后立即 capture 拿到的是发命令前的画面。永远轮询,用提示符或自定义 sentinel 行作为完成标志。
  4. 窗口/面板索引会变。 不要靠 -t 0.1 这种位置定位长期跑的脚本,用 %pane_id。
  5. 嵌套 tmux(在已经 attach 的 tmux 里再 attach 另一个)会让前缀键冲突。Claude 的脚本里发命令用绝对 tmux ... 不需要前缀键,所以这条只在让用户手动接管时关心——告诉用户把外层前缀键连按两次(默认是 Ctrl-b Ctrl-b,若用户改过就用他自己的 prefix 重复一次),就能把前缀传给内层。更彻底的办法是 Claude 本来就用独立 socket 启动会话(tmux -L claude ...),与用户的默认 socket 完全隔离,嵌套和前缀冲突都不存在;详见 references/targets-and-ids.md 的"嵌套"一节。
  6. TERM 必须是 tmux 兼容值。 自动化里很少需要管,但若程序投诉 unknown terminal,在创建会话前 export TERM=tmux-256color 或 screen-256color。
  7. kill 不会问你。 tmux kill-server 会干掉所有会话,慎用;用 kill-session -t $S 只清自己的。
  8. 进程退出后面板会消失,错误现场也丢了。 默认 remain-on-exit 是 off,进程一旦 exit,pane 立刻关闭,再去 capture-pane -t %P 会拿到错误"can't find pane"。要保留崩溃现场用于事后取错信息,创建会话时打开此选项:
    tmux new-session -d -s claude-work \; \
         set-option -t claude-work remain-on-exit on
    # 之后 pane 内进程退出,面板保留并显示 "Pane is dead",capture 仍可用

何时翻参考资料

references/ 下按场景拆分。不要预先全读,需要时再开对应文件:

你正在做的事打开
选 send-keys / capture-pane / pipe-pane 的某个细节 flagreferences/automation.md
拼 -t 目标(跨会话、相对位置、{last}/{up-of} 等)references/targets-and-ids.md
找一个完整可用的脚本模板(dev server 等待就绪、并发服务、REPL 自动化)references/recipes.md
排查 send-keys 没生效 / capture 总拿空 / TUI 显示乱码references/pitfalls.md

参考来源

本技能的命令语法和示例基于本仓库的 tmux 官方 wiki 内容(特别是 Advanced-Use.md 的 "Sending keys"、"Capturing pane content"、"Targets" 与 "Targets for new panes, windows and sessions" 章节)以及 Recipes.md。如果对某条 flag 行为有疑问,回去查 man tmux 是最权威的途径。

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.