# Development Guidelines This document defines project-level development rules for hermes-ui. It is tool-agnostic and applies to all contributors and coding agents. ## Prerequisites - Node.js `>=23` (see `engines` in `package.json`). - Python with `hermes-agent` installed. The Hermes CLI is not bundled; point `HERMES_BIN` at the executable or make `hermes` resolvable from `PATH`. - A C/C++ toolchain, **but only on Linux**: `python3`, `make`, `g++`. See "Platform Notes" below. ## Commands ```bash npm ci --ignore-scripts npm rebuild node-pty npm run electron:setup npm run dev npm run test npm run test:coverage npm run test:e2e npm run build ``` - `npm ci --ignore-scripts` installs exactly what `package-lock.json` pins. Do not upgrade dependencies. - `npm rebuild node-pty` is **required**, not optional. `npm ci --ignore-scripts` skips every install script, and `node-pty`'s install script is what puts a loadable native module in place. Skipping it leaves the terminal feature silently disabled — the server logs a warning and keeps running. - `npm run dev` launches Electron, its local Koa utility process, and the Vite renderer. - `npm run electron:setup` downloads Electron and rebuilds native modules for its ABI. - `npm run dev:web` retains standalone Vite + Koa development. - `npm start` launches the built desktop app; `npm run start:web` serves the web build. - `npm run pack` / `npm run dist` create desktop applications / installers. - See `docs/electron.md` for runtime, data, packaging and smoke tests. - `npm run test` runs Vitest unit tests. - `npm run test:coverage` is what the Build workflow runs before `npm run build`. - `npm run test:e2e` runs Playwright browser tests against a mocked BFF API. - `npm run build` type-checks and builds both client and server. ## Hermes CLI Detection The installation probe runs `hermes --help` in the Web UI service environment. Some Hermes versions synchronously check upstream updates during `--version`, so version output is not a reliable installation/liveness probe. A timeout does not mean Hermes is absent and must not send users to the installation guide. `GET /api/hermes/cli-status` reports `available`, `bin`, and `reason` (`ready`, `missing`, `permission_denied`, `timeout`, or `failed`). `?refresh=1` bypasses the completed-result cache while sharing an in-flight probe. Deploy validation must check this endpoint as well as HTTP health; a running Node process alone does not prove that its service user can execute Hermes. When investigating, reproduce with the service's `HERMES_BIN`, `PATH`, `HOME`, and `HERMES_HOME`. Inspect the complete launcher/interpreter path before changing permissions. Do not use recursive permission changes to treat a probe timeout. ## One-Click Deploy `deploy.sh` deploys a checkout to a host that runs the built server under systemd: ```bash ./deploy.sh # pull, install, build, restart, verify ./deploy.sh --dry-run # print the plan and exit ./deploy.sh --help # all options ``` It pulls `origin/main` with `--ff-only`, reinstalls dependencies only when `package-lock.json` changed, rebuilds the `node-pty` native module, builds the client and the server, restarts the `hermes-ui.service` unit, and verifies the result against both `/health` and `/api/auth/status`. The previous `dist/` is backed up to `~/.local/state/hermes-ui-deploy/backups/` first and restored automatically when the build or the health check fails. `start.sh` is the optional web development launcher (foreground Vite + Koa); `deploy.sh` is the production path. Do not mix them. ## Platform Notes The server runs on Windows, macOS, and Linux. The parts that differ are isolated behind `process.platform` checks, so the same source runs everywhere. ### node-pty `node-pty` ships prebuilt binaries for Windows and macOS only: | Platform | Where the native module comes from | Build step | | --- | --- | --- | | Windows | `prebuilds/win32-/` (shipped in the npm tarball) | not needed | | macOS | `prebuilds/darwin-/` (shipped in the npm tarball) | not needed | | Linux | **none — must be compiled from source** | `npm rebuild node-pty` | On Linux, `npm rebuild node-pty` compiles `node-pty` from source and needs `python3`, `make`, and `g++` on the machine. The Dockerfile installs exactly those for this reason. On macOS the prebuilt `spawn-helper` may arrive without its executable bit. The server repairs that at startup (`packages/server/src/routes/hermes/terminal.ts`), and `bin/hermes-ui.mjs` does the same for the installed CLI. ### Other platform differences - **Terminal shell**: `powershell.exe` on Windows, `$SHELL` (falling back to `/bin/zsh` then `/bin/bash`) on macOS and Linux. - **Agent Bridge transport**: a Unix domain socket at `ipc:///tmp/hermes-agent-bridge.sock` on macOS and Linux, a TCP port (`tcp://127.0.0.1:18765`) on Windows, which has no Unix socket support in Node. - **Python interpreter**: `python3` on macOS and Linux, `python` on Windows. Virtualenv layout differs too (`venv/bin/python3` vs `venv\Scripts\python.exe`). - **Gateway process tree**: `taskkill /T` on Windows, process-group signals on macOS and Linux. - **Hermes home**: `~/.hermes` on macOS and Linux; on Windows, an existing `%LOCALAPPDATA%\hermes` or `%APPDATA%\hermes` takes priority. ### Verification Linux is covered by the `Build` and `Playwright` workflows, which run on `ubuntu-latest`. macOS is not covered by any hosted runner; the `macOS Verification` workflow (`workflow_dispatch` only) runs the same checks when a macOS runner is available. ## Architecture - Frontend code lives under `packages/client/src`. - Server code lives under `packages/server/src`. - Hermes-specific client code stays under `hermes` namespaces: API modules, views, stores, and components. - Server routes should stay thin. Put request handling in controllers and reusable behavior in services. - The chat runtime is Socket.IO based and lives under `packages/server/src/services/hermes/run-chat`. - Web UI state lives under `HERMES_WEB_UI_HOME` or `HERMES_WEBUI_STATE_DIR`. Electron sets these to `userData/state`; standalone web defaults to `~/.hermes-web-ui`. - Hermes `state.db` is read-only. Never open it from Node-side code. ## Coding Rules - Prefer existing local patterns over new abstractions. - Keep changes scoped to the requested behavior. - Do not mix unrelated refactors into feature or bugfix commits. - Do not reintroduce deprecated compatibility switches without a current caller. - Use structured APIs and parsers for structured data instead of ad hoc string edits when possible. - Add comments only where they explain non-obvious behavior or constraints. ## Frontend Rules - Use Vue 3 Composition API with `