Skip to content

看板工人泳道 (Kanban worker lanes)

hermes agent 看板教程

工人泳道 是看板调度器可以路由任务的一类进程。每个泳道都有一个身份标识(受理人字符串)、一种启动机制,以及一份关于启动后必须如何处理任务的协议。

本页面即是该协议。它面向两类受众:

  • 操作人员(Operators):负责挑选哪些泳道接入看板(创建哪些配置文件、使用哪些受理人)。
  • 插件/集成作者:希望添加新的泳道形式(例如封装了 Codex / Claude Code / OpenCode 的 CLI 工人、容器化的审查工人,或通过 API 拉取任务的非 Hermes 服务)。

如果你正在编写工人代码本身——即在泳道 内部 运行的智能体——那么 kanban-worker 技能(skill)提供了更深层次的程序细节。

Hermes Kanban = canonical task lifecycle + audit trail
Worker lane = implementation executor for one assigned card
Reviewer = human or human-proxy that gates "done"
GitHub PR = upstreamable artifact (optional, for code lanes)

Hermes Kanban 掌握生命周期的真相 —— readyrunningblocked / done / archived。工人泳道负责执行工作,但永远不掌握该真相;它们所做的一切都会通过 kanban_* 工具(或者对于非 Hermes 外部工人,通过 API)流回看板内核。审查者负责把控从“代码变更已编写”到“任务完成”的转变。

要成为一个看板工人泳道,集成必须提供以下三样东西:

1. 一个受理人字符串 (Assignee string)

Section titled “1. 一个受理人字符串 (Assignee string)”

调度器会将 task.assignee 与 Hermes 配置文件名称(默认泳道形式)或注册的不可派生标识符(插件泳道形式 —— 参见下文的 添加外部 CLI 工人泳道)进行匹配。受理人无法解析的任务将保持在 ready 状态,并触发 skipped_nonspawnable 事件,以便看板操作员进行修复;这些任务不会被默默丢弃,也不会由任意的备选方案执行。

对于 Hermes 配置文件泳道,调度器通过 _default_spawn 在任务固定的工作空间内运行 hermes -p <assignee> chat -q <prompt>(或当 $PATH 中没有 hermes 垫片时的等效模块形式),并设置以下环境变量:

变量名携带内容
HERMES_KANBAN_TASK工人正在操作的任务 ID
HERMES_KANBAN_DB每个看板唯一的 SQLite 文件的绝对路径
HERMES_KANBAN_BOARD看板别名 (slug)
HERMES_KANBAN_WORKSPACES_ROOT看板工作空间树的根目录
HERMES_KANBAN_WORKSPACE任务工作空间的绝对路径
HERMES_KANBAN_RUN_ID当前运行的 ID(用于生命周期门控)
HERMES_KANBAN_CLAIM_LOCK认领锁定字符串 (<host>:<pid>:<uuid>)
HERMES_PROFILE工人自身的配置文件名称(用于 kanban_comment 的作者归属)
HERMES_TENANT租户命名空间(如果该任务有租户)

对于非 Hermes 泳道(通过插件注册),插件会提供自己的 spawn_fn 可调用对象,该对象接收 taskworkspaceboard 参数,并返回一个用于崩溃检测的可选 PID。

3. 一个生命周期终止符 (Lifecycle terminator)

Section titled “3. 一个生命周期终止符 (Lifecycle terminator)”

每一次认领必须以以下情况之一明确结束:

  • kanban_complete(summary=…, metadata=…) — 任务成功,状态翻转为 done
  • kanban_block(reason=…) — 任务等待人工输入,状态翻转为 blocked。当执行 kanban_unblock 时,调度器会重新派生工人。
  • 工人进程在没有工具调用的情况下退出。内核会回收它并发出 crashed(PID 死亡)、gave_up(触发连续失败断路器)或 timed_out(超过最大运行时间 max_runtime)信号。这是失败路径;健康的工人不应在此结束。

看板内核强制要求每次运行必须由上述情况之一终止。既没有调用工具又正常退出的工人将被视为已崩溃(crashed)。

对于大多数代码变更任务,工作在工人完成的那一刻并算不上真正的 完成——它需要一名人类评审员。看板内核并不强制执行这种区别(“代码变更任务” 定义较模糊,且对每个代码工人强制执行 “以阻塞代替完成” 会破坏那些不需要评审的流程)。这是一种叠加在系统之上的惯约:

  • **以阻塞(Block)代替完成,并在 reason(原因)前缀加上 review-required:**:这样仪表板和 hermes kanban show 就会将该行显示为等待评审。
  • 先将结构化元数据放入 kanban_comment(评论)中:因为 kanban_block 仅携带人类可读的 reason。评论是持久的标注通道——每一个与审计相关的字段(changed_filestests_rundiff_path 或 PR URL、decisions)都属于这里。
  • 评审员要么批准并解除阻塞(这会携带包含后续跟进评论的上下文重新派生工人);要么通过另一条评论要求更改,下一个工人运行周期通过 kanban_show 的上下文即可看到这些内容。

kanban-worker 技能中包含了 kanban_complete(真正的终结性任务——如拼写修复、文档更改、研究报告)和 review-required 阻塞模式的实践案例。

调度器会将每个任务的工人标准输出/错误(stdout/stderr)写入 <board-root>/logs/<task_id>.log。日志可以通过看板元数据进行审计:

  • task_runs(任务运行)行携带 log_path、退出代码(如果可用)、摘要和元数据。
  • task_events(任务事件)行携带每一次状态转换(promotedclaimedheartbeatcompletedblockedgave_upcrashedtimed_outreclaimedclaim_extended)。
  • kanban_show 返回上述两者,因此读取任务的评审员(或后续工人)无需访问仪表板即可获取完整历史记录。

仪表板会渲染带有摘要、元数据块和退出状态徽章的运行历史。CLI 用户可以运行 hermes kanban tail <task_id> 进行实时跟踪,或运行 hermes kanban runs <task_id> 查看历史尝试列表。

目前每个看板工人采用的形式:受理人是一个配置文件名称,调度器派生 hermes -p <profile>,工人自动加载 kanban-worker 技能以及 KANBAN_GUIDANCE 系统提示词块,并使用 kanban_* 工具终止运行。除了定义配置文件外,无需额外设置。

当你为你的集群创建配置文件时,请选择与你希望编排器(orchestrator)路由到的 角色 相匹配的名称。编排器(如果存在)会通过 hermes profile list 发现你的配置文件名称——系统不预设固定的名册(有关合约的编排器端,请参阅 kanban-orchestrator 技能)。

配置文件泳道的一种特殊化:编排器是一个 Hermes 配置文件,其工具集包含 kanban 但不包含用于实现的 terminal / file / code / web。它的工作是将高级目标通过 kanban_create + kanban_link 分解为子任务并退居幕后。编排器技能编码了这些 “防诱惑” 规则。

将非 Hermes 的 CLI 工具(如 Codex CLI、Claude Code CLI、OpenCode CLI、本地编码模型运行器等)接入作为看板工人泳道目前尚非现成的路径。调度器的派生函数是可插拔的(spawn_fndispatch_once 的一个参数),插件可以为非 Hermes 的受理人注册自己的 spawn_fn,但相关的集成工作——如将 CLI 的退出代码包装进 kanban_complete / kanban_block 调用、将 CLI 的工作空间/沙箱惯例映射到调度器的 HERMES_KANBAN_WORKSPACE 环境变量、处理身份验证及各 CLI 特有的策略——仍属于需要逐一设计的集成工作。

如果你正考虑添加 CLI 泳道,请提交一个 Issue 来描述具体的 CLI 以及你尝试启用的工作流。上文所述的“协议”是任何此类泳道必须满足的约束;具体的实现形式(是为每个 CLI 开发一个插件,还是开发一个通过配置参数化的通用 CLI 运行器插件)仍处于开放讨论状态。

与之相关的历史 Issue 为 #19931,以及已关闭但未合并的 Codex 专用 PR #19924 —— 它们描述了最初的架构提案,但并未最终落地运行器。

为了让泳道作者无需重复实现这些功能,调度器处理了以下情况:

  • 过期认领 TTL (Stale claim TTL) — 如果一个工人认领了任务,但从未发送心跳(heartbeat)、完成(complete)或阻塞(block),则在 DEFAULT_CLAIM_TTL_SECONDS(默认 15 分钟)后会被回收——但前提是该工人进程确实已经死亡。对于存活的工人(如正在进行长达 20 分钟以上、无工具调用的 LLM 推理的慢速模型),其认领会被延长而非杀掉;只有检测到 PID 消失时才会被回收。
  • 崩溃的工人 (Crashed worker) — 宿主机本地 PID 消失的工人会被 detect_crashed_workers 检测到并进行收尾;任务的 consecutive_failures(连续失败次数)会递增,并可能在断路器跳闸时自动进入阻塞状态。
  • 运行级重试 (Run-level retry) — 当任务重试时(阻塞后、崩溃后、回收后),工人在终止工具上可以使用 expected_run_id 参数,以便在自身运行已被取代时快速失败。
  • 单任务最大运行时间 (Per-task max runtime)task.max_runtime_seconds 强制限制了单次运行的挂钟时间(wall-clock time),无论 PID 是否存活。这能捕获那些因 PID 存活检测而可能被不断延长的真正死锁的工人。
  • 滞留任务检测 (Stranded-task detection) — 如果一个处于 ready 状态的任务其受理人在 kanban.stranded_threshold_seconds(默认 30 分钟)内从未产生认领,则在 hermes kanban diagnostics 中会显示为 stranded_in_ready 警告。严重程度在 2 倍阈值时升级为错误(error),在 6 倍时升级为紧急(critical)。这一信号能统一捕获拼写错误的受理人、已删除的配置文件以及宕机的外部工人池——它不区分身份,无需手动维护各看板的白名单。
-
0:000:00