第35篇:看板工作通道——分工流水线
Hermes 功能详解第35篇:Kanban Worker Lanes。看板里的分工机制。
这篇讲的是 Hermes Agent 里的“看板工作通道”(Worker Lane)——你可以把它想象成一条工厂流水线,每个工位(通道)负责一类活儿,看板系统负责把任务派给合适的工位,并盯着每项任务从“待办”走到“完成”。
先理解三个角色
- 看板(Kanban):总调度台,记录每张任务卡片的真实状态(待办→进行中→阻塞/完成/归档)。
- 工作通道(Worker Lane):一个“工种”,比如“写代码的”“做研究的”“审代码的”。它只负责干活,不拥有状态——干完必须向看板汇报。
- 审查员(Reviewer):真人(或代理),负责把关“代码改完了”和“任务真完成了”之间的那道门。
第1步:给任务分配“工种”
每个任务卡片上有个 assignee 字段,相当于“派给谁”。看板调度器看到这个字段,就会去找对应的通道。
- 如果
assignee是 Hermes 配置文件的名字(比如coder、researcher),调度器会自动启动hermes -p coder chat -q <提示词>来干活。 - 如果
assignee是外部工具(比如 Codex CLI),目前需要插件来注册,还不是一条铺好的路,需要自己写集成代码。
任务找不到对应通道时,不会被乱执行,而是留在“待办”状态并打上
skipped_nonspawnable标记,等管理员来修。
这个 skipped_nonspawnable 事件里会带上 {assignee},明确告诉你缺的是哪个配置文件。它每张卡只写一次(除非中间又插进了别的事件),所以 show/tail 能一眼看出是哪个 profile 不见了,而不会每个调度周期刷一行。卡片会一直留在 ready,你重新指派或把那个 profile 装上就行。
第2步:工位怎么“开工”?
调度器会在任务的专属工作目录里启动工人,并塞给它一堆环境变量,告诉它“你是谁、在哪个板、任务ID是多少”。比如:
HERMES_KANBAN_TASK=task_123
HERMES_KANBAN_BOARD=my_board
HERMES_KANBAN_WORKSPACE=/path/to/workspace
HERMES_PROFILE=coder
工人拿到这些信息,就知道该干什么了。
第3步:干完怎么“交差”?
每个任务必须且只能有一个结局,三选一:
| 结局 | 调用工具 | 状态变成 |
|---|---|---|
| 成功 | kanban_complete(summary="...") |
done |
| 需要人工介入 | kanban_block(reason="...") |
blocked |
| 进程退出但没汇报 | (无) | crashed / gave_up / timed_out |
最关键的约定:如果任务是“改代码”这类需要人审的,工人应该用 kanban_block 而不是 kanban_complete,并且在 reason 前面加上 review-required: 前缀。这样看板界面就会把这行标成“待审查”。
审查员看完后,如果通过就执行 kanban_unblock,任务会重新派给工人做后续;如果要求修改,就留个评论,下一轮工人会看到。
别把“支援卡”挂到它要解锁的那张卡下面:如果工人卡在
t_parent上,又为缺的那块建了张支援卡,千万别kanban_link(t_parent, t_support)——这样支援卡会变成被阻塞父卡的子卡,反而被它本该解锁的父卡挡住,两张卡都跑不起来。正确做法是在支援卡正文里引用父卡 id。link/kanban_link把一张ready子卡降级时会报gated: true并记一条dependency_wait事件(kanban_create带parents时同理),所以死锁在看板上是看得见的;用hermes kanban unlink <parent> <child>就能解开。
第4步:看日志和审计
每项任务的所有输出都存在 <board根目录>/logs/<任务ID>.log 里。想看历史:
hermes kanban runs <task_id> # 看所有尝试记录
hermes kanban tail <task_id> # 实时跟踪日志
想按状态筛卡片时,hermes kanban list 支持 --sort 参数(可选 completed-desc、created、created-desc、priority、priority-desc、status、assignee、title、updated)。看板上的 done 列是历史记录,按完成时间从新到旧排列;hermes kanban list --status done --sort completed-desc 在命令行里给出同样的顺序。其余各列则按派发顺序排列卡片(先看优先级,再看谁最老——最上面那张就是下一个要开工的)。
第5步:调度器帮你兜底
- 工人假死:超过15分钟没心跳且进程真的死了,任务会被回收重派。
- 工人崩溃:连续失败次数超限,任务自动进入“阻塞”状态等人处理。这个上限的取值顺序是:任务自己的
max_retries→ 调度器的failure_limit/kanban.failure_limit→ 内置默认值。触发时记一条gave_up事件,里面带上{failures, effective_limit, limit_source, error},卡片会带着最后一次的错误自动阻塞。 - 超时:超过最大运行时间,自动标记
timed_out。 - 干完不收工:工人调完
kanban_complete/kanban_block后还赖着不走,等它的运行记录关闭满两分钟就会被终止(按 PID 加启动时间指纹匹配,不会误杀复用的 PID),并记一条terminal_worker_reaped事件。 - 启动即失联:如果调度器在启动工人后、还没来得及记录它的 pid 就挂了,工人会在第一次调用模型前自己把
worker_registered事件({pid, started_at})写进看板。这样存活检查就能看到它,到期的认领会被续期,而不是又拉起第二个工人;反过来,如果工人的这次运行在它走到这一步之前就被回收了,它会直接退出,不再动这张卡。
有一种失败重试也没用:如果工人是因为“换个凭据也修不好”的供应商错误退出的(比如凭据被吊销、模型下线),它会以退出码
78结束,gave_up事件里会带上terminal_provider: true。这种情况第一次尝试就会直接熔断(不管重试上限是多少),卡片立刻阻塞。启动阶段就发现凭据失效、需要重新登录(hermes auth/setup)的,也会在跑第一轮之前就以78退出;其它启动失败则是退出码1。
这些你都不用自己写,调度器全包了。
注意:工作通道里也能用
delegate_task:看板任务在该 profile 的网关下、由隔离的托管工人执行,它派出的delegate_task子任务由这个网关在工人的执行下预留:每个子任务有自己的会话(在卡片会话里列为 subagent),计入delegation.max_concurrent_children和delegation.max_spawn_depth,结果在卡片的这一轮里返回,并随工人一起结束。如果网关在子任务中途挂掉,子任务会被作废、不会恢复。需要活过网关重启、或者需要自己审查员的活儿,仍然应该拆成子卡片(kanban_create带parents)。
第6步:审查用的 gh 登录,走的是“工人自己的身份”
如果任务需要读 GitHub(比如验收时查 PR、看仓库),Hermes 用的是被指派 profile 自己的 gh 登录——也就是那个 profile 的 .env 里的 GH_TOKEN / GH_CONFIG_DIR,不是当前进程的环境登录。
- 一台机器上挂了多个 profile(每个组织一个 GitHub 身份)时,要给每个 profile 单独登录
gh:把GH_CONFIG_DIR写进那个 profile 的.env。 - token 必须放在 profile 的
.env(或配置好的密钥来源)里。只在 shell 里export GH_TOKEN、或者写在 systemd unit 里的,会被从gh子进程里清掉,而且不会被重新加回去。 - 被指派的 profile 自己没有
gh登录、或者这个 profile 已经不存在了,会直接报not logged in拒绝,不会退回去用~/.config/gh。没指派 assignee 的卡片才用环境里的登录。 - 登录了但看不到这个仓库,会以
classification=auth被拒,错误里会点名是哪个 profile、哪个仓库——而不是当成可重试的基础设施故障。
小总结
工作通道 = 一个身份(assignee)+ 一个启动方式(spawn)+ 一个结束约定(terminator)。你只需要定义好配置文件,剩下的调度、重试、审计,看板系统都帮你管好了。
下篇预告:第36篇——看板审查流程:如何让“人工把关”变得高效又省心。
📖 官方文档
本文根据 Hermes Agent 官方文档编写,原文见:官方文档 › user-guide/features/kanban