Kanban 教程
本教程将带你逐步体验 Hermes Kanban 系统设计的四种典型使用场景,所有操作均在浏览器中打开仪表板进行。如果你尚未阅读 Kanban 概览,请先从那里开始——本教程假设你已了解“任务(task)”、“运行(run)”、“分配对象(assignee)”和“调度器(dispatcher)”的基本概念。
设置
hermes kanban init # optional; first `hermes kanban <anything>` auto-inits
hermes dashboard # opens http://127.0.0.1:9119 in your browser
# click Kanban in the left nav
仪表板是 你 监控系统最舒适的位置。调度器所生成的代理工作节点(agent workers)永远不会看到仪表板或 CLI —— 它们通过专用的 kanban_* 工具集(kanban_show, kanban_list, kanban_complete, kanban_block, kanban_heartbeat, kanban_comment, kanban_create, kanban_link, kanban_unblock)来驱动看板。三个界面——仪表板、CLI、工作节点工具——都通过同一个每个看板独立的 SQLite 数据库路由(~/.hermes/kanban.db 为默认看板,~/.hermes/kanban/boards/<slug>/kanban.db 为后续创建的任意看板),因此无论变更来自哪一侧,每个看板始终保持一致。
本教程全程使用 default 看板。如果你想为不同项目 / 仓库 / 领域创建多个相互隔离的队列,请参阅概览中的 看板(多项目) —— 每个看板都遵循相同的 CLI / 仪表板 / 工作节点流程,且工作节点物理上无法访问其他看板上的任务。
在整个教程中,标记为 bash 的代码块是你需要执行的命令。
标记为 # worker tool calls 的代码块是被生成的工作节点模型发出的工具调用 —— 这里展示是为了让你完整看到整个循环过程,并非你需要手动运行它们。
看板概览

从左到右共六个列:
- 待处理(Triage) —— 原始想法。默认情况下,调度器会自动对这里的任务运行 分解器(decomposer)(由编排器驱动的分发式任务拆解):它读取你的角色配置 + 任务描述,生成一个子任务图,将任务分配给最适合的专家,并保留原始任务作为父任务,以便编排器在所有子任务完成后唤醒并判断整体完成状态。点击看板顶部的 “编排模式:自动/手动” 按钮可切换模式。在手动模式下(或没有编排器配置的情况下),点击卡片上的 ⚗ 分解,或运行
hermes kanban decompose <id>//kanban decompose <id>。对于不需要分发的单任务,✨ 明确需求 可一次性重写目标、方法和验收标准,并将其推进至todo。可在auxiliary.kanban_decomposer和auxiliary.triage_specifier下配置相关模型。详见主指南中的 自动 vs 手动编排。 - 待办(Todo) —— 已创建但等待依赖项,或尚未分配。
- 就绪(Ready) —— 已分配,正等待调度器领取。
- 进行中(In progress) —— 有工作节点正在执行该任务。当启用“按角色分车道”(默认开启)时,此列会按分配者分组,让你一眼看清每个工作节点当前的任务。
- 阻塞(Blocked) —— 工作节点请求人工介入,或电路断路器触发。
- 完成(Done) —— 已完成。
顶部栏包含搜索、租户、分配者筛选器,以及一个 Lanes by profile 切换开关和一个 Nudge dispatcher 按钮,可立即触发一次调度轮次,而非等待守护进程的下次周期。点击任意卡片可打开右侧的详细信息抽屉。
平面视图
如果角色车道过于嘈杂,可关闭“按角色分车道”功能,此时“进行中”列将折叠为单一扁平列表,按领取时间排序:

故事 1 —— 单人开发者交付功能
你正在开发一个新功能。经典流程:设计数据结构 → 实现 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。
以下是工作节点内部代理的工具调用循环示例:
# 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 任务,打开抽屉可查看全部信息:

底部的 运行历史(Run History) 是关键新增功能。一次尝试:结果为 completed,工作节点为 @backend-dev,持续时间、时间戳,以及完整的交接摘要。元数据 blob(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”),你会看到如下画面:

两个转录任务已完成,一个正在运行,两个就绪任务正等待下一次调度轮次。"进行中"列按角色分组(默认开启),因此你可以一目了然地看到每位工作节点的当前任务,而无需扫描混杂的列表。一旦当前任务完成,调度器会立即将下一个就绪任务推入运行状态。三个守护进程并行处理三个分配者池,整个内容队列无需进一步人工干预即可清空。
故事 1 中关于结构化交接的所有内容在此同样适用。 一位翻译工作节点完成任务后发出的 kanban_complete(summary="translated 4 pages, style matched existing marketing voice", metadata={"duration_seconds": 720, "tokens_used": 2100}) 调用,对分析和后续依赖任务都非常有用。
故事 3 —— 带重试机制的角色流水线
这才是 Kanban 相较于普通待办清单真正体现价值的地方。产品经理撰写规格说明 → 工程师实现 → 审核人拒绝首次提交 → 工程师修改后重试 → 审核人批准。
在仪表板上,按 auth-project 进行筛选:

三个阶段的链条清晰可见:Spec: password reset flow(已完成,PM)、Implement password reset flow(已完成,后端工程师)、Review password reset PR(就绪,审核人)。每个任务下方绿色显示其父任务,上方列出依赖的子任务。
最有趣的是实现任务,因为它曾被阻塞并重试。以下是三名代理协同工作的完整流程,以各工作节点模型发出的工具调用形式呈现:
# --- 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'
```现在你(作为人类,或一个独立的评审员角色)阅读了阻塞原因,判断修复方向清晰,可通过仪表板的“解除阻塞”按钮——或通过 CLI / 斜杠命令进行解封:
**```bash
hermes kanban unblock $IMPL
# or from a chat: /kanban unblock $IMPL
```**
调度器将 **`$IMPL`** 重新提升至 **`ready`**,并在下一个周期中重新生成 **`backend-dev`** 工作节点。此次重启是一个针对同一任务的**全新运行**:
**```python
# --- 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** — 由 **`blocked`** 执行的 **`@backend-dev`**。评审反馈直接位于结果下方:“缺少密码强度检查,重置链接非一次性(30分钟内可重复使用)”。
- **运行 2** — 由 **`completed`** 执行的 **`@backend-dev`**。全新的摘要与元数据。
每次运行都是 **`task_runs`** 中的一行,拥有独立的结果、摘要和元数据。重试历史并非附加于“最新状态”任务之上的事后补丁——而是核心表示形式。当一个重试工作节点打开该任务时,**`build_worker_context`** 会向其展示之前的尝试记录,使第二轮执行者能够理解首轮失败的具体原因,并针对性地解决问题,而非从头开始重做。
接下来是评审员接手。当他们打开 **`Review password reset PR`** 时,看到的是:

父任务链接指向已完成的实现部分。当评审员的工作节点在 **`Review password reset PR`** 上启动并调用 **`kanban_show()`** 时,返回的 **`worker_context`** 包含父任务最近一次成功运行的摘要 + 元数据——因此评审员能立即读到“已添加 zxcvbn 强度检查,重置令牌现为一次性”,并提前掌握变更文件列表,无需再查看 diff。
---
## 故事 4 —— 电路断路器与崩溃恢复
真实工作节点会失败:凭据缺失、OOM 杀死、瞬时网络错误。调度器设有两道防线:
- **电路断路器**:在连续 N 次失败后自动阻塞,防止看板无限震荡;
- **崩溃检测**:若工作节点 PID 在 TTL 未到期前消失,则主动回收任务。
### 电路断路器 —— 似永久性失败
一个部署任务因配置中未设置 **`AWS_ACCESS_KEY_ID`** 而无法启动工作节点:
**```bash
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`**。
在终端中:
**```bash
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`**,下一周期分配给新工作节点。
种子数据中的示例是一个内存耗尽的迁移任务:
**```bash
# 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 的先前尝试记录**(之前运行的结果、摘要、错误、元数据),确保重试工作节点不会重复失败路径;
- **父任务结果** —— 每个父任务最近一次成功运行的摘要与元数据,使下游工作节点清楚上游工作的**原因与方式**。
这取代了传统看板系统中“翻阅评论和输出内容”的繁琐操作。项目经理在规范元数据中写入验收标准,工程师的工作节点可结构化地读取这些信息;工程师记录运行了哪些测试、通过数量多少,评审员的工作节点在打开 diff 前就已掌握完整清单。
批量关闭的保护机制存在,正是因为这些数据是按运行粒度存储的。**`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>`** —— 当特定任务完成时,获取网关 ping 通知。