# Electron desktop runtime The primary application is now Hermes Desktop. The root `electron/` directory contains the main process, sandboxed metadata preload, and utility-process entry. The retired `packages/desktop` implementation is not restored. ## Install and run ```bash npm ci --ignore-scripts npm run electron:setup npm run dev ``` `electron:setup` downloads the pinned Electron binary and rebuilds `node-pty` for Electron's ABI. `dev` builds the server/main/preload and starts Electron with a Vite renderer on loopback, with hot reload. Restart `dev` after editing server, main, or preload code. `HERMES_WEB_UI_FRONTEND_PORT` changes Vite's default port (8649). ```bash npm run build npm start npm run pack # unpacked application under release/ npm run dist # native installers under release/ ``` Build installers on their target OS: DMG/ZIP on macOS, NSIS EXE on Windows, AppImage/DEB on Linux. The manual Electron packages workflow covers all three. Signing/notarization credentials must be supplied for public distribution. No updater endpoint is supplied: install a new desktop package to upgrade. Web npm self-update and version-preview installation are disabled in Electron. ## Process and request boundaries 1. Electron acquires a single-instance lock for its Chromium user-data directory. 2. The utility process validates `node:sqlite` and `node-pty`, then starts the bundled Koa server on `127.0.0.1`. 3. A private parent port reports readiness and the actual HTTP origin. The first launch uses an OS-assigned port; subsequent launches reuse it. If occupied, another free port is selected. A port change also changes browser storage origin, so users may need to sign in again; server data stays intact. 4. A sandboxed BrowserWindow loads that origin (or loopback Vite in development). Node integration is disabled, context isolation enabled, and preload exposes only platform/Electron metadata. Existing API and Socket.IO contracts remain. 5. External HTTP/HTTPS/mailto links open in the system browser. Other schemes and webview attachment are blocked. Downloads use the native save dialog. 6. Quit sends a private shutdown message and waits for the existing bridge, gateway, Socket.IO, HTTP and DB cleanup, with an 18-second final kill cap. Closing the last macOS window keeps the app running until Quit. The local service checks Host and browser Origin and retains the existing login and API authorization. LAN discovery is off for the desktop. Desktop packaging uses ordinary files (`asar: false`) because Python, MCP and terminal executables must be accessible outside Electron's virtual filesystem. ## Data and external runtime Chromium settings, login storage, saved window geometry and service port live in Electron's `userData`. Service data defaults to `userData/state`; logs are in `state/logs`. The Help menu opens these directories. Existing `HERMES_WEB_UI_HOME` / `HERMES_WEBUI_STATE_DIR` overrides take priority. Point one of them at an existing Web UI directory to reuse its data (stop the old server first). No existing data is copied or deleted automatically. `HERMES_ELECTRON_USER_DATA` overrides the Chromium profile for isolated testing. Hermes Agent/Python are user-installed, and their state stays separate. Use `HERMES_BIN`, `HERMES_HOME`, or `HERMES_AGENT_BRIDGE_PYTHON` as needed. Common GUI-launch PATH locations are added to the service environment. POSIX bridge sockets are scoped by service data directory. MCP uses the app executable in `ELECTRON_RUN_AS_NODE` mode, so installed users do not need a separate Node.js. The optional standalone web commands are `dev:web`, `build:web`, `start:web`. Docker/systemd remain separate web deployment paths. ## Validation ```bash npm run harness:check npm run test:coverage npm run test:e2e npm run build npm run electron:setup npm run test:electron npm run pack ``` Local verification on 2026-10-25 (macOS arm64): coverage suite passed (2,139 tests, 2 skipped), all 69 browser tests passed, and focused additions passed. All three source Electron smoke tests passed; the packaged app passed both production smoke tests. DMG checksums and ZIP integrity were verified. Windows and Linux installers are configured but were not built on this Mac. The local macOS artifacts are unsigned and not notarized. The native smoke test launches the real Electron executable with temporary Chromium, service and Hermes homes, verifies local health and renderer isolation, and confirms the service exits when the app quits. It does not call a model. Set `HERMES_ELECTRON_EXECUTABLE` to a packaged executable to repeat the test against the installer contents. Linux runners require Xvfb and Electron's system libraries. After Electron ABI rebuilds, run `npm rebuild node-pty` before using the standalone Node server if its ABI differs. References: [Electron utility processes](https://www.electronjs.org/docs/latest/api/utility-process), [Electron security](https://www.electronjs.org/docs/latest/tutorial/security), [native modules](https://www.electronjs.org/docs/latest/tutorial/using-native-node-modules).