我的终端原生并行编程智能体配置
在上一篇关于 Pi 的文章里,我提到希望有一个稳定的编程框架,而下层的模型可以不断更换。但一个终端里跑一个智能体,并不能覆盖整个工作流程。我越来越多地需要同时运行多个智能体,有时它们还在同一个代码仓库里工作。
有意思的是,我用一套更简单的工具就能搞定:一个终端、Git worktree,还有一个专为智能体设计的终端复用器。
我目前的配置主要是 Ghostty、Git worktree、Herdr 和 hunk。它还有个好处:整套环境可以远程访问,甚至用 iPhone 也能连上。
整体架构一览
Ghostty → Herdr → Git worktrees → Pi + hunk 面板
iPhone → Heeler → Tailscale + SSH → Herdr
Ghostty 就是终端
我在 macOS 上用 Ghostty 作为终端。
我喜欢它是原生 macOS 应用,而不是 Electron 套壳,而且它专注于把终端该做的基本功做好。我也关注它的作者 Mitchell Hashimoto,欣赏他做软件的整体思路:该原生就原生、快、专注。
自从我开始更多使用编程智能体后,Ghostty 的一个功能变得特别有用:终端内嵌图片。
Ghostty 支持 Kitty 图形协议,终端应用可以直接在终端里显示图片。Pi 就利用了这个能力。如果对话中涉及图片,我能在文字旁边直接看到它。
这对我上一篇提到的 Xcode 和 Figma 工作流程很重要。渲染出来的 SwiftUI 预览图或设计稿,可以和智能体正在实现界面的那段终端对话放在一起。终端不再只能是纯文本界面了。
编程智能体让 Git worktree 变得更有用
只用一个编程智能体时,一切都很简单。但当我想让多个智能体并行工作时,事情就变得有意思了。
可能一个智能体在实现某个功能,另一个在排查 bug,第三个在处理不相关的改动。它们没法都愉快地修改同一个工作目录。
Git 早就有解决方案了:worktree。
worktree(工作树)让每个任务拥有独立的工作目录和分支,同时仍属于同一个 Git 仓库。这让 worktree 天然适合搭配编码 agent:给每个任务分配一个 worktree,每个 agent 就有了一处互不干扰的工作环境。
平常一天里,我可能让一个 agent 实现功能,另一个排查 bug,第三个审查改动。它们各自有独立的 worktree、分支和 Herdr 工作区。
worktree 隔离的是文件系统的改动,并不能让彼此重叠的任务变得安全。所以我依然会给每个 agent 划定清楚、互不交叉的工作范围。
于是问题就从 Git,转到了怎么管理这一堆终端和 worktree。
从 Superset 到 Herdr
我最早用的是 Superset,它就是围绕这个思路做的:用 Git worktree 并行运行编码 agent。
从概念上说,这正是我想要的。但实际用起来,对一个本质就是终端加 Git worktree 的工作流而言,它显得偏重,也没那么可靠。
后来我发现了 Herdr。
关于 Herdr,最好的介绍来自项目自己:如果你用过 tmux,那它基本就是为 agent 重造了一遍的 tmux。这句话也恰好说明了我为什么喜欢它。
Herdr 跑在我现有的终端里。它提供带工作区、标签页和窗格的持久会话,同时还能理解编码 agent 与普通终端进程的差别,尤其是它懂 Git worktree。
我可以给某个仓库新建一个 worktree,它会作为另一个 Herdr 工作区出现。每个 worktree 都可以有自己的 agent 在各自的分支上干活,而 Herdr 把它们归在同一个项目下。
Herdr 还会跟踪编码 agent 的状态。我不用在终端之间来回切换去看情况,直接就能看到某个 agent 是在工作、空闲、已完成,还是卡住了在等我。
所以在我脑子里,它就是「懂编码 agent 和 Git worktree 的 tmux」。
用 tmux 其实也能做到,但 Herdr 补上了两件本来得手动管理的事:能感知 worktree 的工作区,以及能感知 agent 状态。
在代理旁边审查变更
我平时用的 Herdr 工作区分成两栏。左边运行 Pi,作为我的编码工具;右边运行 hunk——一个终端下的差异查看器,展示当前 Git 变更,可读性比直接跑 git diff 好得多。
真正有用的不只是把 diff 显示在代理旁边,而是我能直接在 diff 上加行内评论:指出要改的地方、质疑某个实现选择,或者要求换个思路。Pi 的一项技能可以读取这些评论,把它们回传给代理。
这样就在终端内形成了一个紧凑的审查闭环。Pi 做修改,我在旁边的面板审查,在具体需要关注的代码行上标注,Pi 接着根据这些反馈继续。我不用把每一条意见翻译成单独的提示词,也不用解释我说的是 diff 里的哪一处。
同样的配置也能通过 SSH 使用
把所有东西都放在终端里的一个意外好处是:开发环境其实并不绑定在我 Mac 的显示器上。
Herdr 的会话是持久的。我可以从会话中脱离,之后再 SSH 登录这台机器,重新接入完全相同的代理。
我用 Tailscale 做网络连接,这样不用把 SSH 暴露到公网就能访问我的 Mac。只要 Mac 在线,我就能从另一台电脑连过去,用同一个 Herdr 会话继续工作。甚至用 iPhone 也行。
当然,在 iPhone 上用普通终端并不舒服。但编码代理大幅改变了需求。
我不需要在手机上写代码,那是代理在做的事。
我通常需要的是:看看代理做了什么、回答一个问题、批准某个操作,或者再给它一条指令。
用 iPhone 检查我的代理
为此有了 Heeler。
Heeler 是 Herdr 的原生 iOS 伴侣应用。它通过 SSH 连接到运行 Herdr 的机器,用一个专为手机设计的界面对代理进行展示。
我不用再试图通过小小的 SSH 客户端去操作整个终端复用器,而是可以直接看到哪些代理需要处理,打开其中一个,查看它的实时终端,再给它发一条指令。
它还能在某个代理需要我处理时发通知。
这里有个挺巧的对称:Heeler 用了 Ghostty 的 libghostty 来做终端渲染。于是 Ghostty 出现在这套方案的两端——既是我 Mac 上的终端应用,也是 iPhone 应用内部的终端引擎,我靠这个 iPhone 应用远程和代理交互。
连接由 Tailscale 提供,我可以让代理在 Mac 上继续干活,人走开,过一会儿再掏出手机看它需要什么。
这对我来说,比把 iPhone 硬改造成一台开发机有用得多。
有复杂度,但技术栈不复杂
现在围绕编程代理,专门打造的复杂应用越来越多。很多把代理、编辑器、Git 管理、diff、终端和任务管理揉成一个全新的开发环境。
我走的方向几乎相反。
我目前的工具组合是:
-
Ghostty,原生 macOS 终端,支持内联图片
-
Pi,我的编程代理
-
Git worktree,隔离并行任务
-
Herdr,管理这些 worktree、终端和代理
-
hunk,审查改动,给 Pi 留下内联反馈
-
Tailscale 加 SSH,提供远程连接
-
Heeler,方便我在 iPhone 上查看代理状态
每个组件只做一件相对较小的事,组合起来却很好用。
这也是我最喜欢这套方案的地方。编程代理让并行处理大量工作变得可行,按理说很容易导致开发环境越来越复杂。
但我的最终方案,本质上就是 Git、一个终端,再加一个现代版的 tmux。
代理变复杂了,围绕代理的工具不必跟着变复杂。
另见
-
为什么 Pi 是我的 AI 编程工具
-
用自托管的 Gitea 备份我的代码仓库
-
用 Git worktree 做开发
-
自动合并 Xcode 项目文件里的冲突
-
为个人项目和工作项目使用不同的 Git 配置