Kanban 教程

这是一个关于 Hermes Kanban 系统设计的四个用例的操作指南,浏览器中会打开仪表盘。如果您尚未阅读 Kanban 概述,请从那里开始——本文假设您知道任务、运行、分配者和分发器是什么。

设置

hermes kanban init           # 可选;首次 `hermes kanban <anything>` 会自动初始化
hermes dashboard             # 在浏览器中打开 http://127.0.0.1:9119
# 点击左侧导航中的 Kanban

仪表盘是让观察系统最舒适的地方。分发器生成的工作线程代理永远不会看到仪表盘或 CLI——它们通过专用的 kanban_* 工具集kanban_showkanban_listkanban_completekanban_blockkanban_heartbeatkanban_commentkanban_createkanban_linkkanban_unblock)驱动工单板。所有三个界面——仪表盘、CLI、工作线程工具——都通过同一个每工单板 SQLite 数据库(默认工单板为 ~/.hermes/kanban.db,稍后创建的任何工单板为 ~/.hermes/kanban/boards/<slug>/kanban.db)路由,因此每个工单板无论更改来自哪一侧都是一致的。

本教程全程使用 default 工单板。如果您想要多个隔离的队列(每项目/仓库/域一个),请查看概述中的工单板(多项目)——相同的 CLI / 仪表盘 / 工作线程流程适用于每个工单板,工作线程物理上无法看到其他工单板上的任务。

教程中,标记为 bash 的代码块是您运行的命令。 标记为 # worker tool calls 的代码块是生成的工作线程模型发出的工具调用——在此展示以便您端到端地看到循环,而不是因为您自己会运行它们。

工单一瞥

Kanban 工单板概览

六列,从左到右:

  • Triage(分类)——粗略想法。默认情况下,分发器在此对任务自动运行分解器(编排者驱动的扇出):它读取您的配置名册 + 描述并产生一个路由到最合适专家的子任务图,原始任务保持存活作为父级,以便当所有任务完成时编排者再次唤醒以判断完成。翻转 kanban 页面顶部的 Orchestration: Auto/Manual 药丸以切换模式。在手动模式(或没有编排者配置的设置)下,点击卡片上的 ⚗ Decompose,或运行 hermes kanban decompose <id> / /kanban decompose <id>。对于不需要扇出的单一任务,✨ Specify 执行一次性规范重写(目标、方法、验收标准)并提升到 todo。在 config.yaml 中的 auxiliary.kanban_decomposerauxiliary.triage_specifier 下配置模型。参见主 Kanban 指南中的自动与手动编排
  • Todo(待办)——已创建但等待依赖项,或尚未分配。
  • Ready(就绪)——已分配并等待分发器认领。
  • In progress(进行中)——工作线程正积极处理任务。在”按配置分通道”(默认)开启的情况下,此列按分配者子分组,以便您一目了然地看到每个工作线程在做什么。
  • Blocked(阻塞)——工作线程请求了人工输入,或断路器跳闸。
  • Done(完成)——已完成。

顶部栏有搜索、租户和分配者过滤器,外加一个 按配置分通道 切换和一个 催促分发器 按钮,该按钮立即运行一次分发周期,而不是等待守护进程的下一个间隔。点击任意卡片会在右侧打开其抽屉。

扁平视图

如果配置通道嘈杂,关闭”按配置分通道”选项,进行中列会折叠为按认领时间排序的单个扁平列表:

关闭按配置分通道的工单板

故事 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."

因为 APISCHEMA 为其父任务,而 testsAPI 为其父任务,只有 SCHEMAready 开始。其他两个保持在 todo 中,直到其父任务完成。这是依赖提升引擎做的工作——没有其他工作线程会在有可测试的 API 之前接手编写测试。

在下个分发器周期(默认 60 秒,或者如果您点击了催促分发器则立即),backend-dev 配置以 HERMES_KANBAN_TASK=$SCHEMA 在其环境中生成为一个工作线程。这是从代理内部看到的工作线程工具调用循环:

# worker tool calls — 不是您运行的命令
kanban_show()
# → 返回标题、正文、worker_context、父任务、先前尝试、评论
 
# (工作线程读取 worker_context,使用 terminal/file 工具设计架构,
#  编写迁移、运行自己的检查、提交——真正的工作发生在这里)
 
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 的摘要和元数据附加到父任务交接中——因此它知道架构决策而无需重新阅读冗长的设计文档。

在工单板上点击已完成的架构任务,抽屉会显示一切:

独立开发者——已完成的架构任务抽屉

底部的运行历史部分是关键新增。一次尝试:结果 completed,工作线程 @backend-dev,持续时间,时间戳,以及完整的交接摘要。元数据块(changed_filesdecisions)也存储在运行上,并呈现给读取此父任务的任何下游工作线程。

您可以随时从终端检查相同的数据——这些命令是窥视工单板,而不是工作线程:

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 在扁平 TODO 列表上证明其价值的地方。PM 编写规范。工程师实现它。审查者拒绝第一次尝试。工程师带着更改再次尝试。审查者批准。

仪表盘视图,按 auth-project 过滤:

多角色特性的流水线视图

三阶段链一目了然:Spec: password reset flow(已完成,pm)、Implement password reset flow(已完成,backend-dev)、Review password reset PR(就绪,reviewer)。每个在底部有绿色父任务,子任务作为依赖。

有趣的是实现任务,因为它曾被阻塞并重试。以下是完整的三代理编排,显示为每个工作线程模型发出的工具调用:

# --- PM 工作线程生成在 $SPEC 上并编写验收标准 ---
# 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 已完成;$IMPL 自动从 todo 提升到 ready
 
# --- 工程师工作线程生成在 $IMPL 上(第一次尝试)---
# worker tool calls
kanban_show()   # 在 worker_context 中读取 $SPEC 的摘要 + 验收元数据
# (工程师编写代码、运行测试、打开 PR)
# 审查者反馈到达——工程师决定问题有效并阻塞
kanban_block(
    reason="Review: password strength check missing, reset link isn't "
           "single-use (can be replayed within 30min)",
)
# → $IMPL 转换为 blocked;运行 1 以 outcome='blocked' 关闭

现在您(人类,或单独的审查者配置)读取阻塞原因,确定修复方向是清晰的,然后从仪表盘的”取消阻塞”按钮取消阻塞——或从 CLI / 斜杠命令:

hermes kanban unblock $IMPL
# 或从聊天:/kanban unblock $IMPL

分发器将 $IMPL 提升回 ready,并在下一周期重新生成 backend-dev 工作线程。这第二次生成是同一任务上的新运行

# --- 工程师工作线程生成在 $IMPL 上(第二次尝试)---
# worker tool calls
kanban_show()
# → worker_context 现在包括运行 1 的阻塞原因,因此此工作线程知道
#   需要修复哪两件事,而不是重新读取整个规范
# (工程师添加 zxcvbn 检查、使重置令牌一次性、重新运行测试)
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-dev blocked。审查反馈就在结果下方:“password strength check missing, reset link isn’t single-use (can be replayed within 30min)”。
  • 运行 2——由 @backend-dev completed。新摘要,新元数据。

每个运行是 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 \
    --max-retries 3

分发器尝试生成工作线程。生成失败(RuntimeError: AWS_ACCESS_KEY_ID not set)。分发器释放认领,增加失败计数器,并在下个周期再次尝试。因为此示例设置了 --max-retries 3,断路器在三次连续失败后跳闸:任务进入 blocked,结果 gave_up。如果您省略该标志,Hermes 使用 kanban.failure_limit(默认:2)。在人类取消阻塞之前没有更多重试。

点击被阻塞的任务:

断路器——2 次 spawn_failed + 1 次 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,下个周期将其交给新工作线程。

种子数据中的示例是一个正在耗尽内存的迁移:

# 工作线程认领,开始扫描 2.4M 行,OOM 在约 2.3M 处杀死
# 分发器检测到死亡 pid,释放认领,增加尝试计数器
# 使用分块策略的重试成功

抽屉显示完整的两次尝试历史:

崩溃和恢复——1 次崩溃 + 1 次完成

运行 1——crashed,带有错误 OOM kill at row 2.3M (process 99999 gone)。运行 2——completed,元数据中包含 "strategy": "chunked with LIMIT + WHERE id > last_id"。重试工作线程在其上下文中看到运行 1 的崩溃并选择了更安全的策略;元数据使未来的观察者(或事后分析撰写者)可以清楚地看到更改了什么。

结构化交接——为什么 summarymetadata 重要

在上述每个故事中,工作线程结束时调用 kanban_complete(summary=..., metadata=...)。这不是装饰——它是工作流阶段之间的主要交接渠道。

当工作线程在任务 B 上生成并调用 kanban_show() 时,返回的 worker_context 包括:

  • B 的先前尝试(前次运行:结果、摘要、错误、元数据),以便重试的工作线程不会重复失败的路径
  • 父任务结果——对于每个父任务,最近完成的运行的摘要和元数据——以便下游工作线程看到上游工作完成的原因和方式

这取代了困住扁平 kanban 系统的”挖掘评论和工作输出”的舞步。PM 在规范的元数据中写入验收标准,工程师的工作线程在父任务交接中结构性看到它们。工程师记录他们运行了哪些测试以及多少个通过,审查者的工作线程在打开差异之前就掌握了该列表。

批量关闭防护存在是因为此数据是每运行的。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> —— 在特定任务完成时获取网关通知。