🔥 Hermes OpenAgent Dashboard

Docs > docs/hermes-dashboard-v2-demo.md

📄 Hermes Dashboard v2 Demo

Hermes Dashboard v2 Demo

4 个 UX 痛点修复 + project 模型增强. 本 demo 验证 8 项 acceptance criteria.

Deploy: bash scripts/deploy.sh:8092 200 OK Branch: 本地改动, 未推送 (仅本机 Gitea, 按拍权边界)

§1 编排开发记录 (sub-agent 树)

数据源

task_runs 表 (/home/yi/.hermes/kanban.db), 字段 id, task_id, profile, step_key, status, outcome, worker_pid, started_at, ended_at, summary, metadata. 没有 parent_run_id, 通过 profile/step_key + duration 启发式判断 main run / sub-agent.

实现

  • services/task_subagent_tree.py::get_task_runs(task_id) — 返回所有 run + duration
  • services/task_subagent_tree.py::get_task_subagent_tree(task_id) — 构造 {task_id, total_runs, main_run, sub_agents}
  • GET /api/tasks/<id>/runs → 平铺 list
  • GET /api/tasks/<id>/tree → 树形 JSON
  • templates/task_detail.html 新增 "🧠 编排开发记录" 折叠卡片

验证

$ curl -sS http://127.0.0.1:8092/api/tasks/t_e25193a4/tree | jq
{
  "task_id": "t_e25193a4",
  "total_runs": 2,
  "main_run": {"run_id": 19, "outcome": "timed_out", ...},
  "sub_agents": [{"run_id": 20, "name": "omo-pm", "outcome": "completed", ...}]
}

task_detail 页 HTML 含 "编排开发记录 (2 runs)" 字样, 默认折叠, 点 "展开编排记录" 显示 main run + sub-agent list.

已知限制

omo Sisyphus 派 sub-agent 是进程内 fork, 不另起 task_runs 行. 单 run task (例 t_a6176f7b) tree 只有 1 节点. 要真正看到 sub-agent 树需要 hermes kernel 在 spawn sub-worker 时也写 task_runs. 当前实现已暴露所有可用数据.

§2 最终输出结果

数据源

  • task_runs.summary (拼接所有 run 总结)
  • task_comments 含 ✅ / 产物 / 完成 关键词
  • link_project_commits 在 task 时间窗口 (started_atcompleted_at) 内 git log
  • ~/novel-workspace/docs/ + ~/opencode-blog-showcase/docs/ mtime 在窗口内 (±30s 容错)

实现

  • services/task_outputs.py::get_task_outputs(task_id){summary, comments, commits, docs, project_name}
  • GET /api/tasks/<id>/outputs → JSON
  • templates/task_detail.html 新增 "📦 最终输出结果" 折叠卡片 (summary / docs / commits / output-comments 4 子区块)

验证 (t_47d21b25 novel-app v0.1 续作)

$ curl -sS http://127.0.0.1:8092/api/tasks/t_47d21b25/outputs | jq '{docs: .docs|length, comments: .comments|length}'
{"docs": 1, "comments": 2}

task_detail 页展开后看到: - ✅ done 评论 (novel-app v0.1 完成报告) - 📄 1 个关联文档 (demo doc) - (本 task 时间窗口没新 commit, 因 worker 在子目录写, 但仍能显示 docs/comments)

§3 done task 折叠

实现

  • templates/tasks.html:
  • active_tasks (ready/running/blocked/failed) 和 done_tasks 两区
  • 状态过滤栏加 "✓ 显示 done" toggle button
  • done 卡片默认收起: header 只显示 badge + title + completed_at + 展开 icon
  • 点 header 展开 body: outcome_summary + 详情链接
  • localStorage.hermes:showDone 记忆
  • templates/dashboard.html:
  • kanban board 顶部加 status 分布 (例 68 total: 1 ready / 3 running / 54 done / 10 blocked)
  • done 列前 3 张卡片显示, 其余 CSS 隐藏 (body.show-done 切换)
  • static/js/main.js:
  • toggleDoneVisibility() / toggleDoneCard(taskId) / applyDoneVisibility()
  • 页面 load 时根据 localStorage 应用

验证

$ curl -sS http://127.0.0.1:8092/tasks | grep -c "done-list collapsed"
1
$ curl -sS http://127.0.0.1:8092/tasks | grep -c "done-card"
54   # 54 个 done task 全部输出但默认收起 (CSS :nth-child(-n+5) 只显示前 5)

§4 project 模型增强

4.1 未归类 task 自动归类

services/task_project_linker.py::_TITLE_KEYWORDS 加: - novel-writer / novel_workspace / novel-workspace / 写小说 / 小说 → novel-app - csrf / e2e-verify-csrf → hermes-dashboard - e2e-s4 / 角色名 / prompt 模板 → novel-app

scripts/migrate_task_project_links.py 一次性迁移: 给每个 link 上的 task 写 🔗 linked to project: X comment (幂等, 已有 breadcrumb 则跳过). 跑了 1 次: 59 linked / 0 already / 9 no match.

未归类 task 验证:

t_e25193a4 (V1 3 PR)        -> blog-app
t_eb000e83 (npm 写小说调研)  -> novel-app
t_8b8d0dab (e2e-verify-csrf) -> hermes-dashboard
t_3535d15d / t_ce12c67e      -> hermes-dashboard / novel-app
e2e-s4b / s4c / s4-rerun / s4-fork -> novel-app

15/15 之前未归类的 task 现在全部归上.

4.2 单 task 提升成 project

  • POST /api/projects/from-task/<task_id>:
  • 从 title 提取 slug 作为 project name (regex [a-z0-9][a-z0-9-_]{2,63}), 失败用 task-<id>
  • workspace_path 必须是已存在目录
  • config.py::MANAGED_PROJECTS (文本插入 ]\n\n# Docs directories 标记前) + 内存同步
  • task 留 breadcrumb comment
  • templates/task_detail.html 未 link project 时显示 "⬆️ 提升为项目" 按钮 + modal

验证:

$ curl -X POST /api/projects/from-task/t_2e00173d
{"ok":true, "project":{"name":"analyze","path":"/home/yi/opencode-blog-showcase/blog-app", ...}}

config.py 出现新条目 (事后清理).

4.3 project 接需求 → 自动启动 omo 开发

  • templates/project_detail.html "+ 新需求" 按钮 + modal (标题 / 需求描述 markdown / 优先级 P0-P3 / worker / 关联 sub-task ids)
  • POST /api/projects/<name>/requirements:
  • title 自动加 [<project_name>] 前缀
  • body 尾部附 project / workspace / priority / related 元数据
  • hermes kanban create (subprocess), 不直接 spawn omo
  • task 留 breadcrumb comment

验证:

$ curl -X POST /api/projects/blog-app/requirements -d '{"title":"e2e test","body":"...","priority":"P3"}'
{"ok":true, "task_id":"t_db66e6ae", "project":"blog-app"}
$ sqlite3 ~/.hermes/kanban.db "SELECT title, status FROM tasks WHERE id='t_db66e6ae'"
[blog-app] e2e test requirement: smoke check | ready

omo-pm worker 会自动 claim 该 task (走 kanban 老链路).

4.4 新增 project (手动)

  • templates/projects.html "+ 新建项目" 按钮 + modal (name / path / gitea_repo / color)
  • POST /api/projects:
  • 校验 name slug + path 非空 + 不与现有 project 重名
  • 持久化到 config.py + 内存同步

验证:

$ curl -X POST /api/projects -d '{"name":"test-proj","path":"/tmp","color":"#ff00ff"}'
{"ok":true, "project":{...}}
$ curl /projects | grep test-proj
<td><a href="/projects/test-proj">test-proj</a></td>

§5 已知问题 + 下一步

已知问题

  1. sub-agent 树不直观 — omo Sisyphus 派 sub-agent 是进程内 fork, 不写 task_runs. 当前实现只能显示 main run + 后续 retry/complete run, 无法显示真正的 sub-agent tree. 需要 hermes kernel 配合 (在 spawn sub-worker 时写 task_runs).
  2. commit 时间窗口粒度 — task completed_at 来自 worker 上报, 不一定等于最后一个 commit 时间. 如果 worker 在子目录干活 (例 /home/yi/novel-workspace/novel-app/novel_app/), 父目录 git log 可能看不到.
  3. config.py 文本插入脆弱_append_project_to_config 依赖 ]\n\n# Docs directories 标记. 如果 config.py 结构变化会失败. 建议改成 JSON 配置文件 + 启动时 merge.
  4. requirements 不直接 spawn omo — task 留在 ready 状态等 worker claim. 如果 worker 不在线, task 不会立刻跑. 走 hermes 老链路, 由 kanban dispatcher 负责.
  5. CSRF token 复用 — modal 内嵌 CSRF token 来自 <meta>, session 过期后 fetch 会 403. 没做自动刷新.

下一步

  1. hermes kernel: spawn sub-worker 时写 task_runs 行, 提供 parent_run_id 字段
  2. project 配置文件分离: managed_projects.json 独立存储, config.py 只读
  3. requirements modal 加 dry-run preview (显示将创建的 task title/body)
  4. 编排实时显示 (参考另一个并行 task t_02222bb4 的 SSE 方案)
  5. done task 折叠持久化到 server-side user preference (替代 localStorage)

部署: 当前 dashboard 8092 跑新版, curl /healthz 200. 代码改动: - 新增 services/task_subagent_tree.py (98 行) - 新增 services/task_outputs.py (137 行) - 新增 scripts/migrate_task_project_links.py (76 行) - 改 services/task_project_linker.py (+10 keyword) - 改 routes/api.py (+233 行, 4 新端点) - 改 routes/pages.py (+11 行, 传 tree/outputs 给模板) - 改 templates/task_detail.html (+152 行, 2 折叠卡片 + 1 modal) - 改 templates/tasks.html (重写, 拆 active/done 两区) - 改 templates/dashboard.html (+16 行, 状态分布 + done 列折叠) - 改 templates/projects.html (+46 行, 新建项目 modal) - 改 templates/project_detail.html (+58 行, 新需求 modal) - 改 static/js/main.js (+149 行, toggleDone + modal 提交)

← Back to Docs

⚙️ Running Processes

Loading…