所有文章
使用案例

用手机飞书指挥电脑上的一群 Agent:
Larkway × Herdr 实录

本机 Herdr 里跑着 Claude Code、Codex、pi 等常驻 agent,人出门只带手机。不改一行 Larkway 代码,让一个 Larkway agent 学会用 herdr CLI,飞书里 @ 一下,电脑上的 agent 就开始干活。这篇记录整个过程、踩到的坑和最后沉淀下来的 skill。

Larkway 0.3.x Herdr Claude Code · Codex · pi 2026-09-06 · 约 12 分钟

问题:agent 都在电脑上,我在外面

Herdr 是一个给 coding agent 用的终端工作区管理器。它把 Claude Code、Codex、pi 这些交互式 agent 各放在一个 pane 里常驻,能识别它们是 idle、working 还是 blocked,并且暴露一套 herdr CLI 来操作它们。我的本机 Herdr 里长期挂着四个:一个 Claude Code、两个 Codex、一个跑便宜模型的 pi;Mac mini 上还有两个。

在电脑前,这套东西很顺手。出了门就只剩手机,问题来了:

飞书是我手机上常驻的入口,Larkway 已经把本机 agent 接进了飞书。于是问题变成:能不能让 Larkway 里的 agent 去操作 Herdr 里的 agent?

思路:不加后端,让 agent 学会用工具

第一反应是给 Larkway 加一个 herdr backend,把飞书话题和 Herdr pane 一一绑定。这条路能做,但把用法写死了:一个 bot 只能对应一个 pane,Herdr 里 agent 增减都要改配置。

最后选的是另一条路:Larkway 里的 agent 本来就能跑 Bash,那就让它学会 herdr CLI。它自己去发现现在有哪些 agent、谁有空、在哪个目录,自己决定派给谁,自己等、自己取结果。Larkway 一行代码不改,Herdr 里的成员可以随时变。

手机飞书 @ 管家 管家 agent 拆解 · 挑人 herdr agent prompt 取证 · 回飞书

为此我把一个 Larkway bot 重新定义成「管家」:理解需求和目标,拆解任务,简单的自己做,其余通过 herdr CLI 派给 Herdr 里的 agent,跟进后汇总回报。它的角色,其实和你在电脑前开着的那个 Claude Code 主对话一样,只是入口换成了飞书。

落地:三处配置,零代码

Larkway 的 bot 子进程和 Herdr server 在同一台机器上,走本地 socket 就能通。真正要处理的是三件小事:

  1. 装 herdr skill。Herdr 自带一份给 agent 读的 skill,用 herdr --skill 就能打出来。放到 ~/.agents/skills/herdr/SKILL.md,Claude Code 和 Codex 两种后端都能读到。

  2. 绕过 skill 的守卫。官方 skill 第一步会检查 HERDR_ENV=1,不满足就要求 agent「说明自己不在 Herdr 里并停止」。Larkway 的 bot 不在 pane 里,但 CLI 从外面调完全正常。在 ~/.larkway/.env 里加一行 HERDR_ENV=1,bridge 会透传给子进程。

  3. 放行命令。Larkway 给 Claude 后端的 bot 用的是 acceptEdits 权限模式,Bash 命令靠白名单。在 ~/.larkway/config.jsonpermissions.allowExtra 里加 Bash(herdr *),要操作另一台机器再加一条 Bash(ssh <host> *)

~/.larkway — zsh
# 1. skill
$ mkdir -p ~/.agents/skills/herdr && herdr --skill > ~/.agents/skills/herdr/SKILL.md

# 2. 守卫变量(bridge 透传给 bot 子进程)
$ echo 'HERDR_ENV=1' >> ~/.larkway/.env

# 3. 放行(~/.larkway/config.json)
"permissions": { "allowExtra": ["Bash(herdr *)", "Bash(ssh mac-mini *)"] }

$ larkway stop && larkway start

然后在管家 bot 的职能 memory 里写清角色和原则:你在 Herdr 外面当调度员;每次先 herdr agent list 发现现在有谁;挑人看状态、目录、类型;派出去的任务要自包含;working 的不打断,blocked 的把问题带回来。

实录一:先证明链路是通的

第一条测试故意很小:让 bot 去问 Herdr 里的 pi「1+1 等于几」。

Agents · 飞书群
我 · 手机
@管家 测试 Herdr 操作:先 herdr agent list 看 work-pi 的状态;如果 idle,让 work-pi 回答「1+1 等于几,用一句话回答」,等它完成后把回答贴回来。
管家 Larkway
Herdr 操作测试完成

1. herdr agent list → work-pi 状态 idle

2. herdr agent prompt work-pi "1+1 等于几,用一句话回答" --wait

3. herdr agent read work-pi → work-pi 的回答:「1+1 等于 2。」

与此同时,电脑上 Herdr 那个 pi 的 pane 里,能看到这一问一答真实发生了。链路通了。

实录二:管家自己挑人

第二条不指定 agent,考它「发现、挑人、派活、回报」整套动作:看看 Herdr 里有谁可用,挑一个最轻量的问「今天星期几」,说明挑人的理由。

Agents · 飞书群
管家 Larkway
管家测试通过 — pi 的回答:「今天是星期六。」

当前 Herdr 里的 agent(4 个,全部 idle)

名字类型状态
work-claudeclaudeidle
work-codexcodexidle
work-codex-2codexidle
work-pipiidle

挑人理由:选 work-pi。这是一句话问答,零代码、零项目上下文,按选人原则该给 pi,把 Claude / Codex 两类重型编码 agent 留着跑真活。

一个小插曲:第一次派活我写了「不要执行任何命令」,pi 回「我无法凭空判断今天星期几」。第二次允许它跑 date 后正确答出星期六。结论:问 agent 时间类问题,必须允许它查系统时间。

最后那段「小插曲」是它自己发现并主动写进回报的,之后还追加到了自己的知识库里。这正是我想要的:skill 给基础用法,agent 在使用中把坑记下来,下次自己避开。

实录三:派给 Codex,读文件取证

第三条是真正的派活:让一个空闲的 Codex 在临时目录写一个 hello.py(打印时间和 Python 版本)并运行,把输出原文回报,并说明结果从哪取证。

Agents · 飞书群
管家 Larkway
任务完成

派给了 Herdr 里的 work-codex(Codex agent),它写好并运行了 /tmp/herdr-out/hello.py,输出为 2026-09-06 00:41:16 的时间戳和 Python 3.11.4 版本信息,exit 0。

证据来自它按约定写的结论文件 /tmp/herdr-out/work-codex-20260906-004050.md,我在本机独立重跑一次结果一致。

Codex 那边留下的结论文件长这样:源码、运行命令、输出原文、exit code,一样不少。管家读的是这个文件,不是抓屏。

/tmp/herdr-out/work-codex-20260906-004050.md
# hello.py

## 运行输出原文
2026-09-06 00:41:16.087130
3.11.4 (main, Jul 25 2023, 17:07:07) [Clang 14.0.3 ...]

## exit code
0

整轮从 @ 到卡片回来不到一分钟。

踩到的坑

1. 等待状态:done 不是 idle

第一版 memory 让它用 --wait --until idle。结果 pi 跑完后 Herdr 把状态标成 done(后台完成、UI 没看过),wait 一直等不到 idle,直到 Bash 工具 2 分钟超时。正确用法是 --wait 不加 --until:默认就等 idle、done、blocked 三个状态中的任一个。另外要把 Bash 工具的超时参数调到 10 分钟,不然超时的是 bot 自己。

2. bot 自己重启 bridge,把自己杀了

中途我让管家升级本机 Larkway。它装完新版,问我要不要重启 bridge,我选了「后台延迟重启」。它执行 larkway stop 的瞬间,bridge 连同它自己的进程一起被杀,后面的 larkway start 永远跑不到,四个 bot 离线了几分钟,最后是我手动起的。

所有会影响 bridge、Herdr server、网络的操作,都不该经过这条链路。写进硬规则:bot 不重启自己的 bridge,要重启就把命令给人自己跑。

3. 二手信息会「合理化」

bridge 恢复后,管家自己挂的闹钟触发了,它跑去确认版本,回报里写道「重启脚本撞上了 launchd 竞争,launchd 自己把新进程拉起来了」。结果是对的,原因是编的。它没有证据,但给出了一个听起来合理的解释。这条链路里 agent 转述 agent,每一层都可能加一点自己的推断,所以后来把「取证来源」写成了硬规则。

4. 抓屏当返回值靠不住

herdr agent read 读到的是渲染后的终端文本:状态栏、进度条、输入框、上一轮残留都混在一起。短回答还行,长任务的输出基本没法用。agent 跑在 alternate screen 上时,旧行连 scrollback 都进不去,加大 --lines 也读不回来。

沉淀:herdr-operator skill

把以上全部收进一份 skill,视角是「我在 Herdr 外面调度一群 agent」,放在 ~/.agents/skills/herdr-operator/。管家和备用操作员的 memory 都只指向它,不再各写一遍命令。要点:

这条路适合什么,不适合什么

跑了一晚上,我的判断是:它是一个异步派单系统,不是远程终端。

场景推荐为什么
人在外面,给一个清楚的目标,等结果飞书 → Larkway → Herdr覆盖所有 agent 类型,不用装 SSH 客户端,共享电脑上的会话,回来能接着看。
只用 Claude,要原生流式体验和权限提示Claude Code Remote Control结构化、实时,但只覆盖 Claude。
要盯着屏幕边聊边改SSH + Tailscaleagent 弹选项、要确认的交互场景,一个来回经过飞书要一两分钟,体验会断。

三条不冲突。日常派活走飞书,Claude 深聊用 Remote Control,真要盯屏就开 SSH。

为什么坚持「让 agent 学工具」

做完回头看,这次最关键的决定是没有给 Larkway 写 herdr 后端。管道式的方案会更「稳」,但每次 Herdr 里多一个 agent、换一个项目目录、要并行派两个,都得改配置或改代码。让 agent 学会工具之后,这些都是它自己判断的事:它会看谁有空、谁在哪个目录、哪个便宜,也会在遇到坑之后把经验记下来。

Larkway 一直的定位就是薄通道:bridge 只做 agent 做不了的事(飞书长连、卡片、进程管理),流程和判断交给 agent。这次只是把「工具」从 git 和 MR 换成了另一群 agent。


想自己搭一套

  1. Herdr,把你常用的 agent 起在 pane 里并命名(herdr agent rename)。
  2. Larkway,建一个 bot,跑 larkway start
  3. 按上面三处配置:skill、HERDR_ENV=1allowExtra
  4. 给 bot 的 memory 写清角色(调度员,不是执行者),命令用法交给 skill。
  5. 在群里 @ 它,从一句「问问 pi 1+1 等于几」开始。

有问题欢迎来 交流群 聊。