Both the desktop and web-dashboard remote-backend sections now state up front
that the 'remote backend' is a running 'hermes dashboard' process the desktop
app attaches to (it does not start it for you), and that the gateway is a
separate process needed only for messaging channels.
The documented path for connecting Hermes Desktop to a remote backend was
`--insecure` + a pinned HERMES_DASHBOARD_SESSION_TOKEN — an unauthenticated
bind plus a copy-pasted token. Replace it everywhere with the bundled
username/password dashboard-auth provider: set HERMES_DASHBOARD_BASIC_AUTH_*,
run `hermes dashboard --host 0.0.0.0` (the non-loopback bind engages the auth
gate), and Sign in from the app.
- desktop.md: rewrite 'Connecting to a remote backend' for the user/pass + Sign in flow
- web-dashboard.md: rewrite both remote-backend sections (overview + dedicated);
reframe the auth-gate section so --insecure is a discouraged escape hatch, not a
co-equal use case; drop the removed --tui flag from the systemd example
- environment-variables.md: lead with HERMES_DASHBOARD_BASIC_AUTH_*; drop the
session-token / HERMES_DESKTOP_REMOTE_TOKEN remote-connect entries
- docker.md: mention the username/password provider as the simplest gate provider
The dashboard's embedded Chat surface (/chat, /api/ws, /api/pty) was gated
behind `hermes dashboard --tui` / HERMES_DASHBOARD_TUI=1. The desktop app and
the dashboard's own Chat tab both drive the agent over the /api/ws + /api/pty
WebSockets, so a dashboard started without the flag would pass the /api/status
health check but slam the chat WebSocket shut with WS code 4403 — the app
connects, reports "ready", and chat stays dead. This was the root cause behind
multiple user reports of the desktop app failing to connect to a self-hosted
gateway/dashboard, and it bit Docker and host installs alike.
Make the embedded chat unconditional:
- web_server.py: _DASHBOARD_EMBEDDED_CHAT_ENABLED defaults to True; drop the
embedded_chat parameter and the runtime reassignment from start_server().
The WS gates still read the constant (now always true) so the seam — and its
"rejects when disabled" contract test — stays meaningful.
- main.py: remove the `--tui` argument from the dashboard subparser and the
`embedded_chat = args.tui or HERMES_DASHBOARD_TUI==1` derivation.
- web/: isDashboardEmbeddedChatEnabled() returns true unconditionally; drop the
deprecated __HERMES_DASHBOARD_TUI__ alias and the dead LEGACY_TUI_RE scrape in
the vite dev-token plugin.
- apps/desktop/electron/main.cjs: drop `--tui` from the spawned dashboardArgs
(it would now error with "unrecognized arguments: --tui") and the redundant
HERMES_DASHBOARD_TUI env injection.
- Docker: no s6 run-script change needed — the script never passed --tui; the
HERMES_DASHBOARD_TUI env var is now simply a no-op, so the image works out of
the box with no extra var.
- Docs: remove every dashboard --tui / HERMES_DASHBOARD_TUI reference across the
CLI reference, env-var reference, docker/desktop/web-dashboard guides, in-app
tips, and the zh-Hans translations. The terminal `hermes --tui` / HERMES_TUI
references are intentionally left untouched.
Tests: 270 passing across web_server, dashboard lifecycle, host-header,
auth-gate, and docker-override-scripts suites.
The Desktop Chat section described chat-only and gave no signpost that
remote-hosted Hermes connection is documented. Adds a pointer to the
in-page remote-backend section and to the deeper Web Dashboard doc.
The Desktop App and Web Dashboard remote-connect instructions told users
to start the backend with `hermes dashboard --no-open --insecure --host
0.0.0.0`, omitting --tui. Without --tui the embedded-chat WebSockets
(/api/ws, /api/pty) are refused, so the desktop passes the /api/status
health check and reports the backend "ready" — but chat never works
because the socket is closed on connect.
- Add --tui to both backend command blocks (with an inline why-comment).
- Explain that the desktop chat runs over /api/ws + /api/pty and needs
the embedded-chat surface enabled; a plain dashboard/gateway is not
enough.
- Add a troubleshooting entry for the exact symptom (connects, says
ready, chat dead) on both pages.
The section explained why the Session token is hidden but punted the actual
setup steps to the web-dashboard page via a link — a bounce for someone on
the Desktop App page trying to connect. Inline the concrete steps instead:
backend command block (mint token -> .env -> hermes dashboard --insecure),
the in-app Remote gateway steps, the env-var override, Tailscale guidance,
and a troubleshooting list. Keep a short pointer to the web-dashboard page
for the same setup from that angle.
The Desktop App page covered install, settings, and chat but not how to
connect the app to a backend on another machine — the exact thing
@PedjaDrazic asked about. Add a 'Connecting to a remote backend' section
that explains the Session token is the dashboard token Hermes never
surfaces (pin it via HERMES_DASHBOARD_SESSION_TOKEN + run --insecure),
and link to the web-dashboard page for the full backend setup rather than
duplicating it. Add a reciprocal link from the web-dashboard remote section
back to the Desktop App page.
Add a SHA-256 content-hash based build stamp to `hermes desktop` so
unchanged source trees skip the npm install + build step. Uses pathspec
for .gitignore-aware file matching instead of a hardcoded skip-list.
New CLI flags:
- --build-only: run the build but don't launch the app
- --force-build: rebuild even when the stamp matches
`hermes update` now calls `hermes desktop --build-only` so the
desktop app is rebuilt (if needed) as part of the update flow.
16/16 tests passing.
The native Electron desktop app shipped (PR #20059 and follow-ups) but the
docs only told people how to download it, not what it is or how to use it.
Adds website/docs/user-guide/desktop.md covering install (installer +
prebuilt + Windows GUI), the chat-first UI and management panes, the
hermes desktop CLI flag reference, self-update, how-it-works, and
troubleshooting. Sourced from apps/desktop/README.md, routes.ts, and the
real argparse. Wired into sidebars.ts under Interfaces after the TUI.