{"repo":"NousResearch/hermes-agent","public_id":"9305","display_label":"Nix package missing FastAPI and web dashboard build","summary":"These issues and PRs address the Nix package failing to include FastAPI and omitting the web dashboard frontend build step. Multiple fixes were proposed targeting the same gap in the Nix packaging configuration.","subsystem":null,"counts":{"members":4,"open_issues":0,"open_issues_distinct":0,"open_prs":0,"closed_issues":1,"merged_prs":1,"attempt_prs":2},"landed_fix":{"status":"merged_to_main","basis":"structural","pr":12194,"merged_at":"2026-04-18T15:25:39+00:00"},"resolution":{"state":"resolved","by":"pr-12194"},"freshness":{"state":"stale","last_verified_at":"2026-04-18T15:25:39+00:00","is_stale":true},"grouping":{"backbone":"STRUCTURAL_SPANNING","link_density":0.5},"fix_edges":[{"issue_number":9305,"pr_number":12194,"tier":"verified","basis":"closing_ref","confidence":0.95,"recoverable_from_timeline":true,"pr_merged_at":"2026-04-18T15:25:39+00:00"}],"members":[{"kind":"issue","number":9305,"title":"Nix package: missing fastapi + web dashboard frontend not built","url":null,"state":"closed"},{"kind":"pr","number":9307,"title":"fix(nix): include fastapi and build web frontend for dashboard","url":null,"state":"closed","close_reason":{"category":"uncategorized","implication":"needs_llm"},"merged":false},{"kind":"pr","number":12194,"title":"fix(nix): build web dashboard frontend in Nix package","url":null,"state":"merged","close_reason":{"category":"merged"},"merged":true,"is_fix_pr":true,"fix_tier":"verified","files_changed":["hermes_cli/main.py","hermes_cli/web_server.py","nix/packages.nix","nix/web.nix"],"fix_hunks":[{"file":"hermes_cli/main.py","hunks":["@@ -6229,8 +6229,9 @@ def cmd_dashboard(args):\n         print(f\"Install them with:  {sys.executable} -m pip install 'fastapi' 'uvicorn[standard]'\")\n         sys.exit(1)\n \n-    if not _build_web_ui(PROJECT_ROOT / \"web\", fatal=True):\n-        sys.exit(1)\n+    if \"HERMES_WEB_DIST\" not in os.environ:\n+        if not _build_web_ui(PROJECT_ROOT / \"web\", fatal=True):\n+            sys.exit(1)\n \n     from hermes_cli.web_server import start_server\n "]},{"file":"hermes_cli/web_server.py","hunks":["@@ -59,7 +59,7 @@\n         f\"Install with: {sys.executable} -m pip install 'fastapi' 'uvicorn[standard]'\"\n     )\n \n-WEB_DIST = Path(__file__).parent / \"web_dist\"\n+WEB_DIST = Path(os.environ[\"HERMES_WEB_DIST\"]) if \"HERMES_WEB_DIST\" in os.environ else Path(__file__).parent / \"web_dist\"\n _log = logging.getLogger(__name__)\n \n app = FastAPI(title=\"Hermes Agent\", version=__version__)"]},{"file":"nix/packages.nix","hunks":["@@ -18,6 +18,10 @@\n         filter = path: _type: !(pkgs.lib.hasInfix \"/index-cache/\" path);\n       };\n \n+      hermesWeb = pkgs.callPackage ./web.nix {\n+        npm-lockfile-fix = inputs'.npm-lockfile-fix.packages.default;\n+      };\n+\n       runtimeDeps = with pkgs; [\n         nodejs_22\n         ripgrep","@@ -52,6 +56,7 @@\n \n             mkdir -p $out/share/hermes-agent $out/bin\n             cp -r ${bundledSkills} $out/share/hermes-agent/skills\n+            cp -r ${hermesWeb} $out/share/hermes-agent/web_dist\n \n             # copy pre-built TUI (same layout as dev: ui-tui/dist/ + node_modules/)\n             mkdir -p $out/ui-tui","@@ -62,6 +67,7 @@\n                 makeWrapper ${hermesVenv}/bin/${name} $out/bin/${name} \\\n                   --suffix PATH : \"${runtimePath}\" \\\n                   --set HERMES_BUNDLED_SKILLS $out/share/hermes-agent/skills \\\n+                  --set HERMES_WEB_DIST $out/share/hermes-agent/web_dist \\\n                   --set HERMES_TUI_DIR $out/ui-tui \\\n                   --set HERMES_PYTHON ${hermesVenv}/bin/python3 \\\n                   --set HERMES_NODE ${pkgs.nodejs_22}/bin/node","@@ -104,6 +110,7 @@\n         };\n \n         tui = hermesTui;\n+        web = hermesWeb;\n       };\n     };\n }"]},{"file":"nix/web.nix","hunks":["@@ -0,0 +1,63 @@\n+# nix/web.nix — Hermes Web Dashboard (Vite/React) frontend build\n+{ pkgs, npm-lockfile-fix, ... }:\n+let\n+  src = ../web;\n+  npmDeps = pkgs.fetchNpmDeps {\n+    inherit src;\n+    hash = \"sha256-Y0pOzdFG8BLjfvCLmsvqYpjxFjAQabXp1i7X9W/cCU4=\";\n+  };\n+\n+  npmLockHash = builtins.hashString \"sha256\" (builtins.readFile ../web/package-lock.json);\n+in\n+pkgs.buildNpmPackage {\n+  pname = \"hermes-web\";\n+  version = \"0.0.0\";\n+  inherit src npmDeps;\n+\n+  doCheck = false;\n+\n+  buildPhase = ''\n+    npx tsc -b\n+    npx vite build --outDir dist\n+  '';\n+\n+  installPhase = ''\n+    runHook preInstall\n+    cp -r dist $out\n+    runHook postInstall\n+  '';\n+\n+  nativeBuildInputs = [\n+    (pkgs.writeShellScriptBin \"update_web_lockfile\" ''\n+      set -euox pipefail\n+\n+      REPO_ROOT=$(git rev-parse --show-toplevel)\n+\n+      cd \"$REPO_ROOT/web\"\n+      rm -rf node_modules/\n+      npm cache clean --force\n+      CI=true npm install\n+      ${pkgs.lib.getExe npm-lockfile-fix} ./package-lock.json\n+\n+      NIX_FILE=\"$REPO_ROOT/nix/web.nix\"\n+      sed -i \"s/hash = \\\"[^\\\"]*\\\";/hash = \\\"\\\";/\" $NIX_FILE\n+      NIX_OUTPUT=$(nix build .#web 2>&1 || true)\n+      NEW_HASH=$(echo \"$NIX_OUTPUT\" | grep 'got:' | awk '{print $2}')\n+      echo got new hash $NEW_HASH\n+      sed -i \"s|hash = \\\"[^\\\"]*\\\";|hash = \\\"$NEW_HASH\\\";|\" $NIX_FILE\n+      nix build .#web\n+      echo \"Updated npm hash in $NIX_FILE to $NEW_HASH\"\n+    '')\n+  ];\n+\n+  passthru.devShellHook = ''\n+    STAMP=\".nix-stamps/hermes-web\"\n+    STAMP_VALUE=\"${npmLockHash}\"\n+    if [ ! -f \"$STAMP\" ] || [ \"$(cat \"$STAMP\")\" != \"$STAMP_VALUE\" ]; then\n+      echo \"hermes-web: installing npm dependencies...\"\n+      cd web && CI=true npm install --silent --no-fund --no-audit 2>/dev/null && cd ..\n+      mkdir -p .nix-stamps\n+      echo \"$STAMP_VALUE\" > \"$STAMP\"\n+    fi\n+  '';\n+}\n"]}]},{"kind":"pr","number":12197,"title":"fix(nix): build web dashboard frontend in Nix package","url":null,"state":"closed","close_reason":{"category":"silent_close","implication":"active"},"merged":false}],"trust":{"default_tier":"verified","includes_suggested":false}}