* fix(desktop): make composer message queue reliable The queue felt 'dumb' because of three real bugs: 1. Drained-after-interrupt sends went silent. cancelRun sets interrupted:true and nothing reset it; submitPromptText's optimistic seed preserved it, and the message stream drops every delta while interrupted. So Send-now-while-busy and any interrupt+drain submitted the next turn into a muted session. Fix: a fresh submit is a new turn — seed interrupted:false. 2. Back-to-back queue drains stalled. The drain fires on the busy->false settle edge, but busyRef (synced from the busy store by a separate effect) can still read true on that same edge, so the drained send hit the busy guard, returned false, and the entry was never removed. Fix: fromQueue sends bypass the busyRef guard (the queue drain lock serializes them); the user path keeps the guard. 3. Double-enter-to-interrupt killed single non-queue turns. The hidden 450ms timer meant a natural double-tap after sending stopped the agent. Fix: empty Enter while busy is a no-op; interrupting is explicit — Stop button or Esc. Also: clean stop (no [interrupted] marker), Send-now works while busy (promote + interrupt + auto-drain), settle on the interrupted completion path. Adds regression tests and unblocks the prompt-actions suite by completing its stale @/hermes mock. * fix(desktop): float the queue panel as an overlay so the chat doesn't resize The queue list rendered in-flow inside the composer root, so its height fed --composer-measured-height (the composer rect drives the thread's bottom padding + last-message clearance). Queuing a message grew that rect and the whole chat visibly resized. Anchor the panel out of flow above the composer (absolute bottom-full, capped at 40vh with internal scroll). It no longer contributes to the measured height, so the thread layout stays put and the list overlays the (already faded) chat. Still collapsible via the panel's own disclosure header. * fix(desktop): queue panel collapsed by default + shared border with composer - Default the queue disclosure to collapsed (compact 'N queued' pill) instead of expanded. - Drop the gap and merge the panel into the composer: square bottom corners, no bottom border/radius, and overlap down by the Root's pt-2 (-mb-2) so the panel's borderless bottom lands on the composer surface's top border — one continuous bordered shape. * style(desktop): tighten queue panel padding * style(desktop): trim queue-ux comments to house style * style(desktop): drop 'Cursor' references from comments |
||
|---|---|---|
| .. | ||
| assets | ||
| electron | ||
| public | ||
| scripts | ||
| src | ||
| .prettierrc | ||
| components.json | ||
| eslint.config.mjs | ||
| index.html | ||
| package.json | ||
| preview-demo.html | ||
| README.md | ||
| tsconfig.json | ||
| vite.config.ts | ||
Hermes Desktop ☤
The native desktop app for Hermes Agent — the self-improving AI agent from Nous Research. Same agent, same skills, same memory as the CLI and gateway, in a polished native window — chat with streaming tool output, side-by-side previews, a file browser, voice, and settings, no terminal required. Available for macOS, Windows, and Linux.
| Chat with the full agent | Streaming responses, live tool activity, structured tool summaries, and the same conversation history as every other Hermes surface. |
| Side-by-side previews | Render web pages, files, and tool outputs in a right-hand pane while you keep chatting. |
| File browser | Explore and preview the working directory without leaving the app. |
| Voice | Talk to Hermes and hear it back. |
| Settings & onboarding | Manage providers, models, tools, and credentials from a real UI. First-run setup gets you to your first message in seconds. |
| Stays current | Built-in updates pull the latest agent and rebuild the app in place. |
Install
Install with Hermes (recommended)
Already have the Hermes CLI? Just run:
hermes desktop
It builds and launches the GUI against your existing install — same config, keys, sessions, and skills. On first launch Hermes walks you through picking a provider and model; nothing else to configure.
Prebuilt installers
Prebuilt installers are built and distributed via the Hermes Desktop website..
Updating
The app checks for updates in the background and offers a one-click update when one is ready. You can also update any time from the CLI:
hermes update
Requirements
The installer handles everything for you (Python 3.11+, a portable Git, ripgrep).
Development
Want to hack on the app itself? Install workspace deps from the repo root once, then run the dev server from this directory:
npm install # from repo root — links apps/desktop, web, apps/shared
cd apps/desktop
npm run dev # Vite renderer + Electron, which boots the Python backend
Point the app at a specific source checkout, or sandbox it away from your real config:
HERMES_DESKTOP_HERMES_ROOT=/path/to/clone npm run dev
HERMES_HOME=/tmp/throwaway npm run dev
npm run dev:fake-boot # exercise the startup overlay with deterministic delays
Building installers
npm run dist:mac # DMG + zip
npm run dist:win # NSIS + MSI
npm run dist:linux # AppImage + deb + rpm
npm run pack # unpacked app under release/ (no installer)
Installers are built and uploaded to GitHub Releases manually. macOS/Windows signing & notarization happen automatically when the relevant credentials are present in the environment (CSC_LINK / CSC_KEY_PASSWORD / APPLE_* for macOS, WIN_CSC_* for Windows).
How it works
The packaged app ships only the Electron shell. On first launch it installs the Hermes Agent runtime into HERMES_HOME (~/.hermes, or %LOCALAPPDATA%\hermes on Windows) — the same layout a CLI install uses, so the two are interchangeable. The renderer (React, in src/) talks to a hermes dashboard backend over the standard gateway APIs and reuses the embedded TUI rather than reimplementing chat. The install, backend-resolution, and self-update logic all live in electron/main.cjs.
Verification
Run before opening a PR (lint may surface pre-existing warnings but must exit cleanly):
npm run fix
npm run type-check
npm run lint
npm run test:desktop:all
Troubleshooting
Boot logs land in HERMES_HOME/logs/desktop.log (includes backend output and recent Python tracebacks) — check it first if the app reports a boot failure.
macOS / Linux:
# Force a clean first-launch setup
rm "$HOME/.hermes/hermes-agent/.hermes-bootstrap-complete"
# Rebuild a broken Python venv
rm -rf "$HOME/.hermes/hermes-agent/venv"
# Reset a stuck macOS microphone prompt (macOS only)
tccutil reset Microphone com.nousresearch.hermes
Windows (PowerShell):
# Force a clean first-launch setup
Remove-Item "$env:LOCALAPPDATA\hermes\hermes-agent\.hermes-bootstrap-complete"
# Rebuild a broken Python venv
Remove-Item -Recurse -Force "$env:LOCALAPPDATA\hermes\hermes-agent\venv"
The default Hermes home on Windows is
%LOCALAPPDATA%\hermes. Set theHERMES_HOMEenv var if you've relocated it.
Community
- 💬 Discord
- 📖 Documentation
- 🐛 Issues
License
MIT — see LICENSE.
Built by Nous Research.