Kanban 教程
Hermes Kanban 系统四个典型用例的演练,配合在浏览器中打开的仪表板。如果你还没有阅读过 Kanban 概述,请先从那里开始——本教程假设你知道什么是任务、运行记录、被分配人和调度器。
设置
hermes kanban init # 可选;第一个 `hermes kanban <命令>` 会自动初始化
hermes dashboard # 在浏览器中打开 http://127.0.0.1:9119
# 点击左侧导航中的 Kanban
仪表板是你观察系统最舒适的地方。调度器生成的 Agent 工作节点永远不会看到仪表板或 CLI——它们通过专用的 kanban_* 工具集(kanban_show、kanban_complete、kanban_block、kanban_heartbeat、kanban_comment、kanban_create、kanban_link)驱动看板。三个界面——仪表板、CLI、工作节点工具——都通过同一个每看板 SQLite 数据库(默认看板为 ~/.hermes/kanban.db,之后创建的任何看板为 ~/.hermes/kanban/boards/<slug>/kanban.db)路由,因此无论变更来自哪一侧,每个看板都保持一致。
本教程全程使用 default 看板。如果你想要多个隔离的队列(每个项目/仓库/领域一个),参见概述中的看板(多项目)——相同的 CLI/仪表板/工作节点流程适用于每个看板,且工作节点在物理上无法看到其他看板上的任务。
在整个教程中,标有 bash 的代码块是你运行的命令。 标有 # worker tool calls 的代码块是生成的工作节点模型发出的工具调用——在这里展示是为了让你从头到尾了解整个循环,而不是因为你会自己运行它们。
看板概览

从左到右六列:
- 待分类(Triage) — 粗略想法,规格说明人员需要在任何人开始工作前完善规格。点击任意 triage 卡片上的 ✨ Specify 按钮(或在聊天中运行
hermes kanban specify <id>//kanban specify <id>)即可让辅助 LLM 将一行描述转换为完整规格(目标、方案、验收标准),并一步提升为todo。在config.yaml的auxiliary.triage_specifier下配置使用哪个模型。 - 待办(Todo) — 已创建但等待依赖项,或尚未分配。
- 就绪(Ready) — 已分配并等待调度器认领。
- 进行中(In progress) — 工作节点正在积极执行任务。默认开启"按配置文件分组"时,该列按被分配人分组,让你一眼看出每个工作节点在做什么。
- 已阻断(Blocked) — 工作节点请求了人工输入,或断路器触发。
- 已完成(Done) — 已完成。
顶部工具栏有搜索、租户和被分配人过滤器,加上 Lanes by profile 切换和 Nudge dispatcher 按钮,可以立即运行一次调度轮次,而无需等待守护进程的下一个间隔。点击任何卡片会在右侧打开其抽屉。
平铺视图
如果配置文件分组太嘈杂,关闭"Lanes by profile",进行中列会折叠为按认领时间排序的单个平铺列表:

故事 1——独立开发者发布功能
你正在构建一个功能。经典流程:设计 schema、实现 API、编写测试。三个有父→子依赖关系的任务。
SCHEMA=$(hermes kanban create "Design auth schema" \
--assignee backend-dev --tenant auth-project --priority 2 \
--body "Design the user/session/token schema for the auth module." \
--json | jq -r .id)
API=$(hermes kanban create "Implement auth API endpoints" \
--assignee backend-dev --tenant auth-project --priority 2 \
--parent $SCHEMA \
--body "POST /register, POST /login, POST /refresh, POST /logout." \
--json | jq -r .id)
hermes kanban create "Write auth integration tests" \
--assignee qa-dev --tenant auth-project --priority 2 \
--parent $API \
--body "Cover happy path, wrong password, expired token, concurrent refresh."
因为 API 以 SCHEMA 为父任务,而 tests 以 API 为父任务,所以只有 SCHEMA 从 ready 状态开始。其他两个停留在 todo,直到其父任务完成。这就是依赖项推进引擎在起作用——在有 API 可测试之前,没有其他工作节点会去做测试编写工作。
在下一个调度器轮次(默认 60 秒,或立即点击 Nudge dispatcher),backend-dev 配置文件会以 HERMES_KANBAN_TASK=$SCHEMA 在其环境中生成为工作节点。以下是工作节点工具调用循环在 Agent 内部的样子:
# worker tool calls — NOT commands you run
kanban_show()
# → returns title, body, worker_context, parents, prior attempts, comments
# (worker reads worker_context, uses terminal/file tools to design the schema,
# write migrations, run its own checks, commit — the real work happens here)
kanban_heartbeat(note="schema drafted, writing migrations now")
kanban_complete(
summary="users(id, email, pw_hash), sessions(id, user_id, jti, expires_at); "
"refresh tokens stored as sessions with type='refresh'",
metadata={
"changed_files": ["migrations/001_users.sql", "migrations/002_sessions.sql"],
"decisions": ["bcrypt for hashing", "JWT for session tokens",
"7-day refresh, 15-min access"],
},
)
kanban_show 将 task_id 默认为 $HERMES_KANBAN_TASK,因此工作节点不需要知道自己的 ID。kanban_complete 将摘要和元数据写入当前 task_runs 行,关闭该运行记录,并将任务转换到 done——通过 kanban_db 在一次原子跳转中完成所有这些。
当 SCHEMA 达到 done 时,依赖引擎自动将 API 提升到 ready。API 工作节点在认领时会调用 kanban_show() 并在父任务交接中看到 SCHEMA 的摘要和元数据——因此它知道 schema 决策,无需重新阅读冗长的设计文档。
点击看板上已完成的 schema 任务,抽屉显示所有内容:

底部的运行历史部分是关键新增内容。一次尝试:结果 completed,工作节点 @backend-dev,时长、时间戳以及完整的交接摘要。元数据块(changed_files、decisions)也存储在运行记录上,并呈现给任何读取该父任务的下游工作节点。
你可以随时从终端检查相同的数据——这些命令是你在窥视看板,而不是工作节点:
hermes kanban show $SCHEMA
hermes kanban runs $SCHEMA
# # OUTCOME PROFILE ELAPSED STARTED
# 1 completed backend-dev 0s 2026-04-27 19:34
# → users(id, email, pw_hash), sessions(id, user_id, jti, expires_at); refresh tokens ...
故事 2——批量处理
你有三个工作节点(翻译人员、转录人员、文案撰写人员)和一堆独立任务。你希望三者并行拉取任务并取得可见进展。这是最简单的 kanban 用例,也是原始设计最优化的场景。
创建工作:
for lang in Spanish French German; do
hermes kanban create "Translate homepage to $lang" \
--assignee translator --tenant content-ops
done
for i in 1 2 3 4 5; do
hermes kanban create "Transcribe Q3 customer call #$i" \
--assignee transcriber --tenant content-ops
done
for sku in 1001 1002 1003 1004; do
hermes kanban create "Generate product description: SKU-$sku" \
--assignee copywriter --tenant content-ops
done
启动网关并离开——它托管嵌入的调度器,在同一个 kanban.db 上认领所有三个专家配置文件的任务:
hermes gateway start
现在将看板过滤到 content-ops(或直接搜索"Transcribe"),你会看到:

两个转录已完成,一个正在运行,两个就绪等待下一个调度器轮次。进行中列按配置文件分组("Lanes by profile"默认值),因此你无需扫描混合列表即可看到每个工作节点的活跃任务。调度器将在当前任务完成后立即将下一个就绪任务提升为运行中。三个守护进程并行处理三个被分配人池,整个内容队列无需进一步人工输入即可清空。
故事 1 中关于结构化交接的所有内容在这里同样适用。 完成调用的翻译工作节点会发出 kanban_complete(summary="translated 4 pages, style matched existing marketing voice", metadata={"duration_seconds": 720, "tokens_used": 2100})——对分析和任何依赖此任务的下游任务都很有用。
故事 3——带重试的角色流水线
这才是 Kanban 相较于普通 TODO 列表大放异彩的地方。产品经理编写规格说明。工程师实现。审查人员拒绝第一次尝试。工程师带着修改再次尝试。审查人员批准。
按 auth-project 过滤的仪表板视图:

同时可见三阶段链:Spec: password reset flow(完成,pm)、Implement password reset flow(完成,backend-dev)、Review password reset PR(就绪,reviewer)。每个都在底部有其父任务(绿色)和作为依赖项的子任务。
有趣的是实现任务,因为它被阻断并重试过。以下是完整的三 Agent 编排,显示为每个工作节点模型发出的工具调用:
# --- PM worker spawns on $SPEC and writes the acceptance criteria ---
# worker tool calls
kanban_show()
kanban_complete(
summary="spec approved; POST /forgot-password sends email, "
"GET /reset/:token renders form, POST /reset applies new password",
metadata={"acceptance": [
"expired token returns 410",
"reused last-3 password returns 400 with message",
"successful reset invalidates all active sessions",
]},
)
# → $SPEC is done; $IMPL auto-promotes from todo to ready
# --- Engineer worker spawns on $IMPL (first attempt) ---
# worker tool calls
kanban_show() # reads $SPEC's summary + acceptance metadata in worker_context
# (engineer writes code, runs tests, opens PR)
# Reviewer feedback arrives — engineer decides the concerns are valid and blocks
kanban_block(
reason="Review: password strength check missing, reset link isn't "
"single-use (can be replayed within 30min)",
)
# → $IMPL transitions to blocked; run 1 closes with outcome='blocked'
现在你(人类,或独立的审查人员配置文件)阅读阻断原因,决定修复方向清晰,然后从仪表板的"Unblock"按钮解除阻断——或从 CLI / 斜杠命令:
hermes kanban unblock $IMPL
# or from a chat: /kanban unblock $IMPL
调度器将 $IMPL 提升回 ready,在下一个轮次重新生成 backend-dev 工作节点。第二次生成是同一任务上的新运行记录:
# --- Engineer worker spawns on $IMPL (second attempt) ---
# worker tool calls
kanban_show()
# → worker_context now includes the run 1 block reason, so this worker knows
# which two things to fix instead of re-reading the whole spec
# (engineer adds zxcvbn check, makes reset tokens single-use, re-runs tests)
kanban_complete(
summary="added zxcvbn strength check, reset tokens are now single-use "
"(stored + deleted on success)",
metadata={
"changed_files": [
"auth/reset.py",
"auth/tests/test_reset.py",
"migrations/003_single_use_reset_tokens.sql",
],
"tests_run": 11,
"review_iteration": 2,
},
)
点击实现任务。抽屉显示两次尝试:

- 运行记录 1 — 被
@backend-devblocked。审查反馈就在结果下方:"password strength check missing, reset link isn't single-use (can be replayed within 30min)"。 - 运行记录 2 — 被
@backend-devcompleted。新的摘要,新的元数据。
每条运行记录是 task_runs 中的一行,有其自己的结果、摘要和元数据。重试历史不是层叠在"最新状态"任务上的概念性事后想法——它是主要表示。当重试工作节点打开任务时,build_worker_context 向它显示先前的尝试,因此第二次工作节点知道第一次被阻断的原因并专门解决这些发现,而不是从头重新运行。
审查人员接下来接手。当他们打开 Review password reset PR 时,他们看到:

父任务链接是已完成的实现。当审查人员工作节点在 Review password reset PR 上生成并调用 kanban_show() 时,返回的 worker_context 包括父任务最近完成运行的摘要和元数据——因此审查人员在查看差异之前就读到了"added zxcvbn strength check, reset tokens are now single-use",并手头有已更改文件的列表。
故事 4——断路器和崩溃恢复
真实的工作节点会失败。缺失的凭证、OOM 终止、瞬时网络错误。调度器有两道防线:一个在 N 次连续失败后自动阻断任务的断路器(防止看板无限抖动),以及一个崩溃检测机制,在工作节点 PID 在其 TTL 到期前消失时重新认领任务。
断路器——看似永久性的故障
因为 AWS_ACCESS_KEY_ID 未在配置文件的环境中设置而无法生成工作节点的部署任务:
hermes kanban create "Deploy to staging (missing creds)" \
--assignee deploy-bot --tenant ops
调度器尝试生成工作节点。生成失败(RuntimeError: AWS_ACCESS_KEY_ID not set)。调度器释放认领,增加失败计数器,并在下一个轮次重试。经过三次连续失败(默认 failure_limit)后,断路器触发:任务进入 blocked 状态,结果为 gave_up。在人工解除阻断之前不再重试。
点击被阻断的任务:

三条运行记录,每条 error 字段上都有相同的错误。前两条是 spawn_failed(可重试),第三条是 gave_up(终止)。上方的事件日志显示完整序列:created → claimed → spawn_failed → claimed → spawn_failed → claimed → gave_up。
在终端:
hermes kanban runs t_ef5d
# # OUTCOME PROFILE ELAPSED STARTED
# 1 spawn_failed deploy-bot 0s 2026-04-27 19:34
# ! AWS_ACCESS_KEY_ID not set in deploy-bot env
# 2 spawn_failed deploy-bot 0s 2026-04-27 19:34
# ! AWS_ACCESS_KEY_ID not set in deploy-bot env
# 3 gave_up deploy-bot 0s 2026-04-27 19:34
# ! AWS_ACCESS_KEY_ID not set in deploy-bot env
如果 Telegram / Discord / Slack 已连接,在 gave_up 事件时会触发网关通知,让你无需检查看板即可了解故障情况。
崩溃恢复——工作节点在飞行中死亡
有时生成成功但工作节点进程后来死亡——段错误、OOM、systemctl stop。调度器轮询 kill(pid, 0) 并检测到死亡的 pid;认领被释放,任务返回 ready,下一个轮次将其交给新的工作节点。
种子数据中的示例是一个内存不足的迁移任务:
# Worker claims, starts scanning 2.4M rows, OOM kills it at ~2.3M
# Dispatcher detects dead pid, releases claim, increments attempt counter
# Retry with a chunked strategy succeeds
抽屉显示完整的两次尝试历史:

运行记录 1——crashed,错误为 OOM kill at row 2.3M (process 99999 gone)。运行记录 2——completed,元数据中包含 "strategy": "chunked with LIMIT + WHERE id > last_id"。重试工作节点在上下文中看到了运行记录 1 的崩溃,选择了更安全的策略;元数据使未来的观察者(或事后分析撰写者)清楚地了解发生了什么变化。
结构化交接——为什么 summary 和 metadata 很重要
在上面每个故事中,工作节点在结束时调用了 kanban_complete(summary=..., metadata=...)。这不是装饰——它是工作流各阶段之间的主要交接通道。
当任务 B 上的工作节点被生成并调用 kanban_show() 时,它返回的 worker_context 包括:
- B 的先前尝试(先前的运行记录:结果、摘要、错误、元数据),以便重试工作节点不重复失败的路径。
- 父任务结果——对于每个父任务,最近完成运行的摘要和元数据——以便下游工作节点了解上游工作是如何以及为何完成的。
这取代了困扰平面看板系统的"翻阅评论和工作输出"的麻烦。产品经理在规格说明元数据中写下验收标准,工程师工作节点在父任务交接中结构化地看到它们。工程师记录他们运行了哪些测试以及通过了多少个,审查人员工作节点在打开差异之前就手头有该列表。
批量关闭保护的存在是因为这些数据是每次运行记录的。hermes kanban complete a b c --summary X(你,从 CLI)会被拒绝——将相同的摘要复制粘贴到三个任务几乎总是错误的。不带交接标志的批量关闭对常见的"我完成了一堆管理任务"情况仍然有效。工具界面根本不公开批量变体;kanban_complete 出于同样的原因始终是单任务的。
检查当前正在运行的任务
为了完整性——以下是仍在飞行中的任务的抽屉(故事 1 中的 API 实现,已被 backend-dev 认领但尚未完成):

状态为 Running。活跃运行记录出现在运行历史部分,结果为 active,没有 ended_at。如果该工作节点死亡或超时,调度器会以相应的结果关闭该运行记录,并在下一次认领时打开新的运行记录——尝试行永远不会消失。
后续步骤
- Kanban 概述 — 完整的数据模型、事件词汇表和 CLI 参考。
hermes kanban --help— 每个子命令,每个标志。hermes kanban watch --kinds completed,gave_up,timed_out— 在整个看板实时流式传输终止事件。hermes kanban notify-subscribe <task> --platform telegram --chat-id <id>— 在特定任务完成或被阻断时获取网关通知。