Section: 核心功能 · URL: https://hermesbible.com/docs/user-guide/features/kanban
Kanban — 多 Agent 設定檔協作
想要操作導覽? 閱讀 Kanban 教學 — 四個使用者故事(單人開發者、機隊農場、帶重試的角色管線、熔斷器),每個都有儀表板截圖。本頁是參考文件;教學是敘事導覽。
Hermes Kanban 是一個持久化的任務看板,跨你所有 Hermes 設定檔共享,讓多個具名 Agent 協作處理工作,無需脆弱的行程內子 Agent 群。每個任務是 ~/.hermes/kanban.db 中的一列;每次交接是一列任何人都能讀寫的記錄;每個工作者都是具備自身身份的完整作業系統行程。
兩個操作介面:模型透過工具對話,你透過 CLI 對話
看板有兩個入口,背後都由同一個 ~/.hermes/kanban.db 支援:
- Agent 透過專屬的
kanban_*工具組驅動看板 —kanban_show、kanban_list、kanban_complete、kanban_block、kanban_heartbeat、kanban_comment、kanban_create、kanban_link、kanban_unblock。調度器在生成每個工作者時就將這些工具納入其 schema;編排器設定檔也可以明確啟用kanban工具組。模型直接呼叫工具來讀寫和路由任務,不是透過 shell 呼叫hermes kanban。請參閱下方的工作者如何與看板互動。 - 你(以及腳本、cron)透過 CLI 的
hermes kanban …、斜線命令/kanban …或儀表板來驅動看板。這些是給人類和自動化流程使用的 — 沒有工具呼叫模型的場景。
兩個介面都透過同一個 kanban_db 層路由,因此讀取看到一致的視圖,寫入不會漂移。本頁其餘部分使用 CLI 範例,因為它們容易複製貼上,但每個 CLI 動詞都有對應的工具呼叫等效項供模型使用。
這個形態涵蓋了 delegate_task 無法勝任的工作負載:
- 研究分流 — 平行研究員 + 分析師 + 寫手,人類參與迴圈。
- 排程作業 — 每日定期簡報,跨越數週累積成日誌。
- 數位分身 — 持久化的具名助理(
inbox-triage、ops-review),隨時間累積記憶。 - 工程管線 — 分解 → 在平行工作樹中實作 → 審查 → 迭代 → PR。
- 機隊作業 — 一個專家管理 N 個對象(50 個社交帳號、12 個監控服務)。
完整的設計理念、與 Cline Kanban / Paperclip / NanoClaw / Google Gemini Enterprise 的比較分析,以及八個典範協作模式,請參閱 docs/hermes-kanban-v1-spec.pdf。
Kanban 與 delegate_task 的比較
它們看起來相似,但不是同一種原語。
delegate_task | Kanban | |
|---|---|---|
| 形態 | RPC 呼叫(fork → join) | 持久化訊息佇列 + 狀態機 |
| 父代 | 阻塞等待子代回傳 | create 之後發送即忘 |
| 子代身份 | 匿名子 Agent | 具備持久記憶的具名設定檔 |
| 可恢復性 | 無 — 失敗就是失敗 | Block → unblock → 重新執行;崩潰 → 取回 |
| 人類介入 | 不支援 | 任何時候都能留言 / 解除封鎖 |
| 每個任務的 Agent 數 | 一次呼叫 = 一個子 Agent | 任務生命週期內 N 個 Agent(重試、審查、跟進) |
| 稽核軌跡 | 上下文壓縮後丟失 | SQLite 中的持久列永久保留 |
| 協調模式 | 層級式(呼叫端 → 被呼叫端) | 對等式 — 任何設定檔都能讀寫任何任務 |
一句話區分: delegate_task 是函數呼叫;Kanban 是一個工作佇列,每次交接都是任何設定檔(或人類)都能看到和編輯的一列。
使用 delegate_task 的時機 是父 Agent 在繼續之前需要一個簡短的推理答案,不涉及人類,結果回到父代的上下文中。
使用 Kanban 的時機 是工作跨越 Agent 邊界、需要在重啟後存活、可能需要人類輸入、可能被不同角色接手,或事後需要可被發現。
它們共存:kanban 工作者可以在執行過程中內部呼叫 delegate_task。
核心概念
- 看板(Board) — 一個獨立的任務佇列,擁有自身的 SQLite 資料庫、工作區目錄和調度器迴圈。單一安裝可以有多個看板(例如每個專案、儲存庫或領域一個);請參閱下方的看板(多專案)。單專案使用者停留在
default看板,除了本文件章節外永遠不會看到「看板」這個詞。 - 任務(Task) — 一列包含標題、可選內文、一個指派人(設定檔名稱)、狀態(
triage | todo | ready | running | blocked | done | archived)、可選租戶命名空間、可選幂等鍵(用於去重重複的自動化)。 - 連結(Link) —
task_links列記錄父代 → 子代的依賴關係。當所有父代完成時,調度器將子代從todo → ready提升。 - 留言(Comment) — Agent 間的協作協定。Agent 和人類附加留言;當工作者被(重新)生成時,它會讀取完整的留言串作為上下文的一部分。
- 工作區(Workspace) — 工作者操作的目錄。三種類型:
scratch(預設)— 在~/.hermes/kanban/workspaces/<id>/下的全新 tmp 目錄(非預設看板則為~/.hermes/kanban/boards/<slug>/workspaces/<id>/)。任務完成時刪除 — scratch 設計上是暫時性的,因此當工作者(或hermes kanban complete <id>)將任務標記為完成時,該目錄會立即被清除。如果你想保留工作者的輸出,請改用worktree:或dir:<path>。首次在安裝中建立 scratch 工作區時,調度器會記錄一條警告並在任務上發出tip_scratch_workspace事件(可透過hermes kanban show <id>查看)。dir:<path>— 一個現有的共享目錄(Obsidian vault、郵件作業目錄、每個帳號的資料夾)。必須是絕對路徑。 像dir:../tenants/foo/這樣的相對路徑會在調度時被拒絕,因為它會根據調度器當時所在的 CWD 解析,這具有歧義且是混淆代理的逃脫向量。除此之外路徑是受信任的 — 這是你的盒子、你的檔案系統、工作者以你的 uid 執行。這是受信任的本機使用者威脅模型;kanban 設計上是單主機架構。完成時保留。worktree— 在.worktrees/<id>/下的 git 工作樹,用於程式碼任務。使用worktree:<path>來指定確切的目標路徑。工作者端的git worktree add會建立它,在提供--branch時使用該參數。完成時保留。
- 調度器(Dispatcher) — 一個長生命週期的迴圈,每隔 N 秒(預設 60):取回過期的領取、取回崩潰的工作者(PID 已消失但 TTL 尚未到期)、提升就緒任務、原子性地領取、生成已指派的設定檔。預設在閘道內部執行(
kanban.dispatch_in_gateway: true)。一個調度器每次滴答掃描所有看板;工作者被生成時會釘選HERMES_KANBAN_BOARD,因此看不到其他看板。在同一個任務上連續生成失敗達到kanban.failure_limit次(預設:2)後,調度器會自動將其封鎖並以最後一次錯誤作為原因 — 防止在設定檔不存在、工作區無法掛載等任務上反覆失敗。 - 租戶(Tenant) — 看板內部的可選字串命名空間。一個專家機隊可以服務多個業務(
--tenant business-a),透過工作區路徑和記憶鍵前綴實現資料隔離。租戶是軟性篩選;看板才是硬性隔離邊界。
看板(多專案)
看板讓你將不相關的工作流分隔 — 每個專案、儲存庫或領域一個 — 成獨立的佇列。新安裝恰好有一個名為 default 的看板(DB 在 ~/.hermes/kanban.db 以保持向下相容)。只想要一個工作流的使用者永遠不需要了解看板;此功能是選擇性啟用的。
每個看板的隔離是絕對的:
- 每個看板一個獨立的 SQLite DB(
~/.hermes/kanban/boards/<slug>/kanban.db)。 - 獨立的
workspaces/和logs/目錄。 - 為任務生成的工作者只能看到自己看板的任務 — 调度器在子代環境中設定
HERMES_KANBAN_BOARD,工作者存取的每個kanban_*工具都會讀取它。 - 不允許跨看板連結任務(保持 schema 簡單;如果你真的需要跨專案引用,使用自由文字提及並手動按 id 查找)。
從 CLI 管理看板
# 查看磁碟上的內容。全新安裝只顯示 "default"。
hermes kanban boards list
# 建立新看板。
hermes kanban boards create atm10-server \
--name "ATM10 Server" \
--description "Minecraft modded server ops" \
--icon 🎮 \
--switch # 可選:將其設為當前活躍看板
# 在不切換的情況下操作特定看板。
hermes kanban --board atm10-server list
hermes kanban --board atm10-server create "Restart ATM server" --assignee ops
# 變更後續呼叫的「當前」看板。
hermes kanban boards switch atm10-server
hermes kanban boards show # 目前誰是活躍的?
# 重新命名顯示名稱(slug 是不可變的 — 它是目錄名稱)。
hermes kanban boards rename atm10-server "ATM10 (Prod)"
# 封存(預設)— 將看板目錄移到 boards/_archived/<slug>-<ts>/。
# 可透過將目錄移回來恢復。
hermes kanban boards rm atm10-server
# 永久刪除 — `rm -rf` 看板目錄。無法恢復。
hermes kanban boards rm atm10-server --delete
看板解析順序(優先度由高到低):
- CLI 呼叫中明確指定的
--board <slug>。 HERMES_KANBAN_BOARD環境變數(調度器在生成工作者時設定,因此工作者看不到其他看板)。~/.hermes/kanban/current— 由hermes kanban boards switch持久化的 slug。default。
Slug 驗證規則:小寫字母數字 + 連字元 + 底線,1-64 字元,必須以字母數字開頭。大寫輸入會自動轉小寫。其他任何內容(斜線、空格、點、..)在 CLI 層就會被拒絕,因此路徑遍歷技巧無法用來命名看板。
從儀表板管理看板
hermes dashboard → Kanban 分頁在頂部顯示看板切換器(當存在超過一個看板或任何看板有任務時)。單看板使用者只看到一個小的 + New board 按鈕;切換器在需要之前會被隱藏。
- 看板下拉選單 — 選擇活躍看板。你的選擇會儲存在瀏覽器的
localStorage中,因此在重新整理後仍然保留,不會影響你在終端機中留開的 CLI 的current指標。 - + New board — 開啟一個對話框,要求輸入 slug、顯示名稱、描述和圖示。可選自動切換到新看板。
- 封存 — 僅在非
default看板上顯示。確認後將看板目錄移到boards/_archived/。
所有儀表板 API 端點接受 ?board=<slug> 用於看板範圍限定。Events WebSocket 在連線時釘選到某個看板;在 UI 中切換會針對新看板開啟一個新的 WS。
檔案附件
任務可以攜帶檔案附件 — PDF、圖片、來源文件 — 因此工作者能獲得所需的源材料,無需你將路徑貼入內文並期望它能找到它們。
- 上傳 — 在儀表板抽屜中開啟任務,使用 Attachments 區段的 Upload file 按鈕(一次上傳多個檔案也可以)。每次上傳上限為 25 MB。
- 儲存 — 檔案存放位置為:
預設看板下為
<hermes-home>/kanban/attachments/<task_id>/,指定看板下為<hermes-home>/kanban/boards/<slug>/attachments/<task_id>/。設定HERMES_KANBAN_ATTACHMENTS_ROOT來指定自訂位置。 - 工作者看到的內容 — 當調度器將任務交給工作者時,工作者的上下文中包含一個 Attachments 區段,列出每個檔案的名稱和絕對路徑。工作者擁有完整的檔案/終端機工具存取權,因此可以直接讀取附件(
read_file,或 shell 工具如pdftotext)。 - 下載 / 移除 — 抽屜列出每個附件的下載連結和移除(×)控制項。移除附件會同時刪除元資料列和磁碟上的檔案。
注意 — 遠端終端機後端
附件路徑在本機終端機後端上直接解析,這是 Kanban 工作者的預設後端。如果你在遠端後端(Docker、Modal)上運行工作者,請將看板的
attachments/目錄掛載到沙箱中,以便工作者上下文中的絕對路徑可達。
快速開始
以下命令是你(人類)設定看板和建立任務。一旦任務被指派,調度器會將指定的設定檔生成為工作者,然後模型透過 kanban_* 工具呼叫驅動任務,而非 CLI 命令 — 請參閱工作者如何與看板互動。
# 1. 建立看板(你)
hermes kanban init
# 2. 啟動閘道(託管嵌入式調度器)
hermes gateway start
# 3. 建立任務(你 — 或透過 kanban_create 的編排器 Agent)
hermes kanban create "research AI funding landscape" --assignee researcher
# 4. 即時觀看活動(你)
hermes kanban watch
# 5. 查看看板(你)
hermes kanban list
hermes kanban stats
當調度器撿起 t_abcd 並生成 researcher 設定檔時,該工作者模型做的第一件事就是呼叫 kanban_show() 來讀取它的任務。它不會執行 hermes kanban show t_abcd。
閘道嵌入式調度器(預設)
調度器在閘道行程內部運行。無需安裝額外軟體、無需管理獨立服務 — 如果閘道正在運行,就緒的任務會在下一次滴答(預設 60 秒)時被撿起。
# config.yaml
kanban:
dispatch_in_gateway: true # 預設值
dispatch_interval_seconds: 60 # 預設值
可在運行時透過 HERMES_KANBAN_DISPATCH_IN_GATEWAY=0 覆蓋設定標誌用於除錯。適用標準的閘道監督:直接運行 hermes gateway start,或將閘道設定為 systemd 使用者單元(參見閘道文件)。沒有運行中的閘道時,ready 任務會保持在原位直到閘道啟動 — hermes kanban create 在建立時會對此發出警告。
以獨立行程運行 hermes kanban daemon 已棄用;請使用閘道。如果你確實無法運行閘道(無頭主機策略禁止長生命週期服務等),--force 逃脫按鈕可讓舊的獨立守護行程再運行一個版本週期,但同時針對同一個 kanban.db 運行閘道嵌入式調度器和獨立守護行程會導致領取競態,不受支援。
幂等建立(用於自動化 / webhook)
# 第一次呼叫建立任務。任何後續使用相同鍵的呼叫
# 都會回傳現有的任務 ID 而非建立重複。
hermes kanban create "nightly ops review" \
--assignee ops \
--idempotency-key "nightly-ops-$(date -u +%Y-%m-%d)" \
--json
批次 CLI 動詞
所有生命週期動詞都接受多個 ID,讓你可以在一個命令中清理一批任務:
hermes kanban complete t_abc t_def t_hij --result "batch wrap"
hermes kanban archive t_abc t_def t_hij
hermes kanban unblock t_abc t_def
hermes kanban block t_abc "need input" --ids t_def t_hij
工作者如何與看板互動
工作者不會透過 shell 呼叫 hermes kanban。 當調度器生成工作者時,它在子代環境中設定 HERMES_KANBAN_TASK=t_abcd,該環境變數在模型的 schema 中啟用了一個專屬的 kanban 工具組。同一個工具組也可供在工具組設定中啟用了 kanban 的編排器設定檔使用。這些工具透過 Python kanban_db 層直接讀寫看板,與 CLI 使用相同的代碼路徑。運行中的工作者像使用任何其他工具一樣呼叫這些工具;它永遠不會看到或需要 hermes kanban CLI。
| 工具 | 用途 | 必要參數 |
|---|---|---|
kanban_show | 讀取當前任務(標題、內文、先前嘗試、父代交接、留言、完整的預格式化 worker_context)。預設使用環境中的任務 ID。 | — |
kanban_list | 列出任務摘要,支援 assignee、status、tenant、封存可見性和限制的篩選。供編排器發現看板工作。 | — |
kanban_complete | 以 summary + metadata 結構化交接完結。 | 至少提供 summary / result 其中之一 |
kanban_block | 以 reason 升級請求人類輸入。 | reason |
kanban_heartbeat | 在長時間操作中發出存活訊號。純副作用。 | — |
kanban_comment | 在任務串中附加持久備註。 | task_id、body |
kanban_create | (編排器)以 assignee、可選 parents、skills 等展開成子任務。 | title、assignee |
kanban_link | (編排器)事後新增 parent_id → child_id 依賴邊。 | parent_id、child_id |
kanban_unblock | (編排器)將封鎖的任務移回 ready。 | task_id |
典型的工作者回合看起來像:
# 模型的工具呼叫,按順序:
kanban_show() # 無參數 — 使用 HERMES_KANBAN_TASK
# (模型讀取返回的 worker_context,透過 terminal/file 工具執行工作)
kanban_heartbeat(note="halfway through — 4 of 8 files transformed")
# (更多工作)
kanban_complete(
summary="migrated limiter.py to token-bucket; added 14 tests, all pass",
metadata={"changed_files": ["limiter.py", "tests/test_limiter.py"], "tests_run": 14},
)
編排器工作者則是展開:
kanban_show()
kanban_create(
title="research ICP funding 2024-2026",
assignee="researcher-a",
body="focus on seed + series A, North America, AI-adjacent",
)
# → 回傳 {"task_id": "t_r1", ...}
kanban_create(title="research ICP funding — EU angle", assignee="researcher-b", body="…")
# → 回傳 {"task_id": "t_r2", ...}
kanban_create(
title="synthesize findings into launch brief",
assignee="writer",
parents=["t_r1", "t_r2"], # 兩者都完成後提升為 ready
body="one-pager, 300 words, neutral tone",
)
kanban_complete(summary="decomposed into 2 research tasks + 1 writer; linked dependencies")
標記為「(編排器)」的工具 — kanban_list、kanban_create、kanban_link、kanban_unblock 以及對外部任務的 kanban_comment — 都透過同一個工具組提供;慣例(由 kanban-orchestrator skill 強制執行)是工作者設定檔不會展開或路由不相關的工作,編排器設定檔不會執行實作工作。調度器生成的工作者在破壞性生命週期操作上仍然是任務範圍限定的,不能變更不相關的任務。
為什麼使用工具而非 shell 呼叫 hermes kanban
三個原因:
- 後端可攜性。 終端機工具指向遠端後端(Docker / Modal / Singularity / SSH)的工作者會在容器內部執行
hermes kanban complete,而容器中沒有安裝hermes且~/.hermes/kanban.db未被掛載。kanban 工具在 Agent 自身的 Python 行程中運行,無論終端機後端為何都能存取~/.hermes/kanban.db。 - 無 shell 引號脆弱性。 將
--metadata '{"files": [...]}'透過 shlex + argparse 傳遞是一個隱藏的地雷。結構化工具參數完全跳過此問題。 - 更好的錯誤處理。 工具結果是結構化 JSON,模型可以進行推理,而非它必須解析的 stderr 字串。
正常行程中零 schema 腳印。 一般 hermes chat 行程的 schema 中沒有任何 kanban_* 工具,除非活躍設定檔明確為編排器工作啟用了 kanban 工具組。調度器生成的任務工作者獲得任務範圍的工具,因為 HERMES_KANBAN_TASK 已設定;編排器設定檔透過設定獲得更廣的路由介面。從未接觸 kanban 的使用者不會有工具膨脹。
kanban-worker 和 kanban-orchestrator skill 教導模型在什麼時候以什麼順序呼叫哪個工具。
建議的交接證據
kanban_complete(summary=..., metadata={...}) 設計上是靈活的:
summary 是人類可讀的結案說明,metadata 是下游 Agent、審查者或儀表板可以重複使用而無需解析散文的機器可讀交接。
對於工程和審查任務,建議使用以下可選的 metadata 形態:
{
"changed_files": ["path/to/file.py"],
"verification": ["pytest tests/hermes_cli/test_kanban_db.py -q"],
"dependencies": ["parent task id or external issue, if any"],
"blocked_reason": null,
"retry_notes": "what failed before, if this was a retry",
"residual_risk": ["what was not tested or still needs human review"]
}
這些鍵是一種慣例,而非 schema 要求。有用的特性在於每個工作者留下足夠的證據,讓下一個讀者能快速回答四個問題:
- 改動了什麼?
- 如何驗證的?
- 如果失敗,什麼能解除封鎖或重試?
- 什麼風險被刻意保留?
將機密、原始日誌、權杖、OAuth 材料和不相關的轉錄稿放在 metadata 之外。改為儲存指標和摘要。如果任務沒有檔案或測試,請在 summary 中明確說明,並用 metadata 放置確實存在的證據,例如來源 URL、issue ID 或手動審查步驟。
工作者 Skill
任何應該能處理 kanban 任務的設定檔都必須載入 kanban-worker skill。它教導工作者完整的工具呼叫生命週期,而非 CLI 命令:
- 生成時,呼叫
kanban_show()來讀取標題 + 內文 + 父代交接 + 先前嘗試 + 完整留言串。 cd $HERMES_KANBAN_WORKSPACE(透過終端機工具)並在那裡執行工作。- 在長時間操作中每隔幾分鐘呼叫
kanban_heartbeat(note="...")。如果你的工作可能運行超過 1 小時,請至少每小時呼叫一次kanban_heartbeat— 調度器會取回運行超過kanban.dispatch_stale_timeout_seconds(預設 4 小時)且過去一小時內沒有心跳的任務,假設工作者在沒有清理的情況下崩潰了。取回是良性的(任務回到ready重新調度,不計入失敗計數器),但你會失去當前運行的進度。 - 以
kanban_complete(summary="...", metadata={...})完成,或如果卡住則kanban_block(reason="...")。
最後的 kanban_complete / kanban_block 呼叫是工作者協定的一部分。如果工作者行程在任務仍為 running 時以狀態 0 退出,調度器會將其視為協定違反,發出 protocol_violation 事件,並在下一次滴答自動封鎖任務而非重新生成它進入相同的迴圈。這通常意味著模型寫了一個純文字答案並在未使用 Kanban 工具介面的情況下退出。
kanban-worker 是一個內建 skill,在安裝和更新時同步到每個設定檔 — 沒有獨立的 Skills Hub 安裝步驟。驗證它存在於你用於 kanban 工作者的設定檔中(researcher、writer、ops 等):
hermes -p <your-worker-profile> skills list | grep kanban-worker
如果內建副本缺失,為該設定檔恢復:
hermes -p <your-worker-profile> skills reset kanban-worker --restore
調度器在生成每個工作者時也會自動傳遞 --skills kanban-worker,因此工作者始終有模式庫可用,即使設定檔的預設 skills 設定中未包含它。
將額外 Skill 釘選到特定任務
有時單個任務需要指派設定檔預設未攜帶的專業上下文 — 需要 translation skill 的翻譯任務、需要 github-code-review 的審查任務、需要 security-pr-audit 的安全審計。與其每次都編輯指派者的設定檔,不如直接將 skill 附加到任務上。
從編排器 Agent(常見情況 — 一個 Agent 將工作路由給另一個),使用 kanban_create 工具的 skills 陣列:
kanban_create(
title="translate README to Japanese",
assignee="linguist",
skills=["translation"],
)
kanban_create(
title="audit auth flow",
assignee="reviewer",
skills=["security-pr-audit", "github-code-review"],
)
從人類(CLI / 斜線命令),對每個 skill 重複 --skill:
hermes kanban create "translate README to Japanese" \
--assignee linguist \
--skill translation
hermes kanban create "audit auth flow" \
--assignee reviewer \
--skill security-pr-audit \
--skill github-code-review
從儀表板,在內聯建立表單的 skills 欄位中以逗號分隔輸入 skill 名稱。
這些 skill 是對內建 kanban-worker 的累加 — 調度器為每個(以及內建的)發出一個 --skills <name> 旗標,因此工作者生成時會載入所有這些 skill。skill 名稱必須與指派者設定檔上實際安裝的 skill 匹配(執行 hermes skills list 查看可用的);沒有運行時安裝機制。
目標模式卡片(--goal)
預設情況下每個工作者對其卡片有一次機會 — 執行工作、呼叫 kanban_complete/kanban_block、退出。傳入 --goal(CLI)或 goal_mode=True(kanban_create 工具 / 儀表板)可改為以目標迴圈模式運行該工作者,與 /goal 斜線命令背後相同的 Ralph 風格引擎:每個回合後,一個輔助審查者根據卡片的標題 + 內文(作為驗收標準)檢查工作者的輸出,如果工作未完成 — 且回合預算尚有剩餘 — 工作者會在同一個會話中繼續,直到審查者同意、工作者自行終止任務,或預算用盡(這會封鎖卡片以供人類審查,而非靜默退出)。
hermes kanban create "Translate the docs site to French" \
--body "Acceptance: every page translated, no English left, links intact." \
--assignee linguist \
--goal \
--goal-max-turns 15 # 可選;預設 20
用於開放式、多步驟或「持續執行直到 X 為真」的卡片。對於簡單的一次性工作則跳過 — 每回合的審查者開銷不值得,且調度器現有的重試/熔斷機制已能處理暫時性工作者失敗。審查者的品質取決於你的目標文字,因此請將內文寫成明確的驗收標準。
編排器 Skill
一個行為良好的編排器不會自己執行工作。 它將使用者的目標分解為任務、建立連結、將每個任務指派給你設定的其中一個設定檔,然後退後。kanban-orchestrator skill 將此編碼為工具呼叫模式:反誘惑規則、Step-0 設定檔發現提示(調度器在遇到未知指派者名稱時會靜默失敗,因此編排器必須將每張卡片建立在你機器上實際存在的設定檔上),以及以 kanban_create / kanban_link / kanban_comment 為鍵的分解手冊。
一個典範的編排器回合(兩個平行研究員交接給一個寫手):
# 使用者目標:"draft a launch post on the ICP funding landscape"
kanban_create(title="research ICP funding, NA angle", assignee="researcher-a", body="…") # → t_r1
kanban_create(title="research ICP funding, EU angle", assignee="researcher-b", body="…") # → t_r2
kanban_create(
title="synthesize ICP funding research into launch post draft",
assignee="writer",
parents=["t_r1", "t_r2"], # 兩個研究員都完成後提升為 'ready'
body="one-pager, neutral tone, cite sources inline",
) # → t_w1
# 可選:事後新增後續發現的交叉依賴,無需重新建立任務
kanban_link(parent_id="t_r1", child_id="t_followup")
kanban_complete(
summary="decomposed into 2 parallel research tasks → 1 synthesis task; writer starts when both researchers finish",
)
kanban-orchestrator 是一個內建 skill。它在安裝和更新時同步到每個設定檔,因此沒有獨立的 Skills Hub 安裝步驟。驗證它存在於你的編排器設定檔中:
hermes -p orchestrator skills list | grep kanban-orchestrator
如果內建副本缺失,為該設定檔恢復:
hermes -p orchestrator skills reset kanban-orchestrator --restore
為獲得最佳效果,將其與工具組限縮為看板操作(kanban、gateway、memory)的設定檔搭配,這樣編排器即使嘗試也無法執行實作任務。
儀表板(GUI)
/kanban CLI 和斜線命令足以無頭運行看板,但視覺化看板通常是人類參與迴圈的正確介面:分流、跨設定檔監督、閱讀留言串,以及在欄位間拖曳卡片。Hermes 將其作為內建儀表板外掛提供,位於 plugins/kanban/ — 不是核心功能、不是獨立服務 — 遵循 Extending the Dashboard 中的模式。
開啟方式:
hermes kanban init # 一次性:建立 kanban.db(如果尚未存在)
hermes dashboard # "Kanban" 分頁出現在導覽列中,位於 "Skills" 之後
外掛提供的功能
- 一個 Kanban 分頁,每個狀態一個欄位:
triage、todo、ready、running、blocked、done(加上開啟切換時的archived)。triage是粗略想法的停放欄位。預設情況下(kanban.auto_decompose: true),調度器會自動對落到此處的任務運行分解器。內建分解器使用auxiliary.kanban_decomposer模型路徑,讀取你的設定檔清單(含描述),並將任務展開成一個小型子任務圖,路由給最適合的專家。原始任務保持存活作為每個子代的父代,因此其指派人(kanban.orchestrator_profile,或未設定時的活躍預設設定檔)在全部完成後會被喚醒以判斷完成度。翻轉頁面頂部的 Orchestration: Auto/Manual 藥丸(翡翠綠 = Auto,灰色 = Manual),或直接編輯config.yaml。兩種模式與hermes kanban specify共存 — 當你不想展開時,它仍可用於單任務規格重寫。
- 卡片顯示任務 ID、標題、優先級標記、租戶標籤、指派的設定檔、留言/連結數量、一個進度藥丸(
N/M子代完成數,當任務有依賴時),以及「N 前建立」。每張卡片的核取方塊支援多選。 - Running 內的每個設定檔泳道 — 工具列核取方塊切換 Running 欄位的子群組(按指派者)。
- 透過 WebSocket 即時更新 — 外掛追蹤僅追加的
task_events表的短間隔輪詢;看板在任何設定檔(CLI、閘道或另一個儀表板分頁)執行操作時立即反映變更。重新整理有防抖處理,因此一連串事件只觸發一次重新取得。 - 拖放 卡片在欄位間移動以變更狀態。放下時發送
PATCH /api/plugins/kanban/tasks/:id,透過與 CLI 相同的kanban_db代碼路由 — 三個介面永遠不會漂移。移動到破壞性狀態(done、archived、blocked)時會提示確認。觸控裝置使用基於指標的替代方案,因此看板可從平板使用。 - 內聯建立 — 點擊任何欄位標頭上的
+來輸入標題、指派人、優先級,以及(可選地)從所有現有任務的下拉選單中選擇父代任務。按 Enter 建立任務,Shift+Enter 在標題欄位中插入換行,或 Escape 取消。從 Triage 欄位建立會自動將新任務停放在 triage 中。 - 多選與批次操作 — Shift/Ctrl+點擊卡片或勾選其核取方塊以加入選擇。頂部出現一個批次操作列,提供批次狀態轉換、封存和重新指派(透過設定檔下拉選單或「(unassign)」)。破壞性批次會先確認。單一 ID 的部分失敗會被報告而不中止其餘操作。
- 點擊卡片(不按 Shift/Ctrl)會開啟一個側邊抽屜(Escape 或點擊外部關閉),包含:
- 可編輯標題 — 點擊標題進行重新命名。
- 可編輯指派人 / 優先級 — 點擊元資料列進行重寫。
- 可編輯描述 — 預設為 markdown 渲染(標題、粗體、斜體、行內代碼、圍欄代碼、
http(s)/mailto:連結、項目列表),帶有一個「編輯」按鈕可切換為 textarea。Markdown 渲染是一個小巧、XSS 安全的渲染器 — 每個替換都在 HTML 轉義的輸入上執行,只有http(s)/mailto:連結通過,且target="_blank"+rel="noopener noreferrer"始終被設定。 - 依賴編輯器 — 父代和子代的藥丸列表,每個都有一個
×用於取消連結,加上用於所有其他任務的下拉選單以新增父代或子代。循環嘗試在伺服器端被拒絕並顯示明確訊息。 - 狀態操作列(→ triage / → ready / → running / block / unblock / complete / archive),帶有破壞性轉換的確認提示。對於 Triage 欄位中的卡片,此列還提供兩個 LLM 驅動的操作:⚗ Decompose 將任務展開成一個子任務圖,根據描述路由給專家設定檔;✨ Specify 執行單任務規格重寫。當 LLM 判斷任務不適合展開時,Decompose 會回退到 specify 風格的提升,因此它是嚴格的超集。兩者都可從 CLI(
hermes kanban decompose <id>/specify <id>/--all)、任何閘道平台(/kanban decompose <id>)以及透過POST /api/plugins/kanban/tasks/:id/decompose和…/specify程式化存取。在config.yaml中的auxiliary.kanban_decomposer和auxiliary.triage_specifier下配置模型。 - 結果區段(也是 markdown 渲染)、留言串(Enter 提交)、最近 20 個事件。
- 工具列篩選 — 自由文字搜尋、租戶下拉選單(預設使用
config.yaml中的dashboard.kanban.default_tenant)、指派人下拉選單、「show archived」切換、「lanes by profile」切換,以及一個 Nudge dispatcher 按鈕讓你不必等待下一次 60 秒滴答。
視覺上目標是熟悉的 Linear / Fusion 佈局:深色主題、帶計數的欄位標頭、彩色狀態點、優先級和租戶的藥丸標記。外掛只讀取主題 CSS 變數(--color-*、--radius、--font-mono、...),因此會隨著活躍的儀表板主題自動換膚。
自動 vs 手動編排
kanban 看板有兩種方式處理你丟入 Triage 欄位的任務:
自動(預設) — kanban.auto_decompose: true。閘道嵌入式調度器在每次滴答運行分解器,受 kanban.auto_decompose_per_tick(預設每次滴答 3 個任務)限制,因此大量載入的 triage 任務不會爆發式消耗輔助 LLM。分解器使用內建分解提示加上 auxiliary.kanban_decomposer 模型路徑,讀取你安裝的設定檔及其描述,並要求 LLM 產生一個 JSON 任務圖:要生成哪些任務、交給誰,以及哪些依賴哪些。原始 triage 任務成為圖中每個葉節點的父代,因此它保持存活直到整個圖完成 — 然後提升回 ready,以便其指派人(kanban.orchestrator_profile,或未設定時的活躍預設設定檔)判斷完成度並在工作未完成時新增更多任務。這是「丟入一行指令就走開」的流程。
手動 — kanban.auto_decompose: false。Triage 任務停留在 triage 中直到你採取行動。點擊卡片上的 ⚗ Decompose 按鈕、執行 hermes kanban decompose <id>(或 --all),或在聊天中使用 /kanban decompose <id>。這與看板在分解器之前的行為相符,當你想要完全控制什麼時候運行什麼時很有用。
在 kanban 頁面頂部的 Orchestration: Auto/Manual 藥丸之間切換(翡翠綠 = Auto,灰色 = Manual),或直接編輯 config.yaml。兩種模式與 hermes kanban specify 共存 — 當你不想展開時,它仍可用於單任務規格重寫。
分解器的路由決策取決於設定檔描述,這是你透過 hermes profile create --description "..."、hermes profile describe <name> --text "..."、hermes profile describe <name --auto(LLM 從設定檔安裝的 skill + 模型產生)或儀表板中展開的 Orchestration settings 面板的每個設定檔編輯器設定的每個設定檔標記原語。沒有描述的設定檔仍然出現在名單中 — 它們可按名稱路由,只是精確度較低。分解器永遠不會將子任務指派為 assignee=None:當 LLM 選擇未知設定檔時,子代會被路由到 kanban.default_assignee(或未設定時的活躍預設設定檔)。
kanban.orchestrator_profile 不會將該設定檔的提示、skill 或自訂邏輯載入分解呼叫中。它控制展開後誰擁有根/編排任務。要變更分解器的模型/供應商,配置 auxiliary.kanban_decomposer。要使用設定檔的自訂任務分割邏輯而非內建分解器,切換到手動模式並讓該設定檔明確建立或分解任務。
設定旋鈕(全部在 ~/.hermes/config.yaml 的 kanban: 下):
| 鍵 | 預設值 | 用途 |
|---|---|---|
auto_decompose | true | 調度器每次滴答自動運行分解器。 |
auto_decompose_per_tick | 3 | 每次調度器滴答的分解上限。超出的延遲到下次滴答。 |
orchestrator_profile | "" | 分解後指派給根/編排任務的設定檔。空白 = 回退到活躍預設設定檔。 |
default_assignee | "" | LLM 選擇未知設定檔時子任務的落腳處。空白 = 回退到活躍預設。 |
以及兩個輔助 LLM 槽位:
| 鍵 | 用途 |
|---|---|
auxiliary.kanban_decomposer | 產生任務圖的模型(由 Decompose 呼叫)。設定 provider/model 來覆蓋主聊天模型。 |
auxiliary.profile_describer | 自動產生設定檔描述的模型(由 hermes profile describe --auto 呼叫)。 |
架構
GUI 嚴格是一個讀取資料庫 + 寫入 kanban_db 的層,沒有自己的領域邏輯:
<!-- ascii-guard-ignore -->┌────────────────────────┐ WebSocket (追蹤 task_events)
│ React SPA (外掛) │ ◀──────────────────────────────────┐
│ HTML5 拖放 │ │
└──────────┬─────────────┘ │
│ REST over fetchJSON │
▼ │
┌────────────────────────┐ 寫入直接呼叫 kanban_db.* │
│ FastAPI 路由器 │ — 與 CLI /kanban 動詞 │
│ plugins/kanban/ │ 使用相同的代碼路徑 │
│ dashboard/plugin_api.py │
└──────────┬─────────────┘ │
│ │
▼ │
┌────────────────────────┐ │
│ ~/.hermes/kanban.db │ ───── 追加 task_events ───────────┘
│ (WAL,共享) │
└────────────────────────┘
<!-- ascii-guard-ignore-end -->
REST 介面
所有路由掛載在 /api/plugins/kanban/ 下,並受儀表板的暫時性 session token 保護:
| 方法 | 路徑 | 用途 |
|---|---|---|
GET | /board?tenant=<name>&include_archived=… | 按狀態欄位分組的完整看板,加上篩選下拉選單的租戶和指派人 |
GET | /tasks/:id | 任務 + 留言 + 事件 + 連結 |
POST | /tasks | 建立(包裝 kanban_db.create_task,接受 triage: bool 和 parents: [id, …]) |
PATCH | /tasks/:id | 狀態 / 指派人 / 優先級 / 標題 / 內文 / 結果 |
POST | /tasks/bulk | 將相同的補丁(狀態 / 封存 / 指派人 / 優先級)應用於 ids 中的每個 ID。單一 ID 失敗被報告而不中止其餘 |
POST | /tasks/:id/comments | 附加留言 |
POST | /tasks/:id/specify | 運行 triage 規格化器 — 輔助 LLM 補全任務內文並從 triage 提升到 todo。回傳 {ok, task_id, reason, new_title};ok=false 附帶人類可讀原因的「not in triage」/ 無輔助用戶端 / LLM 錯誤返回 200 而非 4xx |
POST | /tasks/:id/decompose | 運行 kanban 分解器 — 輔助 LLM 產生任務圖,輔助函數原子性地建立子代 + 連結根 + 翻轉 triage → todo。回傳 {ok, task_id, reason, fanout, child_ids, new_title}。LLM 錯誤時同樣返回 200 的慣例。 |
GET | /profiles | 列出已安裝的設定檔及其描述(供儀表板的設定檔描述編輯器和編排器選擇器使用)。 |
PATCH | /profiles/:name | 設定或清除設定檔描述(使用者編寫 — description_auto: false)。回傳 {ok, profile, description}。 |
POST | /profiles/:name/describe-auto | 透過 auxiliary.profile_describer 為設定檔產生描述。以 description_auto: true 持久化,以便儀表板可以顯示「review」標記。 |
GET | /orchestration | 讀取 kanban 編排設定(orchestrator_profile、default_assignee、auto_decompose)加上回退後的解析有效值。 |
PUT | /orchestration | 更新 config.yaml 中三個編輯鍵的一個或多個。驗證非空設定檔名稱是否實際存在。 |
POST | /links | 新增依賴(parent_id → child_id) |
DELETE | /links?parent_id=…&child_id=… | 移除依賴 |
POST | /dispatch?max=…&dry_run=… | 提醒調度器 — 跳過 60 秒等待 |
GET | /config | 從 config.yaml 讀取 dashboard.kanban 偏好設定 — default_tenant、lane_by_profile、include_archived_by_default、render_markdown |
WS | /events?since=<event_id> | task_events 列的即時串流 |
每個處理器都是一個薄包裝 — 外掛約 700 行 Python(路由器 + WebSocket 追蹤 + 批次併發器 + 設定讀取器),不新增任何業務邏輯。一個小巧的 _conn() 輔助函數在每次讀寫時自動初始化 kanban.db,因此全新安裝不論使用者先開啟儀表板、直接使用 REST API,還是執行了 hermes kanban init 都能正常運作。
儀表板設定
~/.hermes/config.yaml 中 dashboard.kanban 下的任何鍵會改變分頁的預設值 — 外掛在載入時透過 GET /config 讀取它們:
dashboard:
kanban:
default_tenant: acme # 預先選定租戶篩選
lane_by_profile: true # "lanes by profile" 切換的預設值
include_archived_by_default: false
render_markdown: true # 設為 false 使用純 <pre> 渲染
每個鍵都是可選的,回退到所示的預設值。
安全模型
儀表板的 HTTP 認證中介軟體明確跳過 /api/plugins/ — 外掛路由在設計上是未認證的,因為儀表板預設綁定到 localhost。這意味著 kanban REST 介面可從主機上的任何行程存取。
WebSocket 採取額外一步:它要求儀表板的暫時性 session token 作為 ?token=… 查詢參數(瀏覽器無法在升級請求上設定 Authorization),與瀏覽器內 PTY 橋接使用的模式相同。
如果你執行 hermes dashboard --host 0.0.0.0,每個外掛路由 — kanban 包含在內 — 都變得可從網路存取。不要在共享主機上這樣做。 看板包含任務內文、留言和工作區路徑;攻擊者存取這些路由就能讀取你的整個協作介面,還可以建立 / 重新指派 / 封存任務。
~/.hermes/kanban.db 中的任務有意地與設定檔無關(這是協調原語)。如果你用 hermes -p <profile> dashboard 開啟儀表板,看板仍然顯示主機上任何其他設定檔建立的任務。同一個使用者擁有所有設定檔,但如果多個角色共存,這一點值得了解。
即時更新
task_events 是一個僅追加的 SQLite 表,具有單調遞增的 id。WebSocket 端點保存每個客戶端的最後看到的事件 ID,並在新列到達時推送。當一連串事件到達時,前端重新整理(非常輕量的)看板端點 — 比嘗試從每種事件類型補丁本地狀態更簡單且更正確。WAL 模式意味著讀取迴圈永遠不會阻塞調度器的 BEGIN IMMEDIATE 領取交易。
擴展
外掛使用標準的 Hermes 儀表板外掛合約 — 請參閱 Extending the Dashboard 了解完整的 manifest 參考、shell 槽位、頁面範圍槽位和 Plugin SDK。額外欄位、自訂卡片外觀、租戶篩選佈局,或完整的 tab.override 替換都可以在不 fork 此外掛的情況下實現。
要停用而不移除:在 config.yaml 中新增 dashboard.plugins.kanban.enabled: false(或刪除 plugins/kanban/dashboard/manifest.json)。
範圍邊界
GUI 設計上是輕量的。外掛做的一切都可以從 CLI 存取;外掛只是讓它對人類更舒適。自動指派、預算、治理門檻和組織圖視圖仍然是使用者空間 — 一個路由器設定檔、另一個外掛,或重用 tools/approval.py — 正如設計規格的範圍外章節所列。
CLI 命令參考
這是你(或腳本、cron、儀表板)用來驅動看板的介面。在調度器內部運行的工作者使用 kanban_* 工具介面執行相同的操作 — 這裡的 CLI 和那裡的工具都透過 kanban_db 路由,因此兩個介面在結構上保持一致。
hermes kanban init # 建立 kanban.db + 顯示守護行程提示
hermes kanban create "<title>" [--body ...] [--assignee <profile>]
[--parent <id>]... [--tenant <name>]
[--workspace scratch|worktree|worktree:<path>|dir:<path>]
[--branch <name>]
[--priority N] [--triage] [--idempotency-key KEY]
[--max-runtime 30m|2h|1d|<seconds>]
[--max-retries N]
[--goal] [--goal-max-turns N]
[--skill <name>]...
[--json]
hermes kanban list [--mine] [--assignee P] [--status S] [--tenant T] [--archived]
[--workflow-template-id <id>] [--current-step-key <key>]
[--sort created|created-desc|priority|priority-desc|status|assignee|title|updated]
[--json]
hermes kanban show <id> [--json]
hermes kanban assign <id> <profile> # 或 'none' 取消指派
hermes kanban reassign <id>... <profile> # 批次重新指派任務給設定檔
hermes kanban edit <id> [--title ...] [--body ...] # 就地編輯任務標題 / 內文 / 優先級
[--priority N]
hermes kanban promote <id>... # 將 todo/blocked 任務移到 ready(恢復用)
hermes kanban schedule <id> --at <ISO8601> # 設定/清除任務的 scheduled_at 開始時間
hermes kanban diagnostics [--json] # 看板健康狀態快照(別名:diag)
hermes kanban link <parent_id> <child_id>
hermes kanban unlink <parent_id> <child_id>
hermes kanban claim <id> [--ttl SECONDS]
hermes kanban comment <id> "<text>" [--author NAME]
# 批次動詞 — 接受多個 ID:
hermes kanban complete <id>... [--result "..."]
hermes kanban block <id> "<reason>" [--ids <id>...]
hermes kanban unblock <id>...
hermes kanban archive <id>...
hermes kanban tail <id> # 追蹤單一任務的事件串流
hermes kanban watch [--assignee P] [--tenant T] # 即時串流所有事件到終端機
[--kinds completed,blocked,…] [--interval SECS]
hermes kanban heartbeat <id> [--note "..."] # 工作者存活訊號,用於長時間操作
hermes kanban runs <id> [--json] # 嘗試歷史(每次運行一列)
hermes kanban assignees [--json] # 磁碟上的設定檔 + 每個指派者的任務計數
hermes kanban dispatch [--dry-run] [--max N] # 單次通過
[--failure-limit N] [--json]
hermes kanban daemon --force # 已棄用 — 獨立調度器(改用 `hermes gateway start`)
[--failure-limit N] [--pidfile PATH] [-v]
hermes kanban stats [--json] # 按狀態 + 按指派者計數
hermes kanban log <id> [--tail BYTES] # 從 ~/.hermes/kanban/logs/ 的工作者日誌
hermes kanban notify-subscribe <id> # 閘道橋接道橋接鉤子(閘道中 /kanban 使用)
--platform <name> --chat-id <id> [--thread-id <id>] [--user-id <id>]
hermes kanban notify-list [<id>] [--json]
hermes kanban notify-unsubscribe <id>
--platform <name> --chat-id <id> [--thread-id <id>]
hermes kanban context <id> # 工作者看到的內容
hermes kanban specify [<id> | --all] [--tenant T] # 將 triage 欄位中的想法
[--author NAME] [--json] # 補全為完整規格並提升到 todo
hermes kanban gc [--event-retention-days N] # 工作區 + 舊事件 + 舊日誌
[--log-retention-days N]
所有命令也可在互動式 CLI 和訊息閘道中作為斜線命令使用(參見下方的 /kanban 斜線命令)。
--max-retries 是每個任務的熔斷器覆蓋。--max-retries 1 在第一次非成功嘗試時封鎖任務,而 --max-retries 3 允許兩次重試,在第三次失敗時封鎖。省略則使用 config.yaml 中的 kanban.failure_limit,然後是內建預設值。
並發、排程和子代提升設定
| 設定鍵 | 預設值 | 用途 |
|---|---|---|
kanban.max_in_progress | 未設定(無限制) | 限制同時運行的任務數量。當看板已有 N 個運行中時,調度器跳過生成更多 — 適用於慢速工作者(本機 LLM、資源受限主機),讓它們先完成手頭的工作再堆疊更多並超時。無效或低於 1 的值會記錄警告並行為無限。 |
kanban.max_in_progress_per_profile | 未設定(無限制) | max_in_progress 的每個設定檔變體 — 限制任何單一指派設定檔可同時運行多少任務。適用於一個設定檔較慢或受限速但其他設定檔應繼續流動的情況。與看板範圍的 max_in_progress 同時適用;兩者都必須允許才能繼續生成。 |
kanban.auto_promote_children | true | 當 decompose_triage_task() 產生沒有父代封鎖依賴的子代後,它們自動提升到 ready 以便調度器撿起。設為 false 以要求手動審查 — 子代停留在 todo 直到你提升它們。 |
kanban.default_workdir | 未設定 | 看板級別的預設工作目錄,套用於既未指定 --workspace 也未由任務本身覆蓋的新任務。每個任務的 workspace: 仍然優先。 |
kanban:
max_in_progress: 2
auto_promote_children: false
default_workdir: ~/work/active-project
排程任務啟動(scheduled_at)
在任務上設定 scheduled_at 以延遲調度直到特定時間。調度器跳過 scheduled_at 在未來的就緒任務,並在該時間戳之後的第一次滴答撿起它們。
hermes kanban create "nightly backup audit" \
--assignee ops --scheduled-at "2026-06-01T03:00:00Z"
重生守護
調度器在以下情況拒絕重新生成就緒任務:上次運行遇到配額/認證/429 錯誤(blocker_auth),或在守護視窗內成功完成了一次運行(recent_success),或近期的任務留言連結到 GitHub PR(active_pr)。這防止在人類跟上之前在同一個臭蟲或任務上重複工作者風暴。參見事件參考中的 respawn_guarded 列。
拖曳刪除和批次刪除(儀表板)
儀表板在 kanban 頁面上提供一個垃圾桶投放區 — 將任何卡片拖入其中以刪除任務(級聯刪除 task_events、子代連結和訂閱)。確認提示防止意外。批次刪除也可透過 DELETE /api/plugins/kanban/tasks 和 JSON body {"ids": ["t_abc", "t_def", ...]} 存取。
工作者可見性端點
儀表板外掛 API 現在為外部監控器提供這些唯讀端點(加上一個執行控制動詞):
| 端點 | 回傳 |
|---|---|
GET /api/plugins/kanban/workers/active | 目前已生成的工作者,含 PID、設定檔、任務 ID、啟動時間、上次心跳 |
GET /api/plugins/kanban/runs/{id} | 單次運行詳情 — 任務 ID、狀態、開始/結束、退出碼、日誌路徑 |
POST /api/plugins/kanban/runs/{run_id}/terminate | 終止可取回的運行 — 停止工作者並釋放任務以供重新調度 |
GET /api/plugins/kanban/inspect | 組合調度器快照 — 積壓、進行中計數 vs. max_in_progress、近期事件 |
所有這些都受與 kanban 外掛 API 其餘部分相同的儀表板外掛認證保護。
Kanban Swarm 拓撲輔助
hermes kanban swarm 一次性建立一個持久的 Kanban Swarm v1 圖:一個完成的根/黑板卡片、N 個平行工作者卡片、一個以所有工作者為依賴的驗證者卡片,以及一個以驗證者為依賴的綜合者卡片。共享的 swarm 上下文(「黑板」)以結構化 JSON 留言儲存在根卡片上,因此任何工作者都能讀取它。
hermes kanban swarm "Design a multi-region failover plan" \
--workers researcher,architect,sre \
--verifier reviewer --synthesizer writer
產生的圖正常調度 — 工作者平行運行,驗證者在它們全部完成後喚醒,綜合者在驗證者標記工作為乾淨後喚醒。
/kanban 斜線命令 {#kanban-slash-command}
每個 hermes kanban <action> 動詞也可作為 /kanban <action> 存取 — 從互動式 hermes chat 會話以及任何閘道平台(Telegram、Discord、Slack、WhatsApp、Signal、Matrix、Mattermost、email、SMS)。兩個介面呼叫完全相同的 hermes_cli.kanban.run_slash() 入口點,重用 hermes kanban 的 argparse 樹,因此參數介面、旗標和輸出格式在 CLI、/kanban 和 hermes kanban 之間完全相同。你無需離開聊天就能驅動看板。
/kanban list
/kanban show t_abcd
/kanban create "write launch post" --assignee writer --parent t_research
/kanban comment t_abcd "looks good, ship it"
/kanban unblock t_abcd
/kanban dispatch --max 3
/kanban specify t_abcd # 將 triage 一行指令補全為真正的規格
/kanban specify --all --tenant engineering # 一次掃描某租戶中的所有 triage 任務
多字元參數的引用方式與 shell 中相同 — run_slash 使用 shlex.split 解析行的其餘部分,因此 "..." 和 '...' 都有效。
執行中使用:/kanban 繞過運行中 Agent 的守護
閘道通常在 Agent 仍在思考時將斜線命令和使用者訊息排入佇列 — 這就是阻止你在第一個回合仍在進行時意外開始第二個回合的機制。/kanban 明確被排除在此守護之外。 看板位於 ~/.hermes/kanban.db,不在運行中 Agent 的狀態中,因此讀取(list、show、context、tail、watch、stats、runs)和寫入(comment、unblock、block、assign、archive、create、link、…)都立即通過,即使在回合中途也是如此。
這正是分離的全部意義:
- 工作者等待對等者而阻塞 → 你從手機發送
/kanban unblock t_abcd,調度器在下一次滴答撿起對等者。被阻塞的工作者不會被中斷 — 它只是不再被阻塞。 - 你發現一張需要人類上下文的卡片 →
/kanban comment t_xyz "use the 2026 schema, not 2025"落在任務串上,該任務的下一次運行會在kanban_show()中讀取它。 - 你想知道你的機隊在做什麼而不中斷編排器 →
/kanban list --mine或/kanban stats檢查看板而不觸碰你的主要對話。
/kanban create 自動訂閱(僅限閘道)
當你從閘道使用 /kanban create "…" 建立任務時,來源聊天(平台 + 聊天 ID + 討論串 ID)會自動訂閱該任務的終端事件(completed、blocked、gave_up、crashed、timed_out)。你會在每個終端事件時收到一條訊息 — 包括工作者在 completed 時的結果摘要第一行 — 無需輪詢或記住任務 ID。
you> /kanban create "transcribe today's podcast" --assignee transcriber
bot> Created t_9fc1a3 (ready, assignee=transcriber)
(subscribed — you'll be notified when t_9fc1a3 completes or blocks)
… ~8 分鐘後 …
bot> ✓ t_9fc1a3 completed by transcriber
transcribed 42 minutes, saved to podcast/2026-05-04.md
訂閱在任務達到 done 或 archived 後自動移除。如果你用 --json(機器輸出)腳本化建立,自動訂閱會被跳過 — 假設腳本化的呼叫者想要透過 /kanban notify-subscribe 明確管理訂閱。
訊息中的輸出截斷
閘道平台有實際的訊息長度上限。如果 /kanban list、/kanban show 或 /kanban tail 產生超過約 3800 字元的輸出,回應會被截斷並附上 … (truncated; use \hermes kanban …` in your terminal for full output)` 頁尾。CLI 介面沒有此上限。
自動完成
在互動式 CLI 中,輸入 /kanban 並按 Tab 會循環瀏覽內建子命令清單(list、ls、show、create、assign、link、unlink、claim、comment、complete、block、unblock、archive、tail、dispatch、context、init、gc)。CLI 參考中列出的其餘動詞(watch、stats、runs、log、assignees、heartbeat、notify-subscribe、notify-list、notify-unsubscribe、daemon)也可以使用 — 只是尚未出現在自動完成提示清單中。
協作模式
看板支援這八種模式,無需任何新的原語:
| 模式 | 形態 | 範例 |
|---|---|---|
| P1 展開(Fan-out) | N 個同級,相同角色 | 「平行研究 5 個角度」 |
| P2 管線(Pipeline) | 角色鏈:偵察員 → 編輯 → 寫手 | 每日簡報組裝 |
| P3 投票 / 多數決 | N 個同級 + 1 個聚合者 | 3 個研究員 → 1 個審查者挑選 |
| P4 長期日誌 | 相同設定檔 + 共享目錄 + cron | Obsidian vault |
| P5 人類介入迴圈 | 工作者阻塞 → 使用者留言 → 解除封鎖 | 模糊的決策 |
P6 @mention | 從散文中內聯路由 | @reviewer look at this |
| P7 討論串範圍工作區 | 討論串中的 /kanban here | 每個專案的閘道討論串 |
| P8 機隊農場 | 一個設定檔,N 個對象 | 50 個社交帳號 |
| P9 Triage 規格化器 | 粗略想法 → triage → hermes kanban specify 補全內文 → todo | 「將這行指令變成規格化的任務」 |
每個模式的實作範例,請參閱 docs/hermes-kanban-v1-spec.pdf。
多租戶使用
當一個專家機隊服務多個業務時,為每個任務標記租戶:
hermes kanban create "monthly report" \
--assignee researcher \
--tenant business-a \
--workspace dir:~/tenants/business-a/data/
工作者收到 $HERMES_TENANT 並按前綴命名空間化其記憶寫入。看板、調度器和設定檔定義都是共享的;只有資料是有範圍的。
閘道通知
當你從閘道(Telegram、Discord、Slack 等)使用 /kanban create … 時,來源聊天會自動訂閱新任務。閘道的背景通知器每隔幾秒輪詢 task_events,在每個終端事件(completed、blocked、gave_up、crashed、timed_out)時向該聊天發送一條訊息。已完成的任務還會發送工作者 --result 的第一行,讓你看到結果而無需 /kanban show。
你可以從 CLI 明確管理訂閱 — 當腳本 / cron 任務想要通知它不是來源的聊天時很有用:
hermes kanban notify-subscribe t_abcd \
--platform telegram --chat-id 12345678 --thread-id 7
hermes kanban notify-list
hermes kanban notify-unsubscribe t_abcd \
--platform telegram --chat-id 12345678 --thread-id 7
訂閱在任務達到 done 或 archived 後自動移除;無需清理。
運行紀錄 — 每次嘗試一列
任務是邏輯工作單位;運行紀錄是一次執行它的嘗試。當調度器領取就緒任務時,它在 task_runs 中建立一列並將 tasks.current_run_id 指向它。當該嘗試結束 — 完成、封鎖、崩潰、超時、生成失敗、被取回 — 運行紀錄列以 outcome 關閉,任務的指標被清除。嘗試過三次的任務有三列 task_runs。
為什麼用兩個表而非直接修改任務:你需要完整的嘗試歷史用於真實世界的事後檢討(「第二次審查者嘗試到了批准,第三次合併了」),你需要一個乾淨的地方掛載每次嘗試的元資料 — 改動了哪些檔案、運行了哪些測試、審查者注意到了哪些發現。這些是運行事實,不是任務事實。
運行紀錄也是結構化交接所在。當工作者透過 kanban_complete(...) 完成任務時,它可以傳遞:
summary(工具參數)/--summary(CLI)— 人類交接;放在運行紀錄上;下游子代在build_worker_context中看到它。metadata(工具參數)/--metadata(CLI)— 運行紀錄上的自由格式 JSON 字典;子代以序列化形式與 summary 一起看到它。result(工具參數)/--result(CLI)— 放在任務列上的簡短日誌行(舊版欄位,為向下相容保留)。
下游子代讀取每個父代最近完成的運行紀錄的 summary + metadata。重試工作者讀取自身任務上的先前嘗試(outcome、summary、error),因此不會重複已失敗的路徑。
# 工作者實際做的 — 一個工具呼叫,從 agent 迴圈內部:
kanban_complete(
summary="implemented token bucket, keys on user_id with IP fallback, all tests pass",
metadata={"changed_files": ["limiter.py", "tests/test_limiter.py"], "tests_run": 14},
result="rate limiter shipped",
)
當你(人類)需要結案工作者無法完成的任務時,同一個交接也可從 CLI 存取 — 例如被放棄的任務,或你從儀表板手動標記完成的任務:
hermes kanban complete t_abcd \
--result "rate limiter shipped" \
--summary "implemented token bucket, keys on user_id with IP fallback, all tests pass" \
--metadata '{"changed_files": ["limiter.py", "tests/test_limiter.py"], "tests_run": 14}'
# 查看重試任務的嘗試歷史:
hermes kanban runs t_abcd
# # OUTCOME PROFILE ELAPSED STARTED
# 1 blocked worker 12s 2026-04-27 14:02
# → BLOCKED: need decision on rate-limit key
# 2 completed worker 8m 2026-04-27 15:18
# → implemented token bucket, keys on user_id with IP fallback
運行紀錄在儀表板上可見(抽屜中的 Run History 區段,每次嘗試一列彩色記錄)以及 REST API(GET /api/plugins/kanban/tasks/:id 回傳 runs[] 陣列)。PATCH /api/plugins/kanban/tasks/:id 配合 {status: "done", summary, metadata} 會將兩者轉發到核心,因此儀表板的「標記完成」按鈕與 CLI 等效。task_events 列攜帶它們所屬的 run_id,以便 UI 可以按嘗試分組它們,且 completed 事件在其 payload 中嵌入第一行摘要(上限 400 字元),以便閘道通知器可以渲染結構化交接而無需第二次 SQL 往返。
批次結案注意事項。 hermes kanban complete a b c --summary X 會被拒絕 — 結構化交接是每次運行的,因此將相同的 summary 複製貼上到 N 個任務幾乎總是錯的。不帶 --summary / --metadata 的批次結案仍然適用於常見的「我完成了一堆管理任務」場景。
因狀態變更而取回的運行。 如果你在儀表板上將運行中的任務從 running 拖走(回到 ready,或直接到 todo),或封存一個仍在運行的任務,進行中的運行會以 outcome='reclaimed' 關閉而非被孤立。當 tasks.current_run_id 為 NULL 時,task_runs 列始終處於終端狀態,反之亦然 — 此不變式在 CLI、儀表板、調度器和通知器之間保持一致。
從未領取完成的合成運行。 完成或封鎖一個從未被領取的任務(例如人類從儀表板以 summary 關閉 ready 任務,或 CLI 使用者執行 hermes kanban complete <ready-task> --summary X)原本會丟失交接。核心改為插入一個零持續時間的運行紀錄列(started_at == ended_at),攜帶 summary / metadata / reason,以便嘗試歷史保持完整。completed / blocked 事件的 run_id 指向該列。
即時抽屜重新整理。 當儀表板的 WebSocket 事件串流報告使用者當前查看的任務有新事件時,抽屜會重新整理自身(透過串入其 useEffect 依賴清單的每任務事件計數器)。不再需要關閉和重新開啟才能看到運行紀錄的新列或更新的結果。
向前相容性
tasks 上的兩個可空欄位保留給 v2 工作流路由:workflow_template_id(此任務屬於哪個範本)和 current_step_key(該範本中哪個步驟是活躍的)。v1 核心忽略它們用於路由但允許客戶端寫入它們,因此 v2 發佈版可以新增路由機制而無需另一次 schema 遷移。
事件參考
每個轉換都會在 task_events 中追加一列。每列攜帶可選的 run_id,以便 UI 可以按嘗試分組事件。種類分為三個群組以便篩選(hermes kanban watch --kinds completed,gave_up,timed_out):
生命週期(任務作為邏輯單位的變更):
| 種類 | Payload | 時機 |
|---|---|---|
created | {assignee, status, parents, tenant} | 任務已插入。run_id 為 NULL。 |
promoted | — | todo → ready 因為所有父代達到 done。run_id 為 NULL。 |
claimed | {lock, expires, run_id} | 調度器原子性地領取了一個 ready 任務以供生成。 |
completed | {result_len, summary?} | 工作者寫入了 --result / --summary 且任務達到 done。summary 是第一行交接(400 字元上限);完整版本在運行紀錄列上。如果在從未領取的任務上呼叫 complete_task 且帶有交接欄位,會合成一個零持續時間的運行,以便 run_id 仍然指向某物。 |
blocked | {reason} | 工作者或人類將任務翻轉為 blocked。在從未領取的任務上呼叫 --reason 時合成零持續時間運行。 |
unblocked | — | blocked → ready,手動或透過 /unblock。run_id 為 NULL。 |
archived | — | 從預設看板中隱藏。如果任務仍在運行中,攜帶因副作用被取回的運行的 run_id。 |
編輯(人類驅動的變更,非轉換):
| 種類 | Payload | 時機 |
|---|---|---|
assigned | {assignee} | 指派人已變更(包括取消指派)。 |
edited | {fields} | 標題或內文已更新。 |
reprioritized | {priority} | 優先級已變更。 |
status | {status} | 儀表板拖放直接寫入了狀態(例如 todo → ready)。攜帶因從 running 拖走而被取回的運行的 run_id;否則 run_id 為 NULL。 |
工作者遙測(關於執行過程,非邏輯任務):
| 種類 | Payload | 時機 |
|---|---|---|
spawned | {pid} | 調度器成功啟動了工作者行程。 |
heartbeat | {note?} | 工作者呼叫 hermes kanban heartbeat $TASK 在長時間操作中發出存活訊號。 |
reclaimed | {stale_lock} | 領取 TTL 到期而未完成;任務回到 ready。 |
crashed | {pid, claimer} | 工作者 PID 不再存活但 TTL 尚未到期。 |
timed_out | {pid, elapsed_seconds, limit_seconds, sigkill} | 超過 max_runtime_seconds;調度器 SIGTERM(然後 5 秒寬限期後 SIGKILL)並重新佇列。 |
stale | {elapsed_seconds, last_heartbeat_at, heartbeat_age_seconds, timeout_seconds, pid, terminated} | 任務運行超過 kanban.dispatch_stale_timeout_seconds(預設 4 小時)且過去一小時內沒有 kanban_heartbeat 到達。調度器 SIGTERM 了本機工作者(如有),將任務重置為 ready 以供重新調度。不會計入失敗計數器(stale 是調度器端的缺席偵測,不是工作者故障)。運行長時間操作的工作者應至少每小時呼叫一次 kanban_heartbeat 以避免此情況。 |
respawn_guarded | {reason} | 調度器本次滴答拒絕重新生成此就緒任務。原因:blocker_auth(上次失敗是配額/認證/429 錯誤 — 等待速率視窗重置)、recent_success(過去一小時內有完成的運行 — 等待審查再重新執行)、active_pr(近期留言中出現 GitHub PR URL — 先前工作者已開啟 PR)。任務保持在 ready;下次滴答有另一次生成機會。如果底層條件持續存在,正常的 consecutive_failures 熔斷器會在 failure_limit 次失敗後透過 gave_up 自動封鎖。 |
spawn_failed | {error, failures} | 一次生成嘗試失敗(缺少 PATH、工作區無法掛載、…)。計數器遞增;任務回到 ready 以供重試。 |
protocol_violation | {pid, claimer, exit_code} | 工作者在任務仍為 running 時成功退出,通常是因為它在未呼叫 kanban_complete 或 kanban_block 的情況下回答了。調度器也立即發出 gave_up 並自動封鎖而非重試。 |
gave_up | {failures, effective_limit, limit_source, error} | 在 N 次連續非成功嘗試後觸發熔斷器。任務以最後一次錯誤自動封鎖。有效限制解析為任務 max_retries,然後調度器 failure_limit / kanban.failure_limit,然後內建預設值。 |
hermes kanban tail <id> 顯示單一任務的這些。hermes kanban watch 串流整個看板的這些。
範圍外
Kanban 有意地是單主機架構。~/.hermes/kanban.db 是一個本機 SQLite 檔案,調度器在同一台機器上生成工作者。不支援在兩台主機間運行共享看板 — 沒有「主機 A 上的工作者 X,主機 B 上的工作者 Y」的協調原語,且崩潰偵測路徑假設 PID 是本機的。如果你需要多主機,每台主機運行一個獨立的看板,並使用 delegate_task / 訊息佇列來橋接它們。
設計規格
完整設計 — 架構、並發正確性、與其他系統的比較、實作計畫、風險、待決問題 — 位於 docs/hermes-kanban-v1-spec.pdf。在提交任何行為變更 PR 之前請先閱讀。