多 Agent 时代的终端困局:工具还停留在单任务时代
2026 年的重度用户早就不是开一个 agent 了:主开发一个、review 一个、跑测试一个、查文档一个、研究依赖一个。然后问题来了——终端这个基础设施还是 tmux 时代的设计:
- 关终端 = 杀进程。笔记本合盖、SSH 断线、终端 app 崩溃,你的 agent 就死了。跑了一半的长任务全部白费。
- 不知道谁在等你。五个 pane 里有一个 agent 卡在权限审批上等你点确认,你得挨个切过去看。浪费的是 agent 的时间,烧的是你的 token。
- agent 之间无法协作。review agent 想等主 agent 改完再跑,只能靠你人肉传话。
- agent 看不见你的「工作区」。它不知道隔壁 pane 在干嘛,不知道哪个服务已经起来了。
这个工坊写过一堆解决部分问题的工具:cmux(macOS 专属的 Ghostty 终端)、claude-squad(tmux + worktree 编排)、superset 和 orca(Electron 桌面 IDE)。但它们要么是 GUI 壳、要么是 tmux 包装、要么平台受限。herdr 选了一个没人做过的角度:做一个常驻 server,直接接管终端本身,把「agent 是活物」这件事做成第一公民。
它是什么:server 住在后台,终端们住在 server 里
herdr 是一个 Rust 写的终端工作区管理器,单二进制(linux-x86_64 约 21MB,无 Electron),Apache-2.0。架构一句话:后台常驻 server 拥有所有 PTY 和进程,TUI 只是一个可以随时断开重连的客户端。
| 层 | 是什么 | 例子 |
|---|---|---|
| Workspace | 顶层项目容器,一个仓库/任务一个 | w1(sidebar 状态按 workspace 汇总) |
| Tab | workspace 内的布局页 | w1:t1(agents / logs / server 分开放) |
| Pane | 一个真实终端,PTY 归 server 管 | w1:p1、w1:p2 |
| Agent | pane 里被识别出来的 coding agent 进程 | Claude Code / Codex / Hermes / Pi / Qwen…20+ 种 |
跟 tmux 的本质区别:tmux 只分屏,不知道里面跑的是什么;herdr 给每个 pane 挂了agent 状态机——blocked(等你审批)、working(干着呢)、done(干完了你没看)、idle(闲着)、unknown(认不出来)。sidebar 把状态一路向上汇总:一个 blocked 的 agent 会让它的 pane、tab、workspace 全部显示「需要你」。开了八个 agent 也不用挨个切。
核心机制一:agent 状态是怎么被「看见」的
状态检测有两条路径,按优先级:生命周期 hooks(integration)> 屏幕快照匹配(screen manifest)。官方 integration 装了之后(herdr integration install claude),agent 通过 hook 主动上报 idle/working/blocked,这是权威来源;没装 integration 的 agent 靠读取 pane 底部缓冲区的实时屏幕快照,跟内置的 TOML 规则匹配——识别到「等待审批」的 UI 形状就标 blocked。规则还能从远端热更新(herdr server update-agent-manifests),不用升级二进制。
| Agent | 状态权威 | 会话恢复 |
|---|---|---|
| Claude Code / Codex / Grok / Devin / Qwen / Hermes… | screen manifest(屏幕规则) | --resume <id> 原生恢复 |
| Pi / OMP / Kimi Code / OpenCode / Kilo / MastraCode | lifecycle hooks(装了 integration 时) | --session <path> 原生恢复 |
| Gemini CLI / Cline | 可检测,测试较少 | — |
blocked 检测是故意保守的:只有屏幕快照明确匹配到已知的审批/提问 UI 才算 blocked,认不出来的新 UI 会落到 idle 兜底(herdr agent explain 能告诉你为什么这么判)。宁可漏报也不误报——这设计很清醒。
核心机制二:持久性是个四级体系
「关终端 agent 不死」不是一句空话,herdr 用四级机制实现,从强到弱:
| 场景 | 进程还活着吗 | 布局回来吗 | 屏幕回来吗 | 会话续上吗 |
|---|---|---|---|---|
| detach / 重连(ctrl+b q) | ✅ 活着 | ✅ | ✅ 活的终端 | ✅ 进程没停过 |
| server 重启 | ❌ 没了 | ✅ 快照恢复 | 仅开 pane_history 时 | ✅ 原生 session restore(16 种 agent 支持 --resume) |
| 升级 --handoff(实验) | ✅ 尽力转移活 pane | ✅ | ✅ | ✅ |
注意两个默认值:pane_history(屏幕历史持久化)默认关,因为 pane 输出里可能有密钥和 token;native session restore 默认开——server 重启后,装了官方 integration 的 agent 会自动用 claude --resume <id> 之类的命令把会话续回来,不用你手动重开。远程场景 herdr --remote workbox 直接 SSH 过去 attach,本机按键绑定不变。
核心机制三:agent 可编程化——CLI、socket API、SKILL.md 三件套
herdr 最好玩的是它把整个会话暴露成了编程接口。CLI 全部输出 JSON,背后是同一个 socket API(协议 v19,90+ 个方法:agent.prompt、agent.wait、pane.wait_for_output、workspace.create、worktree.create…)。再加一个官方 SKILL.md(npx skills add herdrdev/herdr --skill herdr -g),装进你的 coding agent 后,agent 自己就能:
- 开 sibling pane 跑命令,不抢你的焦点(
--no-focus) - 读别的 pane 的输出(
pane read) - 等一个 server 起来(
pane wait-output --match "listening") - 等另一个 agent 干完或卡住(
agent wait reviewer --until blocked) - 起一个 helper agent 干活(
agent start reviewer --kind codex)
skill 第一条是安全守门:test "${HERDR_ENV:-}" = 1——只有确认自己真的跑在 herdr 管理的 pane 里才允许碰 CLI,防止外面的 agent 乱控别人的会话。这个设计值得所有 agent 工具抄。
上手:实测跑通的命令序列
# 安装(curl 脚本 / brew / mise 都行) curl -fsSL https://herdr.dev/install.sh | sh herdr --version # v0.8.0 # 起 server(headless 也行,不需要 TUI 客户端) herdr server # 或直接 herdr 进 TUI # 建工作区 + 分屏 + 跑长命令 herdr workspace create --cwd ~/proj --label api --no-focus herdr pane split w1:p1 --direction right --no-focus herdr pane run w1:p2 'npm test' # 读输出 / 等输出(agent 自动化最爱) herdr pane read w1:p2 --source recent-unwrapped --lines 120 herdr pane wait-output w1:p2 --match "test result" --timeout 120000 # 起一个 agent 并驱动它 herdr agent start h1 --kind codex --pane w1:p2 herdr agent prompt h1 "Review the current diff" --wait --timeout 120000 herdr agent wait h1 --until blocked --timeout 60000 # 等它卡住找你 # 断开 / 重连 / 停服 ctrl+b q # detach,agent 继续跑 herdr # 重连 herdr server stop # 结束会话,停掉所有 pane
实测与踩坑(v0.8.0,Linux headless)
这台机器上没有显示器,正好测它的无头形态。全链路:herdr server 后台起 → workspace/split/pane run/read 全部 JSON 返回 → 模拟状态上报 blocked 立刻进 agent list → agent start h1 --kind hermes 真实拉起 Hermes TUI(检测到 idle、interactive_ready)→ agent prompt h1 真实驱动它调 DeepSeek 回了一句 PONG-herdr,--wait 等到状态回 idle 才返回 → server stop 重启后 workspace 快照恢复,两个 pane 以新 shell 回来。全部跑通。坑有两个:
- 坑 1:
pane wait-output --match DONE提前返回。我往 pane 里跑了个循环脚本(for i in $(seq 1 5); do echo tick-$i; sleep 1; done; echo DONE),等 DONE 出现,结果命令还在 tick-3 就返回了——因为--match是子串匹配,匹配到了你自己敲进去的那行命令回显(循环体里就含 "echo DONE")。等「输出」时要么用--regex '^DONE$'锚定,要么匹配一个命令文本里不会出现的独有字符串。 - 坑 2:
pane report-agent上报的名字不能当 agent target 用。自定义上报--agent codex-sim后,agent list里看得到(状态 blocked 也生效),但agent get codex-sim直接agent_not_found。只有agent start起的命名 agent 或 pane ID(w1:p2)能作为 target。想用自定义 label 编排,得走agent start的命名机制。 - 小坑:读输出选对 source。
--source recent有时返回空(缓冲被裁剪),recent-unwrapped(软换行合并)更稳,visible是当前屏幕快照;agent 跑在 alternate screen 时滚动历史读不到,官方 skill 的建议是让 agent 把完整回复写文件再读。
对比:跟工坊写过的「多 agent 终端」们
| 工具 | 形态 | 进程保活 | agent 感知 | 可编程 | 平台 |
|---|---|---|---|---|---|
| herdr | Rust 常驻 server + TUI | ✅ detach/SSH/重启(四级) | ✅ 状态机 + 20+ 种检测 | ✅ CLI/socket/SKILL | Linux/macOS/Win beta |
| cmux | Ghostty 原生终端 | ✅ 终端级 | 部分(标签显示 git/PR) | ❌ | macOS only |
| claude-squad | Go 二进制(tmux 包装) | ✅ tmux 保活 | 部分(agent 状态有限) | CLI | 跨平台 |
| superset | Electron 桌面 IDE | ✅ 应用级 | ✅ worktree 隔离 | MCP | 桌面 |
| 裸 tmux | 分屏器 | ✅ 但进程照跑 | ❌ 完全不知道谁是谁 | 脚本 | 跨平台 |
一句话:cmux 是「给 agent 用的终端」,superset/orca 是「管 agent 的 IDE」,herdr 是「agent 住进去的运行时」——它不包装任何 agent,只管它们的终端、状态和通信。
什么时候别用它
说点反话:单 agent 轻量用户不需要它,裸 tmux 够用;需要沙箱隔离的,herdr 明确不做安全沙箱(agent 有你的权限,跑不可信代码请上 Docker/VM);重度 GUI 偏好者选 superset 更顺手;macOS 用户想少装一个 Rust 二进制可以先用 cmux。但如果你已经开着多个 agent、为「合盖丢进度」和「不知道谁在等我」烦过——这就是那个把终端从「工具」升级成「基础设施」的东西。4 个月 3 万 star,v0.8.0 刚从 AGPL 改 Apache-2.0,方向赌对了。