Skip to content

fix(dashboard): add true lightweight mode - #61121

Open
deaneeth wants to merge 4 commits into
NousResearch:mainfrom
deaneeth:fix/dashboard-true-lightweight-mode
Open

fix(dashboard): add true lightweight mode#61121
deaneeth wants to merge 4 commits into
NousResearch:mainfrom
deaneeth:fix/dashboard-true-lightweight-mode

Conversation

@deaneeth

@deaneeth deaneeth commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

What does this PR do?

Adds a true lightweight dashboard mode for memory-constrained self-hosted installs.

hermes dashboard --light now starts a small stdlib HTTP server instead of importing the full FastAPI/React dashboard backend. It exposes only the monitoring surface needed by constrained hosts:

  • GET / lightweight status/session page
  • GET /api/status
  • GET /api/sessions

It deliberately skips the full admin backend stack: FastAPI/Pydantic route initialization, React bundle build/serving, dashboard plugin route loading, and background dashboard MCP discovery.

The mode can also be persisted with:

dashboard:
  mode: lightweight

Why

Fixes #58694.

PR #58721 adds a useful lightweight UI/config mode, but the issue reporter confirmed that after first page access the backend still jumps to roughly the full dashboard memory footprint because the full FastAPI/Pydantic route stack is still initialized. This PR takes the deeper route: the lightweight path branches before hermes_cli.web_server is imported.

Safety / security

  • Full dashboard remains the default (dashboard.mode: full).
  • hermes serve remains unchanged and ignores dashboard.mode.
  • Lightweight mode is loopback-only and refuses non-loopback binds because it does not load the full dashboard auth gate.
  • The lightweight server validates the Host header to reject DNS-rebinding style requests even on loopback.
  • Desktop/backend readiness compatibility is preserved by emitting HERMES_DASHBOARD_READY and writing HERMES_DESKTOP_READY_FILE when present.

Changes Made

  • Added hermes_cli/light_dashboard_server.py with a focused stdlib backend.
  • Added hermes dashboard --light plus hidden --legacy alias.
  • Added dashboard.mode: full|lightweight config support and dashboard schema metadata.
  • Preserved named-profile dashboard reroute behavior by forwarding --light through the re-exec path.
  • Documented lightweight mode and its loopback-only limitation.
  • Added tests for parser wiring, config-mode dispatch, no full-web-stack import, Host-header behavior, ready-file compatibility, compact session reads, and config schema.

Validation

python -m compileall -q hermes_cli/light_dashboard_server.py hermes_cli/main.py hermes_cli/subcommands/dashboard.py hermes_cli/web_server.py tests/hermes_cli/test_light_dashboard.py tests/hermes_cli/test_serve_command.py tests/hermes_cli/test_web_server.py
ruff check hermes_cli/light_dashboard_server.py hermes_cli/main.py hermes_cli/subcommands/dashboard.py hermes_cli/web_server.py tests/hermes_cli/test_light_dashboard.py tests/hermes_cli/test_serve_command.py tests/hermes_cli/test_web_server.py
pytest tests/hermes_cli/test_light_dashboard.py tests/hermes_cli/test_serve_command.py tests/hermes_cli/test_web_server.py::TestBuildSchemaFromConfig::test_dashboard_mode_schema_is_select -q
python scripts/run_tests_parallel.py tests/hermes_cli/test_light_dashboard.py tests/hermes_cli/test_serve_command.py -q
git diff --check

Results:

  • compileall: pass
  • ruff: pass
  • targeted pytest: 14 passed
  • per-file runner: 13 passed
  • git diff --check: pass
  • live smoke test: hermes dashboard --light --port 0 --no-open emitted HERMES_DASHBOARD_READY, served / with 200, returned /api/status with mode: lightweight, returned /api/sessions with the expected JSON shape, and rejected a bad Host: evil.example request with 400.

Note: scripts/run_tests.sh could not run in this Windows checkout because WSL Bash sees the repo as /mnt/e/... and no POSIX .venv/bin/activate exists there. I ran the same underlying per-file runner directly via the repo dev environment.

Checklist

Code

  • I've read the Contributing Guide
  • My commit messages follow Conventional Commits
  • I searched for existing PRs to make sure this isn't a duplicate
  • My PR contains only changes related to this fix/feature
  • I've run pytest tests/ -q and all tests pass
  • I've added tests for my changes
  • I've tested on my platform: Windows 11

Documentation & Housekeeping

  • I've updated relevant documentation
  • I've updated cli-config.yaml.example for the new config key
  • I've considered cross-platform impact

Copilot AI review requested due to automatic review settings July 8, 2026 20:50

Copilot AI 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.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@alt-glitch alt-glitch added type/feature New feature or request comp/cli CLI entry point, hermes_cli/, setup wizard comp/dashboard Web dashboard / control panel UI (dashboard/, landing) P3 Low — cosmetic, nice to have labels Jul 8, 2026
@alt-glitch

Copy link
Copy Markdown
Collaborator

This was generated by AI during triage.

Related: #58721 (competing lightweight-dashboard approach) and #58694 (the underlying v0.17.0 dashboard memory regression). Both PRs target #58694, but via different mechanisms: #58721 hides admin routes while still initializing the full FastAPI/Pydantic stack (the reporter noted RAM still jumps after first page access), whereas this PR branches before hermes_cli.web_server is imported and serves a stdlib backend. Flagging the cluster so a maintainer can pick the deeper vs. the lighter-touch approach.

@deaneeth
deaneeth force-pushed the fix/dashboard-true-lightweight-mode branch from 48b315f to 3cbf461 Compare July 9, 2026 10:04
@deaneeth

deaneeth commented Jul 9, 2026

Copy link
Copy Markdown
Contributor Author

Thanks for flagging the cluster @alt-glitch. To make the intended relationship explicit: I see #58721 as the lighter-touch/full-dashboard route-filtering approach, while this PR is the root memory fix for the reporter's follow-up: it branches before \hermes_cli.web_server\ is imported, so lightweight mode does not initialize the FastAPI/Pydantic/admin route stack at all.\n\nI kept full dashboard behavior as the default, made the new path loopback-only with Host-header validation, and preserved the readiness contract. If maintainers prefer, #58721's route-filtering/config work could still be layered onto the full dashboard later, but it does not replace this backend split for the post-page-load RSS regression.

@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 taking the deeper stdlib-server route; current main still imports FastAPI/Pydantic in the ordinary dashboard path (hermes_cli/main.py:12041-12043, hermes_cli/web_server.py:89-98), so the memory premise is valid.

Problems

  • The named-profile compatibility claim is not met. Main routes a profile launch to /?profile=<name> (hermes_cli/main.py:11971), but the new handler parses no profile value and /api/sessions calls the root-scoped payload builder (hermes_cli/light_dashboard_server.py:293-309). initial_profile only affects the auto-open URL (:378-388), so a rerouted worker dashboard shows root-profile data.

Suggested changes

  • Add validated profile-aware session/status resolution without importing hermes_cli.web_server, and cover /?profile=worker or the named-profile reroute in tests/hermes_cli/test_light_dashboard.py.

Automated hermes-sweeper review.

Comment thread hermes_cli/light_dashboard_server.py Outdated
offset = _coerce_int((params.get("offset") or [None])[0], default=0, minimum=0, maximum=100000)
self._send_json(
HTTPStatus.OK,
build_sessions_payload(limit=limit, offset=offset, order=order),

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.

/?profile=<name> is the machine-dashboard routing contract, but this request path never reads or forwards profile; build_sessions_payload() therefore opens the root DEFAULT_DB_PATH. Please add validated profile-aware resolution here (and to status) so named-profile lightweight launches do not silently show root-profile data.

@deaneeth deaneeth Jul 11, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@teknium1 Implemented the requested named-profile scoping in dc8de37.

The lightweight page now forwards its ?profile= selection to both status and sessions. The backend normalizes and validates that profile through the existing profile helpers, rejects malformed/missing profiles, and reads the selected profile's state.db, gateway.pid, and gateway_state.json. Status also preserves the launch-managed runtime PID fallback, scoped with expected_home to prevent cross-profile PID reuse.

Added coverage for named-profile DB resolution, status/runtime resolution, browser-to-API propagation, and invalid/missing profiles. Verified with 17 lightweight/serve tests, Ruff, Ty, the Windows-footgun scan, a real HTTP integration check, and a clean disposable merge onto latest upstream main (291eae6).

Please take another look when you have a moment. If you see any remaining edge case or want the profile contract shaped differently, I will adjust it :)

@teknium1 teknium1 added sweeper:risk-security-boundary Sweeper risk: may affect sandboxing, auth, credentials, or sensitive data 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 10, 2026
@deaneeth
deaneeth requested a review from teknium1 July 11, 2026 00:56
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 sweeper:risk-security-boundary Sweeper risk: may affect sandboxing, auth, credentials, or sensitive data 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

4 participants