仪表盘插件
Dashboard 插件允许你为 Web Dashboard 添加自定义标签页。插件可以拥有自己的 UI、调用 Hermes API,并且可选地注册后端端点,整个过程都无需改动 dashboard 源代码。
快速开始
创建一个插件目录,其中包含 manifest 和 JS 文件:
mkdir -p ~/.hermes/plugins/my-plugin/dashboard/dist
manifest.json:
{
"name": "my-plugin",
"label": "My Plugin",
"icon": "Sparkles",
"version": "1.0.0",
"tab": {
"path": "/my-plugin",
"position": "after:skills"
},
"entry": "dist/index.js"
}
dist/index.js:
(function () {
var SDK = window.__HERMES_PLUGIN_SDK__;
var React = SDK.React;
var Card = SDK.components.Card;
var CardHeader = SDK.components.CardHeader;
var CardTitle = SDK.components.CardTitle;
var CardContent = SDK.components.CardContent;
function MyPage() {
return React.createElement(Card, null,
React.createElement(CardHeader, null,
React.createElement(CardTitle, null, "My Plugin")
),
React.createElement(CardContent, null,
React.createElement("p", { className: "text-sm text-muted-foreground" },
"Hello from my custom dashboard tab!"
)
)
);
}
window.__HERMES_PLUGINS__.register("my-plugin", MyPage);
})();
刷新 dashboard 后,你的标签页就会出现在导航栏中。
插件结构
插件位于标准 ~/.hermes/plugins/ 目录中。Dashboard 扩展部分是一个 dashboard/ 子目录:
~/.hermes/plugins/my-plugin/
plugin.yaml # optional — existing CLI/gateway plugin manifest
__init__.py # optional — existing CLI/gateway hooks
dashboard/ # dashboard extension
manifest.json # required — tab config, icon, entry point
dist/
index.js # required — pre-built JS bundle
style.css # optional — custom CSS
plugin_api.py # optional — backend API routes
同一个插件目录可以同时扩展 CLI / gateway(通过 plugin.yaml + __init__.py)以及 dashboard(通过 dashboard/)。
Manifest 参考
manifest.json 用于向 dashboard 描述你的插件:
{
"name": "my-plugin",
"label": "My Plugin",
"description": "What this plugin does",
"icon": "Sparkles",
"version": "1.0.0",
"tab": {
"path": "/my-plugin",
"position": "after:skills"
},
"entry": "dist/index.js",
"css": "dist/style.css",
"api": "plugin_api.py"
}
| Field | Required | Description |
|---|---|---|
name | Yes | 全局唯一插件标识(小写,允许连字符) |
label | Yes | 导航标签中显示的名称 |
description | No | 简短说明 |
icon | No | Lucide 图标名(默认 Puzzle) |
version | No | Semver 版本号 |
tab.path | Yes | 标签对应的 URL 路径(如 /my-plugin) |
tab.position | No | 插入位置:end(默认)、after:<tab>、before:<tab> |
entry | Yes | JS bundle 相对 dashboard/ 的路径 |
css | No | 要注入的 CSS 文件路径 |
api | No | 包含 FastAPI 路由的 Python 文件路径 |
标签位置
position 字段决定标签在导航中的显示位置:
"end"— 放在所有内置标签之后(默认)"after:skills"— 放在 Skills 标签之后"before:config"— 放在 Config 标签之前"after:cron"— 放在 Cron 标签之后
冒号后的值对应目标标签的路径段(不含前导 /)。
可用图标
插件可使用以下 Lucide 图标名:
Activity, BarChart3, Clock, Code, Database, Eye, FileText, Globe, Heart, KeyRound, MessageSquare, Package, Puzzle, Settings, Shield, Sparkles, Star, Terminal, Wrench, Zap
无法识别的图标名会回退为 Puzzle。
Plugin SDK
插件不需要自行打包 React 或 UI 组件,它们直接使用挂在 window.__HERMES_PLUGIN_SDK__ 上的 SDK。这可以避免版本冲突,并显著减小插件 bundle 体积。
SDK 内容
var SDK = window.__HERMES_PLUGIN_SDK__;
// React
SDK.React // React instance
SDK.hooks.useState // React hooks
SDK.hooks.useEffect
SDK.hooks.useCallback
SDK.hooks.useMemo
SDK.hooks.useRef
SDK.hooks.useContext
SDK.hooks.createContext
// API
SDK.api // Hermes API client (getStatus, getSessions, etc.)
SDK.fetchJSON // Raw fetch for custom endpoints — handles auth automatically
// UI Components (shadcn/ui style)
SDK.components.Card
SDK.components.CardHeader
SDK.components.CardTitle
SDK.components.CardContent
SDK.components.Badge
SDK.components.Button
SDK.components.Input
SDK.components.Label
SDK.components.Select
SDK.components.SelectOption
SDK.components.Separator
SDK.components.Tabs
SDK.components.TabsList
SDK.components.TabsTrigger
// Utilities
SDK.utils.cn // Tailwind class merger (clsx + twMerge)
SDK.utils.timeAgo // "5m ago" from unix timestamp
SDK.utils.isoTimeAgo // "5m ago" from ISO string
// Hooks
SDK.useI18n // i18n translations
SDK.useTheme // Current theme info
使用 SDK.fetchJSON
SDK.fetchJSON("/api/plugins/my-plugin/data")
.then(function (result) {
console.log(result);
})
.catch(function (err) {
console.error("API call failed:", err);
});
fetchJSON 会自动注入会话认证 token、处理错误并解析 JSON。
使用现有 API 方法
// Fetch agent status
SDK.api.getStatus().then(function (status) {
console.log("Version:", status.version);
});
// List sessions
SDK.api.getSessions(10).then(function (resp) {
console.log("Sessions:", resp.sessions.length);
});
后端 API 路由
如果在 manifest 中设置了 api 字段,插件就可以注册 FastAPI 路由。创建一个导出 router 的 Python 文件:
# plugin_api.py
from fastapi import APIRouter
router = APIRouter()
@router.get("/data")
async def get_data():
return {"items": ["one", "two", "three"]}
@router.post("/action")
async def do_action(body: dict):
return {"ok": True, "received": body}
这些路由会被挂载到 /api/plugins/<name>/ 下。
访问 Hermes 内部能力
后端路由可以直接导入 hermes-agent 代码:
from fastapi import APIRouter
from hermes_state import SessionDB
from hermes_cli.config import load_config
router = APIRouter()
@router.get("/session-count")
async def session_count():
db = SessionDB()
try:
count = len(db.list_sessions(limit=9999))
return {"count": count}
finally:
db.close()
自定义 CSS
如果插件需要自定义样式,可以添加一个 CSS 文件并在 manifest 中声明:
{
"css": "dist/style.css"
}
/* dist/style.css */
.my-plugin-chart {
border: 1px solid var(--color-border);
background: var(--color-card);
padding: 1rem;
}
插件加载流程
- Dashboard 启动后,
main.tsx会把 SDK 暴露到window.__HERMES_PLUGIN_SDK__ App.tsx调用usePlugins(),发起GET /api/dashboard/plugins- 对每个插件注入 CSS(如有)并加载 JS
- 插件 JS 调用
window.__HERMES_PLUGINS__.register(name, Component) - Dashboard 把该标签加入导航,并将组件挂载到对应路由
插件脚本加载后最多有 2 秒完成注册。若某个插件加载失败,dashboard 会跳过它而继续运行。
插件发现
Dashboard 会扫描以下目录中的 dashboard/manifest.json:
- User plugins:
~/.hermes/plugins/<name>/dashboard/manifest.json - Bundled plugins:
<repo>/plugins/<name>/dashboard/manifest.json - Project plugins:
./.hermes/plugins/<name>/dashboard/manifest.json(仅当设置了HERMES_ENABLE_PROJECT_PLUGINS)
用户插件优先级最高。如果同名插件同时存在多个来源,用户版本会覆盖其他版本。
如果你添加了新插件但不想重启服务,也可以强制重新扫描:
curl http://127.0.0.1:9119/api/dashboard/plugins/rescan
插件 API 端点
| Endpoint | Method | Description |
|---|---|---|
/api/dashboard/plugins | GET | 列出已发现插件 |
/api/dashboard/plugins/rescan | GET | 强制重新扫描新插件 |
/dashboard-plugins/<name>/<path> | GET | 提供插件静态资源 |
/api/plugins/<name>/* | * | 插件注册的 API 路由 |
示例插件
仓库中自带 plugins/example-dashboard/ 作为示例插件,展示了:
- 使用 SDK 组件(Card、Badge、Button)
- 调用后端 API 路由
- 通过
window.__HERMES_PLUGINS__.register()完成注册
提示
- 无需构建步骤 — 你可以直接写纯 JavaScript IIFE。若更喜欢 JSX,可用任意打包工具输出 IIFE bundle,并将 React 设为 external
- 保持 bundle 小巧 — React 和 UI 组件都由 SDK 提供,插件 bundle 只需包含自己的逻辑
- 使用主题变量 — 在 CSS 中使用
var(--color-*),可自动匹配当前主题 - 本地测试 — 运行
hermes dashboard --no-open,再用浏览器开发者工具检查插件是否正确加载与注册