hermes - ✅(Solved) Fix Dashboard rebuilds web UI on every startup - causes OOM on low-memory VPS (≤1GB) [1 pull requests, 1 comments, 2 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
NousResearch/hermes-agent#14898Fetched 2026-04-24 10:44:26
View on GitHub
Comments
1
Participants
2
Timeline
5
Reactions
0
Timeline (top)
labeled ×3commented ×1cross-referenced ×1

Error Message

Error Output

Fix Action

Fix / Workaround

Workarounds Tried

  • Added --insecure flag (fixed security check, not the OOM)
  • Disabled systemd auto-start (avoids loop but loses dashboard)

PR fix notes

PR #14914: fix(cli): skip web UI rebuild when dist/ is present and sources are unchanged

Description (problem / solution / changelog)

What does this PR do?

`_build_web_ui()` ran `npm install` + `npm run build` unconditionally on every `hermes dashboard` startup. On low-memory hosts (≤1GB RAM) the Node build process peaked at ~388MB and was OOM-killed by systemd before the server could start. Docker installs hit the same root cause when overlayfs blocked `npm install` on a read-only layer.

Parity fix: adds `_web_ui_build_needed()` that mirrors the mtime-based staleness check already used by `_tui_build_needed()` for the TUI. The Vite manifest (`dist/.vite/manifest.json`) is used as the sentinel — it is written last and therefore has the newest mtime of any build artifact. Falls back to `dist/index.html` for older builds. Rebuild is triggered when any tracked source file (`.ts`, `.tsx`, `.js`, `.jsx`, `.css`, `.html`, `.vue`) or dependency manifest (`package.json`, `package-lock.json`, `yarn.lock`, `pnpm-lock.yaml`, `vite.config.*`) is newer than the sentinel. When `dist/` is absent the existing build path runs unchanged.

Related Issue

Fixes #14898 Fixes #12243

Type of Change

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

Changes Made

  • `hermes_cli/main.py`: add `_web_ui_build_needed(web_dir)` (+33 lines); add early-return guard in `_build_web_ui()` (+2 lines)
  • `tests/hermes_cli/test_web_ui_build.py`: 9 tests covering missing dist, stale sources, fresh dist, sentinel fallback, lockfile changes, vite config changes, node_modules exclusion, npm skip, npm run (+110 lines, new file)

How to Test

pytest tests/hermes_cli/test_web_ui_build.py -v

All 9 tests pass. To verify end-to-end: run `hermes dashboard` once to build, then run again — the second startup should skip the npm build entirely.

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
  • I've run pytest tests/hermes_cli/test_web_ui_build.py -v and all 9 tests pass
  • I've added tests for my changes
  • I've tested on my platform: macOS

Documentation & Housekeeping

  • I've updated relevant documentation — or N/A
  • I've updated `cli-config.yaml.example` — or N/A
  • I've updated `CONTRIBUTING.md` or `AGENTS.md` — or N/A
  • I've considered cross-platform impact — fix uses `os.walk` + `pathlib.Path`, cross-platform safe
  • I've updated tool descriptions/schemas — or N/A

Changed files

  • hermes_cli/main.py (modified, +37/-0)
  • tests/hermes_cli/test_web_ui_build.py (added, +108/-0)

Code Example

Apr 24 03:56:14 glockbot systemd[1]: hermes-dashboard.service: Failed with result 'oom-kill'.
Apr 24 03:56:14 glockbot systemd[1]: hermes-dashboard.service: Consumed 43.891s CPU time, 387.9M memory peak

---

# pseudocode for dashboard startup
dist_path = Path(__file__).parent / "web" / "dist"
source_mtime = max(f.stat().st_mtime for f in web_src.rglob("*"))
dist_mtime = dist_path.stat().st_mtime if dist_path.exists() else 0

if not dist_path.exists() or source_mtime > dist_mtime:
    build_web_ui()  # npm run build
# else: serve existing dist/

---

hermes dashboard build    # one-time build
hermes dashboard serve    # just serve existing dist/
RAW_BUFFERClick to expand / collapse

Problem

The hermes dashboard command rebuilds the entire web UI (npm install + TypeScript + Vite build) on every startup, causing OOM kills on low-memory VPS instances (≤1GB RAM).

Error Output

Apr 24 03:56:14 glockbot systemd[1]: hermes-dashboard.service: Failed with result 'oom-kill'.
Apr 24 03:56:14 glockbot systemd[1]: hermes-dashboard.service: Consumed 43.891s CPU time, 387.9M memory peak

Environment

  • Hermes Agent version: latest main (6fdbf2f2)
  • OS: Ubuntu 22.04 LTS
  • RAM: 960MB (VPS)
  • Command: hermes dashboard --host <ip> --port 80 --no-open --insecure

Reproduction Steps

  1. Run hermes dashboard --host 0.0.0.0 --port 80 on a VPS with ≤1GB RAM
  2. Process builds web UI from scratch (~45s, peaks at 387MB)
  3. systemd OOM killer terminates the process

Expected Behavior

Dashboard should:

  • Use a pre-built web/dist/ if present (ship static assets in releases)
  • Or build once and cache (check timestamps before rebuild)
  • Skip npm build entirely when dist/ exists and is fresh

Proposed Solutions

Option A: Ship pre-built dist/ in PyPI releases

Include web/dist/ in the wheel/sdist so users never need npm/node.

Option B: Lazy build with caching

# pseudocode for dashboard startup
dist_path = Path(__file__).parent / "web" / "dist"
source_mtime = max(f.stat().st_mtime for f in web_src.rglob("*"))
dist_mtime = dist_path.stat().st_mtime if dist_path.exists() else 0

if not dist_path.exists() or source_mtime > dist_mtime:
    build_web_ui()  # npm run build
# else: serve existing dist/

Option C: Separate build command

hermes dashboard build    # one-time build
hermes dashboard serve    # just serve existing dist/

Impact

  • Breaks dashboard functionality on low-resource servers
  • Wastes CPU/memory on every restart (systemd service loops)
  • Forces users to disable dashboard entirely

Workarounds Tried

  • Added --insecure flag (fixed security check, not the OOM)
  • Disabled systemd auto-start (avoids loop but loses dashboard)

extent analysis

TL;DR

Implement a caching mechanism to avoid rebuilding the web UI on every startup, such as shipping pre-built static assets or building with caching.

Guidance

  • Consider implementing Option B: Lazy build with caching, which checks the timestamps of the source and dist directories to determine if a rebuild is necessary.
  • If implementing Option B, ensure that the build_web_ui() function is properly handling the npm build process and that the dist_path and source_mtime variables are correctly calculated.
  • Evaluate the feasibility of shipping pre-built static assets in releases (Option A) to eliminate the need for npm/node altogether.
  • As a temporary workaround, consider using Option C: Separate build command to build the web UI once and then serve the existing dist/ directory.

Example

import os
from pathlib import Path

# pseudocode for dashboard startup
dist_path = Path(__file__).parent / "web" / "dist"
source_mtime = max(f.stat().st_mtime for f in Path(__file__).parent.rglob("*"))
dist_mtime = dist_path.stat().st_mtime if dist_path.exists() else 0

if not dist_path.exists() or source_mtime > dist_mtime:
    # npm run build
    build_web_ui()
# else: serve existing dist/

Notes

The chosen solution may depend on the specific requirements and constraints of the project, such as the need for up-to-date dependencies or the availability of resources.

Recommendation

Apply workaround by implementing Option B: Lazy build with caching, as it provides a balance between ensuring the web UI is up-to-date and avoiding unnecessary rebuilds.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING