kanban-code-orchestrator:用 Hermes Kanban 构建可恢复的编程工作流
项目地址:lichenrobo/kanban-code-orchestrator
核心入口:SKILL.md
完整协议:workflow-protocol.md
摘要
kanban-code-orchestrator 是一个运行在 Hermes Agent 上的软件开发编排 Skill。它把调用 Skill 的持久 TUI/Gateway chat session 直接作为 Orchestrator,只创建三个执行型 Profile:
kanban-code-coder:实现需求并修复缺陷;kanban-code-tester:独立验证并输出 QA 结论;kanban-code-reviewer:在 QA 通过后执行最终工程审查。
工作流不是把三个 Agent 一次性并发启动,也不是依赖自然语言“约定俗成”地交接,而是在 Hermes Kanban 的持久 Task、run、parent link 和 terminal event 之上实现一台显式状态机。Orchestrator 只接受 Worker 最新 completed run 的 metadata.result 作为状态转换输入;网络中断、Worker 崩溃和通知丢失都不会隐式转移工作流所有权。
这套设计要解决的不是“让三个模型互相聊天”,而是四个更具体的工程问题:
- 谁拥有创建下一张 Task 的唯一权限;
- 如何区分 Task 生命周期结束与业务验收通过;
- 如何在会话恢复后重建状态并避免重复建卡;
- 如何把业务重试与基础设施重试拆成两个独立熔断域。
Hermes Kanban 是什么
Hermes Kanban 是 Hermes Agent 内置的多 Profile 持久任务板。它不是一次性的 subagent 调用,而是一个由 SQLite 持久化的任务队列与状态系统:Task、run、依赖关系、评论和事件都写入 Kanban 数据层,Worker 则以具有独立 Profile 身份的 OS 进程运行。
Hermes 官方文档将它与 delegate_task 的差别概括为两类计算模型:后者接近同步 RPC,父 Agent 发起调用并等待返回;Kanban 更接近 durable work queue,任务可以跨会话、跨进程、跨人工干预继续存在。
Kanban 的关键组件包括:
| 组件 | 技术职责 |
|---|---|
| Board | 隔离任务、事件、Workspace 和日志的持久队列;默认 Board 使用 ~/.hermes/kanban.db |
| Task | 带 assignee、body、status、Workspace 和依赖关系的工作单元 |
| Run | Worker 对 Task 的一次执行尝试,保存 outcome、summary 和 metadata |
| Profile | 独立的 Hermes Home,拥有自己的模型配置、.env、SOUL.md、memory 和 session |
| Dispatcher | 周期性提升、原子认领 Task,并拉起对应 Profile 的 Worker 进程 |
| Terminal event | completed、blocked、gave_up、crashed、timed_out 等终态事件 |
模型通过 kanban_create、kanban_show、kanban_complete 等结构化工具访问任务板,而不是在 shell 中执行 hermes kanban ...。CLI 面向人类和脚本;kanban_* toolset 面向正在推理的 Agent。两条入口最终访问同一数据层,但工具调用避免了 shell quoting、远程终端中找不到 Hermes CLI,以及从 stderr 反解析状态等问题。
Profile 与 Workspace 也必须区分。按照 Hermes Profiles 文档,Profile 是 Agent 的配置与状态边界,并不等价于文件系统沙箱;Workspace 才是本次 Task 实际操作的目录。kanban-code-orchestrator 因此不会把某个项目路径永久写入 Worker 的 terminal.cwd,而是在每张 Task 上显式传递绝对 dir:<path> Workspace。
为什么不能只写一句“Coder 完成后交给 Tester”
自然语言角色提示可以约束单个 Agent,却不能自动提供分布式工作流需要的控制语义。例如:
- Coder 说“完成了”,但没有调用
kanban_complete,Task 仍未形成持久交接; - Task 进入
done,只说明某次执行结束,不代表 Tester 返回了QA_PASS; - Reviewer 拒绝后直接重新审查,跳过 Tester,会让修复代码绕过回归测试;
- Orchestrator 断线后,其他 session 若擅自补建 Task,可能产生两个并行状态分支;
QA_FAIL与模型 API 崩溃都表现为“没成功”,但它们需要完全不同的重试预算。
因此,本项目把角色提示、Task 数据契约和 Orchestrator 状态机同时纳入协议。SOUL 负责约束 Worker 能做什么;Task body 负责携带不可丢失的上下文;metadata.result 负责机器可判定的交接;当前 chat session 负责唯一的状态转换。
Skill 的整体工作流
1. 首次运行:配置控制面与三个执行面
第一次调用 /kanban-code-orchestrator 时,Skill 先做只读 readiness 检测。只有发现缺项时才加载 first-run-setup.md,并与用户交互确认:
- 同名 Worker Profile 是复用、备份后更新,还是重建;
- 三个 Worker 继承现有模型/API 配置,还是分别手动配置;
- 当前 Profile 是否具有 Kanban 编排工具;
- 三个 Worker 是否启用 coding toolset;
auto_decompose=false与auto_subscribe_on_create=true是否成立;- 哪个 Gateway 是唯一 Dispatcher owner;
- 是否允许执行可能产生模型费用的 smoke test。
首次配置只创建三个 Worker Profile,不创建 kanban-code-orchestrator Profile。Worker SOUL 来自仓库中的固定模板;API Key、OAuth token 和 bot token 不进入聊天或仓库,只在本地 setup、环境变量或 Profile .env 中配置。
2. 正常运行:当前 session 成为唯一 Orchestrator
后续调用若 readiness 已满足,当前 TUI/Gateway chat session 直接成为 workflow 的 initiator、owner 与 Orchestrator:
Current persistent chat session
(Orchestrator)
│
▼
kanban-code-coder
│ IMPLEMENTATION_COMPLETE
▼
kanban-code-tester
┌──────┴──────┐
QA_FAIL QA_PASS
│ │
▼ ▼
Coder Fix kanban-code-reviewer
│ ┌────┴─────────┐
└─Tester │ │
REVIEW_REJECT REVIEW_APPROVE
│ │
▼ ▼
Coder Fix → Tester WORKFLOW_DONE
启动新 workflow 前必须确定:稳定的 workflow_id、绝对 Workspace、完整需求、acceptance criteria,以及业务重试和 Worker 基础设施重试上限。
3. 状态机
定义阶段集合:
S = {CODER, TESTER, REVIEWER, DONE, ESCALATION, ERROR}
Worker 允许输出的业务结果集合:
R_coder = {IMPLEMENTATION_COMPLETE}
R_tester = {QA_PASS, QA_FAIL}
R_reviewer = {REVIEW_APPROVE, REVIEW_REJECT}
状态转换函数可以写成:
δ(CODER, IMPLEMENTATION_COMPLETE) = create(TESTER)
δ(TESTER, QA_PASS) = create(REVIEWER)
δ(TESTER, QA_FAIL) = tester_retry++ ; create(CODER_FIX)
δ(REVIEWER, REVIEW_REJECT) = reviewer_retry++ ; create(CODER_FIX)
δ(REVIEWER, REVIEW_APPROVE) = DONE
δ(any, unknown_or_missing_result) = ERROR
其中两个回路存在严格约束:
QA_FAIL → Coder Fix → Tester
REVIEW_REJECT → Coder Fix → Tester → Reviewer
任何 Coder 修改都必须重新经过 Tester。Reviewer 拒绝后的修复不能直接回到 Reviewer,这是协议最重要的回归测试不变量之一。
工作流实现原理
原理一:Chat session 是控制平面,不再创建 Orchestrator Worker
早期常见设计会创建一个独立 Orchestrator Profile,再由它的无头 Worker 派发任务。问题在于,无头进程未必携带正确的平台 session identity;如果它错误继承其他进程的 session key,自动订阅可能绑定到错误会话。Orchestrator 一旦断线,外层 chat 又可能误以为自己需要“接管”,最终形成双写控制面。
本项目直接让发起 Skill 的持久 TUI/Gateway chat 成为 Orchestrator。这样,创建者身份、事件订阅目标和用户可见会话天然重合:
workflow_owner_kind: chat_session
workflow_owner_profile: <current profile>
workflow_owner_session_id: <current session identity when available>
它只编排,不直接编码、测试或审查。Dispatcher 只负责拉起 Worker,也不拥有业务分支决策权。
原理二:唯一写入者与显式所有权
每条 workflow 只有 owner session 可以执行以下 mutation:
- 创建 Coder、Tester、Reviewer 和 Fix Task;
- 增加业务重试计数器;
- 选择下一状态;
- 建立 parent chain。
Worker 只能 complete 或 block 自己当前的 Task,不能创建下一阶段。网络中断、Gateway 重启、通知失败、Worker crashed 或 timed_out 都不是 ownership transfer event。owner 不可用时系统 fail closed,进入 WORKFLOW_ORCHESTRATOR_UNAVAILABLE,而不是让任意 Profile 猜测并补写任务图。
新的 session 只有在用户明确授权后才能接管,并且必须先读取完整 Task、run、parent 与 event 链,找到最后一个合法 completed run,再检查下一阶段 Task 是否已经存在。
原理三:通过 kanban_create 建立 creator-session subscription
Owner chat 必须直接调用 kanban_create,不能退化为 shell、subprocess 或 hermes kanban create。这不仅是接口风格问题,还关系到订阅来源:auto_subscribe_on_create=true 会把 terminal event 绑定到发起创建的持久 session。
创建后必须保存并验证:
task_id = <new task id>
subscribed = true
subscription target = owner session
delivery_mode = notify | notify+wake
Hermes 官方订阅语义 中,notify 只投递被动消息,notify+wake 还会触发目标 Agent 的新推理轮次。因此本 Skill 接受两者,但不会把 notify 宣称为完全无人值守:若只有被动通知,用户可能需要在同一 session 中执行:
/kanban-code-orchestrator continue <workflow_id>
工作流不使用 sleep 或轮询保活。事件到达后才读取 Task;用户主动查询状态时也只执行只读检查。
原理四:Terminal event 只是中断信号,metadata.result 才是业务输入
completed event 只意味着 Worker run 到达终态,可能只携带截断摘要。Orchestrator 收到事件后的读取路径固定为:
event.task_id
→ kanban_show(task_id)
→ latest run where outcome=completed
→ run.summary + run.metadata
→ branch on run.metadata.result only
它不会依据 Task 标题、顶层 status=done、通知文本、summary 首行或顶层 result 推进。缺少或出现未知 metadata.result 时进入 WORKFLOW_PROTOCOL_ERROR。
这是典型的控制面/数据面分离:terminal event 类似中断,只负责通知“有状态变化”;completed run metadata 才是状态机读取并验证的持久数据。
Worker 的结构化交接示例:
{
"result": "QA_FAIL",
"tests_executed": ["pytest tests/test_auth.py"],
"tests_passed": 17,
"tests_failed": 1,
"failing_tests": ["test_expired_refresh_token"],
"reproduction_steps": ["issue an expired refresh token", "POST /token/refresh"],
"expected_result": "401 with token_expired",
"actual_result": "500 Internal Server Error",
"suspected_location": ["src/auth/refresh.py"],
"severity": "high"
}
代码缺陷是正常业务结果,所以 QA_FAIL 和 REVIEW_REJECT 仍通过 kanban_complete 形成成功交接;只有缺少权限、外部服务不可达、测试环境缺失或需要用户决策等真正外部阻塞才调用 kanban_block。
原理五:Task body 是可恢复日志,不依赖模型短期记忆
每张 Task 都重复携带恢复所需的最小完整状态:
workflow_id: login-api-001
workflow_owner_kind: chat_session
workflow_owner_profile: default
workflow_owner_session_id: <session id>
workspace: dir:/workspace/myproject
tester_retry: 0
tester_retry_limit: 5
reviewer_retry: 0
reviewer_retry_limit: 3
同时保留原始需求和 acceptance criteria,并尽可能把直接上游 completed Task 设为 parent。parent chain 提供因果关系,但不是唯一状态源;关键字段仍显式写入每张 Task,避免 parent 数据缺失或上下文压缩导致不可恢复。
恢复算法是确定性的:
- 枚举 workflow 的 Task、run、parent 和 terminal event;
- 找到最后一个协议合法的 completed run;
- 从 Task body 恢复 Workspace 与计数器;
- 根据
metadata.result计算应有的下一阶段; - 检查该 Task 是否已经存在;
- 只有不存在时才创建。
第 5 步是恢复路径上的幂等性闸门,可避免 session 在“Task 已创建、回复尚未送达”之间断线后重复建卡。
原理六:业务重试与基础设施重试分离
默认业务预算:
tester_retry_limit = 5
reviewer_retry_limit = 3
tester_retry 只在 QA_FAIL 时增加;reviewer_retry 只在 REVIEW_REJECT 时增加。计数器在后续通过时也不清零,因为它们描述的是整条 workflow 已消耗的业务迭代预算。
Worker 的 max_retries=3 则用于 spawn failure、模型 API 异常、crash 或 protocol failure 等基础设施问题。把两者分开可以避免两个错误:代码持续不满足验收却被基础设施重试无限掩盖,或者一次临时 API 故障错误消耗 QA 修复额度。
关键不变量
这套工作流的正确性依赖以下不变量,而不是依赖 Agent “大致理解流程”:
- 当前持久 chat 是唯一 Orchestrator,不存在 Orchestrator Profile 或 Task;
- 所有 Worker/Fix Task 只能由 owner chat 直接调用
kanban_create创建; - Worker 只能结束或阻塞自己的当前 Task;
done不等于业务通过,只读取最新 completed run 的metadata.result;QA_FAIL必须返回 Coder;- 所有 Coder 修改后必须重新 Tester;
REVIEW_REJECT后固定执行 Coder → Tester → Reviewer;- 只有
REVIEW_APPROVE可以产生WORKFLOW_DONE; - 每张 Task 显式携带绝对 Workspace,不永久修改 Worker
terminal.cwd; - ownership 不因断网、通知失败或 Worker 故障自动转移。
安装与调用
直接从 GitHub 安装:
hermes skills install lichenrobo/kanban-code-orchestrator/skills/kanban-code-orchestrator
或者将仓库添加为 Skill Tap:
hermes skills tap add lichenrobo/kanban-code-orchestrator
hermes skills install lichenrobo/kanban-code-orchestrator/kanban-code-orchestrator
必须在持续运行的 TUI 或 Gateway chat 中调用:
/kanban-code-orchestrator 在 C:\projects\example 中实现登录 API,验收条件是……
不要从 chat -q、cron、一次性 CLI 或 Dispatcher worker 启动。那些无头上下文无法可靠提供 owner chat 所需的持续 session identity 和通知路由。
边界与结论
kanban-code-orchestrator 不是通用 CI/CD 替代品,也不提供容器级安全隔离。它解决的是 Agent 编码工作流中的控制一致性:用持久 Task 保存交接,用结构化结果驱动状态机,用唯一 owner 防止多写者竞争,用 terminal event 代替轮询,并在失败恢复时从 Task 图而不是聊天记忆重建状态。
其核心判断可以浓缩成一句话:LLM 可以负责实现和判断,但工作流推进必须由持久协议约束,而不能依赖自然语言暗示。