feat(dashboard): complete admin panel — MCP catalog, enable/disable toggles, hook creation, system stats (#36736)

* feat(dashboard): MCP catalog + enable/disable, webhook toggle, hook create/delete, system stats

Backend for the comprehensive admin pass:
- MCP: GET /api/mcp/catalog (browse Nous-approved optional-mcps), POST
  /api/mcp/catalog/install, PUT /api/mcp/servers/{name}/enabled
- Webhooks: PUT /api/webhooks/{name}/enabled; gateway rejects disabled routes
  with 403 (hot-reloaded, no restart)
- Hooks: POST/DELETE /api/ops/hooks — create (with consent approval) + remove;
  list now reports accurate allowlist status + valid events
- System: GET /api/system/stats — OS/arch/python/cpu + psutil memory/disk/
  uptime/process, stdlib fallback

All gated by dashboard auth; secrets never returned.

* feat(dashboard): MCP catalog UI, enable/disable toggles, hook create, system stats

- McpPage: catalog section (browse Nous-approved MCPs, one-click install with
  env prompts) + per-server enable/disable toggle with gateway-restart note
- WebhooksPage: per-subscription enable/disable toggle (muted + badge when off)
- SystemPage: new Host stats section (OS/arch/python/cpu/mem/disk/uptime/load),
  shell-hook create modal + delete, 'Create backup' label
- api.ts: client methods + types for catalog, toggles, hook CRUD, system stats

* test(dashboard): cover catalog, toggles, hook CRUD, system stats, webhook toggle

Adds tests for the comprehensive pass: MCP enable/disable + catalog list +
catalog-install-unknown, hook create/delete with consent, system stats shape,
and webhook enable/disable. 26 tests total, all green.

* docs(dashboard): document the comprehensive admin pass + fresh screenshots

Updates the MCP/Webhooks/Pairing/System sections for catalog browse+install,
enable/disable toggles, hook creation, and host system stats; adds the new
endpoints to the API table; replaces the screenshots with live captures of
the rebuilt pages (real data, no dummies) including the hook-create modal.

* feat(dashboard): curator, portal status, and prompt-size/dump/migrate ops

Closes the last in-scope CLI gaps from the coverage audit:
- Curator: GET /api/curator (status), PUT /api/curator/paused, POST
  /api/curator/run (background)
- Portal: GET /api/portal (Nous auth + Tool Gateway routing, read-only)
- Diagnostics: POST /api/ops/prompt-size, /api/ops/dump, /api/ops/config-migrate
  (backgrounded, tailed via action status)

Host-bound commands (secrets/proxy/lsp/acp/computer-use/desktop/completion/
postinstall/uninstall/claw) remain CLI-only by design.

* feat(dashboard): curator + portal + diagnostics UI, tests

- SystemPage: Nous Portal status section (auth + Tool Gateway routing),
  Skill curator card (status + pause/resume + run now), and three new
  Operations buttons (prompt size, support dump, migrate config)
- api.ts: client methods + CuratorStatus/PortalStatus types
- tests: curator pause/resume, portal shape, system-stats shape, + auth-gate
  coverage for the new GET endpoints (31 tests total)

* docs(dashboard): document curator, portal, and diagnostics + refresh System screenshots

Updates the System section for the Nous Portal status, Skill curator
controls, and the new prompt-size/dump/migrate operations; adds them to the
API table; refreshes the System screenshots (now showing Portal + Curator)
and adds a dedicated curator/gateway/memory capture.

* feat(dashboard): session stats/export/prune + skills hub search endpoints

Completes the existing tabs' backend depth (audit vs CLI):
- Sessions: GET /api/sessions/stats (store stats), GET /api/sessions/{id}/export,
  POST /api/sessions/prune. /stats is registered before /{session_id} so the
  literal path isn't captured by the parameterized route.
- Skills: GET /api/skills/hub/search — parallel multi-source hub search (threaded),
  returns installable identifiers
- (rename via PATCH and cron-edit via PUT already existed; now surfaced in UI)

* feat(dashboard): complete existing tabs — sessions mgmt, skills hub browse, cron edit

Audited every existing tab against its CLI command and filled the gaps:
- Sessions: store stats bar, per-row rename + export (JSON download), and a
  prune-old-sessions control (mirrors hermes sessions rename/export/prune/stats)
- Skills: new 'Browse hub' view — search the skill hub across all sources,
  install by identifier with a live install log, and 'Update all' (mirrors
  hermes skills search/install/update)
- Cron: per-job Edit modal (pre-filled) calling updateCronJob (hermes cron edit)
- api.ts: renameSession/getSessionStats/exportSessionUrl/pruneSessions,
  updateCronJob, searchSkillsHub + types

Models tab was already comprehensive (provider+model picker, dynamic per-provider
lists, main + all 11 aux-task assignments, reset) — verified, no change needed.

* test(dashboard): cover session stats/rename/export/prune + skills hub search

Adds the route-shadowing guard for /api/sessions/stats (must not be captured
by /api/sessions/{session_id}), rename/export/prune, and the empty-query
short-circuit for hub search. 36 tests total, all green.

* docs(dashboard): document enhanced Sessions, Skills hub, and Cron edit

Sessions: stats bar, rename, export, prune (+ screenshot). Skills: new Browse
hub view for search/install/update (+ screenshot). Cron: edit action. API
table updated with the new endpoints.
This commit is contained in:
Teknium
2026-06-02 00:16:11 -04:00
committed by GitHub
parent 40ae170647
commit bd8e2ec1a6
20 changed files with 2597 additions and 210 deletions
@@ -142,10 +142,16 @@ Advanced/rarely-used keys are hidden by default behind a toggle.
Browse and inspect all agent sessions. Each row shows the session title, source platform icon (CLI, Telegram, Discord, Slack, cron), model name, message count, tool call count, and how long ago it was active. Live sessions are marked with a pulsing badge.
- **Search** — full-text search across all message content using FTS5. Results show highlighted snippets and auto-scroll to the first matching message when expanded.
- **Stats** — a summary bar shows total sessions, how many are active in the store, archived count, total messages, and a per-source breakdown.
- **Expand** — click a session to load its full message history. Messages are color-coded by role (user, assistant, system, tool) and rendered as Markdown with syntax highlighting.
- **Tool calls** — assistant messages with tool calls show collapsible blocks with the function name and JSON arguments.
- **Rename** — set or clear a session's title inline (pencil icon).
- **Export** — download a session (metadata + full message history) as JSON (download icon).
- **Prune** — the header "Prune old sessions" button deletes ended sessions older than N days.
- **Delete** — remove a session and its message history with the trash icon.
![Sessions admin page — stats bar, prune, and per-row rename / export / delete](/img/dashboard/admin-sessions.png)
### Logs
View agent, gateway, and error log files with filtering and live tailing.
@@ -173,28 +179,42 @@ Create and manage scheduled cron jobs that run agent prompts on a recurring sche
- **Create** — fill in a name (optional), prompt, cron expression (e.g. `0 9 * * *`), and delivery target (local, Telegram, Discord, Slack, or email)
- **Job list** — each job shows its name, prompt preview, schedule expression, state badge (enabled/paused/error), delivery target, last run time, and next run time
- **Pause / Resume** — toggle a job between active and paused states
- **Edit** — open a pre-filled modal to change a job's prompt, schedule, name, or delivery target
- **Trigger now** — immediately execute a job outside its normal schedule
- **Delete** — permanently remove a cron job
### Skills
Browse, search, and toggle skills and toolsets. Skills are loaded from `~/.hermes/skills/` and grouped by category.
Browse, search, and toggle installed skills and toolsets, and install new ones from the hub. Skills are loaded from `~/.hermes/skills/` and grouped by category.
- **Search** — filter skills and toolsets by name, description, or category
- **Search** — filter installed skills and toolsets by name, description, or category
- **Category filter** — click category pills to narrow the list (e.g. MLOps, MCP, Red Teaming, AI)
- **Toggle** — enable or disable individual skills with a switch. Changes take effect on the next session.
- **Toolsets** — a separate section shows built-in toolsets (file operations, web browsing, etc.) with their active/inactive status, setup requirements, and list of included tools
- **Toolsets** — a separate view shows built-in toolsets (file operations, web browsing, etc.) with their active/inactive status, setup requirements, and list of included tools
- **Browse hub** — a third view searches the skill hub across all sources (the same as `hermes skills search`), installs any result by identifier with a live install log, and offers an "Update all" button to refresh installed skills.
![Skills admin page — the Browse hub view: search, install, and update](/img/dashboard/admin-skills-hub.png)
### MCP
Manage [MCP](/integrations/mcp) servers without the CLI. The same `mcp_servers`
block in `config.yaml` that `hermes mcp` reads from.
**Your MCP servers:**
- **Add** — register an HTTP/SSE server (URL) or a stdio server (command + args), with optional `KEY=VALUE` environment variables for stdio servers
- **Enable / disable** — toggle a server on or off without deleting it. A disabled server stays in config so you can re-enable it later. Takes effect on the next gateway restart.
- **Test** — connect to a server, list its tools, and disconnect — verifies the connection before the agent depends on it
- **Remove** — delete a server from the config
- Secret-shaped env values are redacted in the list view
**Catalog:** browse the Nous-approved MCP servers (the bundled `optional-mcps/`
catalog) and install any of them with one click. Entries that need API keys
prompt for them inline; the values go to `.env`. This is the same catalog
`hermes mcp catalog` / `hermes mcp install` use.
![MCP admin page — your servers with enable/disable toggles, plus the install catalog](/img/dashboard/admin-mcp.png)
### Webhooks
Manage dynamic [webhook subscriptions](/user-guide/messaging/webhooks). The
@@ -202,28 +222,47 @@ webhook platform must be enabled in messaging settings first; the page shows a
hint when it isn't.
- **Create** — name, description, event filter, delivery target, optional direct-delivery mode, and an agent prompt. On creation the page surfaces the route URL and the one-time HMAC secret to copy.
- **Enable / disable** — toggle a subscription on or off. Disabled routes stay in the subscriptions file but the gateway rejects their incoming events (403). The gateway hot-reloads the file, so the change takes effect on the next event — no restart needed.
- **List** — each subscription shows its URL, events, and delivery target
- **Delete** — remove a subscription (hot-reloaded by the gateway, no restart needed)
- **Delete** — remove a subscription
![Webhooks admin page — subscriptions with enable/disable toggles](/img/dashboard/admin-webhooks.png)
### Pairing
Approve and revoke messaging users without the CLI — how a remote admin
onboards Telegram/Discord/etc. users to a paired gateway.
onboards Telegram/Discord/etc. users to a paired gateway. Full parity with
`hermes pairing`.
- **Pending requests** — each shows platform, code, user, and age, with an Approve button
- **Approved users** — each shows platform and user, with a Revoke button
- **Clear pending** — drop all outstanding pairing codes
![Pairing admin page](/img/dashboard/admin-pairing.png)
### System
A consolidated administration panel for installation-wide operations:
- **Host** — live system stats: OS / kernel, architecture, hostname, Python and Hermes versions, CPU core count + utilization, memory, disk usage of the Hermes home, uptime, and load average. (CPU/memory/disk come from `psutil` when installed; identity fields are always shown.)
- **Nous Portal** — login status, the active inference provider, and the Tool Gateway routing table (which tools run via the Portal vs. locally), with a link to manage your subscription. Read-only mirror of `hermes portal`.
- **Skill curator** — the background skill-maintenance status (active / paused, interval, last run) with pause/resume and a run-now button. Mirrors `hermes curator`.
- **Gateway** — start, stop, and restart the messaging gateway, with live status (running/stopped, PID, state)
- **Memory** — pick the external memory provider (or built-in only), and reset the built-in `MEMORY.md` / `USER.md` stores
- **Credential pool** — add and remove the rotating API keys the agent round-robins through (per provider). Keys are redacted in the list; the raw value only ever reaches the agent.
- **Operations** — run `doctor`, a security audit, a backup, restore from a backup archive, or update skills. Each spawns a background action whose live log streams into the page.
- **Operations** — run `doctor`, a security audit, create a backup, restore from a backup archive, update skills, show the system-prompt size breakdown, generate a support dump, or migrate config for retired settings. Each spawns a background action whose live log streams into the page.
- **Checkpoints** — see the `/rollback` shadow store size and prune it
- **Shell hooks** — read-only list of configured hooks with their consent-allowlist status
- **Shell hooks** — list configured hooks with their consent + executable status, **create** a hook (event, command, matcher, timeout, with an opt-in consent grant), and remove one. Hooks run arbitrary commands, so the create form carries a security warning and the hook only fires after consent is granted.
![System admin page — host stats and Nous Portal status](/img/dashboard/admin-system-top.png)
![System admin page — skill curator, gateway, memory, and credential pool](/img/dashboard/admin-system-curator.png)
![System admin page — operations, checkpoints, and shell hooks](/img/dashboard/admin-system-ops.png)
Creating a shell hook (note the consent checkbox and the run-arbitrary-commands warning):
![New shell hook modal](/img/dashboard/admin-hook-create.png)
:::warning Security
The web dashboard reads and writes your `.env` file, which contains API keys and secrets. It binds to `127.0.0.1` by default — only accessible from your local machine. If you bind to `0.0.0.0`, anyone on your network can view and modify your credentials. The dashboard has no authentication of its own.
@@ -350,7 +389,10 @@ same auth gate as the rest of `/api/`.
| `GET /api/mcp/servers` | List configured MCP servers (env values redacted) |
| `POST /api/mcp/servers` | Add a server. Body: `{name, url?, command?, args?, env?, auth?}` |
| `POST /api/mcp/servers/{name}/test` | Connect, list tools, disconnect |
| `PUT /api/mcp/servers/{name}/enabled` | Enable / disable a server |
| `DELETE /api/mcp/servers/{name}` | Remove a server |
| `GET /api/mcp/catalog` | Browse the Nous-approved MCP catalog |
| `POST /api/mcp/catalog/install` | Install a catalog entry (with required env) |
| `GET /api/pairing` | List pending + approved messaging users |
| `POST /api/pairing/approve` | Approve a code. Body: `{platform, code}` |
| `POST /api/pairing/revoke` | Revoke a user. Body: `{platform, user_id}` |
@@ -368,7 +410,19 @@ same auth gate as the rest of `/api/`.
| `POST /api/ops/doctor` · `/security-audit` · `/backup` · `/import` | Diagnostics & maintenance (backgrounded; tail via `/api/actions/{name}/status`) |
| `GET /api/ops/hooks` | Configured shell hooks + allowlist status |
| `GET /api/ops/checkpoints` · `POST .../prune` | Inspect / prune the `/rollback` store |
| `POST /api/ops/hooks` · `DELETE /api/ops/hooks` | Create / remove a shell hook (consent-gated) |
| `GET /api/system/stats` | Host stats — OS, CPU, memory, disk, uptime |
| `GET /api/curator` · `PUT .../paused` · `POST .../run` | Skill-curator status + pause/resume + run |
| `GET /api/portal` | Nous Portal auth + Tool Gateway routing (read-only) |
| `POST /api/ops/prompt-size` · `/dump` · `/config-migrate` | Diagnostics (backgrounded) |
| `PUT /api/webhooks/{name}/enabled` | Enable / disable a webhook route |
| `POST /api/skills/hub/install` · `/uninstall` · `/update` | Skills hub actions (backgrounded) |
| `GET /api/skills/hub/search` | Search the skill hub across all sources |
| `GET /api/sessions/stats` | Session-store statistics |
| `PATCH /api/sessions/{id}` | Rename / archive a session |
| `GET /api/sessions/{id}/export` | Export a session (metadata + messages) as JSON |
| `POST /api/sessions/prune` | Delete ended sessions older than N days |
| `PUT /api/cron/jobs/{id}` | Edit a cron job's prompt / schedule / name / deliver |
## OAuth Authentication (gated mode)