ByteNoteByteNote

字节笔记本

2026年6月21日

hermes教程-Kanban 教程

API中转
¥120

Kanban 教程

本教程将介绍 Hermes Kanban 系统设计的四种使用场景,并在浏览器中打开仪表盘进行操作。如果你还没有阅读 Kanban 概述,请先阅读该文档——本教程假设你已经了解任务、运行、负责人和调度器的概念。

设置

bash
hermes kanban init           # 可选;首次执行 `hermes kanban <任何命令>` 会自动初始化
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 board overview

从左到右共六列:

  • Triage(分类) — 原始想法。默认情况下,调度器会自动对这里的任务运行分解器:内置的分解器使用 auxiliary.kanban_decomposer,读取你的配置文件名单和描述,并生成一个子任务图,路由到最合适的专家。原始任务作为父任务保持存活,以便其负责人(kanban.orchestrator_profile,或未设置时的活动默认配置文件)在所有子任务完成后重新唤醒并判断完成情况。点击看板页面顶部的 Orchestration: Auto/Manual 按钮可切换模式。在 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(完成) — 已完成。

顶部栏有搜索、租户和负责人的过滤器,以及一个 Lanes by profile 切换按钮和一个 Nudge dispatcher 按钮,点击后立即执行一次调度滴答,而不是等待守护进程的下一个间隔。点击任何卡片会在右侧打开其抽屉。

平面视图

如果角色泳道过于杂乱,关闭“按角色分泳道”开关,In Progress 列将折叠为按认领时间排序的单一平面列表:

Board with lanes by profile off

故事 1 — 独立开发者交付一个功能

你正在构建一个功能。经典流程:设计模式,实现 API,编写测试。三个任务,具有父→子依赖关系。

bash
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。以下是工作器从代理内部看到的工具调用循环:

python
## 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 的摘要和元数据附加在父任务交接中——因此它知道模式决策,无需重新阅读冗长的设计文档。

点击看板上已完成的模式任务,抽屉会显示所有信息:

Solo dev — completed schema task drawer

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

你可以随时从终端检查相同的数据——这些命令是在查看看板,而不是工作器:

bash
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 — 集群式批量处理

你有三个工作器(一个翻译员、一个转录员、一个文案撰写员)和一堆独立任务。你希望它们全部并行工作并展示可见的进度。这是最简单的看板用例,也是原始设计优化的目标。

创建工作:

bash
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 上拾取所有三个专家角色的任务:

bash
hermes gateway start

现在将看板过滤到 content-ops(或仅搜索“Transcribe”),你会得到以下结果:

Fleet view filtered to transcribe tasks

两个转录任务已完成,一个正在运行,两个就绪等待下一个调度器滴答。In Progress 列按角色分组(默认的“按角色分泳道”),因此你可以看到每个工作器的活动任务,而无需扫描混合列表。调度器会在当前任务完成后立即将下一个就绪任务提升为运行状态。三个守护进程在三个负责人池上并行工作,整个内容队列无需人工干预即可排空。

故事 1 中关于结构化交接的所有内容在此同样适用。 翻译员工作器完成一个调用时会发出 kanban_complete(summary="translated 4 pages, style matched existing marketing voice", metadata={"duration_seconds": 720, "tokens_used": 2100})——这对于分析以及任何依赖此任务的下游任务都很有用。

故事 3 — 带重试的角色流水线

这是 Kanban 相对于平面待办列表的真正价值所在。PM 编写规格。工程师实现它。审查者拒绝第一次尝试。工程师根据修改再次尝试。审查者批准。

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

Pipeline view for a multi-role feature

三阶段链一目了然:Spec: password reset flow(DONE,pm),Implement password reset flow(DONE,backend-dev),Review password reset PR(READY,reviewer)。每个任务底部都有绿色的父任务,以及作为依赖项的子任务。

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

python
## --- 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 / 斜杠命令:

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,
    },
)

点击实现任务。抽屉显示两次尝试

Implementation task with two runs — blocked then completed

  • 运行 1blocked,由 @backend-dev 执行。审查反馈直接显示在结果下方:“password strength check missing, reset link isn't single-use (can be replayed within 30min)”。
  • 运行 2completed,由 @backend-dev 执行。新的摘要,新的元数据。

每次运行都是 task_runs 表中的一行,包含自己的结果、摘要和元数据。重试历史不是附加在“最新状态”任务之上的概念性事后想法——它是主要表示。当重试工作器打开任务时,build_worker_context 会向其显示先前的尝试,因此第二次通过的工作器会看到第一次通过被阻塞的原因,并针对这些具体发现进行处理,而不是从头开始重新运行。

审查者接下来接手。当他们打开 Review password reset PR 时,会看到:

Reviewer's drawer view of the pipeline

父链接是已完成的实现。当审查者的工作器生成并调用 kanban_show() 时,返回的 worker_context 包含父任务最近一次完成运行的摘要 + 元数据——因此审查者在查看差异之前就已经读到了“added zxcvbn strength check, reset tokens are now single-use”并掌握了更改文件列表。

故事 4 — 断路器和崩溃恢复

真实的工作器会失败。缺少凭据、OOM 杀死、瞬时网络错误。调度器有两道防线:断路器,在连续 N 次失败后自动阻塞,以免看板永远抖动;崩溃检测,在工作器 PID 在其 TTL 过期前消失时回收任务。

断路器——看似永久性的失败

一个部署任务,因为 AWS_ACCESS_KEY_ID 未在角色的环境中设置而无法生成工作器:

bash
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)。在人类解除阻塞之前,不再进行重试。

点击阻塞的任务:

Circuit breaker — 2 spawn_failed + 1 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

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

Crash and recovery — 1 crashed + 1 completed

运行 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 的先前尝试(之前的运行:结果、摘要、错误、元数据),以便重试工作器不会重复失败的路径。
  • 父任务结果——对于每个父任务,最近一次完成运行的摘要和元数据——以便下游工作器了解上游工作的原因和方式。

这取代了扁平看板系统中常见的“翻阅评论和工作输出”的繁琐过程。PM 在规格的元数据中编写验收标准,工程师的工作器在父任务交接中结构化地看到它们。工程师记录他们运行了哪些测试以及通过了多少,审查者的工作器在打开差异之前就已经掌握了该列表。

批量关闭保护的存在是因为这些数据是按运行存储的。hermes kanban complete a b c --summary X(你,从 CLI)会被拒绝——将相同的摘要复制粘贴到三个任务几乎总是错误的。不带交接标志的批量关闭仍然适用于常见的“我完成了一堆管理任务”的情况。工具表面根本不暴露批量变体;kanban_complete 始终是单任务一次,原因相同。

检查当前正在运行的任务

为了完整性——以下是仍在进行中的任务的抽屉(故事 1 中的 API 实现,已被 backend-dev 认领但尚未完成):

Claimed, in-flight task

状态为 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> — 在特定任务完成时接收网关通知。

分享: