What happened?
spawn list → Enter Hermes Agent always opens http://localhost:9119/ (SSH -L 9119:127.0.0.1:9119) but the reconnect path never starts the Hermes dashboard on the VM. The browser tab is blank / connection reset by peer. The CLI TUI still works over SSH.
This is not a missing user step. Spawn's Hermes recipe already knows it must start the dashboard:
packages/cli/src/shared/agent-setup.ts → startHermesDashboard() (nohup/setsid hermes dashboard --port 9119 --host 127.0.0.1 --no-open)
- Hermes agent config sets
preLaunch: () => startHermesDashboard(runner) plus tunnel.remotePort: 9119
That preLaunch hook does not run on spawn list reconnect. History metadata still has tunnel_remote_port=9119 / tunnel_browser_url_template=http://localhost:__PORT__/, so connect opens the browser anyway.
Related: #3293 (tunnel piping, shipped) and #3407 (provision-time hermes dashboard start is already flaky on DigitalOcean). This report is the reconnect gap, which #3407 does not cover.
Steps to Reproduce
- Have an existing DigitalOcean Hermes spawn (not a fresh
spawn hermes digitalocean).
spawn list → select it → Enter Hermes Agent.
- Spawn prints
If the browser didn't open, visit: http://localhost:9119/ and opens a tab.
- Observe: tunnel process is
ssh -N -L 9119:127.0.0.1:9119 root@<vm>, launch cmd is just hermes (TUI). No startHermesDashboard / no hermes dashboard on the VM.
curl http://127.0.0.1:9119 → connection reset. ss -lptn on the VM: nothing on :9119.
Expected Behavior
Before opening the browser, reconnect should run the same preLaunch as first provision: start (or detect) hermes dashboard on 127.0.0.1:9119, wait until it listens, then open the tab. If start fails, don't open a dead URL (or say the TUI is the only surface).
Actual Behavior
Tunnel + browser open immediately. Dashboard is not started. Failures in startHermesDashboard() are already non-fatal (Hermes web dashboard failed to start — TUI still available), so a first-provision miss plus a reconnect that never retries leaves :9119 dead forever.
Two extra landmines that make the 60s wait in startHermesDashboard() miss even when preLaunch does run:
- First
hermes dashboard may npm run build the SPA (web_dist missing). That can exceed 60s.
- Dashboard is session-scoped nohup, not systemd (comment in
startHermesDashboard says this is intentional vs OpenClaw). Reboot or a dead nohup process → nothing listening, and reconnect does not restart it.
Environment
- spawn v1.1.1 (darwin arm64, bun 1.3.6)
- Agent: hermes / cloud: digitalocean
- Remote Hermes: v0.21.3 (dashboard subcommand does exist; fastapi/uvicorn/ptyprocess present)
- Local: macOS,
spawn list reconnect (not a fresh provision)
Workaround
On the VM (loopback only):
cd ~/.hermes/hermes-agent/web && npm run build # if web_dist missing
hermes dashboard --host 127.0.0.1 --port 9119 --no-open --skip-build
Persist with a user systemd unit if you want it to survive reboot. After that, Spawn's existing tunnel serves http://localhost:9119/ (HTTP 200, title "Hermes Agent - Dashboard").
Suggested fix
In the spawn list / connect path: call startHermesDashboard() (or generic preLaunch) before openBrowser(). Probe :9119 first. If the SPA isn't built, either pre-build during install or pass --skip-build only after web_dist exists — don't burn the 60s wait on a first-time Vite build. Optionally persist the dashboard like OpenClaw's gateway so reconnect isn't required to resurrect it.
What happened?
spawn list→ Enter Hermes Agent always openshttp://localhost:9119/(SSH-L 9119:127.0.0.1:9119) but the reconnect path never starts the Hermes dashboard on the VM. The browser tab is blank /connection reset by peer. The CLI TUI still works over SSH.This is not a missing user step. Spawn's Hermes recipe already knows it must start the dashboard:
packages/cli/src/shared/agent-setup.ts→startHermesDashboard()(nohup/setsidhermes dashboard --port 9119 --host 127.0.0.1 --no-open)preLaunch: () => startHermesDashboard(runner)plustunnel.remotePort: 9119That
preLaunchhook does not run onspawn listreconnect. History metadata still hastunnel_remote_port=9119/tunnel_browser_url_template=http://localhost:__PORT__/, so connect opens the browser anyway.Related: #3293 (tunnel piping, shipped) and #3407 (provision-time
hermes dashboardstart is already flaky on DigitalOcean). This report is the reconnect gap, which #3407 does not cover.Steps to Reproduce
spawn hermes digitalocean).spawn list→ select it → Enter Hermes Agent.If the browser didn't open, visit: http://localhost:9119/and opens a tab.ssh -N -L 9119:127.0.0.1:9119 root@<vm>, launch cmd is justhermes(TUI). NostartHermesDashboard/ nohermes dashboardon the VM.curl http://127.0.0.1:9119→ connection reset.ss -lptnon the VM: nothing on:9119.Expected Behavior
Before opening the browser, reconnect should run the same
preLaunchas first provision: start (or detect)hermes dashboardon127.0.0.1:9119, wait until it listens, then open the tab. If start fails, don't open a dead URL (or say the TUI is the only surface).Actual Behavior
Tunnel + browser open immediately. Dashboard is not started. Failures in
startHermesDashboard()are already non-fatal (Hermes web dashboard failed to start — TUI still available), so a first-provision miss plus a reconnect that never retries leaves:9119dead forever.Two extra landmines that make the 60s wait in
startHermesDashboard()miss even whenpreLaunchdoes run:hermes dashboardmaynpm run buildthe SPA (web_distmissing). That can exceed 60s.startHermesDashboardsays this is intentional vs OpenClaw). Reboot or a dead nohup process → nothing listening, and reconnect does not restart it.Environment
spawn listreconnect (not a fresh provision)Workaround
On the VM (loopback only):
Persist with a user systemd unit if you want it to survive reboot. After that, Spawn's existing tunnel serves
http://localhost:9119/(HTTP 200, title "Hermes Agent - Dashboard").Suggested fix
In the
spawn list/ connect path: callstartHermesDashboard()(or genericpreLaunch) beforeopenBrowser(). Probe:9119first. If the SPA isn't built, either pre-build during install or pass--skip-buildonly afterweb_distexists — don't burn the 60s wait on a first-time Vite build. Optionally persist the dashboard like OpenClaw's gateway so reconnect isn't required to resurrect it.