Promote closeRightRailTab/closeActiveRightRailTab as the single public entry point. Drops the activeTabRef + handleCloseDocument indirection in ChatPreviewRail, the unused $rightRailHasContent atom, and the legacy dismissFilePreviewTarget alias. -70 LOC.
Hermes Desktop
Native Electron shell for Hermes. It packages the desktop renderer, a bundled Hermes source payload, and installer targets for macOS and Windows.
Setup
Install workspace dependencies from the repo root so apps/desktop, apps/dashboard, and apps/shared stay linked:
npm install
Use the normal Hermes Python environment for local runs:
source .venv/bin/activate # or: source venv/bin/activate
python -m pip install -e .
Development
cd apps/desktop
npm run dev
npm run dev starts Vite on 127.0.0.1:5174, launches Electron, and lets Electron boot the Hermes dashboard backend on an open port in 9120-9199. This path is for UI iteration and may still show Electron/dev identities in OS prompts.
Useful overrides:
HERMES_DESKTOP_HERMES_ROOT=/path/to/hermes-agent npm run dev
HERMES_DESKTOP_PYTHON=/path/to/python npm run dev
HERMES_DESKTOP_CWD=/path/to/project npm run dev
HERMES_DESKTOP_IGNORE_EXISTING=1 npm run dev
HERMES_DESKTOP_IGNORE_EXISTING=1 skips any hermes CLI already on PATH, which is useful when testing the bundled/runtime bootstrap path.
Dashboard Dev
Run the Python dashboard backend with embedded chat enabled:
hermes dashboard --tui --no-open
For dashboard HMR, start Vite in another terminal:
cd apps/dashboard
npm run dev
Open the Vite URL. The dev server proxies /api, /api/pty, and plugin assets to http://127.0.0.1:9119 and fetches the live dashboard HTML so the ephemeral session token matches the running backend.
Build
npm run build
npm run pack # unpacked app at release/mac-<arch>/Hermes.app
npm run dist:mac # macOS DMG + zip
npm run dist:mac:dmg # DMG only
npm run dist:mac:zip # zip only
npm run dist:win # NSIS + MSI
Before packaging, stage:hermes copies the Python Hermes payload into build/hermes-agent. Electron Builder then ships it as Contents/Resources/hermes-agent.
Automated Releases
Desktop installers are published by .github/workflows/desktop-release.yml with two channels:
- Stable: runs on published GitHub releases and uploads signed artifacts to that release tag.
- Nightly: runs on
mainpushes and updates the rollingdesktop-nightlyprerelease.
The workflow injects a channel-aware desktop version at build time:
- stable: derived from the release tag (for example
v2026.5.5->2026.5.5) - nightly:
0.0.0-nightly.YYYYMMDD.<sha>
Artifact names include channel, platform, and architecture:
Hermes-<version>-<channel>-<platform>-<arch>.<ext>
Each run also publishes SHA256SUMS-<platform>.txt so installers can be verified.
Stable release gates
Stable builds fail fast if signing credentials are missing:
- macOS signing + notarization:
CSC_LINK,CSC_KEY_PASSWORD,APPLE_API_KEY,APPLE_API_KEY_ID,APPLE_API_ISSUER - Windows signing:
WIN_CSC_LINK,WIN_CSC_KEY_PASSWORD
Stable macOS builds also validate stapling and Gatekeeper assessment in CI before upload.
Icons
Desktop icons live in assets/:
assets/icon.icnsassets/icon.icoassets/icon.png
The builder config points at assets/icon. Replace these files directly if the app icon changes.
Testing Install Paths
Use the package-local test scripts from this directory:
npm run test:desktop:all
npm run test:desktop:existing
npm run test:desktop:fresh
npm run test:desktop:dmg
test:desktop:existing builds the packaged app and opens it normally. It should use an existing hermes CLI if one is on PATH, preserving the user’s real ~/.hermes config.
test:desktop:fresh builds the packaged app, deletes the bundled desktop runtime, sets HERMES_DESKTOP_IGNORE_EXISTING=1, and launches the app through the bundled payload path. Use this repeatedly to test first-run bootstrap.
test:desktop:dmg builds and opens the DMG.
For fast reruns without rebuilding:
HERMES_DESKTOP_SKIP_BUILD=1 npm run test:desktop:fresh
HERMES_DESKTOP_SKIP_BUILD=1 npm run test:desktop:existing
HERMES_DESKTOP_SKIP_BUILD=1 npm run test:desktop:dmg
Installing Locally
npm run dist:mac:dmg
open release/Hermes-0.0.0-arm64.dmg
Drag Hermes to Applications. If testing repeated installs, replace the existing app.
Runtime Bootstrap
Packaged desktop startup resolves Hermes in this order:
HERMES_DESKTOP_HERMES_ROOT- existing
hermesCLI, unlessHERMES_DESKTOP_IGNORE_EXISTING=1 - bundled
Contents/Resources/hermes-agent - dev repo source
- installed
python -m hermes_cli.main
When the bundled path is used, Electron creates or reuses:
~/Library/Application Support/Hermes/hermes-runtime
The runtime is validated before use. If required dashboard imports are missing, it reinstalls the desktop runtime dependencies and retries.
Debugging
Desktop boot logs are written to:
~/Library/Application Support/Hermes/desktop.log
If the UI reports Desktop boot failed, check that log first. It includes the backend command output and recent Python traceback context.
To reset bundled runtime state:
rm -rf "$HOME/Library/Application Support/Hermes/hermes-runtime"
To reset stale macOS microphone permission prompts:
tccutil reset Microphone com.github.Electron
tccutil reset Microphone com.nousresearch.hermes
Verification
Run before handing off installer changes:
npm run fix
npm run type-check
npm run lint
npm run test:desktop:all
Current lint may report existing warnings, but it should exit with no errors.