在 nanobot 中用 tmux Skill 远程操控交互式终端:会话管理、安全输入与多 Agent 并行编排实战
2026/9/19 15:08:53 网站建设 项目流程

在 nanobot 中用 tmux Skill 远程操控交互式终端:会话管理、安全输入与多 Agent 并行编排实战

【免费下载链接】nanobotUltra-lightweight, open-source, self-hosted personal AI agent framework in Python with WebUI, tools, memory, MCP, multi-agent workflows, automation, and chat apps项目地址: https://gitcode.com/gh_mirrors/nanob/nanobot

导读

本篇文章基于 nanobot 内置的 tmux Skill 展开,介绍如何让 AI Agent 通过 tmux 远程操控交互式 CLI:创建隔离的 tmux 会话、向指定 pane 发送按键、抓取 pane 输出并轮询等待特定文本,以及利用多会话并行编排 Codex、Claude Code 等编码 Agent。读完本文,你将掌握一套可复制的 "交互式 TTY 远程控制" 操作范式,并理解其背后的技能加载机制与配套 Bash 脚本的实现细节。

tmux Skill 是什么

tmux 是运行在 macOS / Linux 上的终端复用器。nanobot 将其封装为一个内置技能(skill),使 Agent 能在自己的执行环境中通过tmux -S <socket>命令族,对后台运行的交互式程序(如 Python REPL、交互式 CLI、编码 Agent)进行远程控制。

技能元数据位于 SKILL.md 的 YAML frontmatter 中:

--- name: tmux description: Remote-control tmux sessions for interactive CLIs by sending keystrokes and scraping pane output. metadata: {"nanobot":{"emoji":"🧵","os":["darwin","linux"],"requires":{"bins":["tmux"]}}} ---

其中requires.bins: ["tmux"]声明了该技能的前置条件。从 skills.py 的实现看,技能加载器会用shutil.which("tmux")检查 PATH 中是否存在该二进制,若缺失则在技能摘要中标记为unavailable。同时os: ["darwin", "linux"]说明它只在 macOS / Linux 上生效,Windows 上需要借助 WSL。

技能的使用边界在文档开头就明确给出:只有需要交互式 TTY 时才使用 tmux;对于长时间运行、无需交互的后台任务,应优先使用 exec 后台模式,而不是占用一个 tmux 会话。

Quickstart:用隔离 socket 快速起一个 REPL 会话

核心思路是使用独立的 socket 文件隔离 Agent 的 tmux 实例,避免与用户桌面上其他 tmux 会话冲突。完整启动流程如下:

SOCKET_DIR="${NANOBOT_TMUX_SOCKET_DIR:-${TMPDIR:-/tmp}/nanobot-tmux-sockets}" mkdir -p "$SOCKET_DIR" SOCKET="$SOCKET_DIR/nanobot.sock" SESSION=nanobot-python tmux -S "$SOCKET" new -d -s "$SESSION" -n shell tmux -S "$SOCKET" send-keys -t "$SESSION":0.0 -- 'PYTHON_BASIC_REPL=1 python3 -q' Enter tmux -S "$SOCKET" capture-pane -p -J -t "$SESSION":0.0 -S -200
  • new -d:以 detached(分离)模式创建会话,Agent 无需真的附加到终端;
  • send-keys ... Enter:向 pane 发送命令并按下回车;
  • capture-pane -p -J -t ... -S -200:抓取最近 200 行 pane 输出(-J合并被折行的行,-S表示从倒数第 N 行开始)。

启动后,Skill 要求 Agent 总是打印一段 "monitor commands" 备忘,方便后续人工或 Agent 自己监控:

To monitor: tmux -S "$SOCKET" attach -t "$SESSION" tmux -S "$SOCKET" capture-pane -p -J -t "$SESSION":0.0 -S -200

Socket 约定

  • 一律使用环境变量NANOBOT_TMUX_SOCKET_DIR指定 socket 目录;
  • 默认 socket 路径为"$NANOBOT_TMUX_SOCKET_DIR/nanobot.sock"
  • 未设置该环境变量时,回退到${TMPDIR:-/tmp}/nanobot-tmux-sockets(该回退逻辑同样体现在 find-sessions.sh 中)。

这种 "每实例一个私有 socket" 的约定,将 nanobot 的 tmux 会话与其他 tmux 用户完全隔离开,是安全性的第一层保障。

定位与命名:target 格式与查询命令

tmux 的 target 格式为session:window.pane,未指定时默认为:0.0(即当前会话的第一个窗口的第一个 pane)。技能建议:

  • 会话、窗口名称保持简短,避免空格,方便作为 target 直接引用;
  • tmux -S "$SOCKET" list-sessions列出会话;
  • tmux -S "$SOCKET" list-panes -a列出所有 pane。

用 find-sessions.sh 查找会话

当会话散落在多个 socket 上时,直接使用仓库自带的辅助脚本:

# 列出当前 socket 上的会话 {baseDir}/scripts/find-sessions.sh -S "$SOCKET" # 扫描 NANOBOT_TMUX_SOCKET_DIR 下所有 socket {baseDir}/scripts/find-sessions.sh --all

脚本路径在仓库中为 nanobot/skills/tmux/scripts/find-sessions.sh(SKILL.md 中的{baseDir}即技能目录)。从源码看,它支持三类参数:

参数含义
-L, --sockettmux socket 名称(透传tmux -L
-S, --socket-pathtmux socket 路径(透传tmux -S
-A, --all扫描NANOBOT_TMUX_SOCKET_DIR下所有 socket(与-L/-S互斥)
-q, --query大小写不敏感的子串过滤会话名

脚本内部用list-sessions -F '#{session_name}\t#{session_attached}\t#{session_created_string}'格式化输出会话名、附加状态与创建时间,并标注attached/detached(见 find-sessions.sh)。--all模式只会处理目录下类型为 socket(-S判断)的条目,避免误伤普通文件。

安全输入:优先字面量发送

向 pane 发送按键是远程操控的核心动作,技能给出两条铁律:

  • 优先字面量发送tmux -S "$SOCKET" send-keys -t target -l -- "$cmd"-l(literal)会按字面解释按键,而不是把内容当作按键名称解析,可避免命令内容被 tmux 误解释;
  • 控制键单独发送tmux -S "$SOCKET" send-keys -t target C-c发送C-cC-dEnter这类控制键时不要使用-l,直接以按键名发送。

观察输出:抓取与等待

capture-pane 抓取历史

tmux -S "$SOCKET" capture-pane -p -J -t target -S -200

-S -200表示抓取倒数 200 行以内的历史输出,是 Agent 读取运行结果的标准姿势。-J合并折行,保证长行内容完整。

wait-for-text.sh 轮询等待

多数场景下 Agent 需要 "等到某个输出出现后再继续",仓库为此提供了轮询脚本 wait-for-text.sh:

{baseDir}/scripts/wait-for-text.sh -t session:0.0 -p 'pattern' [-F] [-T 20] [-i 0.5] [-l 2000]

参数说明(与脚本 help 一致):

参数含义默认值
-t, --targetpane target(必填)
-p, --pattern要匹配的正则(必填)
-F, --fixed将 pattern 视为固定字符串(对应grep -F关闭(默认grep -E
-T, --timeout超时秒数(整数)15
-i, --interval轮询间隔秒数0.5
-l, --lines参与匹配的历史行数(整数)1000

从 wait-for-text.sh 的实现看,脚本循环执行tmux capture-pane -p -J -t "$target" -S "-${lines}",将抓取结果交给grep匹配;命中即exit 0,超时则把最后lines行输出打印到 stderr 并exit 1。它还会校验timeoutlines必须为整数,并检查tmux是否在 PATH 中——这保证了脚本在 Agent 环境中的确定性。

人工附加

技能明确表示 attach 是被允许的,但要求用Ctrl+b d分离,避免长时间占用。

派生进程的注意事项

当目标程序是 Python REPL 时,务必设置PYTHON_BASIC_REPL=1

PYTHON_BASIC_REPL=1 python3 -q

技能文档指出:非 basic 的 REPL 会破坏 send-keys 流程。因为带语法高亮、行编辑等增强特性的 REPL 会向 TTY 发送 ANSI 转义序列并采用非标准的输入解析,字面量 send-keys 的结果会与预期不符;-q则关闭启动 banner,减少抓屏噪声。

Windows / WSL 支持

  • tmux 只支持 macOS / Linux;
  • Windows 上请使用 WSL,并在 WSL 内部安装 tmux;
  • 技能在元数据层被限定为darwin/linux,并要求tmux在 PATH 中,不满足条件的平台不会加载该技能。

实战:并行编排多个编码 Agent(Codex、Claude Code)

tmux 的最大价值场景是并行运行多个编码 Agent,每个 Agent 独占一个会话,互不干扰:

SOCKET="${TMPDIR:-/tmp}/codex-army.sock" # 创建多个会话 for i in 1 2 3 4 5; do tmux -S "$SOCKET" new-session -d -s "agent-$i" done # 在不同的工作目录启动 Agent tmux -S "$SOCKET" send-keys -t agent-1 "cd /tmp/project1 && codex --yolo 'Fix bug X'" Enter tmux -S "$SOCKET" send-keys -t agent-2 "cd /tmp/project2 && codex --yolo 'Fix bug Y'" Enter # 轮询完成状态(检查 shell 提示符是否已返回) for sess in agent-1 agent-2; do if tmux -S "$SOCKET" capture-pane -p -t "$sess" -S -3 | grep -q "❯"; then echo "$sess: DONE" else echo "$sess: Running..." fi done # 获取已完成会话的完整输出 tmux -S "$SOCKET" capture-pane -p -t agent-1 -S -500

实战要点(来自 SKILL.md 的 Tips):

  • 并行修复不同问题时,使用独立的 git worktree,避免分支冲突;
  • 对全新 clone 的仓库,先执行pnpm install再运行 codex,避免依赖安装期间 Agent 空转;
  • 以 shell 提示符($)是否出现来判断 Agent 是否完成;
  • Codex 需要--yolo--full-auto才能进行非交互式修复。

这套模式的核心是 "创建会话 → 注入命令 → 抓屏轮询 → 读取结果",与 wait-for-text.sh 结合后,还可以把grep -q "❯"的轮询升级为等待具体输出模式。

清理:回收会话与 socket

会话用完后必须清理,避免资源泄漏:

# 杀掉单个会话 tmux -S "$SOCKET" kill-session -t "$SESSION" # 杀掉该 socket 上的所有会话 tmux -S "$SOCKET" list-sessions -F '#{session_name}' | xargs -r -n1 tmux -S "$SOCKET" kill-session -t # 彻底移除私有 socket(连 server 一起结束) tmux -S "$SOCKET" kill-server

kill-server会终止该 socket 对应的整个 tmux server,是清理私有 socket 的最彻底方式;对于共享 socket 则建议按会话逐个 kill。

技能如何被 nanobot 加载

tmux Skill 位于仓库 nanobot/skills/tmux/ 目录,是 nanobot 的内置技能之一(完整列表见 skills/README.md)。加载机制集中在 nanobot/agent/skills.py:

  • BUILTIN_SKILLS_DIR指向nanobot/skills(见 skills.py),SkillsLoader._skill_entries_from_dir遍历每个子目录寻找SKILL.md(见 skills.py);
  • frontmatter 的name/description是技能触发与身份识别字段,metadata中可携带requires.binsrequires.envalwaysos等扩展信息;
  • _check_requirementsshutil.which校验bins、用os.environ校验env,不满足则技能标记为 unavailable(见 skills.py);
  • Agent 会话构建上下文时,会通过build_skills_summary以渐进式加载的方式把技能名、描述与可用性注入上下文,Agent 按需用 read_file 读取完整 SKILL.md(见 skills.py)。

此外,用户可以在配置中通过agents.defaults.disabledSkills屏蔽不需要的内置技能(见 docs/configuration.md 中关于 disabledSkills 的说明)。该技能目录的 layout(SKILL.md+scripts/)也完全符合 skill-creator 技能所描述的 "SKILL.md 保持精简、确定性逻辑下沉到 scripts" 的渐进式披露原则。

小结

tmux Skill 为 nanobot 的 Agent 提供了一套低成本、确定性的 "交互式 TTY 远程控制" 能力:私有 socket 隔离环境、字面量发送保证输入可靠、capture-pane + wait-for-text.sh 实现输出观察与同步等待,多会话并行则让编码 Agent 编排成为可能。配合 find-sessions.sh 与 wait-for-text.sh 两个经过参数校验的脚本,整套流程既适合 Agent 自主执行,也方便人工介入排障。需要特别牢记的是:tmux 只用于真正需要交互式 TTY 的场景,非交互的长时间任务应交给 exec 后台模式,这也是技能文档开篇反复强调的边界。

【免费下载链接】nanobotUltra-lightweight, open-source, self-hosted personal AI agent framework in Python with WebUI, tools, memory, MCP, multi-agent workflows, automation, and chat apps项目地址: https://gitcode.com/gh_mirrors/nanob/nanobot

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询