Hermes-agent

This commit is contained in:
Zakaria
2026-06-14 14:30:48 -04:00
commit dac4b88b94
5058 changed files with 1884848 additions and 0 deletions
@@ -0,0 +1,207 @@
---
title: "Kanban Orchestrator"
sidebar_label: "Kanban Orchestrator"
description: "用于通过 Kanban 路由工作的编排器 profile 的任务分解手册及反诱惑规则"
---
{/* This page is auto-generated from the skill's SKILL.md by website/scripts/generate-skill-docs.py. Edit the source SKILL.md, not this page. */}
# Kanban Orchestrator
用于通过 Kanban 路由工作的编排器 profile 的任务分解手册及反诱惑规则。"不要自己执行工作"规则和基本生命周期会自动注入每个 kanban worker 的系统 prompt(提示词)中;本 skill 是当你专门扮演编排器角色时使用的更深层手册。
## Skill 元数据
| | |
|---|---|
| 来源 | 内置(默认安装) |
| 路径 | `skills/devops/kanban-orchestrator` |
| 版本 | `3.0.0` |
| 平台 | linux, macos, windows |
| 标签 | `kanban`, `multi-agent`, `orchestration`, `routing` |
| 相关 skill | [`kanban-worker`](/user-guide/skills/bundled/devops/devops-kanban-worker) |
## 参考:完整 SKILL.md
:::info
以下是 Hermes 在触发此 skill 时加载的完整 skill 定义。这是 skill 激活时 agent 所看到的指令内容。
:::
# Kanban Orchestrator — 任务分解手册
> **核心 worker 生命周期**(包括 `kanban_create` 扇出模式和"分解而非执行"规则)通过 `KANBAN_GUIDANCE` 系统 prompt 块自动注入每个 kanban 进程。本 skill 是当你作为编排器 profile、整个职责就是路由时使用的更深层手册。
## Profile 由用户配置——不是固定名单
Hermes 的配置因人而异。有些用户运行单个 profile 处理所有事务;有些运行小型集群(`docker-worker``cron-worker`);有些运行自己命名的精选专家团队。**没有默认的专家名单**——编排器 skill 不知道此机器上存在哪些 profile。
在扇出之前,你必须基于实际存在的 profile 来制定分解方案。调度器会静默地忽略无法识别的 assignee 名称——它不会自动纠正、不会建议、也不会回退。因此,在只有 `docker-worker` 的配置上,分配给 `researcher` 的卡片会永远停留在 `ready` 状态。
**第 0 步:在规划前发现可用的 profile。**
使用以下方法之一:
- `hermes profile list` — 打印此机器上已配置的 profile 表。如果有终端工具,通过终端工具运行;否则询问用户。
- `kanban_list(assignee="<some-name>")` — 验证单个名称。对于未知 assignee 返回空列表(而非报错),因此只能确认你已在考虑的名称。
- **直接询问用户。** 当目标需要多个专家时,"你配置了哪些 profile?"是一个合理的开场问题。
将结果缓存在工作记忆中供本次对话使用。每轮都重新询问会浪费工具调用。
## 何时使用看板(vs. 直接执行工作)
当以下任一条件成立时,创建 Kanban 任务:
1. **需要多个专家。** 研究 + 分析 + 写作需要三个 profile。
2. **工作应在崩溃或重启后继续存在。** 长期运行、周期性或重要的任务。
3. **用户可能需要介入。** 任意步骤需要人工参与。
4. **多个子任务可以并行运行。** 扇出以提高速度。
5. **预期需要审查/迭代。** 审查者 profile 循环处理起草者的输出。
6. **审计追踪很重要。** 看板行永久保存在 SQLite 中。
如果*以上均不适用*——这是一个小型一次性推理任务——改用 `delegate_task` 或直接回答用户。
## 反诱惑规则
你的职责描述是"路由,不执行"。执行该规则的约束:
- **不要自己执行工作。** 你受限的工具集通常甚至不包含用于实现的终端/文件/代码/网络工具。如果你发现自己在"快速修复这个"——停下来,为合适的专家创建任务。
- **对于任何具体任务,创建 Kanban 任务并分配它。** 每一次都如此。
- **在创建卡片之前拆分多通道请求。** 用户的一个 prompt 可能包含多个独立的工作流。先提取这些通道,然后每个通道创建一张卡片,而不是将不相关的工作打包到单个实现者卡片中。
- **并行运行独立通道。** 如果两张卡片不需要彼此的输出,不要链接它们,让调度器可以扇出处理。只链接真正的数据依赖。
- **永远不要将依赖工作创建为独立的 ready 卡片。** 如果一张卡片必须等待另一张卡片,在原始 `kanban_create` 调用中传入 `parents=[...]`。不要先创建再链接,也不要依赖卡片正文中的"等待 T1"之类的描述。
- **如果没有专家适合现有 profile,询问用户应创建哪个 profile 或使用哪个现有 profile。** 不要凭空发明 profile 名称;调度器会静默丢弃未知 assignee。
- **分解、路由、汇总——这就是全部工作。**
## 任务分解手册
### 第 1 步——理解目标
如果目标不明确,提出澄清性问题。询问的成本很低;派出错误的团队代价高昂。
### 第 2 步——草拟任务图
在创建任何内容之前,在回复用户时大声(在响应中)草拟任务图。将每个具体工作流视为候选卡片:
1. 从请求中提取通道。
2. 将每个通道映射到第 0 步中发现的某个 profile。如果某个通道不适合任何现有 profile,询问用户使用或创建哪个。
3. 决定每个通道是独立的还是受另一个通道门控的。
4. 将独立通道创建为无父链接的并行卡片。
5. 将综合/审查/集成卡片创建时带上其所依赖通道的父链接。使用未完成父任务创建的子任务从 `todo` 开始;调度器仅在每个父任务完成后才将其提升为 `ready`
应该扇出的 prompt 示例(使用占位符 profile 名称——替换为用户配置中实际存在的名称):
- "构建一个应用" → 一张卡片给面向设计的 profile 负责产品/UI 方向,一两张卡片给工程 profile 负责实现,如果用户有审查者 profile,再加一张后续的集成/审查卡片。
- "修复阻塞项并检查模型变体" → 一张实现卡片用于修复阻塞项,加一张发现/研究卡片用于配置/源码验证。最终的审查者卡片可以依赖两者。
- "研究文档并实现" → 文档研究卡片可以与代码库发现卡片并行运行;只有当实现真正需要这些发现时才等待。
- "分析这张截图并找到相关代码" → 一张卡片给具备视觉能力的 profile 进行视觉分析,同时另一张卡片搜索代码库。
"也"、"最后"或"和"等词语不自动意味着依赖关系。它们通常意味着"确保在汇报前涵盖这一点"。只有当一张卡片在另一张卡片的输出存在之前无法开始时,才链接任务。
在创建卡片之前将任务图展示给用户。让他们纠正——包括哪个实际 profile 名称应该负责每个通道。
### 第 3 步——创建任务并链接
使用第 0 步中的 profile 名称。以下示例使用占位符 `<profile-A>``<profile-B>``<profile-C>`——替换为用户实际拥有的名称。
```python
t1 = kanban_create(
title="research: Postgres cost vs current",
assignee="<profile-A>", # whichever profile handles research on this setup
body="Compare estimated infrastructure costs, migration costs, and ongoing ops costs over a 3-year window. Sources: AWS/GCP pricing, team time estimates, current Postgres bills from peers.",
tenant=os.environ.get("HERMES_TENANT"),
)["task_id"]
t2 = kanban_create(
title="research: Postgres performance vs current",
assignee="<profile-A>", # same profile, run in parallel
body="Compare query latency, throughput, and scaling characteristics at our expected data volume (~500GB, 10k QPS peak). Sources: benchmark papers, public case studies, pgbench results if easy.",
)["task_id"]
t3 = kanban_create(
title="synthesize migration recommendation",
assignee="<profile-B>", # whichever profile does synthesis/analysis
body="Read the findings from T1 (cost) and T2 (performance). Produce a 1-page recommendation with explicit trade-offs and a go/no-go call.",
parents=[t1, t2],
)["task_id"]
t4 = kanban_create(
title="draft decision memo",
assignee="<profile-C>", # whichever profile drafts user-facing prose
body="Turn the analyst's recommendation into a 2-page memo for the CTO. Match the tone of previous decision memos in the team's knowledge base.",
parents=[t3],
)["task_id"]
```
`parents=[...]` 门控提升——子任务保持在 `todo` 状态,直到每个父任务达到 `done`,然后自动提升为 `ready`。无需手动协调;调度器和依赖引擎会处理这一切。
如果任务图有依赖关系,先创建父卡片,捕获其返回的 id,并在子卡片的 `kanban_create` 调用中将这些 id 包含在 `parents` 列表中。避免并行创建所有卡片后再链接;这会产生一个时间窗口,调度器可能在子任务的输入存在之前就认领它。
### 第 4 步——完成你自己的任务
如果你是作为任务被派生的(例如,规划者 profile 被分配了 `T0: "调查 Postgres 迁移"`),用你创建内容的摘要标记它为完成:
```python
kanban_complete(
summary="decomposed into T1-T4: 2 research lanes in parallel, 1 synthesis on their outputs, 1 prose draft on the recommendation",
metadata={
"task_graph": {
"T1": {"assignee": "<profile-A>", "parents": []},
"T2": {"assignee": "<profile-A>", "parents": []},
"T3": {"assignee": "<profile-B>", "parents": ["T1", "T2"]},
"T4": {"assignee": "<profile-C>", "parents": ["T3"]},
},
},
)
```
### 第 5 步——向用户汇报
用简明的文字告诉他们你创建了什么,并说明你使用的实际 profile 名称:
> 我已排队 4 个任务:
> - **T1**`<profile-A>`):成本对比
> - **T2**`<profile-A>`):性能对比,与 T1 并行
> - **T3**`<profile-B>`):综合 T1 + T2 生成建议
> - **T4**`<profile-C>`):将 T3 转化为 CTO 备忘录
>
> 调度器现在将认领 T1 和 T2。T3 在两者完成后启动。T4 完成时你会收到 gateway 通知。使用仪表板或 `hermes kanban tail <id>` 跟踪进度。
## 常见模式
**扇出 + 扇入(研究 → 综合):** N 张无父链接的研究类卡片,一张以所有研究卡片为父的综合卡片。
**并行实现 + 验证:** 一张实现者卡片进行变更,同时一张探索/研究卡片验证配置、文档或源码映射。审查者卡片可以依赖两者。不要因为用户在一句话中同时提到了两者,就让实现者承担不相关的验证工作。
**带门控的流水线:** `planner → implementer → reviewer`。每个阶段的 `parents=[previous_task]`。审查者阻塞或完成;如果审查者阻塞,操作员带着反馈解除阻塞并重新派发。
**同 profile 队列:** N 个任务,全部分配给同一个 profile,彼此之间无依赖。调度器串行处理——该 profile 按优先级顺序处理它们,在自己的记忆中积累经验。
**人工参与循环:** 任何任务都可以调用 `kanban_block()` 等待输入。调度器在 `/unblock` 后重新派发。评论线程携带完整上下文。
## 常见陷阱
**发明不存在的 profile 名称。** 调度器会静默地忽略无法识别的 assignee——卡片会永远停留在 `ready` 状态。始终从第 0 步发现的 profile 中分配;如果不确定,询问用户。
**将独立通道打包到一张卡片中。** 如果用户要求两个独立的结果,创建两张卡片。示例:"修复阻塞项并检查模型变体"不是一个修复任务;为修复创建一张修复/工程卡片,为变体检查创建一张探索/研究卡片,然后可选地将审查门控在两者之上。
**因措辞而过度链接。** "最后检查 X"如果 X 是静态配置、文档或源码发现,仍然可以与实现并行。只有当检查依赖于实现结果时,才将其链接在实现之后。
**忘记依赖链接。** 如果任务图说 `research -> implement -> review`,不要将所有任务创建为独立的 ready 卡片。使用父链接,确保 implement/review 在其输入存在之前无法运行。
**重新分配 vs. 新任务。** 如果审查者以"需要修改"阻塞,创建一个从审查者任务链接的**新**任务——不要用严厉的眼神重新运行同一个任务。新任务分配给原始实现者 profile。
**链接的参数顺序。** `kanban_link(parent_id=..., child_id=...)` — 父任务在前。混淆顺序会将错误的任务降级为 `todo`
**如果形状取决于中间发现,不要预先创建整个任务图。** 如果 T3 的结构取决于 T1 和 T2 的发现,让 T3 作为一个"综合发现"任务存在,其第一步是读取父任务的交接内容并规划其余部分。编排器可以派生编排器。
**Tenant 继承。** 如果你的环境中设置了 `HERMES_TENANT`,在每次 `kanban_create` 调用中传入 `tenant=os.environ.get("HERMES_TENANT")`,以确保子任务保持在同一命名空间中。
## 恢复卡住的 worker
当一个 worker profile 持续崩溃、产生幻觉或被自身错误阻塞时(通常是:错误的模型、缺少 skill、凭据损坏),kanban 仪表板会在任务上标记 ⚠ 徽章,并在抽屉中打开**恢复**部分。三个主要操作:
1. **Reclaim**(或 `hermes kanban reclaim <task_id>`)——立即中止正在运行的 worker 并将任务重置为 `ready`。现有认领 TTL 约为 15 分钟;这是最快的解决路径。
2. **Reassign**(或 `hermes kanban reassign <task_id> <new-profile> --reclaim`)——将任务切换到不同的 profile(此配置上存在的 profile)并让调度器用新 worker 认领它。
3. **更改 profile 模型**——仪表板会打印 `hermes -p <profile> model` 的复制粘贴提示,因为 profile 配置存储在磁盘上;在终端中编辑它,然后 Reclaim 以使用新模型重试。
当 worker 的 `kanban_complete(created_cards=[...])` 声明包含不存在或非该 worker profile 创建的卡片 id 时(门控会阻止完成),或者自由格式摘要引用了无法解析的 `t_<hex>` id 时(建议性文本扫描,非阻塞),会出现幻觉警告。两者都会产生审计事件,即使在恢复操作后也会持久保存——追踪记录保留用于调试。
@@ -0,0 +1,202 @@
---
title: "Kanban Worker — Hermes Kanban worker 的陷阱、示例与边界情况"
sidebar_label: "Kanban Worker"
description: "Hermes Kanban worker 的陷阱、示例与边界情况"
---
{/* This page is auto-generated from the skill's SKILL.md by website/scripts/generate-skill-docs.py. Edit the source SKILL.md, not this page. */}
# Kanban Worker
Hermes Kanban worker 的陷阱、示例与边界情况。生命周期本身会自动注入到每个 worker 的系统 prompt(提示词)中,作为 `KANBAN_GUIDANCE`(来自 `agent/prompt_builder.py`);当你需要深入了解特定场景时,加载此 skill 即可。
## Skill 元数据
| | |
|---|---|
| 来源 | 内置(默认安装) |
| 路径 | `skills/devops/kanban-worker` |
| 版本 | `2.0.0` |
| 平台 | linux, macos, windows |
| 标签 | `kanban`, `multi-agent`, `collaboration`, `workflow`, `pitfalls` |
| 相关 skill | [`kanban-orchestrator`](/user-guide/skills/bundled/devops/devops-kanban-orchestrator) |
## 参考:完整 SKILL.md
:::info
以下是 Hermes 在触发此 skill 时加载的完整 skill 定义。这是 skill 激活时 agent 所看到的指令内容。
:::
# Kanban Worker — 陷阱与示例
> 你看到此 skill,是因为 Hermes Kanban 调度器以 `--skills kanban-worker` 参数将你作为 worker 派生——它会为每个被派发的 worker 自动加载。**生命周期**6 个步骤:orient → work → heartbeat → block/complete)也存在于自动注入到你系统 prompt 中的 `KANBAN_GUIDANCE` 块里。此 skill 是更深层的细节:良好的交接形式、重试诊断、边界情况。
## 工作区处理
你的工作区类型决定了你在 `$HERMES_KANBAN_WORKSPACE` 内部的行为方式:
| 类型 | 含义 | 操作方式 |
|---|---|---|
| `scratch` | 全新的临时目录,仅供你使用 | 自由读写;任务归档后会被 GC 回收。 |
| `dir:<path>` | 共享的持久化目录 | 其他运行实例会读取你写入的内容。将其视为长期状态。路径保证为绝对路径(内核拒绝相对路径)。 |
| `worktree` | 位于已解析路径的 Git worktree | 若 `.git` 不存在,先从主仓库执行 `git worktree add <path> <branch>`,然后 cd 进去正常工作。在此提交工作。 |
## 租户隔离
`$HERMES_TENANT` 已设置,则该任务属于某个租户命名空间。在读写持久化内存时,请为内存条目添加租户前缀,以防上下文跨租户泄漏:
- 正确:`business-a: Acme is our biggest customer`
- 错误(会泄漏):`Acme is our biggest customer`
## 良好的 summary + metadata 形式
`kanban_complete(summary=..., metadata=...)` 的交接方式是下游 worker 读取你工作成果的途径。以下是有效的模式:
**编码任务:**
```python
kanban_complete(
summary="shipped rate limiter — token bucket, keys on user_id with IP fallback, 14 tests pass",
metadata={
"changed_files": ["rate_limiter.py", "tests/test_rate_limiter.py"],
"tests_run": 14,
"tests_passed": 14,
"decisions": ["user_id primary, IP fallback for unauthenticated requests"],
},
)
```
**需要人工审查的编码任务(review-required):**
对于大多数涉及代码变更的任务,在人工审查者过目之前,工作并未真正*完成*。应使用 block 而非 complete,并在 `reason` 前加 `review-required: ` 前缀,以便仪表板将该行标记为待审查。先将结构化元数据(变更文件、测试计数、diff/PR url)写入 comment,因为 `kanban_block` 只携带人类可读的原因——comment 是持久化注释的渠道。审查者可执行 `hermes kanban unblock <id>` 批准(这会携带 comment 线程重新派生你以处理后续事项),或通过另一条 comment 要求修改。
```python
import json
kanban_comment(
body="review-required handoff:\n" + json.dumps({
"changed_files": ["rate_limiter.py", "tests/test_rate_limiter.py"],
"tests_run": 14,
"tests_passed": 14,
"diff_path": "/path/to/worktree", # or PR url if pushed
"decisions": ["user_id primary, IP fallback for unauthenticated requests"],
}, indent=2),
)
kanban_block(
reason="review-required: rate limiter shipped, 14/14 tests pass — needs eyes on the user_id/IP fallback choice before merging",
)
```
仅在任务真正终结时使用 `kanban_complete`——例如单行拼写修复、无功能影响的文档变更,或产出物本身即为成果的研究任务。
**研究任务:**
```python
kanban_complete(
summary="3 competing libraries reviewed; vLLM wins on throughput, SGLang on latency, Tensorrt-LLM on memory efficiency",
metadata={
"sources_read": 12,
"recommendation": "vLLM",
"benchmarks": {"vllm": 1.0, "sglang": 0.87, "trtllm": 0.72},
},
)
```
**审查任务:**
```python
kanban_complete(
summary="reviewed PR #123; 2 blocking issues found (SQL injection in /search, missing CSRF on /settings)",
metadata={
"pr_number": 123,
"findings": [
{"severity": "critical", "file": "api/search.py", "line": 42, "issue": "raw SQL concat"},
{"severity": "high", "file": "api/settings.py", "issue": "missing CSRF middleware"},
],
"approved": False,
},
)
```
请将 `metadata` 的结构设计为下游解析器(审查者、聚合器、调度器)无需重新阅读你的文字描述即可直接使用。
## 认领你实际创建的卡片
若你的运行产生了新的 kanban 任务(通过 `kanban_create`),请在 `kanban_complete``created_cards` 中传入这些 id。内核会验证每个 id 是否存在且由你的 profile 创建;任何幻构的 id 都会导致完成操作被阻断,并附带错误列表说明问题所在,且被拒绝的尝试会永久记录在任务的事件日志中。**只列出你从成功的 `kanban_create` 返回值中捕获的 id——绝不凭空捏造 id,绝不粘贴来自早期运行的 id,绝不认领其他 worker 创建的卡片。**
```python
# 正确 — 捕获返回值,然后认领。
c1 = kanban_create(title="remediate SQL injection", assignee="security-worker")
c2 = kanban_create(title="fix CSRF middleware", assignee="web-worker")
kanban_complete(
summary="Review done; spawned remediations for both findings.",
metadata={"pr_number": 123, "approved": False},
created_cards=[c1["task_id"], c2["task_id"]],
)
```
```python
# 错误 — 认领没有捕获返回值的 id。
kanban_complete(
summary="Created remediation cards t_a1b2c3d4, t_deadbeef", # 幻构
created_cards=["t_a1b2c3d4", "t_deadbeef"], # → 门控拒绝
)
```
`kanban_create` 调用失败(异常、tool_error),则卡片未被创建——不要为其包含幻构 id。重试创建,或省略该 id 并在 summary 中说明失败情况。散文扫描阶段也会捕获你自由格式 summary 中无法解析的 `t_<hex>` 引用;这些不会阻断完成操作,但会在仪表板的任务上显示为建议性警告。
## 能快速得到回应的 block 原因
差:`"stuck"` — 人类没有任何上下文。
好:一句话说明你需要的具体决策。将更长的上下文作为 comment 留下。
```python
kanban_comment(
task_id=os.environ["HERMES_KANBAN_TASK"],
body="Full context: I have user IPs from Cloudflare headers but some users are behind NATs with thousands of peers. Keying on IP alone causes false positives.",
)
kanban_block(reason="Rate limit key choice: IP (simple, NAT-unsafe) or user_id (requires auth, skips anonymous endpoints)?")
```
block 消息是仪表板/gateway 通知器中显示的内容。comment 是人类打开任务时阅读的深层上下文。
## 值得发送的 heartbeat
好的 heartbeat 应说明进度:`"epoch 12/50, loss 0.31"``"scanned 1.2M/2.4M rows"``"uploaded 47/120 videos"`
差的 heartbeat`"still working"`、空 notes、亚秒级间隔。最多每隔几分钟发送一次;对于约 2 分钟以内的任务可完全跳过。
## 重试场景
若你打开任务后 `kanban_show` 返回的 `runs: [...]` 中包含一个或多个已关闭的运行,说明你是一次重试。先前运行的 `outcome` / `summary` / `error` 会告诉你哪里出了问题。不要重复那条路径。典型的重试诊断:
- `outcome: "timed_out"` — 上次尝试达到了 `max_runtime_seconds`。你可能需要将工作分块或缩短。
- `outcome: "crashed"` — OOM 或段错误。减少内存占用。
- `outcome: "spawn_failed"` + `error: "..."` — 通常是 profile 配置问题(缺少凭证、错误的 PATH)。通过 `kanban_block` 询问人类,而不是盲目重试。
- `outcome: "reclaimed"` + `summary: "task archived..."` — 操作员在上次运行期间将任务归档;你可能根本不应该在运行,请仔细检查状态。
- `outcome: "blocked"` — 上次尝试被阻断;解除阻断的 comment 现在应该已在线程中。
## 禁止事项
- 不要用 `delegate_task` 替代 `kanban_create``delegate_task` 用于你的运行内部的短期推理子任务;`kanban_create` 用于跨 agent 的、超出单次 API 循环的交接。
- 不要修改 `$HERMES_KANBAN_WORKSPACE` 之外的文件,除非任务正文明确要求。
- 不要创建分配给自己的后续任务——分配给合适的专家。
- 不要完成一个你实际上没有完成的任务。改为 block 它。
## 陷阱
**任务状态可能在调度与启动之间发生变化。** 从调度器认领任务到你的进程实际启动之间,任务可能已被 block、重新分配或归档。始终先执行 `kanban_show`。若其报告 `blocked``archived`,请停止——你不应该在运行。
**工作区可能存在过期产物。** 尤其是 `dir:``worktree` 工作区可能包含来自先前运行的文件。阅读 comment 线程——它通常会解释你为何再次运行以及工作区处于何种状态。
**当指导已可用时,不要依赖 CLI。** `kanban_*` 工具可在所有终端后端(Docker、Modal、SSH)上工作。从你的终端工具执行 `hermes kanban <verb>` 在容器化后端中会失败,因为 CLI 未安装在那里。如有疑问,使用工具。
## CLI 回退(用于脚本)
每个工具都有对应的 CLI 等价命令,供人工操作员和脚本使用:
- `kanban_show``hermes kanban show <id> --json`
- `kanban_complete``hermes kanban complete <id> --summary "..." --metadata '{...}'`
- `kanban_block``hermes kanban block <id> "reason"`
- `kanban_create``hermes kanban create "title" --assignee <profile> [--parent <id>]`
- 等等。
在 agent 内部使用工具;CLI 供终端前的人类使用。