Skill: hermes-dashboard-subpath-ops
- typ: interní publikace agentem vytvořeného skillu
- vytvořil:
agent - created_at:
2026-05-22T07:30:46.079979+00:00 - patch_count:
9 - dostupné profily:
default - zdroj:
~/.hermes/skills/devops/hermes-dashboard-subpath-ops/SKILL.md
Hermes Dashboard Subpath Operations
Use this skill when managing a Hermes dashboard mounted behind a reverse-proxy subpath like /kanban/, especially when the same host also serves a separate WWW app and root-level dashboard routes must stay private.
When to use
- Dashboard is exposed via Caddy/Nginx subpath such as
/kanban/ - You need to reinstall, rebuild, stop/start, or verify the dashboard service
- A dashboard plugin loads with
404orCOULD NOT LOAD THIS PLUGIN'S SCRIPT - Public routing must remain constrained; do not broaden root
/api,/assets,/sessions, or/dashboard-pluginsunless explicitly asked
Core workflow
- Inspect current mount + service
- Confirm reverse-proxy route exists and whether it sets
X-Forwarded-Prefix. - Confirm the dashboard service definition, working directory, and PATH include the Node/npm location.
-
Check whether port
9119is listening. -
Rebuild/reinstall safely
- If reinstalling from repo, sync to the intended git revision first.
- Ensure the repo is installed in the venv (
pip install -e .) when appropriate. - Build the frontend from
web/sohermes_cli/web_dist/exists. -
Recreate/enable the user systemd service if needed.
-
Verify only prefixed routes
- Local prefixed checks with
X-Forwarded-Prefix: /kanbanshould return200for://api/dashboard/plugins/dashboard-plugins/kanban/dist/index.js/sessions
- Confirm the page injects
window.__HERMES_BASE_PATH__ = "/kanban". -
On mixed hosts, unprefixed public
/sessionsand/api/dashboard/pluginsshould remain404unless intentionally exposed. -
Treat public
403correctly - If public
/kanban/...returns403while local prefixed checks pass, that usually means an allowlist or outer proxy rule is blocking access. - Do not widen public access as a debugging shortcut.
Known pitfalls
0) Kanban route broken by corrupt board DB even though dashboard service is running
Symptom pattern:
- /kanban/kanban looks broken or renders an empty page after an update
- hermes-dashboard.service is still active (running) and port 9119 is listening
- dashboard HTML loads, but the Kanban board/plugin fails behind the scenes
- systemd logs show KanbanDbCorruptError / database disk image is malformed
Required checks:
- inspect systemctl --user status hermes-dashboard --no-pager -l for KanbanDbCorruptError
- verify which board DB is corrupt (for example ~/.hermes/kanban/boards/multi-agent/kanban.db)
- check backup candidates carefully: extracted daily backup directories can contain an empty per-board DB even when the ZIP snapshot for the same day contains a healthy non-zero board DB
- validate candidate backups before restore (PRAGMA integrity_check, non-zero size, expected task count / latest task)
Recovery rule: - restoring a Kanban DB backup changes user data, so get explicit user approval before replacing the live DB - prefer the newest healthy board-specific backup, not merely the newest extracted backup directory
Reference: references/kanban-db-corruption-recovery.md
1) Broken plugin advertised by registry
A plugin can appear in /api/dashboard/plugins even when its bundle does not exist.
Symptoms:
- dashboard error about plugin script load
- registry includes plugin name
- /dashboard-plugins/<name>/dist/index.js returns 404
Preferred fix:
- disable the plugin in the local checkout rather than broadening routes
- for the bundled example dashboard, renaming manifest.json to manifest.disabled.json is a valid local mitigation
2) Plugin script loads, but plugin API calls still 404 under subpath
A plugin can serve JS/CSS with 200 and still fail at runtime if it hardcodes root-relative API paths like:
fetch('/api/plugins/<plugin-name>/...')
Under /kanban/, that misses the required prefix and often produces browser-side 404 Not Found.
Required pattern:
const base = window.__HERMES_BASE_PATH__ || '';
const url = base + '/api/plugins/<plugin-name>' + path;
When a bundled plugin lacks source files in the checkout, the repo-tracked built dist/index.js may be the only practical patch point.
2b) Mixed subpath pitfall: HTTP and WebSocket paths may need DIFFERENT treatment
The Kanban dashboard plugin has a subtle split-brain path rule on subpath deployments like /kanban/:
- HTTP API calls via
SDK.fetchJSON(...)must stay root-relative, e.g.js const API = '/api/plugins/kanban';because the dashboard SDK already prependswindow.__HERMES_BASE_PATH__internally. - WebSocket URLs must be built manually with the base path included, e.g.
js const BASE_PATH = (window.__HERMES_BASE_PATH__ || '').replace(/\/$/, ''); const API = '/api/plugins/kanban'; const WS_API = `${BASE_PATH}${API}`; const url = `${proto}//${window.location.host}${WS_API}/events?${qs}`;
If you prefix both HTTP and WS with BASE_PATH, the HTTP side double-prefixes (/kanban/kanban/...) and the browser can fail with errors such as "The string did not match the expected pattern." or board-load failures. If you prefix neither, WebSocket events break under the reverse-proxy subpath.
For bundled Kanban on this repo, the practical hotfix point is:
- plugins/kanban/dashboard/dist/index.js
Quick verification after patch:
- hard reload the browser
- confirm HTTP requests go to /kanban/api/plugins/kanban/... only once after SDK prefixing
- confirm WebSocket connects to /kanban/api/plugins/kanban/events?...
- restart hermes-dashboard.service after patching the bundled dist file
3) Reinstall can resurrect broken bundled plugins
SDK.fetchJSON(${API}/board);
const ws = new WebSocket(${proto}//${window.location.host}${WS_API}/events?...);
Failure mode if you get this wrong:
- patching `API` itself to include the base path can produce malformed/duplicated paths once `SDK.fetchJSON` prefixes it again, leading to browser errors such as `The string did not match the expected pattern.` or requests hitting the wrong URL.
When a bundled plugin lacks source files in the checkout, the repo-tracked built `dist/index.js` may be the only practical patch point.
### 3) Reinstall can resurrect broken bundled plugins
Concrete regression to check immediately after updates:
- `plugins/kanban/dashboard/dist/index.js` can regress from a subpath-aware API base back to a root-relative constant like `const API = "/api/plugins/kanban";`
- symptom pattern: dashboard shell loads at `/kanban/...`, but the Kanban tab is blank/broken because plugin backend calls miss the `/kanban` prefix
After reinstall/update, re-check:
- plugin registry contents
- each advertised plugin bundle route
- subpath-aware API URL construction inside affected plugin bundles
- specifically grep the Kanban bundle for `const API = "/api/plugins/kanban";` and replace it with a base-path-aware form such as:
```js
const BASE_PATH = (window.__HERMES_BASE_PATH__ || "").replace(/\/$/, "");
const API = `${BASE_PATH}/api/plugins/kanban`;
Reference: references/zico-vm-kanban-plugin-subpath-regression.md
Verification checklist
- service exists and is
active (running) - port
9119is listening - local prefixed routes return
200 - dashboard registry advertises only plugins whose bundle routes return
200 - public root-level dashboard routes are not accidentally exposed
- if public
/kanbanis blocked, confirm whether that is expected due to allowlist
References
references/zico-vm-dashboard-hotfixes.md— concrete VM-specific checks, paths, and hotfix details for the Azure VM setupreferences/subpath-plugin-http-vs-websocket-basepath.md— rule of thumb for plugin subpath routing when SDK HTTP calls and manual WebSocket URLs coexist