Agent-first 终端控制面深入报告:从 PTY、状态感知到多 Agent 编排

AI 时代的 terminal 正在发生一次职责上移:它不再只渲染字符、托管 shell 或复用 pane,而是在尝试理解“哪个 Agent 正在做什么、谁需要人、怎样被程序控制、重启后怎样继续”。这已经是控制面,只是它主要控制的是本地执行,而不是组织承诺。

Terminal 从字符渲染、进程复用到 Agent-first 控制能力的范围对照。

信息图 A|从 terminal data plane 到 Agent-first control 的能力阶梯;最上层仅用于标示产品能力边界,不表示 terminal 与某种外部控制面存在固定的部署关系。原创分析图;生成记录见 ImageGen Manifest。

研究范围:主样本为固定提交的 cmux 17466308 与 Herdr d6dae883;Ghostty、Warp/Oz、Orca 与 tmux 只用于能力边界对照。完整文件级证据、版本、链接和未验证项见 Source Manifest;研究问题与验收标准见 Research Spec。

文中使用三种措辞:

  • 实现事实:固定提交源码、同提交文档或官方文档直接支持;
  • 跨项目归纳:cmux、Herdr 或其他对照样本出现相似职责,但对象名与实现不同;
  • 设计建议:本文为自建系统提出的接口与模块,不代表任何项目已经采用。

先给结论

如果只记住一个公式,可以记住:

Agent-first terminal = 可持久的 PTY 容器 + Agent 语义层 + 注意力路由 + 可编程控制接口 + 分级恢复。

它与传统 terminal、tmux 和完整 Agent 产品控制面之间的区别,不在于“是否有 AI 按钮”,而在于控制对象逐级变化:

Terminal        控制字符、屏幕和输入输出
Multiplexer     控制 PTY、pane、布局和进程存活
Agent terminal  控制 Agent 身份、状态、注意力、Session 与自动化
Product plane   控制任务意图、owner、依赖、预算、权限、验收与审计

本次源码研究得到十二个核心判断:

  1. Agent-first 的关键不是内置一个聊天模型,而是 terminal 开始维护 Agent 语义。 能区分 plain shell 与 Agent、识别 working / blocked / done / idle、保存原生 Session 引用,并把状态向上聚合,才算跨过分界线。
  2. terminal 控制面首先是边缘控制面。 它最擅长掌握 PTY、进程、cwd、屏幕、输入和本地 Session;它通常不知道任务为何存在、谁承诺了什么、什么叫验收通过。
  3. 可编程执行容器不是“暴露一个 pane ID”就结束。 当 terminal 希望让人、脚本和其他 Agent 共同控制一个执行单元时,它至少要提供可寻址、可观察、可驱动、可等待、可恢复、可订阅的接口,并有明确的信任边界。
  4. 最难的不是启动 Agent,而是回答“现在是什么状态,谁说了算”。 进程名只能证明身份,屏幕与 OSC 容易误判,hooks 可能漏报;一个可靠实现必须显式仲裁状态来源。
  5. cmux 与 Herdr 代表两条不同路线。 cmux 是原生 macOS GUI:以稳定 surface、语义事件日志、通知、browser 和大范围 CLI/socket primitives 构建控制面;Herdr 是 server-owned PTY multiplexer:以 foreground process、screen manifests、单一 hook authority 和强 Agent API 构建语义运行时。
  6. “未读”是 Agent 状态之外的第二维。 Herdr 用 state + seen 把已经完成但尚未看过的 idle 映射为 done;cmux 用 notification queue/unread/ring 把需要注意的 pane 提升到 workspace。这个维度无法只靠 Agent 生命周期表达。
  7. read / send / wait 比“打开很多 pane”更接近编排。 只有稳定选择器、结构化读取、状态等待、事件订阅和超时,另一个 Agent 才能可靠地驱动目标 Agent;模拟键盘仍然是最弱的一环。
  8. 恢复不是一个功能,而是四种不同连续性。 detach 保留原进程;snapshot 只重建布局;native resume 重建 Agent 对话;live handoff 转移 PTY/进程。把它们都叫“Session restore”会制造错误预期。
  9. Agent Session ID 不是进程,也不是 pane。 同一 pane 可以运行不同进程;同一原生 Agent Session 不应被两个 pane 同时恢复;layout identity、runtime identity 与 conversation identity 必须分开。
  10. terminal 已经可以协调 Agent,但通常还不能治理 Agent。 cmux Teams 和 Herdr 的 Agent API 能创建 pane、发 prompt、等待状态、收集结果;但 owner、依赖、产物验收、成本与审计仍应在上层控制面。
  11. 本地并不自动安全。 socket 控制、输入注入、屏幕读取、scrollback 持久化、Session ID、自动 resume command 与 SSH 转发都跨越信任边界;控制接口本身等同于代码执行能力。
  12. 最值得抄的不是某个 UI,而是一组深模块。 Container Registry、Agent Adapter、State Arbiter、Attention Router、Session Ledger、Recovery Planner、Control API 与 Policy Gate 应彼此分离。

零、先把 Herdr 当成一款软件用

后文会出现 PTY、state authority、screen manifest、Session ref、event sequence 等概念。如果还没有形成产品画面,这些词很容易变成一堵实现细节墙。先暂时忘掉源码,把 Herdr 当成一个“专门同时看守多个 Agent TUI 的 tmux”用十分钟:打开一个项目,分成两个终端,各运行一个 Agent,只在侧边栏需要你时切回去,然后离开并重新连接。

1. 一屏看懂 Herdr

Herdr 官方桌面界面:左侧汇总 workspace 与 Agent 状态,中间和右侧是保留完整 TUI 的真实终端 pane。

官方界面截图|Herdr 固定提交 d6dae883 的仓库资产,Apache-2.0;本地副本与 SHA-256 见 Source Manifest。

这张图可以分成五个区域来读:

界面区域用户看到什么它替用户记住了什么
左上 workspace 列表herdr、pi-extensions 等项目,旁边带状态点哪些项目存在;哪个项目里有 Agent 仍在工作或需要关注
左下 agents 列表pi idle、claude working 等跨 workspace 汇总不必逐 pane 轮询;可以直接跳到某个 Agent
中央 pane一个完整 Agent 对话或普通 shell这里是真实终端,不是控制面重新摘要过的聊天记录
蓝色 pane 边框当前焦点所在的 terminal键盘输入发给谁;哪个完成结果已经被用户“看过”
pane 内部 TUICodex、Claude 等 Agent 自己的输入框、工具调用和状态栏Agent 仍拥有自己的交互协议、上下文与权限 UI

Herdr 并没有把 Claude、Codex 改造成自己的聊天组件。它保留每个 Agent 的原生 TUI,只在外围补上项目组织、稳定终端、状态汇总、跳转和自动化。这一点是理解全文的起点:Herdr 控制的是装着 Agent 的终端,而不是替代 Agent Runtime。

2. 十分钟完成第一次使用

以 macOS 或 Linux 为例,可以用 Homebrew 安装,然后从项目目录启动:

brew install herdr
cd ~/Projects/my-project
herdr

官方也提供安装脚本、mise、Nix、Windows 和手动二进制方式;这里不展开成安装手册。第一次执行 herdr 时,它会启动或连接默认后台 Session;没有 workspace 时自动创建一个 workspace、一个 tab 和一个根 pane。你看到 shell 提示符时,已经同时拥有了 Herdr client、后台 server、workspace/tab/pane 拓扑和一个真实 PTY。

接下来可以完全用鼠标操作:在第一个 pane 运行 codex;右键选择向右分割;在新 pane 运行 claude;拖动分割线调整大小;点击左侧 Agent 或任一 pane 切换焦点。Herdr 从 foreground process 自动识别两个 Agent,并把状态显示到侧边栏。

如果更喜欢键盘,prefix 默认是 ctrl+b:先按下并松开 ctrl+b,再按动作键。先记六个就够:

用户动作默认按键鼠标等价操作
向右 / 向下分割prefix+v / prefix+minuspane 右键菜单选择 split
在 pane 间移动prefix+h/j/k/l直接点击 pane
新建 tabprefix+c右键创建 tab
打开 workspace / Agent 导航prefix+w点击左侧项目或 Agent
查看全部生效快捷键prefix+?—
分离 client、让进程继续prefix+q关闭当前终端窗口也可分离

这里最容易混淆的是最后一项:prefix+q 不是退出 Agent。它只让当前 TUI client 离开后台 Session;Herdr server、PTY、Codex 和 Claude 仍继续运行。稍后再次执行 herdr,会连接回原 Session。只有 herdr server stop 才会停止默认 server,并结束其中的 pane 进程。

3. 侧边栏状态就是主要交互

Herdr 的日常循环不是频繁切 pane,而是让 Agent 在后台工作,只根据侧边栏决定下一眼看哪里:

状态界面语义用户通常做什么
workingAgent 仍在运行继续做别的事,不必进入 pane 轮询
blocked检测到审批、问题或输入请求跳到该 Agent,阅读原生 TUI 后作决定
doneAgent 已经停下来,但完成后尚未被查看切过去检查结果、diff 或测试
idleAgent 已停下来,而且相关 pane 已被查看可以继续输入新任务,或暂时忽略
unknown已识别 Agent,但无法可靠判断生命周期仍按普通 terminal 使用,不把状态点当事实

done → idle 很能说明为什么这类产品不只是给进程加颜色:Agent 底层可能一直都是 idle,变化的是 seen / unseen。当后台 Agent 停下来,Herdr 显示 done;当你聚焦该 tab/pane 后,它才成为 idle。仅用 CLI 读取输出不会把它标成已看,界面焦点才会改变 attention state。workspace 旁的状态点则是内部 Agent 状态的优先级汇总,而不是另一个独立任务状态。

4. 同一套能力有三种入口

Herdr 的特殊之处不是另做了一套“自动化模式”,而是鼠标、快捷键、CLI 和其他 Agent 最终操作同一份 server-owned 状态:

入口适合谁典型动作
TUI / 鼠标人类日常工作split、focus、resize、查看 blocked/done、直接回答权限问题
CLI / socket API脚本与外部工具查询拓扑、读屏幕、发输入、等输出或 Agent 状态
Herdr Skill运行在 Herdr pane 内的另一个 Agent创建 helper pane、分配工作、等待、收集结果

先用只读命令观察界面背后的对象即可:

herdr workspace list
herdr agent list
herdr agent get w1:p2
herdr agent explain w1:p2
herdr agent wait w1:p2 --until blocked --until done --timeout 120000
herdr agent read w1:p2 --source recent-unwrapped --lines 80

实际使用时,应从 workspace list、pane list 或 agent list 的返回值取得 ID,不要照抄 w1:p2 猜目标。agent explain 用来回答“为什么它显示这个状态”;agent wait 等语义状态;agent read 读取目标 Agent 的真实终端内容。这三个命令分别对应后文的可解释性、可等待性和可观察性。

5. 把一次操作映射到后文概念

下面这张表是全文的阅读索引。后文每个看似抽象的概念,都可以还原成刚才经历过的一个界面动作:

刚才的用户动作界面结果内部真正发生的事后文对应
在项目目录执行 herdr出现 workspace 和根 paneclient 连接后台 Session;server 创建/恢复 workspace、tab、pane 与 PTY第二、六章
右键或 prefix+v 分割多出一个真实 terminallayout registry 创建新 pane identity 与 PTY第二、三章
在 pane 中执行 codex / claude侧边栏出现 Agent 名称与状态foreground process detection 把当前 pane occupant 识别成 Agent第四、六章
后台 Agent 停下来workspace/Agent 出现 donelifecycle state 与 seen 合成 attention state,再向上汇总第二、四、六章
点击 done Agent跳到正确 pane,状态变 idlestable pane/Agent selector 完成寻址;focus 更新 seen第二、六章
prefix+q 后再次执行 herdr回到原进程与原屏幕client detach/attach;原 server 和 PTY 从未停止第六、十章
server 真正重启布局回来,但任意进程未必还在snapshot 重建 topology;受支持 Agent 可用 native Session ref 启动新进程继续对话第十章
CLI read / wait / send脚本也能控制同一个 pane/Agentsocket API 在 identity guard、state sequence 与 policy 下操作 server registry第三、六、九、十一章

如果先记住这条用户旅程,后文就不是八组陌生模块,而是在回答八个具体问题:Herdr 怎么找到正确 pane?状态点为什么可信?done 为什么会随查看消失?关窗口后进程为什么还在?重启后又究竟恢复了什么?脚本为什么能等待 Agent 而不只是盲发键盘?


一、为什么半年内会出现这么多“新 terminal”

Claude Code、Codex、Gemini CLI、Pi、Hermes、OpenCode 等 Agent 把大量软件开发重新拉回 terminal。原因不是 terminal 比 GUI 更现代,而是它已经拥有 Agent 最需要的几个原语:任意命令、真实文件系统、现有凭据、编译器和调试器、SSH、管道、脚本,以及可以长时间运行的交互式进程。

但传统 terminal 的对象模型仍停留在“人盯着一个前台程序”:

  • terminal emulator 解析 VT/ANSI 字节流并渲染屏幕;
  • shell 启动命令;
  • tmux/Zellij 之类 multiplexer 让 PTY 和 pane 在客户端离开后继续存在;
  • 用户自己记住哪个 pane 在做什么,并轮询它是否需要输入。

单 Agent 时,这些缺口可以靠人的短时记忆掩盖。十几个并行 Agent 出现后,人遇到的是一个调度问题:

  • 哪个 Agent 正在工作,哪个已经完成?
  • 哪个停在权限确认、问题或计划审批?
  • 哪个输出还没看过?
  • 当前 pane 属于哪个 repo、branch、worktree 和原生会话?
  • 能否从脚本或另一个 Agent 读取、发送、等待,而不是人工切 pane?
  • app、server 或机器重启后,到底能继续什么?

所以这批产品虽然外形差异很大——native terminal、TUI multiplexer、worktree IDE、cloud agent shell——却在共同补一层东西:把“多个黑盒 PTY”提升为“多个有身份、有状态、可寻址、可恢复的 Agent 执行单元”。

1. 能力阶梯

层级控制对象解决的问题典型能力典型代表(主要覆盖)仍然不知道什么
L0 Terminal data plane字节、cell、screenTUI 能否正确显示与输入VT/ANSI、字体、GPU 渲染、clipboardGhostty / libghostty、xterm.js、AlacrittyAgent 身份与任务
L1 MultiplexerPTY、pane、session进程能否持续、布局能否复用split、detach/attach、scrollbacktmux、Zellij、GNU screen谁需要注意
L2 Attention controlnotification、seen/unread人应先看哪里ring、badge、jump、rollupcmux notification rings / unread、Orca Needs You / done-unread可靠生命周期
L3 Agent semanticsAgent、phase、session refpane 里是谁、在做什么hooks、manifest、working/blocked/idleHerdr process/screen/hook 状态权威、cmux Agent Journal、Orca Agent hooks业务验收
L4 Programmable containerselector、command、event人/脚本/Agent 能否统一控制read/send/wait/subscribe/resumeHerdr Agent/socket API、cmux CLI/socket/browser API、Orca CLI组织承诺
L5 Product control planetask、owner、dependency、budget为什么做、谁负责、是否完成queue、lease、approval、auditWarp / Oz—

这里的“典型代表”不是互斥的产品分类,而是用来说明每一级新增了什么职责。同一产品通常纵向跨层:cmux 从 libghostty 数据面一直覆盖到可编程 API,Herdr 从持久 PTY 覆盖到 Agent/socket API,Orca 从终端容器覆盖到 Agent 感知与 CLI,而 Warp / Oz 已进一步进入任务、委派和治理所在的产品控制面。L5 只是能力范围的对照项,不表示它与 L0–L4 必须组成一套上下层系统。

Ghostty 很好地说明了 L0 与上层的分工。官方把核心拆为跨平台、C ABI 的 libghostty,负责 terminal emulation、字体和渲染;GUI 承担平台原生 tabs/splits 等界面。cmux 直接复用 libghostty,把研发精力投入 workspace、通知、browser、Agent hooks 和控制 API。这不是“Ghostty 不够 Agent-first”,而是稳定 terminal core 让更上层的控制面可以独立生长。


二、通用对象模型:Agent 不等于 pane,也不等于 Session

不同产品命名不一致,但两个主样本呈现出相似的执行拓扑:

Mermaid diagram

图 1|通用对象关系。它是跨项目归纳,不是 cmux 或 Herdr 的官方类图。

需要刻意分开四种身份:

  1. 布局身份:workspace、tab、pane/surface。用于找到“屏幕在哪里”。
  2. 运行身份:PTY、foreground process group、PID。用于判断“什么在运行”。
  3. Agent 身份:claude、codex、pi 或自定义 label。用于判断“谁在运行”。
  4. 会话身份:Agent 自己的 conversation/session ID 或 path。用于判断“重启后继续哪段上下文”。

这四者的生命周期不同。pane 可以活着但 Agent 已退出;一个新 Agent 可以复用旧 pane;app 重启后 pane 被重建但原进程已不存在;native resume 可以在新 PID 中延续旧 conversation。把它们压成一个 session_id,几乎一定会在恢复、并发或重绑定时出错。

Herdr 的实现已经把这种分离写进类型:PaneState 只保存 attached terminal 与 seen;TerminalState 保存 cwd、detected agent、fallback state、hook authority、native session reference、revision 和 launch argv;PaneAgentSessionSnapshot 再只保存 source / agent / kind / value。cmux 则把 CMUX_SURFACE_ID 当作 hook 归属与恢复绑定的关键身份,同时区分 workspace、surface 和 Agent native session。

done 为什么通常不是 Agent 原生状态

Herdr 的底层 AgentState 只有 Idle / Working / Blocked / Unknown。用户看到的 done 来自另一个事实:Agent 已 idle,但这个 pane 自状态改变后还没被用户看过。源码中 PaneState.seen 与 AgentState 分开保存,workspace 聚合优先级则把 blocked、unseen idle、working、seen idle、unknown 排序。

这揭示了一个通用设计:

Agent lifecycle 回答“机器在做什么”;attention state 回答“人是否处理过这次变化”。

把二者混在单一 enum 中,会让“完成但未读”“等待用户但已查看”“后台仍在工作”之间难以演化。

回到 Herdr 界面: 左侧的 claude working 不是 pane 本身的名字;它是 Herdr 先用 pane 找到 PTY,再用 foreground process 识别 Agent,最后把有效生命周期与 seen 合成出来的视图。点击这一行时,Herdr 用稳定 Agent/pane identity 跳转,而不是按屏幕标题猜位置。


三、终端如何成为可编程的 Agent 执行容器

这里的“容器”只是功能比喻:它不是 Docker 容器,也不意味着把终端暴露到公网。它指 terminal 将一个承载 Agent TUI 的执行单元,通过稳定身份、结构化状态、命令、事件和恢复接口,开放给 UI、脚本、插件、远程客户端与其他 Agent 控制。这样的可编程执行容器需要七项契约。

可编程的 Agent 执行容器需要稳定身份、执行上下文、可观察、可驱动、可等待、可恢复与策略边界。

信息图 B|可编程执行容器的七项契约。容器不是 pane 外观,而是一组跨生命周期接口。

契约最低要求cmux 例子Herdr 例子缺失后的故障
Addressable稳定 ID、selector、当前上下文UUID、refs、CMUX_SURFACE_IDworkspace/tab/pane public IDs、agent name事件归错 pane;脚本依赖焦点
Structuredworkspace/tab/pane 拓扑可查询tree、list/create/move/splitworkspace/tab/pane schema 与 layout API只能模拟快捷键
Observable读 screen、process、cwd、state、revisionread-screen、top、sidebar statepane.read、agent.get/explain只能盲发输入
Actuatablesend text/key、focus、run、promptsend、send-key、browser APIpane.send_*、agent.prompt无法自动处理交互
Waitable状态/输出等待、timeout、identity guardreconnectable events;通知流agent.wait、events.wait、output matchpolling、竞态、误把旧结果当新结果
Recoverablelayout、screen、process、Agent Session 分级恢复snapshot + native resume + trusted bindingdetach + snapshot + native resume + handoff“恢复”含义不清;重复恢复
Policy-boundsocket ACL、command trust、secret handlingpassword/socket、signed resume prefix、env sanitizelocal socket 权限、handoff token、history opt-in控制 API 变成无门槛 RCE

真正的分界是 wait

send 很容易实现,本质是向 PTY 写字节;read 也可以从 emulator buffer 截取文本。但自动化是否可靠,取决于是否能表达:

  • 等目标 Agent 进入一组语义状态;
  • 只接受这次 prompt 之后发生的变化;
  • 目标进程或 Session 被替换时立即失败;
  • 超时返回结构化错误;
  • 短暂状态不会因为轮询间隔而丢失。

Herdr 的 agent.prompt --wait 会先记录 state_change_seq,要求 prompt 后五秒内观察到活动,再等待目标状态;等待期间还会验证 terminal identity、Agent identity 与事件序列。这个实现已经比“每秒读取一次屏幕”可靠得多,但官方文档也明确提醒:它等待的是状态,不是严格的 turn correlation;如果目标本来就在 working,一个既有回合可能满足条件。

因此自建协议还应增加 turn_id / command_id / causation_id。状态等待解决“什么时候安静下来”,因果标识才解决“是不是我刚才发起的工作完成了”。

回到 Herdr 界面: 鼠标点击 pane、prefix+w 选择 Agent、CLI 的 agent get/read/wait 看似是三种交互,其实都需要同一项基础能力:先稳定找到目标,再对目标当前 occupant 做操作。七项契约就是把“这个界面很好用”翻译成可以实现和测试的系统属性。


四、状态权威:terminal 控制面最难的核心

状态识别通常有四类信号,它们回答的问题不同:

信号能证明什么不能可靠证明什么典型风险
Foreground processpane 当前是否由已知 Agent 进程占用Agent 正在思考、等待还是完成wrapper/runtime 名称、子进程、进程切换
Screen / OSC当前 TUI 最近显示了什么完整生命周期、因果与长期身份文本误匹配、历史内容、UI 版本变化
Lifecycle hook/pluginAgent 主动声明语义事件hook 未覆盖的路径、进程是否仍活着漏报、乱序、旧 Session 延迟事件
Native session reference可恢复哪段 Agent conversation当前运行状态、任务完成stale/duplicate ref、Provider 兼容变化

Agent 状态需要经过进程识别、屏幕或 Hook 信号、单一状态权威、序列归约与注意力聚合。

信息图 C|状态权威与注意力路由。身份、生命周期、会话连续性和是否已读是四类不同事实。

Mermaid diagram

图 2|不要直接把任一输入信号写进 UI;先显式仲裁,再生成有效状态。

1. Herdr:一个 pane 只能有一个状态 authority

Herdr 先从 foreground process 识别 Agent;然后在两条状态路线中选一条:

  • 对 Pi、OMP、OpenCode、Kimi、MastraCode 等具有完整 lifecycle integration 的 Agent,live hook/plugin 上报是 authority;同一时刻不再让 screen fallback 与它竞争。
  • 对 Claude、Codex、Hermes 等只上报 Session 身份或 hook 不完整的 Agent,仍由 bottom-buffer screen manifest 与 OSC 信号判定状态,Session report 只负责恢复身份。

源码把仲裁集中在 TerminalState:HookAuthority 带 source / agent_label / state / reported_at / session_ref;设置 authority 时检查 source sequence、foreground Agent 冲突、Session owner 冲突、进程退出和旧 Session 延迟事件。完整 lifecycle authority 存活时,visible blocker 也不能反向覆盖它。

这比简单的优先级表更重要:authority 不是“hook 总比 screen 强”,而是与具体 Agent、当前 foreground process 和 Session ownership 绑定。 当进程退出或 Session 被替换,authority 必须释放;否则旧 hook 可以把一个已经变成 shell 的 pane 永久标成 working。

2. Screen detection 不是正则堆,而是小型感知系统

Herdr 的 screen route 包含几个容易被忽略的可靠性细节:

  • 读取 recent bottom-of-buffer,而不是用户滚动后的 viewport;
  • manifests 可以同时匹配 screen、OSC title 与 OSC progress;
  • 把 visible_idle / visible_blocker / visible_working 作为置信元数据,而不只返回 enum;
  • working → plain idle 需要短暂多次确认,避免 TUI 重绘瞬间抖动;
  • Agent 自己的 transcript/history viewer 可以设置 skip_state_update,避免浏览旧文本改变 live state;
  • agent explain 暴露 manifest、匹配规则与证据,状态误判可以调试,而不是黑盒。

它仍然是脆弱适配层:Agent TUI 改文案、布局或 spinner,都可能让规则失效。Herdr 用可远程更新的 TOML manifests 和本地 override 降低升级成本,但这只是让 heuristic 可维护,并没有把它变成协议。

3. cmux:从 hook 事件到可重放的语义日志

cmux 当前源码的 Agent Journal 走了更事件化的路线:hook 不直接设置一个 sidebar 字符串,而是发出 sessionStarted / turnStarted / turnCompleted / approvalRequested / questionRequested / planReviewRequested / errorReported / sessionEnded 等语义事件。事件先持久写入 append-only journal,失败进入有界 dead-letter JSONL;reducer 再按 sequence 去重、丢弃 stale arrival,按 surface 与 Agent 聚合成 unknown / running / needsInput / idle / error。

Mermaid diagram

图 3|cmux 的语义事件归约。未归属事件保留为 diagnostic,而不是猜一个 pane。

AgentLifecycleReducer 的关键不是 enum 本身,而是归约契约:结果只取每个 Session 最新的 lifecycle-bearing event,重复和乱序不改变结果;surface 上有多个同类 Session 时再按 precedence 合并。subagent 事件不会直接改写宿主 pane badge,因为子 Agent 完成并不等于父 Agent 完成。

与 Herdr 相比,cmux 更依赖 Agent hook 生态,但事件日志天然适合重放、诊断和多端 reconcile;Herdr 的 screen route 覆盖面更广,但适配成本与误判风险更高。两者不是谁完全取代谁,而是代表“主动协议”与“被动感知”的两端。

回到 Herdr 界面: 侧边栏的一个状态点并不是 Agent 直接画上去的。对 Codex/Claude,它可能来自“前台进程已识别 + bottom-buffer 命中 manifest + 稳定化”;对具有完整 lifecycle integration 的 Agent,它可能来自 hook authority。用户只看到统一状态,内部必须记住证据来自哪条路线。


五、cmux 源码剖析:原生 GUI 上长出的可组合控制面

cmux 以 libghostty 为 terminal core,在其上加入 surface identity、Agent hooks、journal、通知、browser 与 socket API。

信息图 D|左:cmux 的 native GUI / surface / event-journal 路线;右:Herdr 的 server-owned PTY / state-authority / Agent API 路线。

cmux 的 README 对自己的定位很克制:它是一个 primitive,不是一个规定工作流的 orchestrator。它提供 terminal、browser、notifications、workspaces、splits、tabs 和 CLI,让用户或 Agent 自己组合。这个定位与源码相符:控制面不是单一 AgentManager,而是多个可编排 subsystem 的组合。

1. 数据面:libghostty + native macOS UI

cmux 不是 Ghostty fork,而是把 libghostty 当 WebKit 式的渲染库。Swift/AppKit 管 workspace、sidebar、split、browser、notifications 和 session persistence;libghostty 负责 terminal emulation/rendering。这使“terminal correctness”和“Agent workflow”成为可独立演进的模块。

2. 容器身份:surface 是事件归属的锚点

每个 cmux terminal surface 注入 CMUX_WORKSPACE_ID、CMUX_SURFACE_ID、CMUX_TAB_ID 与 socket context。Agent 从这个 shell 中启动后自然继承 surface token;hook CLI 也可以通过显式参数、环境、TTY 或 process tree 把事件绑定回具体 surface。

这个设计解决了一个常见错误:不能用 cwd、tab title 或“最新 transcript 文件”猜某个 Agent 属于哪个 pane。多个 pane 可以在同一 repo、同一 cwd 运行相同 Agent;标题和 mtime 都不是 identity。cmux 对无法形成完整 target 的事件不强行归属,而是写成 unattributed diagnostic。

3. 控制接口:GUI 对象被系统化暴露

cmux 的 CLI contract 已经远超传统 terminal automation:

  • 以 UUID、workspace:2 之类 ref 或 index 选择 window/workspace/pane/surface/tab;
  • 创建、移动、拆分、重排 workspace、pane 和 surface;
  • read-screen、send、send-key、process/resource top;
  • notifications、status pill、progress、log、sidebar state;
  • browser open/navigate/snapshot/click/fill/evaluate;
  • reconnectable NDJSON events 与 raw v2 RPC;
  • native Agent sessions 列表、hooks、resume binding、teams/subagent panes。

这就是可编程执行容器的关键:GUI 的主要对象不只接受鼠标和快捷键控制,也能被 Agent 与脚本寻址、读取和驱动;CLI 不是旁路工具,而是同一 socket capability 的客户端。

4. Attention router:通知不是弹窗,而是可导航状态

cmux 同时接收标准 OSC 9/99/777、cmux notify 与 Agent hooks。通知经历 received、unread、read、cleared;pane 有 ring,workspace 有 badge,notification panel 保存队列,用户可以跳到最新 unread。它还抑制当前窗口/当前 workspace 已在看的桌面通知。

与传统 macOS notification 最大的区别是:通知携带 workspace/surface address,可以回到正确执行现场。可导航性把 notification 从信息变成了控制索引。

5. Browser 让容器跨出 PTY

cmux 的 browser pane 暴露 accessibility snapshot、element refs、click、fill 与 JS evaluation。对 Web 开发 Agent 来说,terminal 负责代码与进程,browser 负责运行结果与交互验收;二者都在同一 workspace/split 和 socket API 下。

这也是 cmux 与 Herdr 的重要差别:cmux 更像一个本地 Agent workbench,容器不止 terminal;Herdr 更像可嵌入/远程的 Agent-aware terminal runtime。

6. 恢复:先重建 layout,再运行受信任的 continuation

cmux 明确区分:

  • app-owned state:window/workspace/pane layout、cwd、best-effort scrollback、browser URL/history;
  • arbitrary process state:不 checkpoint;tmux、vim、shell 等默认只恢复成普通 terminal;
  • supported Agent state:hook 捕获 native Session ID 后运行 Agent 自己的 resume command;
  • custom surface binding:例如 tmux attach -t work,只有 process-detected trusted binding 或用户批准的签名 command prefix 才自动执行。

批准还绑定 cwd 和精确环境值;token、password、secret、API key 等敏感环境变量在持久化前被丢弃。这个机制揭示了恢复真正的安全含义:restore 不是读 JSON,而是在未来某个时刻执行一条命令。 Resume Ledger 必须同时是 Policy Ledger。


六、Herdr 源码剖析:把 multiplexer 变成 Agent runtime API

Herdr 从另一个方向出发。它的 server 拥有 pane 与进程状态,client 只是附着的 TUI;用户 detach 后 server、PTY 和 Agent 继续运行。Workspace 是项目容器,Tab 是布局,Pane 是真实 terminal,Agent 是 pane 中被识别的 foreground process,Session 是彼此隔离的 server namespace。

沿着“零章”的操作继续往下看: 启动 herdr 对应 client/server;第一次看到的项目行对应 Workspace;右键分屏对应 Pane/PTY registry;运行 codex 对应 Agent detection;左侧状态点对应 authority + attention rollup;prefix+q 对应 client detach。下面五小节只是把这几个可见动作逐层展开。

1. Server-owned terminal 把“用户离开”与“进程退出”解耦

传统 terminal window 一关,child process 往往随之结束;tmux 通过 server 解决这个问题。Herdr 继承这一模型,并把 Agent state、metadata、Session reference 与 API event hub 一并放到 server。多个客户端、本地 CLI 或 SSH thin client 因此看到同一组运行时事实。

Mermaid diagram

图 4|Herdr 的 client/server 结构让 terminal runtime 成为共享服务,而不是某个窗口的内部状态。

2. Agent API 明确高于 Pane API

Herdr 把 layout、pane、Agent 定义成三种 primitive:

  • layout 创建和组织位置;
  • pane 操作 raw terminal:run、send、read、wait output;
  • Agent 操作 recognized process:start、prompt、send keys、read、wait、focus、rename、explain。

agent.start 必须指定一个已有 shell pane,不会隐式创建布局。这个边界很值得抄:容器创建与 Agent 启动分开,自动化不会因为一次启动顺便重写 UI topology。

Socket schema 中 Agent 查询返回 terminal_id / agent / status / session / workspace_id / tab_id / pane_id / state_change_seq / cwd / foreground_cwd / revision;events 可以订阅 pane.agent_detected、pane.agent_status_changed、pane.output_changed 等;pane.report_agent 与 pane.report_agent_session 分开,使生命周期和可恢复身份不必绑在同一 hook 上。

3. 可解释的状态检测是适配器开发工具

Herdr 内置 22 类 Agent 身份,20 类 screen manifest;运行时识别 Node/Python/Bun/shell wrapper 内真实 argv,避免只看到 node 或 python。当状态错误时,agent explain 会显示最终 state、manifest source/version、matched rule、evidence 和为什么跳过 screen detection。

这使 Adapter 的职责从“写几条 regex”升级为一个可测试的感知包:

process matcher
+ screen / OSC manifest
+ optional lifecycle reporter
+ optional native Session reporter
+ explain fixture
+ resume command builder

4. 状态向上聚合,本质是人类注意力调度

Herdr 的 workspace rollup 不是对所有 Agent 求平均,而是选最需要人的状态:blocked 最高;unseen idle 表示 done;working 其次;seen idle 再次;unknown 最低。用户无需逐 pane 轮询,只看 sidebar 就能决定下一次注意力切换。

这仍不是任务调度器。它不知道两个 working Agent 是否修改同一文件、blocked 是否影响关键路径、done 的产物是否通过测试。它优化的是人类下一眼看哪里,不是组织下一步做什么。

5. Live handoff 展示了 multiplexer 的独特上限

Herdr 的 experimental live handoff 会把 session snapshot 与 pane runtime state 发给新 server,并通过 Unix file descriptor transfer 交接 PTY;token、protocol/version validation、validated → restored → ready → committed → owned 握手避免两端同时认为自己拥有 runtime。

它能尽力保住原 pane 进程,因此比 native Agent resume 更强:不需要终止当前 Agent,也不需要重新执行 prompt。但它不能保住 in-flight API requests、waits、subscriptions、client sockets 和 pane-to-pane messages;调用方仍需 reconnect/retry。

这个边界说明:控制面的运行连续性与控制协议的请求连续性是两件事。 进程活着不代表某个 wait 还能收到结果;协议必须支持幂等、重订阅与快照对账。


七、cmux 与 Herdr:同一个问题的两种答案

维度cmuxHerdr可复用判断
产品形态native macOS terminal/workbench跨平台 TUI multiplexer + background serverUI 形态不决定控制深度
Terminal corelibghostty自有 server-owned terminal runtime渲染层应与 Agent 语义解耦
基本容器window/workspace/pane/surfacesession/workspace/tab/pane/terminal至少分 topology 与 runtime identity
Agent 识别hooks、env/TTY/process binding、Agent registryforeground process + wrapper argv detection不能只看 title/cwd
状态主路线semantic hook events → journal → reducerlifecycle authority;否则 screen/OSC manifest需要一个可解释的 arbiter
Attentionnotifications queue、ring、unread、jumpstate + seen,pane→tab→workspace rolluplifecycle 与 attention 分层
Control API大范围 CLI/socket,另含 browser强类型 local socket API,Agent/pane/events/waitpublic IDs + structured responses
编排Claude/Codex teams、split、browser、eventsagent start/prompt/read/wait、pluginswait 与 causation 是自动化门槛
远程SSH workspace、remote daemon、iOS/设备能力server/client、SSH/thin client、named sessionruntime owner 必须明确
普通重启layout + cwd + scrollback + browserlayout + cwd;history opt-insnapshot 只恢复形状
Agent 恢复hooks 保存 ID,native resume;custom trusted bindingofficial integration ref,dedupe 后 native resumesession ref 与 command policy同行
保活/迁移remote PTY/session 与专用机制持续演化detach/attach;experimental FD live handoffprocess continuity 单独建模
哲学composable primitive,偏 human workbenchAgent-aware runtime,偏 automation substrate可组合与意见化编排可分层

最有价值的差异不是 Swift vs Rust,也不是 GUI vs TUI,而是两个系统选择的“深模块”不同:

  • cmux 把 stable surface identity + semantic event journal + notification/browser surface 做深;
  • Herdr 把 server-owned PTY + status authority + explainable detection + waitable Agent API + handoff 做深。

一个理想实现可以组合两者:用 Herdr 式 state authority 与 wait semantics 管运行时,用 cmux 式 semantic journal 与 workspace/browser/attention surface 管人类工作台。


八、Ghostty、tmux、Orca、Warp 分别站在哪里

这些产品不能粗暴排成“谁更先进”,因为它们承担不同层级。

产品它首先是什么Agent-first 能力控制面边界
Ghostty高性能原生 terminal emulator / libghostty为上层提供可靠渲染和平台 UI 基础不以 Agent 身份、状态和编排为核心
tmux持久 PTY multiplexerdetach/attach、session/window/pane、可脚本化只认识进程与 pane,不认识 Agent 语义
cmuxnative terminal + browser workbenchhook/journal、notification、unread、session resume、teams、socket API仍以 composable execution primitives 为主
HerdrAgent-aware terminal workspace managerprocess/screen/hook authority、rollup、Agent API、native resume、handoff不拥有完整业务 task/approval/audit
Orcaworktree-first Agent development workspaceAgent tabs/status、hooks、CLI、browser、remote、hibernation、mobile更意见化地把 worktree 当隔离与任务容器
Warp / Ozterminal + proprietary Agent orchestration platformlocal/cloud agents、跨机器/repo/team 并发、trigger/schedule/audit已跨进完整产品控制面,开源实现证据有限

Orca 的官方文档尤其能说明市场正在向相同对象收敛:一个 Agent Session 被定义为“一个 worktree 的一个 terminal 中运行的一个 Agent CLI”;tab 显示 working、waiting、done/unread;状态来自 OSC title 与 hooks;CLI 可以管理 worktree、terminal、browser 与 runtime;idle Agent 还可以 hibernate,并用原生 resume flag 恢复。

Warp 则进一步把 terminal 当本地交互入口,把 Oz 定义为底层 orchestration platform,负责 local/cloud agents、trigger、schedule、environment、跨机器/repo/team 协调与审计。它说明这条演化的终点可能不是“更好的 terminal”,而是terminal 成为一个完整 Agent 平台的高带宽本地入口。


九、多 Agent:从“摆很多 pane”到可编程协调

传统 multiplexer 已经允许人同时启动多个 Agent;Agent-first terminal 的新增价值是把这种并发变成一个 feedback loop:

Mermaid diagram

图 5|可编程协调回路。Agent state 只能触发检查,不能替代产物验收。

要让这个回路可靠,需要五个条件:

  1. 隔离工作目录。 不同 Agent 至少使用不同 worktree 或明确写冲突策略;pane 隔离不是文件系统隔离。
  2. 稳定因果标识。 同一次协调中的 prompt、hook event 与 output 共享 command_id 或映射记录。
  3. 语义等待。 等 state change、permission、process exit 或 artifact,而不是固定 sleep。
  4. 结构化产物。 diff、test、file、URL 或 review result 应独立于 terminal prose 被检查。
  5. 独立验收。 Agent 进入 idle/done 只表示一次执行尝试结束,不表示产物已经正确。

cmux 的 teams 能把 Claude/Codex 子 Agent 显示为 native splits;Herdr 的 skill/API 允许一个 Agent 创建 pane、启动 helper、发 prompt、等待并读取结果。这已经是 coordination。但如果 terminal 自身没有协调记录,父 Agent 崩溃后仍可能不知道这些 worker 为什么存在、谁拥有结果、是否需要重试。

所以更准确的判断是:

Agent-first terminal 可以提供 orchestration substrate;是否进一步维护任务账本,是 terminal 产品自身的能力选择。

回到 Herdr 界面: 人手动右键分屏、在两个 pane 输入任务、等侧边栏出现 done 再切回去,已经是在执行同一个协调回路。CLI/Skill 并没有发明另一套工作方式,只是把 split、prompt、wait、read 从人的点击变成可组合命令。


十、恢复不是一个布尔值:四种连续性与一种假象

Detach、live handoff、snapshot restore 与 native Agent resume 分别保留不同层级的状态。

信息图 E|恢复阶梯。越靠左越接近保留原运行,越靠右越接近重建;screen replay 只恢复外观。

路径原进程PTY / live screen布局/cwdAgent conversationin-flight wait/subscription
Client detach / reattach保留保留保留因进程仍活着而保留server 若仍活着可保留部分状态
Live server handoff尽力保留通过 FD/runtime 转移保留因进程仍活着而保留通常中断,需重连重试
Snapshot restore不保留不保留重建不自动保留不保留
Native Agent resume新进程新 PTY重建Agent 自己恢复不保留旧请求
Screen/history replay不保留只重放文本可重建不恢复不保留

回到 Herdr 界面: 关掉终端窗口再运行 herdr,看到的是原进程继续运行,属于 detach/reattach;执行 herdr server stop 后再启动,看到相似布局却已经可能是新 shell 或 Agent native resume,属于重建。界面看起来都像“回来了”,底层连续性完全不同。

Herdr 的实现还处理了两个细节:

  • 同一个 native Agent Session 在一次 restore 中只能恢复一次;重复引用的 pane 不再启动相同 conversation。
  • 如果 native resume 生效,就不把旧 pane history 注入新 Agent terminal,因为那只是 presentation,不是 conversation,而且可能污染 TUI。

cmux 也按“先 layout,后 native resume command”重建。二者共同支持一个结论:terminal 层保存形状,Agent Runtime 保存对话;没有任一层可以单独恢复完整工作。 如果还要恢复 task ownership、重试次数、预算和验收状态,就必须由上层控制面保存。


十一、安全:控制 terminal 等于获得本地执行权

Agent-first terminal 的 API 看起来像 UI automation,实际上通常拥有读取屏幕、发送键盘、启动进程、访问 cwd、操纵 browser 和恢复命令的能力。设计时应把它视为本地 RCE control socket,而不是普通偏好设置接口。

回到 Herdr 界面: 右键 split、键盘输入和 agent send-keys 最终都可能向真实 PTY 写入字节;差别只在调用者与路径。一个“帮我点一下审批”的 Agent 自动化能力,和一个可以在本机执行任意命令的 socket,只隔着身份、权限与策略校验。

1. 六条主要信任边界

边界风险最低防线
Local socket client → server任意读取/输入/启动命令0600 socket、peer identity、capability/token、可审计调用
Agent hook → pane authority伪造状态、污染其他 Sessionstable surface token、source ownership、monotonic seq、process corroboration
Screen/scrollback → persistenceprompt、token、命令输出泄露默认关闭或 bounded、加密/权限、敏感提示、可清除
Resume ledger → future shell持久化命令注入command canonicalization、签名 prefix、cwd/env binding、manual approval
Remote client → host跨主机输入与 secret 暴露host identity、transport auth、least privilege、显式路由
Orchestrator Agent → worker paneprompt injection、误操作、写冲突worktree sandbox、policy gate、command/task correlation、artifact review

Herdr 的 handoff socket 会收紧为 0600,并用一次性 token、协议/版本校验和 ownership handshake;pane history 因可能含 secrets 默认关闭。cmux 的 custom resume command 要经过 trusted binding 或用户批准的签名前缀,且在保存前过滤敏感环境键。这些都不是附属功能,而是控制面正确性的一部分。

2. “worktree 就是 sandbox”不是通用安全结论

Orca 默认可以为受支持 Agent 预填 permission-bypass/yolo flags,其产品假设是 disposable worktree 提供主要隔离。但 worktree 只隔离 Git checkout,不隔离 home directory、network、credential helper、Docker socket、SSH agent 或系统命令。

如果自建产品采用类似模式,应明确拆开:

  • 代码冲突隔离:worktree;
  • 文件与进程隔离:container/sandbox/VM;
  • 凭据隔离:scoped token / broker;
  • 工具审批:Agent Runtime 或 terminal policy;
  • 产物验收:独立 verifier 或人工检查。

十二、自建蓝图:八个深模块,而不是一个巨型 TerminalManager

Mermaid diagram

图 6|建议实现分层。深模块之间通过小而明确的数据结构连接。

1. Container Registry

负责稳定身份与 topology,不解释 Agent:

Container {
  workspace_id, tab_id, pane_id, terminal_id,
  cwd, env_policy, foreground_process,
  revision, created_at, runtime_owner
}

关键不变量:pane/surface ID 在它声称的生命周期内不可因 UI 重排而变化;restore 若重新生成对象,必须有 durable identity 与 remap 记录。

2. Agent Adapter Registry

每个 Agent 适配器声明能力,而不是假装全都一样:

identify(process) -> confidence
observe(screen, osc) -> DetectionEvidence?
map_hook(native_event) -> SemanticEvent?
capture_session(event/files) -> SessionRef?
resume(session_ref, cwd, launch) -> Command?
capabilities -> { lifecycle, permission, interrupt, resume, usage }

Screen manifest、hook mapper、Session collector 和 resume builder 应拆开版本;Claude 可以由 screen 判状态、hook 只报 Session,而 Pi 可以由完整 lifecycle hook 说了算。

3. State Arbiter

不要让 adapter 直接写 UI。Arbiter 接收 evidence,并执行:

  • foreground ownership 校验;
  • 每 source monotonic sequence;
  • Session replacement / stale event 防护;
  • 单一 active authority;
  • working→idle debounce;
  • process-exit backstop;
  • provenance 与 explain trace。

建议输出同时带 state / authority / confidence / changed_seq / occurred_at / observed_at。

4. Attention Router

独立保存 seen_at / unread_since / notification_reason / priority,再按 workspace/task 聚合。不要把 done 固化进底层 lifecycle;它通常是 idle + unseen 的 presentation。

5. Session Ledger 与 Recovery Planner

Ledger 保存的是可恢复声明,不是“最后一次命令字符串”:

SessionBinding {
  pane_id, agent_kind, native_ref,
  cwd, launch_fingerprint, provider_identity_hint,
  captured_by, captured_at, resume_capability,
  trust_provenance
}

Planner 再决定 reattach_live / import_runtime / native_resume / restore_shell / manual_only,并显式去重同一个 native Session。

6. Control API

最小协议应同时有快照、命令和事件:

{"id":"c-42","method":"agent.prompt","params":{"target":"reviewer","command_id":"run-17","text":"Review the diff","wait":{"until":["blocked","idle"],"timeout_ms":600000}}}
{"sequence":891,"event":"agent.state_changed","data":{"pane_id":"w1:p2","agent":"codex","state":"idle","authority":"hook","state_change_seq":44,"causation_id":"run-17"}}

协议至少需要:

  • response 与 event 都可关联 request/command;
  • 快照带 revision,事件带 global sequence;
  • reconnect 后用 snapshot + events_after(sequence) 对账;
  • selectors 先解析成稳定 ID,等待期间持续验证 identity;
  • 能力查询明确哪些 Agent 支持 hook、permission、interrupt、resume。

十三、最小原型:四个阶段就能验证方向

Phase 1:一个可寻址的 PTY Registry

  • background server 拥有 PTY;
  • workspace/pane 有稳定 ID;
  • 支持 list/get/read/send/process-info;
  • client detach 不杀进程。

不要一开始做 browser、cloud、mobile 或华丽 sidebar。先证明 runtime ownership 与 ID 不变量。

Phase 2:两种 Agent 的状态权威

选择一个 hook 完整的 Agent(例如 Pi/OpenCode)和一个主要依赖 screen 的 Agent(例如 Codex/Claude):

  • foreground process identification;
  • hook semantic events + sequence;
  • screen manifest + explain;
  • single authority arbitration;
  • idle + unseen = done attention projection。

Phase 3:结构化 prompt / wait / event

  • agent.start 与 layout create 分开;
  • agent.prompt(command_id);
  • 观察活动门、状态 wait、timeout、target-replaced error;
  • reconnectable event stream;
  • 将 output 只作为证据,不作为唯一完成事实。

Phase 4:native Session restore

  • 捕获 Session ref 与 provenance;
  • snapshot 只保存 topology/cwd;
  • native resume 去重;
  • manual-only 与 trusted auto-resume;
  • restore 后通过新 hook/session ref 重新确认绑定。

Conformance tests

主题必须验证的失败场景
Identity两个同 cwd、同 Agent 的 pane 不串事件;重排布局不换 ID
Sequence重复、乱序、延迟旧 Session hook 不回滚状态
Authority完整 hook 存活时 screen 不抢权;进程退出后 authority 释放
Attention后台 idle 变 done;查看后只清 seen,不伪造 lifecycle
Waitprompt 无活动时报 stalled;目标进程替换时报 not-running;timeout 可重试
Resume同一 Session ref 只恢复一次;无效 ref 回落为 shell;不重放旧屏幕污染新 TUI
Security未授权 socket client 被拒;secret env 不入 ledger;未批准命令不自动执行
Reconcile事件丢失后 snapshot 修正;重连不重复执行 command

十四、附录

A. Herdr Cheatsheet

适用证据版本:Herdr 固定提交 d6dae883。Herdr 仍在快速演化,真实使用前可运行 herdr --version,并以当前二进制的 herdr --help、herdr <command> --help 和 herdr api schema 为准。

A.1 先背这一行对象关系

Session(后台 server 命名空间)
└── Workspace(项目 / 仓库 / 调查)
    └── Tab(同一项目内的一组布局)
        └── Pane(真实 terminal + PTY)
            └── Agent(当前 pane 中被识别的前台 Agent 进程)

最重要的区别:

  • Session 决定一整套后台运行时是否隔离;多数时候只用默认 Session。
  • Workspace 是日常项目边界;一个仓库或任务一个 workspace。
  • Tab 用来区分 agents / logs / server / review 等视图。
  • Pane 是稳定可寻址的真实终端;普通 shell、测试和服务器也可以运行在里面。
  • Agent 不是容器,而是 Herdr 在 pane 中识别出的当前进程;Agent 退出或被替换后,pane 仍然存在。

A.2 日常使用最短路径

想做什么操作
在当前项目启动或重连默认 Sessionherdr
在 pane 中运行 Agent直接执行 claude、codex、pi、opencode 等
向右 / 向下分屏prefix+v / prefix+minus,或 pane 右键菜单
在 pane 间移动prefix+h/j/k/l,或直接点击
查看所有 workspace 与 Agentprefix+w
新建 tabprefix+c
临时放大当前 paneprefix+z
查看全部生效快捷键prefix+?
离开但保持所有进程运行prefix+q,或关闭当前 client 窗口
回来再次执行 herdr
真正停止默认 Session 及其中进程herdr server stop

prefix 默认是 ctrl+b:按下并松开 ctrl+b,再按动作键。例如 prefix+v 不是同时按三个键,而是先 ctrl+b、再 v。

A.3 高频快捷键

分组动作默认按键
Pane向右 / 向下分割prefix+v / prefix+minus
Pane左 / 下 / 上 / 右移动焦点prefix+h/j/k/l
Pane缩放 / 还原当前 paneprefix+z
Pane关闭当前 paneprefix+x
Pane调整大小模式prefix+r
Pane复制模式prefix+[
Tab新建 tabprefix+c
Tab下一个 / 上一个 tabprefix+n / prefix+p
Tab跳转到 tab 1–9prefix+1..9
Workspace打开 workspace / Agent 导航prefix+w
Workspace新建 workspaceprefix+shift+n
UI切换侧边栏prefix+b
Session分离 clientprefix+q
Help查看并搜索快捷键prefix+?,随后按 / 搜索

鼠标同样是一等入口:点击对象以聚焦,拖动分割边框调整大小,右键创建 split/tab,拖选文本直接复制。快捷键是效率层,不是使用前提。

A.4 如何读 Agent 状态

状态含义推荐动作
workingAgent 正在运行继续做别的事,不要轮询 pane
blocked识别到审批、提问或输入请求agent focus/read 后查看原生 TUI,再明确回应
done底层已经 idle,但完成后尚未被看过切过去检查结果、diff 与测试
idleAgent 已停下来,且 pane 已经被查看可继续发新 prompt
unknownAgent 存在,但 Herdr 无法可靠判断生命周期当普通 terminal 使用,不假定成功或失败

记忆口诀:

blocked:现在需要我
working:还不用看
done:做完了但我没看
idle:做完了而且我看过
unknown:Herdr 不确定

done 与 idle 的底层 Agent 生命周期可能相同,差异是 unseen / seen。agent read 只读内容,不会把结果标记为已看;agent focus 或在 UI 中聚焦相应 pane 才会更新 attention state。

A.5 查询对象:永远先拿 ID,不要猜

herdr status
herdr session list
herdr workspace list
herdr tab list --workspace <workspace_id>
herdr pane list --workspace <workspace_id>
herdr pane current --current
herdr agent list
herdr agent get <agent_name_or_pane_id>

大多数创建命令返回 JSON。自动化脚本应从响应读取 workspace_id / tab_id / pane_id,不要依赖“当前是 w1:p2”之类的位置猜测。手动启动的 Agent 默认可以用其 pane ID 寻址;需要稳定可读的目标名时再执行:

herdr agent rename <pane_id> reviewer
herdr agent get reviewer

A.6 布局与普通终端进程

# 创建项目 workspace;同时创建第一个 tab 和根 pane
herdr workspace create --cwd ~/project --label api --no-focus
 
# 为当前 pane 向右创建一个新 pane
herdr pane split --current --direction right --no-focus
 
# 新建 tab
herdr tab create --workspace <workspace_id> --label review --no-focus
 
# 查看 pane 的当前进程与屏幕
herdr pane process-info --pane <pane_id>
herdr pane read <pane_id> --source recent-unwrapped --lines 120
 
# 在普通 shell pane 中运行命令
herdr pane run <pane_id> "just test --watch"
 
# 等普通进程输出;这不解释 Agent 生命周期
herdr pane wait-output <pane_id> --regex "passed|failed" --timeout 120000

选择原则:

  • shell、测试、服务器、日志监视器使用 pane run/read/wait-output;
  • 已被 Herdr 识别的编程 Agent 使用 agent prompt/read/wait;
  • 提交 shell 命令优先使用 pane run,不要自行拼 send-text 再发送 Enter;
  • workspace close 只关闭 Herdr 中的 workspace;worktree remove 才会显式执行 Git worktree 删除流程。

A.7 Agent 控制

# 列出、查看、聚焦和解释 Agent
herdr agent list
herdr agent get reviewer
herdr agent focus reviewer
herdr agent explain reviewer --verbose
 
# 在已经存在且停在 shell prompt 的 pane 中启动 Agent
herdr agent start reviewer --kind codex --pane <pane_id>
 
# 发 prompt,并等待 idle / done / blocked 之一
herdr agent prompt reviewer "Review the current diff" --wait --timeout 120000
 
# 只等待状态;显式列出感兴趣的状态更清楚
herdr agent wait reviewer \
  --until blocked \
  --until done \
  --until idle \
  --timeout 120000
 
# 读取真实 TUI 内容
herdr agent read reviewer --source recent-unwrapped --lines 120
 
# 对审批框或 TUI 明确发送逻辑按键
herdr agent send-keys reviewer esc
herdr agent send-keys reviewer enter
 
# 直接附加到一个 Agent terminal,而不是打开完整 Herdr UI
herdr agent attach reviewer

关键限制:

  • agent start 只启动 Agent,不创建布局;先创建 workspace/tab/pane。
  • 目标必须是唯一 live Agent name 或其当前 pane ID,不能只写 codex 这种 Agent kind。
  • 目标已经 blocked 时,agent prompt 会拒绝盲发新 prompt;应先 read,再用 send-keys 明确处理交互。
  • agent wait 等的是生命周期状态,不保证严格对应某一次 prompt;重要自动化仍需额外保存命令与产物的因果关系。
  • agent wait、agent prompt --wait 和 pane wait-output 不写 --timeout 时可能无限等待。

A.8 一套可以照抄的 reviewer 协作配方

下面的流程来自 Herdr 官方 Agent Automation 文档:分出新 pane、从 JSON 响应取得 ID、启动具名 Codex、分配 review、等待并读取结果。

split_json=$(herdr pane split --current --direction right --no-focus)
review_pane=$(printf '%s\n' "$split_json" | jq -r '.result.pane.pane_id')
 
herdr agent start reviewer --kind codex --pane "$review_pane"
herdr agent prompt reviewer "Review the current diff" \
  --wait \
  --timeout 120000
herdr agent read reviewer --source recent-unwrapped --lines 120

如果想专门等待 Agent 请求决策:

herdr agent wait reviewer --until blocked --timeout 120000
herdr agent read reviewer --source recent-unwrapped --lines 80
# 读懂原生交互后,再选择 esc、enter、方向键或其他明确输入
herdr agent send-keys reviewer esc

agent read 取得的是终端文本,不等于验收结果。Review 是否可信,仍要检查 diff、测试或独立 verifier。

A.9 Worktree 隔离

# 从当前仓库创建 Git worktree,并作为新 workspace 打开
herdr worktree create \
  --cwd ~/project \
  --branch agent/reviewer \
  --base HEAD \
  --label reviewer \
  --no-focus
 
# 查看 worktree workspace
herdr worktree list --cwd ~/project
 
# 显式移除检出;脏 worktree 会被 Git 拒绝,除非使用 --force
herdr worktree remove --workspace <workspace_id>

Worktree 只隔离 Git checkout,不隔离 home、network、credential helper、SSH agent、Docker socket 或系统命令。不要把它当安全 sandbox。

A.10 分离、停止、恢复与更新

动作命令 / 按键原进程是否继续
分离当前 clientprefix+q是
重连默认 Sessionherdr是,连接原 server
查看命名 Sessionherdr session list不改变进程
连接命名 Sessionherdr session attach work连接该 Session
停止默认 Sessionherdr server stop否,会结束 pane 进程
停止命名 Sessionherdr session stop work否,会结束该 Session 的 pane 进程
普通更新herdr update兼容 server 可继续;需重启时按提示处理
实验性实时交接更新herdr update --handoff对受支持 server 尽力保留

冷重启后的“画面回来”不保证原进程还在:布局/cwd 来自 snapshot;可选 pane history 只重放文本;受支持 Agent 可以通过原生 Session ref 启动新进程恢复对话。想判断恢复强度,回看第十章的恢复矩阵。

A.11 本地、SSH 与远程瘦客户端

# 本地
herdr
 
# 传统方式:先 SSH 到代码所在机器,再运行远端 Herdr
ssh you@server
herdr
 
# 本地 Herdr 作为瘦客户端,通过 SSH 连接远端 server
herdr --remote workbox
herdr --remote ssh://you@server:2222

选择方式:

  • 已经处在 SSH shell 或使用手机 SSH 客户端:远端执行 herdr;
  • 希望沿用本地按键绑定并桥接本地桌面能力:herdr --remote <host>;
  • 代码、凭据、Agent 和 PTY 都运行在 server 所在机器,不会因为本地 client 断开而迁移回本机。

A.12 集成与状态排障

# 安装或检查 Agent integration
herdr integration install codex
herdr integration install claude
herdr integration status
 
# 状态不对时,先解释证据
herdr agent explain <target> --verbose
 
# 查看、更新或重载 screen detection manifests
herdr server agent-manifests --json
herdr server update-agent-manifests
herdr server reload-agent-manifests
症状先检查什么常见原因 / 处理
Agent 没被识别pane process-info、agent listwrapper 只暴露 node/python;在宿主可见 wrapper 命令上设置 HERDR_AGENT=<agent>
状态明显错误agent explain --verboseTUI 文案或布局变化;更新 manifest,必要时添加本地 override
一直 unknownforeground process、manifest、integrationHerdr 知道 Agent 存在,但没有可靠生命周期证据;不要猜完成状态
blocked 没识别explain 中的 visible evidencescreen detection 对 blocked 刻意保守;新权限 UI 可能尚无规则
pane 内又启动 tmux 后看不到 Agentpane process-infoHerdr 看到的前台进程是内层 tmux;不要在 Herdr pane 内自动进入另一层 tmux
agent prompt 返回 agent_blockedagent read先理解审批/问题,再用 agent send-keys 回应
agent_prompt_stalled状态序列是否在 5 秒内变化prompt 已发送,但没观察到生命周期活动;检查目标、TUI 与检测证据
wait 不返回是否设置 --timeout、目标身份是否仍有效默认可能无限等待;为自动化始终设置超时
重启后只剩 shellintegration status、Session refsnapshot 只能重建布局;缺少有效 native Session ref 时不会恢复 Agent 对话

A.13 给其他 Agent 使用 Herdr

Herdr 内置一份与二进制版本匹配的 Skill,可直接查看:

herdr --skill

支持 Skills 的 Agent 可以安装 Herdr 仓库中的 skills/herdr/SKILL.md。这份 Skill 教 Agent 使用 pane split/run/read/wait-output 与 agent start/prompt/read/wait。它首先检查 HERDR_ENV=1;变量不存在时,Agent 不应假装自己位于一个可控制的 Herdr pane 中。

A.14 最后只记住八条

  1. 日常用 Workspace 分项目,只有需要完全隔离 server/socket 时才用命名 Session。
  2. Pane 是终端位置,Agent 是当前 occupant;先建 pane,再启动 Agent。
  3. 看状态做注意力调度:blocked 先处理,done 去验收,working 不打扰。
  4. 自动化先 list/create 并读取返回 ID,不要猜 pane ID,也不要依赖焦点。
  5. 普通进程用 pane wait-output;Agent 用 agent wait。
  6. read 不等于 focus,idle/done 不等于产物正确。
  7. prefix+q 只是 detach;server stop 才会杀掉 Session 中的进程。
  8. 每个 wait 都加 timeout;每次自动输入前都确认目标 identity 与当前状态。

B. 主流 Agent TUI 如何接入 terminal 控制面

下表不是抽象猜测,而是对 cmux 固定提交的 resume registry/README 与 Herdr 固定提交的 Agent enum、manifest、integration/restore 文档做的合并速查。screen 表示从 bottom-buffer/OSC 识别状态;lifecycle 表示官方 integration 可以成为状态 authority;session 表示至少能上报 native Session 供恢复。具体 CLI 版本变化很快,实施前应重新跑 capability probe。

Agent身份/启动入口Herdr 状态路线cmux / Herdr Session 恢复Adapter 实现重点
Claude Codeclaudescreen;integration 主要提供 sessionclaude --resume <id>hook 覆盖不等于完整 lifecycle;permission/question 事件可单独映射
Codexcodexscreen;integration 主要提供 sessioncodex resume <id>OSC/TUI 规则与 hooks setup;区分 approval、turn end 与 process exit
Pipilifecycle hook 优先;否则 screenpi --session <path-or-id>可作为完整 hook authority 样本;Session 可能是 path 或 id
Hermes Agenthermesscreen;integration 提供 sessionhermes --resume <id>Python/wrapper 进程识别;hook 只覆盖部分事件时不可抢 lifecycle authority
OpenCodeopencodelifecycle plugin 优先;否则 screenopencode --session <id>plugin event bus、Session 与 state 可同时上报
OMPomplifecycle hookomp --resume=<path-or-id> / cmux registry 使用原生会话参数需要 source sequence 与 Session replacement 防护
Kimi Codekimilifecycle hook 优先;否则 screenkimi --session <id>lifecycle + session;兼顾 TUI fallback
MastraCodemastracodelifecycle hookmastracode --thread <id>(Herdr)thread 是 conversation identity,不是 pane identity
Kilo Code CLIkilolifecycle plugin 优先;否则 screenkilo --session <id>(Herdr)plugin authority 与 screen fallback 互斥
Gemini CLIgeminiscreen(Herdr 标为较少测试)gemini --resume <id>(cmux)TUI 版本漂移与较弱 fixture 覆盖
Cursor Agent CLIcursor-agentscreen;session integrationcursor-agent --resume <id>bundled Node wrapper argv 识别
Grok / Grok Buildgrokscreen + OSCcmux 文档 grok -r <id>;Herdr grok --resume <id>CLI 版本/参数差异必须 capability probe,不能硬编码一个全局命令
GitHub Copilot CLIcopilotscreen;session integrationcmux copilot --resume <id>;Herdr copilot --resume=<id>同样存在参数形态差异;用 per-version builder
Devin CLIdevinscreen;session integrationdevin --resume <id>(Herdr)status 主要靠 TUI;Session hook 不做 lifecycle authority
Droid / Factorydroidscreen;session integrationdroid --resume <id>process exit、interrupt 后 screen state 要重新确认
Antigravity CLIagyscreen;session integrationagy --conversation <id>Agent alias 规范化;conversation ref 独立保存
Qoder CLIqodercliscreen;session integrationqodercli --resume <id>中英文/发行渠道 binary alias 与 TUI 文案变化
Qwen Codeqwenscreen;session integrationHerdr integration 可保存 session;恢复以当前官方 integration 为准Node/Bun wrapper 识别;Session-only 上报不改变状态
Ampampscreenamp threads continue <id>(cmux)resume 不是统一 --resume 形态,需要独立 builder
Clineclinescreen,较少测试主样本未证明统一 native resume先声明 resume=false,不要虚构能力
Kiro CLIkiroscreen主样本中状态/恢复支持深度不一致分开检测支持与恢复支持
Makimakiscreen主样本未证明统一 native resume只提供检测时应明确 capability degradation
OpenClaw / 非 TUI Runtime可能通过 daemon/API/普通命令运行无通用 pane-native authority由自身 control/session protocol 决定不应强行 screen scrape;需要时使用其原生 API,而不是硬套 terminal adapter

这张表最重要的不是命令,而是三条适配原则:

  1. 检测、生命周期、Session、权限、取消、Resume 是独立 capability。 支持其中一个不代表全支持。
  2. 同一 Agent 在不同控制面甚至不同版本中 resume 参数可能不同。 需要 version probe 与 builder,不应在核心逻辑中散落 shell 字符串。
  3. 未知能力应降级为 plain terminal。 不支持 rich state 或 native resume 时,Agent 仍应能正常运行;UI 显示 unknown,恢复成 shell,绝不能靠猜测自动执行。

十五、最后的判断:terminal 正在成为 Agent 的本地操作系统外壳

把 Agent 类比为进程时,传统 terminal 只提供字符设备,tmux 提供进程容器;cmux、Herdr、Orca、Warp 这一波产品继续补上身份、状态、注意力、API、恢复和协调。这个类比足以帮助我们理解演化方向,不必把它做成严谨的一一映射。

但工程边界必须清楚:

  • PTY/process continuity 不等于 Agent conversation continuity;
  • Agent conversation continuity 不等于 task continuity;
  • Agent idle/done 不等于 artifact accepted;
  • 多个 pane 不等于多 Agent orchestration;
  • worktree isolation 不等于安全 sandbox;
  • local execution 不等于没有控制面。

因此,Agent-first terminal 可以从自身内部理解为三层组合:

  1. terminal / multiplexer core 管理字符、PTY、pane、布局和进程连续性;
  2. Agent semantic control 管理身份、状态、注意力、事件、等待和恢复入口;
  3. Runtime-specific integration 适配不同 Agent 的 hooks、Session、权限与 resume 语义。

对想“抄作业”的实现者来说,最值得复制的不是侧边栏、状态点或某组快捷键,而是两个主样本暴露出的共同纪律:稳定寻址,不猜绑定;状态有权威,不让信号打架;事件可重放,等待有因果;恢复分层,自动命令受信任;执行状态永远不冒充业务完成。


Source Manifest

  • 完整来源、固定提交、文件定位、访问日期与证据边界:Source Manifest。
  • ImageGen prompt、尺寸、SHA-256、视觉检查与事实边界:ImageGen Manifest。
  • 本地相关证据:Agent 控制面、远程 Agent 控制栈、Agent 可观测性、tmux source note、Agent 产品的控制面与入口竞争。