Skip to content

fix(dashboard): add lightweight mode - #58721

Open
izumi0uu wants to merge 2 commits into
NousResearch:mainfrom
izumi0uu:fix/dashboard-lightweight-mode-58694
Open

fix(dashboard): add lightweight mode#58721
izumi0uu wants to merge 2 commits into
NousResearch:mainfrom
izumi0uu:fix/dashboard-lightweight-mode-58694

Conversation

@izumi0uu

@izumi0uu izumi0uu commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

What does this PR do?

Adds a lightweight dashboard mode for constrained self-hosted servers that only need the basic session/status surface.

The mode can be enabled per launch with hermes dashboard --light or persistently with dashboard.mode: lightweight. In lightweight mode, the dashboard:

  • keeps the basic surfaces: Sessions, Files, Logs, Chat, Config, Keys, Docs, and sidebar status
  • hides admin-heavy routes such as MCP, Channels, Webhooks, Plugins, Cron, Models, Analytics, Profiles, and System
  • suppresses dashboard plugin loading and plugin slots
  • skips the dashboard background MCP discovery thread

This intentionally avoids changing the shared MCP subprocess-pool behavior because that overlaps with #56832.

Related Issue

Fixes #58694

Type of Change

  • 🐛 Bug fix (non-breaking change that fixes an issue)
  • ✨ New feature (non-breaking change that adds functionality)
  • 🔒 Security fix
  • 📝 Documentation update
  • ✅ Tests (adding or improving test coverage)
  • ♻️ Refactor (no behavior change)
  • 🎯 New skill (bundled or hub)

Changes Made

  • Added dashboard.mode config with full / lightweight schema options.
  • Added hermes dashboard --light plus hidden --legacy alias.
  • Preserved lightweight mode through named-profile dashboard reroute.
  • Disabled dashboard plugin catalog/loading and background MCP discovery when lightweight mode is active.
  • Filtered the React dashboard route/nav surface for lightweight mode.
  • Documented lightweight mode in the Web Dashboard docs.
  • Added backend and frontend tests for parsing, config exposure, plugin suppression, MCP startup skipping, and route/nav filtering.

How to Test

  1. Run hermes dashboard --light --port 9119.
  2. Confirm the sidebar only exposes the lightweight dashboard surfaces.
  3. Confirm /api/config reports dashboard.mode: lightweight for that process and /api/dashboard/plugins returns an empty list.

Validation run locally:

pytest tests/hermes_cli/test_subcommands_batch.py tests/hermes_cli/test_serve_command.py tests/hermes_cli/test_dashboard_unified_launch.py tests/hermes_cli/test_web_server.py::TestBuildSchemaFromConfig tests/hermes_cli/test_web_server.py::TestConfigRoundTrip -q
npm --workspace web run typecheck
npm --workspace web run test -- dashboard-mode.test.ts
npm --workspace web exec eslint src/lib/dashboard-mode.ts src/lib/dashboard-mode.test.ts
python -m hermes_cli.main dashboard --legacy --status
git diff --check

Checklist

Code

  • I've read the Contributing Guide
  • My commit messages follow Conventional Commits (fix(scope):, feat(scope):, etc.)
  • I searched for existing PRs to make sure this isn't a duplicate
  • My PR contains only changes related to this fix/feature (no unrelated commits)
  • I've run pytest tests/ -q and all tests pass
  • I've added tests for my changes (required for bug fixes, strongly encouraged for features)
  • I've tested on my platform: macOS arm64 (Darwin 24.6.0)

Documentation & Housekeeping

  • I've updated relevant documentation (README, docs/, docstrings) — or N/A
  • I've updated cli-config.yaml.example if I added/changed config keys — or N/A
  • I've updated CONTRIBUTING.md or AGENTS.md if I changed architecture or workflows — or N/A
  • I've considered cross-platform impact (Windows, macOS) per the compatibility guide — or N/A
  • I've updated tool descriptions/schemas if I changed tool behavior — or N/A

For New Skills

N/A

Screenshots / Logs

Full npm --workspace web run lint was not used as a merge gate because this checkout currently reports pre-existing React compiler lint errors in unrelated files. The new dashboard mode helper files pass targeted ESLint, and the web package typecheck passes.

@izumi0uu
izumi0uu marked this pull request as ready for review July 5, 2026 08:16
@alt-glitch alt-glitch added type/feature New feature or request comp/dashboard Web dashboard / control panel UI (dashboard/, landing) comp/cli CLI entry point, hermes_cli/, setup wizard P3 Low — cosmetic, nice to have labels Jul 5, 2026
@teknium1 teknium1 added sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform labels Jul 15, 2026

@teknium1 teknium1 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the focused configuration and route-filtering work. The underlying constrained-host problem remains on current main, but this implementation does not yet meet the memory-reduction claim.

Problems

  • The --light path still reaches the full backend: cmd_dashboard imports FastAPI/uvicorn at hermes_cli/main.py:12194-12196 and then imports hermes_cli.web_server at :12290. That module constructs FastAPI(...) at hermes_cli/web_server.py:264 and mounts plugin API routes at :17105. This matches the #58694 follow-up that RSS rises after the first request.
  • Plugin suppression is incomplete: discover_plugins() remains unconditional at hermes_cli/main.py:12261-12263, and web/src/App.tsx:352 calls usePlugins() before the new filtering; the hook fetches manifests at web/src/plugins/usePlugins.ts:26-35.
  • --light is placed in the shared dashboard/serve runtime parser. Because the new mode resolution does not exclude headless_backend, it also changes serve, which is the desktop/remote backend path (hermes_cli/subcommands/dashboard.py:130-156).

Suggested changes

  • Branch before importing FastAPI or hermes_cli.web_server, or re-scope this as UI filtering rather than a memory fix.
  • Keep serve behavior unchanged and add a regression test for it.

Automated hermes-sweeper review.

Comment thread hermes_cli/main.py
@@ -11906,6 +11906,24 @@ def cmd_dashboard(args):
remaining = _find_stale_dashboard_pids()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

serve uses this same handler with headless_backend=True, and --light is added to its shared parser. This mode calculation needs to be bypassed for serve (or the flag must be dashboard-only), otherwise a persisted dashboard.mode: lightweight changes the Desktop/remote backend path.

Comment thread web/src/App.tsx Outdated
};
setShowTokenAnalytics(dash.show_token_analytics === true);
setDashboardMode(normalizeDashboardMode(dash.mode));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This only discards manifests after usePlugins() has already run. That hook still fetches /api/dashboard/plugins; more importantly, the backend has already imported and mounted plugin routes before this SPA code executes. Gate plugin discovery/mounting before importing hermes_cli.web_server if startup-memory reduction is required.

@izumi0uu
izumi0uu force-pushed the fix/dashboard-lightweight-mode-58694 branch from c52fed6 to 0902bf3 Compare July 18, 2026 15:35
@izumi0uu
izumi0uu force-pushed the fix/dashboard-lightweight-mode-58694 branch from 0902bf3 to 9a6773f Compare July 18, 2026 16:27
@izumi0uu

izumi0uu commented Jul 18, 2026

Copy link
Copy Markdown
Contributor Author

Addressed in c1c176923.

I implemented an early lightweight-dashboard path using a stdlib HTTP server, with profile-scoped sessions, transcripts, logs, and configuration. It retains the read-only everyday views for status, sessions, files, logs, and safe configuration without initializing the full FastAPI/Uvicorn, plugin, and MCP stack.

The three-run median results are:

Metric Full Lightweight
Daily-use RSS 140.77 MiB 48.72 MiB
Request memory growth 36.48 MiB 3.75 MiB
Startup time 715.77 ms 155.25 ms
Status p95 12.87 ms 4.16 ms

I added the reproducible benchmark separately in 9a6773ffa, so the maintainers can evaluate whether they want to include the script in the repository. The implementation does not depend on the benchmark commit, so it can be omitted without affecting the fix.

The focused test suite passes with 469 tests, and Ruff passes for all changed Python files.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/cli CLI entry point, hermes_cli/, setup wizard comp/dashboard Web dashboard / control panel UI (dashboard/, landing) P3 Low — cosmetic, nice to have sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades type/feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Dashboard memory regression in v0.17.0: ~300-400MB increase, request lightweight mode option

3 participants