Skip to content

fix(desktop): derive SSH lock/token/log paths from remote HERMES_HOME - #69615

Open
francois352 wants to merge 2 commits into
NousResearch:mainfrom
francois352:fix/desktop-ssh-remote-hermes-home
Open

fix(desktop): derive SSH lock/token/log paths from remote HERMES_HOME#69615
francois352 wants to merge 2 commits into
NousResearch:mainfrom
francois352:fix/desktop-ssh-remote-hermes-home

Conversation

@francois352

Copy link
Copy Markdown

Problem

Desktop's SSH remote lifecycle hardcodes ~/.hermes/desktop-ssh for its lock/token/log state (REMOTE_LOCK_DIR). When the remote host runs Hermes with a custom HERMES_HOME (e.g. /root/hermes-data), the Desktop uploads the one-time SSH session token under ~/.hermes/... while the backend expects its state under the custom home — so the backend rejects the token and the connection fails with an auth error on every attempt.

Fix

Derive the lock, token and log paths from the remote HERMES_HOME already returned by probeRemoteHermesHome(), threaded through as a parameter (no mutable global state). DEFAULT_REMOTE_HERMES_HOME = '~/.hermes' remains the fallback so behavior is unchanged for default-home remotes, and the probed value passes validateRemotePath before use.

Testing

  • 64 focused tests in remote-lifecycle.test.ts pass (includes new cases for custom-home path derivation)
  • tsc -p tsconfig.electron.json --noEmit clean
  • eslint clean on both files
  • Verified end-to-end against a real remote with HERMES_HOME=/root/hermes-data: token adopted (file removed after adoption), lock/log created under the custom home, backend spawned --isolated on loopback and correctly reused across Desktop reconnects

Notes for reviewers

  • Pre-existing lockfiles under the old hardcoded path fail the logPath equality check and are treated as absent (clean respawn); they are not migrated or deleted.
  • The helpers keep a default hermesHome parameter for the exported test surface; if you prefer, we can make it required on the internal call chain to prevent future call-sites silently regressing to ~/.hermes.

🤖 Generated with Claude Code

Copilot AI review requested due to automatic review settings July 22, 2026 20:55

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes Hermes Desktop’s SSH remote lifecycle by ensuring Desktop’s remote lock/token/log artifacts are created under the remote host’s actual HERMES_HOME, rather than a hardcoded ~/.hermes/desktop-ssh. This aligns Desktop’s upload/lock/log locations with where the remote Hermes backend expects to find its SSH session token and related state, avoiding repeated auth failures on remotes configured with a custom HERMES_HOME.

Changes:

  • Derive the remote desktop-ssh lock/token/log root from the probed HERMES_HOME, and thread it through the lifecycle helpers instead of using a hardcoded directory.
  • Validate the probed remote home path before using it.
  • Add a unit test covering custom-home path derivation to prevent regressions.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
apps/desktop/electron/remote-lifecycle.ts Derives lock/token/log paths from probed remote HERMES_HOME and threads it through lifecycle helpers.
apps/desktop/electron/remote-lifecycle.test.ts Adds coverage ensuring custom remote HERMES_HOME is used for lock/token/log paths.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +85 to 87
function lockRootDir(hermesHome) {
return `${hermesHome || DEFAULT_REMOTE_HERMES_HOME}/desktop-ssh`
}
@alt-glitch alt-glitch added type/bug Something isn't working P2 Medium — degraded but workaround exists comp/desktop Electron desktop app (apps/desktop/*) backend/ssh SSH remote execution area/config Config system, migrations, profiles sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades labels Jul 22, 2026
Desktop hardcoded ~/.hermes/desktop-ssh for SSH lifecycle state; VPS2 uses
HERMES_HOME=/root/hermes-data, so the backend rejected the one-time token
uploaded under the wrong home. Derive lock/token/log paths from the probed
remote HERMES_HOME without mutable global state.

Beast3 local patch, commissioning 2026-07-22. Not pushed upstream.
@francois352
francois352 force-pushed the fix/desktop-ssh-remote-hermes-home branch 2 times, most recently from 94dc966 to b449212 Compare July 23, 2026 18:58
…e backend

The detached setsid spawn does not reliably inherit exec-channel env
(ssh-config SetEnv), and newer backends validate --ssh-session-token-file
against $HERMES_HOME/desktop-ssh. Passing the probed home explicitly makes
the spawn transport-agnostic.
@francois352
francois352 force-pushed the fix/desktop-ssh-remote-hermes-home branch from b449212 to f25213b Compare July 23, 2026 19:00

@teknium1 teknium1 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for addressing the custom remote HERMES_HOME path mismatch. The path threading and explicit detached-process HERMES_HOME propagation address the verified backend validation contract in hermes_cli/main.py:9974-9978.

Problems

  • apps/desktop/electron/remote-lifecycle.ts:333 rejects a pre-PR default-home lock whose persisted logPath is ~/.hermes/... when the probe returns the equivalent /home/<user>/.hermes. Because connect() receives null, it cannot call cleanupStale() before spawning and overwriting the ownership record. Current fixtures demonstrate both representations at remote-lifecycle.test.ts:44-45 and :507.

Suggested changes

  • Accept or migrate that legacy default-home representation when it maps to the same probed lock root, preserving reuse or safe cleanup.
  • Add a regression test for a legacy lock plus an absolute default-home probe result.

Automated hermes-sweeper review.

}

if (parsed.logPath !== spawnLogPath(ownershipId, parsed.spawnNonce)) {
if (parsed.logPath !== spawnLogPath(ownershipId, parsed.spawnNonce, hermesHome)) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A pre-PR default-home lock stores logPath as ~/.hermes/..., while the probe may return the equivalent /home/<user>/.hermes. This equality then rejects a live valid lock before connect() can reuse or clean it, causing a fresh backend to overwrite its record. Please accept or migrate the safe legacy default-home representation and cover that upgrade path.

@teknium1 teknium1 added the sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform label Jul 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/config Config system, migrations, profiles backend/ssh SSH remote execution comp/desktop Electron desktop app (apps/desktop/*) P2 Medium — degraded but workaround exists sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants