Hermes WebUI 开发文档
这个项目是什么
Hermes WebUI 是 Hermes Agent 的浏览器界面:把原本活在终端里的自主 Agent 搬进网页,做到与 CLI 几乎 1:1 对等——终端里能做的事,网页里都能做。它刻意保持轻量:没有前端框架、没有打包器、没有构建步骤,后端是 Python,前端是原生 JavaScript,一条命令即可启动。本仓库(jinghui/hermes-webui)是该 WebUI 的私有部署镜像仓库,与上游 nesquena/hermes-webui 同源。
技术栈与架构
- 后端:纯 Python HTTP 服务(
server.py路由壳 +api/业务模块),复用你机器上已有的 Hermes Agent 运行时与模型配置,不需要额外申请任何服务。 - 前端:原生 JS + CSS(
static/目录),SSE 流式输出、Prism.js 语法高亮、Mermaid 图表渲染均通过 CDN 引入(带 SRI 校验)。 - 分层:
server.py(约 450 行的 HTTP 路由壳 + 认证中间件)→api/(认证、配置发现、会话模型、路由、SSE 流式引擎、上传、工作区等模块)→static/(index.html 模板 + 各功能 JS)。 - 认证:可选密码(
HERMES_WEBUI_PASSWORD),HMAC 签名的 HttpOnly Cookie(24 小时有效期),可选 WebAuthn/passkey。 - 状态:所有会话、工作区、设置、项目数据存放在仓库之外的
~/.hermes/webui/(可用HERMES_WEBUI_STATE_DIR覆盖)。 - 测试:pytest,约 488 个测试文件、5300+ 用例,运行在隔离状态目录的独立服务实例上,绝不触碰生产数据和真实 cron 任务。
仓库结构
顶层真实文件/目录及职责:
| 路径 | 说明 |
|---|---|
server.py |
HTTP 入口与路由壳、认证中间件 |
api/ |
后端核心:auth.py(密码认证/签名 Cookie)、config.py(环境发现与可重载配置)、models.py(会话 CRUD + CLI 会话桥)、routes.py(全部 GET/POST 处理器)、streaming.py(SSE 引擎、run_agent、取消支持)、onboarding.py(首次启动向导)、profiles.py(Profile 管理)、upload.py、workspace.py、updates.py 等 |
static/ |
前端:index.html、style.css、ui.js、sessions.js、messages.js、panels.js、commands.js、workspace.js、boot.js |
tests/ |
pytest 测试与隔离服务夹具 |
bootstrap.py |
一键引导:检测/安装 Hermes Agent、准备 Python 环境、启动服务 |
start.sh / start.ps1 |
POSIX / Windows 启动脚本(含自动发现逻辑) |
ctl.sh |
守护进程生命周期封装:start / status / logs / restart / stop |
Dockerfile + docker-compose.yml / docker-compose.two-container.yml / docker-compose.three-container.yml |
单容器与多容器部署 |
mcp_server.py |
MCP 服务入口 |
docs/ |
深度文档:docker.md、onboarding.md、troubleshooting.md、THEMES.md、ARCHITECTURE.md 等 |
.env.example / .env.docker.example |
环境变量模板 |
本地开发环境
前置条件:Linux / macOS / WSL2(原生 Windows 不支持 bootstrap,社区另有 Windows 原生方案),以及已装好的 Hermes Agent(缺失时 bootstrap 会尝试调用官方安装脚本)。
# 方式一:引导脚本(推荐)
python3 bootstrap.py
# 方式二:常规启动
./start.sh
# 方式三:常驻后台(自托管/家用服务器推荐,不依赖 fuser/pkill)
./ctl.sh start # 后台守护进程,PID 写入 ~/.hermes/webui.pid
./ctl.sh status # PID、运行时长、绑定地址端口、日志路径、/health
./ctl.sh logs --lines 100 # 查看 ~/.hermes/webui.log
./ctl.sh restart
./ctl.sh stop
自动发现逻辑:start.sh 会依次查找 Hermes Agent 目录(HERMES_WEBUI_AGENT_DIR → $HERMES_HOME/hermes-agent → 同级 ../hermes-agent)、Python 可执行文件(Agent venv → 本仓库 .venv → 系统 python3)、状态目录与默认工作区,全部找到则无需任何额外配置。
手动直接启动(不经 start.sh)需要使用装有 Hermes 依赖的 Python 环境:
cd /path/to/hermes-agent
HERMES_WEBUI_PORT=8787 venv/bin/python /path/to/hermes-webui/server.py
# 健康检查
curl http://127.0.0.1:8787/health
运行测试:
pytest tests/ -v --timeout=60
配置项说明
常用环境变量(均真实存在于 README 与启动脚本):
| 配置键 | 默认值 | 含义 |
|---|---|---|
HERMES_WEBUI_AGENT_DIR |
自动发现 | hermes-agent 检出路径 |
HERMES_WEBUI_PYTHON |
自动发现 | Python 可执行文件 |
HERMES_WEBUI_HOST |
127.0.0.1 |
绑定地址(0.0.0.0 全 IPv4,:: 全 IPv6) |
HERMES_WEBUI_PORT |
8787 |
端口(也可作为 start.sh 第一个参数) |
HERMES_WEBUI_STATE_DIR |
$HERMES_HOME/webui |
会话与状态存储目录 |
HERMES_WEBUI_DEFAULT_WORKSPACE |
~/workspace |
默认工作区 |
HERMES_WEBUI_DEFAULT_MODEL |
跟随 provider 默认 | 可选的模型覆盖 |
HERMES_WEBUI_PASSWORD |
未设置 | 设置后启用密码认证 |
HERMES_WEBUI_CSP_CONNECT_EXTRA |
未设置 | 反代/隧道部署时追加 CSP connect-src 来源 |
HERMES_WEBUI_EXTENSION_DIR |
未设置 | 本地扩展目录,挂到 /extensions/ |
HERMES_WEBUI_EXTENSION_SCRIPT_URLS |
未设置 | 注入的同源脚本 URL(逗号分隔) |
HERMES_WEBUI_EXTENSION_STYLESHEET_URLS |
未设置 | 注入的同源样式 URL |
HERMES_HOME |
POSIX 为 ~/.hermes |
Hermes 状态基目录(影响所有路径) |
HERMES_CONFIG_PATH |
$HERMES_HOME/config.yaml |
Hermes 配置文件路径 |
可选的高级项:
| 配置键 | 含义 |
|---|---|
HERMES_WEBUI_CHAT_BACKEND=gateway |
把浏览器新回合路由到 Hermes Gateway API 服务(只接受 gateway / api_server / api-server,故意不认 1、true 这类值) |
HERMES_WEBUI_GATEWAY_BASE_URL |
Gateway 地址,如 http://127.0.0.1:8642 |
HERMES_WEBUI_GATEWAY_API_KEY |
WebUI↔Gateway 的密钥(缺省时回退用 API_SERVER_KEY) |
webui_prefill_messages_script / HERMES_WEBUI_PREFILL_MESSAGES_SCRIPT |
会话预填脚本钩子(配合 ..._TIMEOUT,默认 5 秒),供 Joplin/Obsidian 等笔记源做路由式预填 |
HERMES_WEBUI_AUTO_INSTALL=1 |
允许自动安装 Agent 依赖(默认关闭) |
构建与发布
# 本地构建镜像
docker build -t hermes-webui .
# 容器运行(UID/GID 透传,保证宿主机可读容器内文件)
docker run -d \
-e WANTED_UID=$(id -u) -e WANTED_GID=$(id -g) \
-v ~/.hermes:/home/hermeswebui/.hermes \
-e HERMES_WEBUI_STATE_DIR=/home/hermeswebui/.hermes/webui \
-v ~/workspace:/workspace \
-p 127.0.0.1:8787:8787 \
hermes-webui
上游在每次发版时向 GHCR 发布 amd64 + arm64 预构建镜像,CI 由 .github/workflows/ 里的多架构构建 + tag 触发的 Release 流程完成。
部署方式
单容器 compose(5 分钟路径):
cp .env.docker.example .env
# 若宿主 UID 不是 1000(如 macOS 从 501 起),编辑 .env 调整
docker compose up -d
# 打开 http://localhost:8787
多容器形态(命名卷从构造上解决 UID/GID 问题):
docker compose -f docker-compose.two-container.yml up -d # Agent + WebUI
docker compose -f docker-compose.three-container.yml up -d # Agent + Dashboard + WebUI
默认 compose 只绑定 127.0.0.1;要暴露到网络需把端口改成 "8787:8787" 并设置 HERMES_WEBUI_PASSWORD。远程服务器推荐 SSH 隧道:ssh -N -L 8787:127.0.0.1:8787 user@server。
二次开发要点
- 前端零构建:改
static/下的 JS/CSS 重启即生效,非常适合快速迭代 UI;后端改api/后直接重启进程。 - 体量提示:
routes.py与streaming.py是最大的两个后端模块(近万行与四千行级),SSE 流式、取消、审批、子代理委派逻辑都集中在streaming.py,改动前建议先跑测试。 - 已知架构限制:双容器模式下从 WebUI 触发的工具运行在 WebUI 容器内而非 Agent 容器(仓库 issue #681),需要 git/node 等工具时应改用单容器或扩展 Dockerfile;多容器默认把 Agent 源码只读挂载进 WebUI(#2453),属于实现耦合桥而非稳定 API 边界。
- 常见坑:绑定挂载启动报
PermissionError是宿主 UID 不匹配,在.env设UID=$(id -u);.env: permission denied由凭据权限加固(0600)引起,可设HERMES_SKIP_CHMOD=1跳过。 - 认证相关:登录限速、PBKDF2 密钥分离、64 位 HMAC-SHA256 会话签名等安全逻辑在
api/auth.py,改动需保持向后兼容迁移桥。 - 会话数据兼容:CLI 会话桥从 hermes-agent 的 SQLite 存储读取会话,前端带金色
cli徽章展示,二次开发时不要破坏该读取路径。
相关链接
- Gitea 仓库:http://127.0.0.1:3200/jinghui/hermes-webui
- 上游项目:https://github.com/nesquena/hermes-webui
- Hermes Agent 官方文档:https://hermes-agent.nousresearch.com/docs