# NousResearch/hermes-agent · Desktop remote backend file/path integration issues

## Open now

- 2 issues, 0 PRs open on GitHub.
- #38369: Desktop Remote Gateway should make Terminal/File Explorer execution target explicit
- #39553: \[Feature\]: Desktop Remote - working directory and terminal show server file/process

These issues and PRs address problems and feature work around the Desktop app's file browser, plugin resolution, and terminal when connected to remote or WSL backends — including ENOENT errors from mismatched local/remote paths, folder picker bridging, and remote workspace support.

## TL;DR

- 19 member(s): 2 open issue(s), 7 closed issue(s), 0 open PR(s), 3 merged PR(s), 7 PR(s) closed without merging.
- A fix was merged to main in PR #44326. Verify it addresses your case.
- **Recommended:** read PR #44326 (and any competing PRs below) before filing. Confirm the merged change covers your symptom.

## Maintainer resolution verdict

- Internal-tracker verdict over this cluster's issue members: `partially_resolved` · deciding PR(s): `pr-44326,pr-73926`. This is distinct from the fix status above. Weigh it yourself.

## How this cluster was grouped

- Link evidence (`STRUCTURAL_PARTIAL`): some members are connected by structural evidence (shared changed files, or a closing/superseded reference); the rest are joined by an automated relevance judgement over their text.
- Members outside that structural core may belong to a different underlying problem.
- Pairwise link density `0.09`: the share of member pairs that carry a link, counting a structural link in full and a relevance-only link at 0.36. `1.00` means every pair is linked.

## Open related issues

- #38369: Desktop Remote Gateway should make Terminal/File Explorer execution target explicit
- #39553: \[Feature\]: Desktop Remote - working directory and terminal show server file/process

## Closed / duplicate issues

- #38671: Desktop Remote Gateway should support a true remote workspace/file browser
- #42431: Desktop Files panel reads local filesystem but defaults to remote session cwd → always ENOENT in remote mode
- #42878: \[Bug\]: Desktop file browser shows 'unreadable' (ENOENT) when connected to remote gateway — reads server cwd on local filesystem
- #43042: Desktop file browser ENOENT: session.info CWD overwrite ignores local filesystem
- #43270: \[Bug\]: Desktop file browser ENOENT when connected to WSL backend — Electron reads WSL paths that Node.js Windows cannot resolve
- #66899: Desktop runtime plugins cannot resolve their local directory with a remote backend
- #68267: Desktop disk plugins disappear in remote gateway mode

## Prior & competing PRs

- **#42936: fix(desktop): show clear message for file browser in remote gateway mode**. closed without merge · fix tier `suggested`
  - maintainer direction: category `superseded_by_pr`; implication `superseded`; refs `#42497`, `#42878`, `#42497`, `#42497`
  - _suggested-tier fix detail withheld; re-request with `?tier=all` to include it._
- **#43069: fix(desktop): guard CWD overwrite from remote session.info events**. closed without merge · fix tier `suggested`
  - maintainer direction: category `superseded_by_pr`; implication `superseded`; refs `8878484f85192a0d443a4c856b8e9f424ac46d2c`, `#43042`, `#42878`
  - _suggested-tier fix detail withheld; re-request with `?tier=all` to include it._
- **#44326: feat(desktop): browse remote backend files (salvage #43434)**. merged to main · fix tier `verified`
  - maintainer direction: category `merged`; implication `superseded`
  - files: `apps/desktop/src/app/chat/right-rail/preview-file.tsx`, `apps/desktop/src/app/chat/right-rail/preview-pane.test.tsx`, `apps/desktop/src/app/chat/right-rail/preview-pane.tsx`, `apps/desktop/src/app/gateway/hooks/use-gateway-boot.ts`, `apps/desktop/src/app/right-sidebar/files/ipc.ts`, `apps/desktop/src/app/right-sidebar/files/remote-picker.tsx`, `apps/desktop/src/app/right-sidebar/files/use-project-tree.test.ts`, `apps/desktop/src/app/right-sidebar/files/use-project-tree.ts`, `apps/desktop/src/app/right-sidebar/index.tsx`, `apps/desktop/src/i18n/en.ts`, `apps/desktop/src/i18n/ja.ts`, `apps/desktop/src/i18n/types.ts`, `apps/desktop/src/i18n/zh-hant.ts`, `apps/desktop/src/i18n/zh.ts`, `apps/desktop/src/lib/desktop-fs.test.ts`, `apps/desktop/src/lib/desktop-fs.ts`, `apps/desktop/src/lib/local-preview.ts`, `apps/desktop/src/store/session.test.ts`, `apps/desktop/src/store/session.ts`, `hermes_cli/web_server.py` (+1 more)
  - fix hunks:
  - `apps/desktop/src/app/chat/right-rail/preview-file.tsx`

    ```diff
    @@ -13,6 +13,7 @@ import { Streamdown } from 'streamdown'
     import { HERMES_PATHS_MIME } from '@/app/chat/hooks/use-composer-actions'
     import { PageLoader } from '@/components/page-loader'
     import { translateNow, useI18n } from '@/i18n'
    +import { readDesktopFileDataUrl, readDesktopFileText } from '@/lib/desktop-fs'
     import { cn } from '@/lib/utils'
     import type { PreviewTarget } from '@/store/preview'
     
    ```

    ```diff
    @@ -180,15 +181,13 @@ function looksBinaryBytes(bytes: Uint8Array) {
     }
     
     async function readTextPreview(filePath: string) {
    -  if (window.hermesDesktop.readFileText) {
    -    try {
    -      return await window.hermesDesktop.readFileText(filePath)
    -    } catch (error) {
    -      const message = error instanceof Error ? error.message : String(error)
    -
    -      if (!message.includes("No handler registered for 'hermes:readFileText'")) {
    -        throw error
    -      }
    +  try {
    +    return await readDesktopFileText(filePath)
    +  } catch (error) {
    +    const message = error instanceof Error ? error.message : String(error)
    +
    +    if (!message.includes("No handler registered for 'hermes:readFileText'")) {
    +      throw error
         }
       }
     
    ```

    ```diff
    @@ -448,7 +447,7 @@ export function LocalFilePreview({ reloadKey, target }: { reloadKey: number; tar
             if (isImage) {
               // Prefer bytes the caller already handed us (a pasted/dropped
               // screenshot) over re-reading a path that may be transient/unreadable.
    -          const dataUrl = target.dataUrl || (await window.hermesDesktop.readFileDataUrl(filePath))
    +          const dataUrl = target.dataUrl || (await readDesktopFileDataUrl(filePath))
     
               if (active) {
                 setState({ dataUrl, loading: false })
    ```
  - `apps/desktop/src/app/chat/right-rail/preview-pane.test.tsx`

    ```diff
    @@ -1,11 +1,50 @@
     import { act, cleanup, render } from '@testing-library/react'
    -import { afterEach, describe, expect, it, vi } from 'vitest'
    +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
    +
    +import { $connection } from '@/store/session'
     
     import { PreviewPane } from './preview-pane'
     
     describe('PreviewPane console state', () => {
    +  beforeEach(() => {
    +    vi.stubGlobal('requestAnimationFrame', (callback: FrameRequestCallback) => window.setTimeout(() => callback(Date.now()), 0))
    +    vi.stubGlobal('cancelAnimationFrame', (id: number) => window.clearTimeout(id))
    +  })
    +
       afterEach(() => {
         cleanup()
    +    $connection.set(null)
    +    vi.unstubAllGlobals()
    +  })
    +
    +  it('does not watch backend-only remote filesystem previews locally', () => {
    +    const watchPreviewFile = vi.fn(async () => ({ id: 'watch-1', path: '/remote/file.txt' }))
    +    const onPreviewFileChanged = vi.fn(() => vi.fn())
    +    $connection.set({ mode: 'remote' } as never)
    +    vi.stubGlobal('window', {
    +      ...window,
    +      hermesDesktop: {
    +        onPreviewFileChanged,
    +        watchPreviewFile
    +      }
    +    })
    +
    +    render(
    +      <PreviewPane
    +        setTitlebarToolGroup={vi.fn()}
    +        target={{
    +          kind: 'file',
    +          label: 'file.txt',
    +          path: '/remote/file.txt',
    +          previewKind: 'text',
    +          source: '/remote/file.txt',
    +          url: 'file:///remote/file.txt'
    +        }}
    +      />
    +    )
    +
    +    expect(watchPreviewFile).not.toHaveBeenCalled()
    +    expect(onPreviewFileChanged).not.toHaveBeenCalled()
       })
     
       it('does not rebuild the pane titlebar group for streamed console logs', () => {
    ```
  - `apps/desktop/src/app/chat/right-rail/preview-pane.tsx`

    ```diff
    @@ -5,6 +5,7 @@ import { useCallback, useEffect, useRef, useState } from 'react'
     import type { SetTitlebarToolGroup, TitlebarTool } from '@/app/shell/titlebar-controls'
     import { Tip } from '@/components/ui/tooltip'
     import { type Translations, useI18n } from '@/i18n'
    +import { isDesktopFsRemoteMode } from '@/lib/desktop-fs'
     import { Bug } from '@/lib/icons'
     import { cn } from '@/lib/utils'
     import { notify, notifyError } from '@/store/notifications'
    ```

    ```diff
    @@ -406,6 +407,7 @@ export function PreviewPane({
       useEffect(() => {
         if (
           target.kind !== 'file' ||
    +      isDesktopFsRemoteMode() ||
           !window.hermesDesktop?.watchPreviewFile ||
           !window.hermesDesktop?.onPreviewFileChanged
         ) {
    ```
  - `apps/desktop/src/app/gateway/hooks/use-gateway-boot.ts`

    ```diff
    @@ -3,6 +3,7 @@ import { useEffect, useRef } from 'react'
     import type { HermesConnection } from '@/global'
     import { HermesGateway } from '@/hermes'
     import { translateNow } from '@/i18n'
    +import { desktopDefaultCwd } from '@/lib/desktop-fs'
     import { isGatewayReauthRequired, resolveGatewayWsUrl } from '@/lib/gateway-ws-url'
     import {
       $desktopBoot,
    ```

    ```diff
    @@ -25,12 +26,16 @@ import {
     import { notify, notifyError } from '@/store/notifications'
     import { $activeGatewayProfile, normalizeProfileKey, touchActiveGatewayBackend } from '@/store/profile'
     import {
    +  $activeSessionId,
       $attentionSessionIds,
       $connection,
    +  $currentCwd,
       $sessions,
       $workingSessionIds,
       ensureDefaultWorkspaceCwd,
       setConnection,
    +  setCurrentBranch,
    +  setCurrentCwd,
       setSessionsLoading
     } from '@/store/session'
     import type { RpcEvent } from '@/types/hermes'
    ```

    ```diff
    @@ -353,6 +358,11 @@ export function useGatewayBoot({
               progress: 97
             })
             await ensureDefaultWorkspaceCwd()
    +        const remoteDefault = await desktopDefaultCwd().catch(() => null)
    +        if (remoteDefault?.cwd && !$activeSessionId.get() && !$currentCwd.get()) {
    +          setCurrentCwd(remoteDefault.cwd)
    +          setCurrentBranch(remoteDefault.branch || '')
    +        }
             await callbacksRef.current.refreshHermesConfig()
     
             if (cancelled) {
    ```
  - `apps/desktop/src/app/right-sidebar/files/ipc.ts`

    ```diff
    @@ -1,5 +1,6 @@
     import ignore from 'ignore'
     
    +import { desktopFsCacheKey, desktopGitRoot, readDesktopDir, readDesktopFileDataUrl } from '@/lib/desktop-fs'
     import type { HermesReadDirEntry, HermesReadDirResult } from '@/global'
     
     export type ProjectTreeEntry = HermesReadDirEntry
    ```

    ```diff
    @@ -63,15 +64,11 @@ function ancestorDirs(root: string, dir: string) {
     }
     
     async function gitRootFor(start: string) {
    -  if (!window.hermesDesktop?.gitRoot) {
    -    return null
    -  }
    -
    -  const key = clean(start)
    +  const key = `${desktopFsCacheKey()}:${clean(start)}`
       let cached = gitRootCache.get(key)
     
       if (!cached) {
    -    cached = window.hermesDesktop.gitRoot(key)
    +    cached = desktopGitRoot(start)
         gitRootCache.set(key, cached)
       }
     
    ```

    ```diff
    @@ -80,18 +77,14 @@ async function gitRootFor(start: string) {
     
     /** Read .gitignore at `dir` if it actually exists — never probe missing files. */
     async function readGitignore(dir: string): Promise<GitignoreRule | null> {
    -  if (!window.hermesDesktop?.readDir || !window.hermesDesktop.readFileDataUrl) {
    -    return null
    -  }
    -
       try {
    -    const listing = await window.hermesDesktop.readDir(dir)
    +    const listing = await readDesktopDir(dir)
     
         if (!listing.entries.some(e => e.name === '.gitignore' && !e.isDirectory)) {
           return null
         }
     
    -    const text = decodeDataUrl(await window.hermesDesktop.readFileDataUrl(`${dir}/.gitignore`))
    +    const text = decodeDataUrl(await readDesktopFileDataUrl(`${dir}/.gitignore`))
     
         return { base: dir, ig: ignore().add(text) }
       } catch {
    ```

    ```diff
    @@ -100,11 +93,11 @@ async function readGitignore(dir: string): Promise<GitignoreRule | null> {
     }
     
     async function gitignoreFor(dir: string) {
    -  const key = clean(dir)
    +  const key = `${desktopFsCacheKey()}:${clean(dir)}`
       let cached = gitignoreCache.get(key)
     
       if (!cached) {
    -    cached = readGitignore(key)
    +    cached = readGitignore(clean(dir))
         gitignoreCache.set(key, cached)
       }
     
    ```

    ```diff
    @@ -142,9 +135,10 @@ export async function readProjectDir(dirPath: string, rootPath = dirPath): Promi
         return { entries: [], error: 'no-bridge' }
       }
     
    -  const result = await window.hermesDesktop.readDir(dirPath)
    +  const result = await readDesktopDir(dirPath)
    +  const entries = result?.entries ?? []
     
    -  return { ...result, entries: await filterIgnored(result.entries, rootPath, dirPath) }
    +  return { ...result, entries: await filterIgnored(entries, rootPath, dirPath) }
     }
     
     export function clearProjectDirCache(rootPath?: string) {
    ```

    ```diff
    @@ -155,7 +149,7 @@ export function clearProjectDirCache(rootPath?: string) {
         return
       }
     
    -  const key = clean(rootPath)
    +  const key = `${desktopFsCacheKey()}:${clean(rootPath)}`
       gitRootCache.delete(key)
       gitignoreCache.delete(key)
     }
    ```
  - `apps/desktop/src/app/right-sidebar/files/remote-picker.tsx`

    ```diff
    @@ -0,0 +1,177 @@
    +import { useEffect, useMemo, useState } from 'react'
    +
    +import { Button } from '@/components/ui/button'
    +import { Codicon } from '@/components/ui/codicon'
    +import { Dialog, DialogContent, DialogDescription, DialogTitle } from '@/components/ui/dialog'
    +import { useI18n } from '@/i18n'
    +import { readDesktopDir, setDesktopFsRemotePicker } from '@/lib/desktop-fs'
    +import { cn } from '@/lib/utils'
    +
    +function clean(path: string) {
    +  return path.replace(/\/+$/, '') || '/'
    +}
    +
    +function parentDir(path: string) {
    +  const value = clean(path)
    +  if (value === '/') {
    +    return '/'
    +  }
    +  const parent = value.slice(0, value.lastIndexOf('/'))
    +  return parent || '/'
    +}
    +
    +function pathName(path: string) {
    +  return path.split('/').filter(Boolean).pop() || path
    +}
    +
    +interface PendingSelection {
    +  defaultPath: string
    +  resolve: (paths: string[]) => void
    +  title: string
    +}
    +
    +export function RemoteFolderPicker() {
    +  const { t } = useI18n()
    +  const r = t.rightSidebar
    +  const [pending, setPending] = useState<PendingSelection | null>(null)
    +  const [currentPath, setCurrentPath] = useState('/')
    +  const [entries, setEntries] = useState<Array<{ name: string; path: string }>>([])
    +  const [error, setError] = useState<string | null>(null)
    +  const [loading, setLoading] = useState(false)
    +
    +  useEffect(() => {
    +    setDesktopFsRemotePicker({
    +      selectPaths: options =>
    +        new Promise(resolve => {
    +          const defaultPath = clean(options?.defaultPath || '/')
    +          setCurrentPath(defaultPath)
    +          setPending({ defaultPath, resolve, title: options?.title || r.remotePickerTitle })
    +        })
    +    })
    +    return () => setDesktopFsRemotePicker(null)
    +  }, [r.remotePickerTitle])
    +
    +  useEffect(() => {
    +    if (!pending) {
    +      return
    +    }
    +
    +    let active = true
    +    setLoading(true)
    +    setError(null)
    +
    +    void readDesktopDir(currentPath)
    +      .then(result => {
    +        if (!active) {
    +          return
    +        }
    +        if (result.error) {
    +          setError(result.error)
    +          setEntries([])
    +          return
    +        }
    +        setEntries(result.entries.filter(entry => entry.isDirectory).map(entry => ({ name: entry.name, path: entry.path })))
    +      })
    +      .catch(err => {
    +        if (active) {
    +          setError(err instanceof Error ? err.message : String(err))
    +          setEntries([])
    +        }
    +      })
    +      .finally(() => {
    +        if (active) {
    +          setLoading(false)
    +        }
    +      })
    +
    +    return () => {
    +      active = false
    +    }
    +  }, [currentPath, pending])
    +
    +  const crumbs = useMemo(() => {
    +    const parts = clean(currentPath).split('/').filter(Boolean)
    +    const out = [{ label: '/', path: '/' }]
    +    let acc = ''
    +    for (const part of parts) {
    +      acc += `/${part}`
    +      out.push({ label: part, path: acc })
    +    }
    +    return out
    +  }, [currentPath])
    +
    +  const close = (paths: string[] = []) => {
    +    pending?.resolve(paths)
    +    setPending(null)
    +    setEntries([])
    +    setError(null)
    +  }
    +
    +  return (
    +    <Dialog onOpenChange={open => !open && close()} open={Boolean(pending)}>
    +      <DialogContent className="max-w-lg gap-0 overflow-hidden p-0">
    +        <div className="border-b border-border/70 px-4 py-3">
    +          <DialogTitle className="text-sm">{pending?.title || r.remotePickerTitle}</DialogTitle>
    +          <DialogDescription className="mt-1 text-xs">{r.remotePickerDescription}</DialogDescription>
    +        </div>
    +
    +        <div className="flex min-h-[22rem] flex-col">
    +          <div className="flex flex-wrap items-center gap-1 border-b border-border/50 px-3 py-2 text-xs text-muted-foreground">
    +            {crumbs.map((crumb, index) => (
    +              <button
    +                className={cn('rounded px-1.5 py-0.5 hover:bg-muted hover:text-foreground', index === crumbs.length - 1 && 'text-foreground')}
    +                key={crumb.path}
    +                onClick={() => setCurrentPath(crumb.path)}
    +                type="button"
    +              >
    +                {crumb.label}
    +              </button>
    +            ))}
    +          </div>
    +
    +          <div className="min-h-0 flex-1 overflow-y-auto p-2">
    +            <FolderRow disabled={currentPath === '/'} name=".." onClick={() => setCurrentPath(parentDir(currentPath))} />
    +            {loading ? (
    +              <div className="flex items-center gap-2 px-2 py-3 text-xs text-muted-foreground">
    +                <Codicon name="loading" size="0.8rem" spinning />
    +                {r.loadingFiles}
    +              </div>
    +            ) : error ? (
    +              <div className="px-2 py-3 text-xs text-destructive">{r.unreadableBody(error)}</div>
    +            ) : entries.length === 0 ? (
    +              <div className="px-2 py-3 text-xs text-muted-foreground">{r.emptyBody}</div>
    +            ) : (
    +              entries.map(entry => <FolderRow key={entry.path} name={pathName(entry.path)} onClick={() => setCurrentPath(entry.path)} />)
    +            )}
    +          </div>
    +        </div>
    +
    +        <div className="flex items-center justify-between gap-2 border-t border-border/70 px-4 py-3">
    +          <div className="min-w-0 truncate text-xs text-muted-foreground">{currentPath}</div>
    +          <div className="flex shrink-0 items-center gap-2">
    +            <Button onClick={() => close()} size="sm" variant="ghost">
    +              {t.common.cancel}
    +            </Button>
    +            <Button onClick={() => close([currentPath])} size="sm">
    +              {r.remotePickerSelect}
    +            </Button>
    +          </div>
    +        </div>
    +      </DialogContent>
    +    </Dialog>
    +  )
    +}
    +
    +function FolderRow({ disabled = false, name, onClick }: { disabled?: boolean; name: string; onClick: () => void }) {
    +  return (
    +    <button
    +      className="flex w-full items-center gap-2 rounded-md px-2 py-1.5 text-left text-xs text-(--ui-text-secondary) hover:bg-(--ui-row-hover-background) hover:text-foreground disabled:pointer-events-none disabled:opacity-40"
    +      disabled={disabled}
    +      onClick={onClick}
    +      type="button"
    +    >
    +      <Codicon name="folder" size="0.875rem" />
    +      <span className="min-w-0 truncate">{name}</span>
    +    </button>
    +  )
    +}
    ```
  - `apps/desktop/src/app/right-sidebar/files/use-project-tree.test.ts`

    ```diff
    @@ -1,19 +1,24 @@
    -import { act, renderHook, waitFor } from '@testing-library/react'
    +import { act, cleanup, renderHook, waitFor } from '@testing-library/react'
     import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
     
    +import { $connection } from '@/store/session'
     import type { HermesReadDirResult } from '@/global'
     
    +import { clearProjectDirCache, readProjectDir } from './ipc'
     import { resetProjectTreeState, useProjectTree } from './use-project-tree'
     
     const readDir = vi.fn<(path: string) => Promise<HermesReadDirResult>>()
     
     beforeEach(() => {
    +  $connection.set(null)
       resetProjectTreeState()
       readDir.mockReset()
       ;(window as unknown as { hermesDesktop: { readDir: typeof readDir } }).hermesDesktop = { readDir }
     })
     
     afterEach(() => {
    +  cleanup()
    +  $connection.set(null)
       resetProjectTreeState()
       delete (window as unknown as { hermesDesktop?: unknown }).hermesDesktop
     })
    ```

    ```diff
    @@ -106,6 +111,36 @@ describe('useProjectTree', () => {
         expect(readDir).toHaveBeenCalledTimes(1)
       })
     
    +  it('reads gitignore from the real path while caching per connection', async () => {
    +    const readFileDataUrl = vi.fn(async () => `data:text/plain;base64,${btoa('ignored.log\n')}`)
    +    const gitRoot = vi.fn(async () => '/repo')
    +    readDir.mockImplementation(async path => {
    +      if (path === '/repo') return ok([{ name: '.gitignore', path: '/repo/.gitignore', isDirectory: false }])
    +      if (path === '/repo/src') {
    +        return ok([
    +          { name: 'app.ts', path: '/repo/src/app.ts', isDirectory: false },
    +          { name: 'ignored.log', path: '/repo/src/ignored.log', isDirectory: false }
    +        ])
    +      }
    +      throw new Error(`unexpected path ${path}`)
    +    })
    +    ;(window as unknown as { hermesDesktop: unknown }).hermesDesktop = { gitRoot, readDir, readFileDataUrl }
    +
    +    $connection.set({ baseUrl: 'local-a', mode: 'local' } as never)
    +    await expect(readProjectDir('/repo/src', '/repo')).resolves.toMatchObject({
    +      entries: [{ name: 'app.ts', path: '/repo/src/app.ts', isDirectory: false }]
    +    })
    +    expect(readDir).toHaveBeenCalledWith('/repo')
    +    expect(readDir).not.toHaveBeenCalledWith(expect.stringContaining('local-a'))
    +
    +    $connection.set({ baseUrl: 'local-b', mode: 'local' } as never)
    +    clearProjectDirCache()
    +    await expect(readProjectDir('/repo/src', '/repo')).resolves.toMatchObject({
    +      entries: [{ name: 'app.ts', path: '/repo/src/app.ts', isDirectory: false }]
    +    })
    +    expect(readDir.mock.calls.filter(([path]) => path === '/repo')).toHaveLength(2)
    +  })
    +
       it('captures per-folder error code and shows an error placeholder child', async () => {
         readDir.mockResolvedValueOnce(ok([{ name: 'priv', path: '/p/priv', isDirectory: true }]))
         readDir.mockResolvedValueOnce({ entries: [], error: 'EACCES' })
    ```
  - `apps/desktop/src/app/right-sidebar/files/use-project-tree.ts`

    ```diff
    @@ -2,6 +2,8 @@ import { useStore } from '@nanostores/react'
     import { atom } from 'nanostores'
     import { useCallback, useEffect, useMemo } from 'react'
     
    +import { $connection } from '@/store/session'
    +
     import { clearProjectDirCache, readProjectDir } from './ipc'
     
     export interface TreeNode {
    ```

    ```diff
    @@ -96,6 +98,7 @@ const initialState: ProjectTreeState = {
     const inflight = new Set<string>()
     const $projectTree = atom<ProjectTreeState>(initialState)
     let nextRootRequestId = 0
    +let lastConnectionKey = ''
     
     function setProjectTree(updater: (current: ProjectTreeState) => ProjectTreeState) {
       $projectTree.set(updater($projectTree.get()))
    ```

    ```diff
    @@ -157,6 +160,7 @@ async function loadRoot(cwd: string, { force = false }: { force?: boolean } = {}
     }
     
     export function resetProjectTreeState() {
    +  lastConnectionKey = ''
       clearProjectTree()
       clearProjectDirCache()
     }
    ```

    ```diff
    @@ -170,6 +174,8 @@ export function resetProjectTreeState() {
      */
     export function useProjectTree(cwd: string): UseProjectTreeResult {
       const state = useStore($projectTree)
    +  const connection = useStore($connection)
    +  const connectionKey = `${connection?.mode || 'local'}:${connection?.profile || ''}:${connection?.baseUrl || ''}`
     
       const refreshRoot = useCallback(() => loadRoot(cwd, { force: true }), [cwd])
     
    ```

    ```diff
    @@ -248,8 +254,15 @@ export function useProjectTree(cwd: string): UseProjectTreeResult {
       )
     
       useEffect(() => {
    +    const connectionChanged = lastConnectionKey !== '' && lastConnectionKey !== connectionKey
    +    lastConnectionKey = connectionKey
    +    if (connectionChanged) {
    +      clearProjectDirCache()
    +      void loadRoot(cwd, { force: true })
    +      return
    +    }
         void loadRoot(cwd)
    -  }, [cwd])
    +  }, [connectionKey, cwd])
     
       return useMemo(
         () => ({
    ```
  - `apps/desktop/src/app/right-sidebar/index.tsx`

    ```diff
    @@ -7,6 +7,7 @@ import { Codicon } from '@/components/ui/codicon'
     import { Loader } from '@/components/ui/loader'
     import { Tip } from '@/components/ui/tooltip'
     import { useI18n } from '@/i18n'
    +import { selectDesktopPaths } from '@/lib/desktop-fs'
     import { normalizeOrLocalPreviewTarget } from '@/lib/local-preview'
     import { cn } from '@/lib/utils'
     import { $panesFlipped } from '@/store/layout'
    ```

    ```diff
    @@ -16,6 +17,7 @@ import { $currentCwd } from '@/store/session'
     
     import { SidebarPanelLabel } from '../shell/sidebar-label'
     
    +import { RemoteFolderPicker } from './files/remote-picker'
     import { ProjectTree } from './files/tree'
     import { useProjectTree } from './files/use-project-tree'
     
    ```

    ```diff
    @@ -54,7 +56,7 @@ export function RightSidebarPane({ onActivateFile, onActivateFolder, onChangeCwd
       const canCollapse = Object.values(openState).some(Boolean)
     
       const chooseFolder = async () => {
    -    const selected = await window.hermesDesktop?.selectPaths({
    +    const selected = await selectDesktopPaths({
           defaultPath: hasCwd ? currentCwd : undefined,
           directories: true,
           multiple: false,
    ```

    ```diff
    @@ -90,6 +92,8 @@ export function RightSidebarPane({ onActivateFile, onActivateFolder, onChangeCwd
               : 'border-l shadow-[inset_0.0625rem_0_0_color-mix(in_srgb,white_18%,transparent)]'
           )}
         >
    +      <RemoteFolderPicker />
    +
           <FilesystemTab
             canCollapse={canCollapse}
             collapseNonce={collapseNonce}
    ```
  - `apps/desktop/src/i18n/en.ts`

    ```diff
    @@ -1532,6 +1532,9 @@ export const en: Translations = {
         terminal: 'Terminal',
         noFolderSelected: 'No folder selected',
         changeCwdTitle: 'Change working directory',
    +    remotePickerTitle: 'Choose remote folder',
    +    remotePickerDescription: 'Browse folders on the connected backend.',
    +    remotePickerSelect: 'Select folder',
         folderTip: cwd => `${cwd} — click to change folder`,
         openFolder: 'Open folder',
         refreshTree: 'Refresh tree',
    ```
  - `apps/desktop/src/i18n/ja.ts`

    ```diff
    @@ -1665,6 +1665,9 @@ export const ja = defineLocale({
         terminal: 'ターミナル',
         noFolderSelected: 'フォルダーが選択されていません',
         changeCwdTitle: '作業ディレクトリを変更',
    +    remotePickerTitle: 'リモートフォルダーを選択',
    +    remotePickerDescription: '接続中のバックエンド上のフォルダーを参照します。',
    +    remotePickerSelect: 'フォルダーを選択',
         folderTip: cwd => `${cwd} — クリックしてフォルダーを変更`,
         openFolder: 'フォルダーを開く',
         refreshTree: 'ツリーを更新',
    ```
  - `apps/desktop/src/i18n/types.ts`

    ```diff
    @@ -1194,6 +1194,9 @@ export interface Translations {
         terminal: string
         noFolderSelected: string
         changeCwdTitle: string
    +    remotePickerTitle: string
    +    remotePickerDescription: string
    +    remotePickerSelect: string
         folderTip: (cwd: string) => string
         openFolder: string
         refreshTree: string
    ```
  - `apps/desktop/src/i18n/zh-hant.ts`

    ```diff
    @@ -1626,6 +1626,9 @@ export const zhHant = defineLocale({
         terminal: '終端機',
         noFolderSelected: '未選擇資料夾',
         changeCwdTitle: '變更工作目錄',
    +    remotePickerTitle: '選擇遠端資料夾',
    +    remotePickerDescription: '瀏覽已連線後端上的資料夾。',
    +    remotePickerSelect: '選擇資料夾',
         folderTip: cwd => `${cwd} — 點擊以變更資料夾`,
         openFolder: '開啟資料夾',
         refreshTree: '重新整理檔案樹',
    ```
  - `apps/desktop/src/i18n/zh.ts`

    ```diff
    @@ -1712,6 +1712,9 @@ export const zh: Translations = {
         terminal: '终端',
         noFolderSelected: '未选择文件夹',
         changeCwdTitle: '更改工作目录',
    +    remotePickerTitle: '选择远程文件夹',
    +    remotePickerDescription: '浏览已连接后端上的文件夹。',
    +    remotePickerSelect: '选择文件夹',
         folderTip: cwd => `${cwd} — 点击更改文件夹`,
         openFolder: '打开文件夹',
         refreshTree: '刷新文件树',
    ```
  - `apps/desktop/src/lib/desktop-fs.test.ts`

    ```diff
    @@ -0,0 +1,116 @@
    +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
    +
    +import { $connection } from '@/store/session'
    +
    +import {
    +  desktopDefaultCwd,
    +  desktopGitRoot,
    +  readDesktopDir,
    +  readDesktopFileDataUrl,
    +  readDesktopFileText,
    +  selectDesktopPaths,
    +  setDesktopFsRemotePicker
    +} from './desktop-fs'
    +
    +const readDir = vi.fn(async () => ({ entries: [{ name: 'local', path: '/local', isDirectory: true }] }))
    +const readFileText = vi.fn(async () => ({ path: '/local/file.txt', text: 'local', byteSize: 5 }))
    +const readFileDataUrl = vi.fn(async () => 'data:text/plain;base64,bG9jYWw=')
    +const gitRoot = vi.fn(async () => '/local')
    +const selectPaths = vi.fn(async () => ['/local'])
    +const api = vi.fn(async ({ path }: { path: string }) => {
    +  if (path.startsWith('/api/fs/list?')) return { entries: [{ name: 'remote', path: '/remote', isDirectory: true }] }
    +  if (path.startsWith('/api/fs/read-text?')) return { path: '/remote/file.txt', text: 'remote', byteSize: 6 }
    +  if (path.startsWith('/api/fs/read-data-url?')) return { dataUrl: 'data:text/plain;base64,cmVtb3Rl' }
    +  if (path.startsWith('/api/fs/git-root?')) return { root: '/remote' }
    +  if (path === '/api/fs/default-cwd') return { cwd: '/backend/project', branch: 'main' }
    +  throw new Error(`unexpected path ${path}`)
    +})
    +
    +function stubBridge() {
    +  vi.stubGlobal('window', {
    +    hermesDesktop: {
    +      api,
    +      gitRoot,
    +      readDir,
    +      readFileDataUrl,
    +      readFileText,
    +      selectPaths
    +    }
    +  })
    +}
    +
    +describe('desktop filesystem facade', () => {
    +  beforeEach(() => {
    +    stubBridge()
    +    $connection.set(null)
    +  })
    +
    +  afterEach(() => {
    +    vi.unstubAllGlobals()
    +    vi.clearAllMocks()
    +    $connection.set(null)
    +    setDesktopFsRemotePicker(null)
    +  })
    +
    +  it('uses local Electron filesystem methods in local mode', async () => {
    +    $connection.set({ mode: 'local' } as never)
    +
    +    await expect(readDesktopDir('/work')).resolves.toEqual({ entries: [{ name: 'local', path: '/local', isDirectory: true }] })
    +    await expect(readDesktopFileText('/work/file.txt')).resolves.toMatchObject({ text: 'local' })
    +    await expect(readDesktopFileDataUrl('/work/file.txt')).resolves.toBe('data:text/plain;base64,bG9jYWw=')
    +    await expect(desktopGitRoot('/work')).resolves.toBe('/local')
    +    await expect(selectDesktopPaths({ directories: true })).resolves.toEqual(['/local'])
    +
    +    expect(readDir).toHaveBeenCalledWith('/work')
    +    expect(readFileText).toHaveBeenCalledWith('/work/file.txt')
    +    expect(readFileDataUrl).toHaveBeenCalledWith('/work/file.txt')
    +    expect(gitRoot).toHaveBeenCalledWith('/work')
    +    expect(selectPaths).toHaveBeenCalledWith({ directories: true })
    +    expect(api).not.toHaveBeenCalled()
    +  })
    +
    +  it('routes filesystem reads through authenticated backend REST in remote mode', async () => {
    +    $connection.set({ mode: 'remote' } as never)
    +
    +    await expect(readDesktopDir('/home/user/project')).resolves.toMatchObject({ entries: [{ name: 'remote' }] })
    +    await expect(readDesktopFileText('/home/user/project/a b.txt')).resolves.toMatchObject({ text: 'remote' })
    +    await expect(readDesktopFileDataUrl('/home/user/project/a b.txt')).resolves.toBe('data:text/plain;base64,cmVtb3Rl')
    +    await expect(desktopGitRoot('/home/user/project')).resolves.toBe('/remote')
    +    await expect(desktopDefaultCwd()).resolves.toEqual({ cwd: '/backend/project', branch: 'main' })
    +
    +    expect(api).toHaveBeenCalledWith({ path: '/api/fs/list?path=%2Fhome%2Fuser%2Fproject' })
    +    expect(api).toHaveBeenCalledWith({ path: '/api/fs/read-text?path=%2Fhome%2Fuser%2Fproject%2Fa%20b.txt' })
    +    expect(api).toHaveBeenCalledWith({ path: '/api/fs/read-data-url?path=%2Fhome%2Fuser%2Fproject%2Fa%20b.txt' })
    +    expect(api).toHaveBeenCalledWith({ path: '/api/fs/git-root?path=%2Fhome%2Fuser%2Fproject' })
    +    expect(api).toHaveBeenCalledWith({ path: '/api/fs/default-cwd' })
    +    expect(readDir).not.toHaveBeenCalled()
    +    expect(readFileText).not.toHaveBeenCalled()
    +    expect(readFileDataUrl).not.toHaveBeenCalled()
    +    expect(gitRoot).not.toHaveBeenCalled()
    +  })
    +
    +  it('uses the registered in-app directory picker in remote mode', async () => {
    +    const remoteSelect = vi.fn(async () => ['/remote/project'])
    +    $connection.set({ mode: 'remote' } as never)
    +    setDesktopFsRemotePicker({ selectPaths: remoteSelect })
    +
    +    await expect(selectDesktopPaths({ defaultPath: '/remote', directories: true, multiple: false })).resolves.toEqual([
    +      '/remote/project'
    +    ])
    +
    +    expect(remoteSelect).toHaveBeenCalledWith({ defaultPath: '/remote', directories: true, multiple: false })
    +    expect(selectPaths).not.toHaveBeenCalled()
    +  })
    +
    +  it('does not treat the remote directory picker as a general file picker', async () => {
    +    const remoteSelect = vi.fn(async () => ['/remote/project'])
    +    $connection.set({ mode: 'remote' } as never)
    +    setDesktopFsRemotePicker({ selectPaths: remoteSelect })
    +
    +    await expect(selectDesktopPaths({ directories: false, multiple: false })).resolves.toEqual([])
    +    await expect(selectDesktopPaths({ directories: true, multiple: true })).resolves.toEqual([])
    +
    +    expect(remoteSelect).not.toHaveBeenCalled()
    +    expect(selectPaths).not.toHaveBeenCalled()
    +  })
    +})
    ```
  - `apps/desktop/src/lib/desktop-fs.ts`

    ```diff
    @@ -0,0 +1,95 @@
    +import { $connection } from '@/store/session'
    +
    +import type { HermesConnection, HermesReadDirResult, HermesReadFileTextResult, HermesSelectPathsOptions } from '@/global'
    +
    +export interface DesktopFsRemotePicker {
    +  selectPaths: (options?: HermesSelectPathsOptions) => Promise<string[]>
    +}
    +
    +let remotePicker: DesktopFsRemotePicker | null = null
    +
    +export function setDesktopFsRemotePicker(next: DesktopFsRemotePicker | null) {
    +  remotePicker = next
    +}
    +
    +function connectionCacheKey(connection: HermesConnection | null) {
    +  if (!connection) {
    +    return 'local:'
    +  }
    +  return `${connection.mode || 'local'}:${connection.profile || ''}:${connection.baseUrl || ''}`
    +}
    +
    +export function desktopFsCacheKey() {
    +  return connectionCacheKey($connection.get())
    +}
    +
    +export function isDesktopFsRemoteMode() {
    +  return $connection.get()?.mode === 'remote'
    +}
    +
    +function fsPath(endpoint: string, filePath: string) {
    +  return `/api/fs/${endpoint}?path=${encodeURIComponent(filePath)}`
    +}
    +
    +function bridge() {
    +  const desktop = window.hermesDesktop
    +  if (!desktop) {
    +    throw new Error('Hermes Desktop bridge is unavailable')
    +  }
    +  return desktop
    +}
    +
    +export async function readDesktopDir(path: string): Promise<HermesReadDirResult> {
    +  const desktop = bridge()
    +  if (!isDesktopFsRemoteMode()) {
    +    return desktop.readDir(path)
    +  }
    +  return desktop.api<HermesReadDirResult>({ path: fsPath('list', path) })
    +}
    +
    +export async function readDesktopFileText(path: string): Promise<HermesReadFileTextResult> {
    +  const desktop = bridge()
    +  if (!isDesktopFsRemoteMode()) {
    +    return desktop.readFileText(path)
    +  }
    +  return desktop.api<HermesReadFileTextResult>({ path: fsPath('read-text', path) })
    +}
    +
    +export async function readDesktopFileDataUrl(path: string): Promise<string> {
    +  const desktop = bridge()
    +  if (!isDesktopFsRemoteMode()) {
    +    return desktop.readFileDataUrl(path)
    +  }
    +
    +  const result = await desktop.api<string | { dataUrl?: string }>({ path: fsPath('read-data-url', path) })
    +  return typeof result === 'string' ? result : result.dataUrl || ''
    +}
    +
    +export async function desktopGitRoot(path: string): Promise<string | null> {
    +  const desktop = bridge()
    +  if (!isDesktopFsRemoteMode()) {
    +    return desktop.gitRoot ? desktop.gitRoot(path) : null
    +  }
    +
    +  const result = await desktop.api<{ root: string | null }>({ path: fsPath('git-root', path) })
    +  return result.root
    +}
    +
    +export async function desktopDefaultCwd(): Promise<{ branch: string; cwd: string } | null> {
    +  if (!isDesktopFsRemoteMode()) {
    +    return null
    +  }
    +
    +  return bridge().api<{ branch: string; cwd: string }>({ path: '/api/fs/default-cwd' })
    +}
    +
    +export async function selectDesktopPaths(options?: HermesSelectPathsOptions): Promise<string[]> {
    +  const desktop = bridge()
    +  if (!isDesktopFsRemoteMode()) {
    +    return desktop.selectPaths(options)
    +  }
    +  if (!options?.directories || options.multiple !== false) {
    +    return []
    +  }
    +  return remotePicker ? remotePicker.selectPaths(options) : []
    +}
    ```
  - `apps/desktop/src/lib/local-preview.ts`

    ```diff
    @@ -1,3 +1,4 @@
    +import { isDesktopFsRemoteMode, readDesktopFileText } from '@/lib/desktop-fs'
     import type { PreviewTarget } from '@/store/preview'
     
     const HTML_EXTENSIONS = new Set(['.htm', '.html'])
    ```

    ```diff
    @@ -107,6 +108,26 @@ export function localPreviewTarget(rawTarget: string, cwd?: string | null): Prev
       }
     }
     
    +async function enrichPreviewTarget(target: PreviewTarget | null): Promise<PreviewTarget | null> {
    +  if (!isDesktopFsRemoteMode() || !target || target.kind !== 'file' || target.previewKind === 'image') {
    +    return target
    +  }
    +
    +  try {
    +    const result = await readDesktopFileText(target.path || target.source)
    +    return {
    +      ...target,
    +      binary: result.binary,
    +      byteSize: result.byteSize,
    +      language: result.language || target.language,
    +      large: (result.byteSize ?? 0) > 512 * 1024,
    +      mimeType: result.mimeType
    +    }
    +  } catch {
    +    return target
    +  }
    +}
    +
     export async function normalizeOrLocalPreviewTarget(
       rawTarget: string,
       cwd?: string | null
    ```

    ```diff
    @@ -115,12 +136,12 @@ export async function normalizeOrLocalPreviewTarget(
         const normalized = await window.hermesDesktop?.normalizePreviewTarget?.(rawTarget, cwd || undefined)
     
         if (normalized) {
    -      return normalized
    +      return enrichPreviewTarget(normalized)
         }
       } catch {
         // Running Electron may still have the old HTML-only preview IPC. Fall
         // through to renderer-side local classification so text/images still open.
       }
     
    -  return localPreviewTarget(rawTarget, cwd)
    +  return enrichPreviewTarget(localPreviewTarget(rawTarget, cwd))
     }
    ```
  - `apps/desktop/src/store/session.test.ts`

    ```diff
    @@ -5,12 +5,14 @@ import type { SessionInfo } from '@/types/hermes'
     import {
       $activeSessionId,
       $attentionSessionIds,
    +  $connection,
       $currentCwd,
       $workingSessionIds,
       applyConfiguredDefaultProjectDir,
       getRecentlySettledSessionIds,
       mergeSessionPage,
       sessionPinId,
    +  setCurrentCwd,
       setSessionAttention,
       setSessionWorking,
       workspaceCwdForNewSession
    ```

    ```diff
    @@ -184,9 +186,12 @@ describe('mergeSessionPage', () => {
     describe('workspaceCwdForNewSession', () => {
       afterEach(() => {
         applyConfiguredDefaultProjectDir(null)
    +    $connection.set(null)
         $currentCwd.set('')
         $activeSessionId.set(null)
         window.localStorage.removeItem('hermes.desktop.workspace-cwd')
    +    window.localStorage.removeItem('hermes.desktop.workspace-cwd.remote.http%3A%2F%2Fbackend-a.default')
    +    window.localStorage.removeItem('hermes.desktop.workspace-cwd.remote.http%3A%2F%2Fbackend-b.default')
       })
     
       it('prefers the configured default over the sticky remembered workspace', () => {
    ```

    ```diff
    @@ -216,6 +221,26 @@ describe('workspaceCwdForNewSession', () => {
         expect($currentCwd.get()).toBe('/live/session/path')
         expect(workspaceCwdForNewSession()).toBe('/home/user/configured')
       })
    +
    +  it('keeps remote workspace memory separate from local and other remotes', () => {
    +    window.localStorage.setItem('hermes.desktop.workspace-cwd', '/local/project')
    +    $currentCwd.set('/live/session/path')
    +    $connection.set({ baseUrl: 'http://backend-a', mode: 'remote' } as never)
    +
    +    expect(workspaceCwdForNewSession()).toBe('')
    +
    +    setCurrentCwd('/backend/project-a')
    +    expect(workspaceCwdForNewSession()).toBe('/backend/project-a')
    +
    +    $connection.set({ baseUrl: 'http://backend-b', mode: 'remote' } as never)
    +    expect(workspaceCwdForNewSession()).toBe('')
    +
    +    setCurrentCwd('/backend/project-b')
    +    expect(workspaceCwdForNewSession()).toBe('/backend/project-b')
    +
    +    $connection.set(null)
    +    expect(workspaceCwdForNewSession()).toBe('/local/project')
    +  })
     })
     
     describe('getRecentlySettledSessionIds', () => {
    ```
  - `apps/desktop/src/store/session.ts`

    ```diff
    @@ -10,13 +10,19 @@ type Updater<T> = T | ((current: T) => T)
     
     const WORKSPACE_CWD_KEY = 'hermes.desktop.workspace-cwd'
     
    -// Cached copy of Settings → Sessions → Default project directory. The main
    -// process persists this in project-dir.json, but the renderer must also honor it
    -// when seeding $currentCwd — otherwise PR #37586's sticky localStorage home dir
    -// wins and new sessions ignore the user's explicit picker choice.
     let configuredDefaultProjectDir = ''
     
    -export const getRememberedWorkspaceCwd = (): string => storedString(WORKSPACE_CWD_KEY)?.trim() || ''
    +function workspaceCwdKey(connection: HermesConnection | null = $connection.get()): string {
    +  if (connection?.mode !== 'remote') {
    +    return WORKSPACE_CWD_KEY
    +  }
    +
    +  const base = encodeURIComponent(connection.baseUrl || 'remote')
    +  const profile = encodeURIComponent(connection.profile || 'default')
    +  return `${WORKSPACE_CWD_KEY}.remote.${base}.${profile}`
    +}
    +
    +export const getRememberedWorkspaceCwd = (): string => storedString(workspaceCwdKey())?.trim() || ''
     
     export const getConfiguredDefaultProjectDir = (): string => configuredDefaultProjectDir
     
    ```

    ```diff
    @@ -54,6 +60,13 @@ export async function ensureDefaultWorkspaceCwd(): Promise<void> {
         }
       }
     
    +  const remembered = getRememberedWorkspaceCwd()
    +
    +  if ($connection.get()?.mode === 'remote') {
    +    seedLiveCwd(remembered)
    +    return
    +  }
    +
       if (configured) {
         const { cwd } = await sanitize(configured)
         seedLiveCwd(cwd)
    ```

    ```diff
    @@ -61,8 +74,10 @@ export async function ensureDefaultWorkspaceCwd(): Promise<void> {
         return
       }
     
    -  const { cwd } = await sanitize(getRememberedWorkspaceCwd())
    -  seedLiveCwd(cwd)
    +  if (remembered) {
    +    const { cwd } = await sanitize(remembered)
    +    seedLiveCwd(cwd)
    +  }
     }
     
     export function applyConfiguredDefaultProjectDir(dir: null | string | undefined): void {
    ```

    ```diff
    @@ -238,15 +253,16 @@ export const setYoloActive = (next: Updater<boolean>) => updateAtom($yoloActive,
     
     export const setCurrentCwd = (next: Updater<string>) => {
       updateAtom($currentCwd, next)
    -  // Keep localStorage in sync with the atom: a real folder is remembered, an
    -  // empty cwd clears the key (|| null → removeItem).
    -  persistString(WORKSPACE_CWD_KEY, $currentCwd.get().trim() || null)
    +  persistString(workspaceCwdKey(), $currentCwd.get().trim() || null)
     }
     
    -/** Workspace for a brand-new chat. Explicit Settings override wins; otherwise
    - *  fall back to the sticky last-used folder, then whatever is already live. */
    -export const workspaceCwdForNewSession = (): string =>
    -  getConfiguredDefaultProjectDir() || getRememberedWorkspaceCwd() || $currentCwd.get().trim()
    +export const workspaceCwdForNewSession = (): string => {
    +  if ($connection.get()?.mode === 'remote') {
    +    return getRememberedWorkspaceCwd()
    +  }
    +
    +  return getConfiguredDefaultProjectDir() || getRememberedWorkspaceCwd() || $currentCwd.get().trim()
    +}
     
     export const setCurrentBranch = (next: Updater<string>) => updateAtom($currentBranch, next)
     export const setCurrentUsage = (next: Updater<UsageStats>) => updateAtom($currentUsage, next)
    ```
  - `hermes_cli/web_server.py`

    ```diff
    @@ -920,6 +920,178 @@ class ManagedFilesPolicy:
         can_change_path: bool
     
     
    +_FS_READDIR_HIDDEN = {
    +    ".git",
    +    ".hg",
    +    ".svn",
    +    ".cache",
    +    ".next",
    +    ".turbo",
    +    ".venv",
    +    "__pycache__",
    +    "build",
    +    "dist",
    +    "node_modules",
    +    "target",
    +    "venv",
    +}
    +_FS_DATA_URL_MAX_BYTES = 16 * 1024 * 1024
    +_FS_TEXT_SOURCE_MAX_BYTES = 64 * 1024 * 1024
    +_FS_TEXT_PREVIEW_MAX_BYTES = 512 * 1024
    +_FS_PREVIEW_LANGUAGE_BY_EXT = {
    +    ".c": "c",
    +    ".conf": "ini",
    +    ".cpp": "cpp",
    +    ".css": "css",
    +    ".csv": "csv",
    +    ".go": "go",
    +    ".graphql": "graphql",
    +    ".h": "c",
    +    ".hpp": "cpp",
    +    ".html": "html",
    +    ".java": "java",
    +    ".js": "javascript",
    +    ".json": "json",
    +    ".jsx": "jsx",
    +    ".kt": "kotlin",
    +    ".lua": "lua",
    +    ".md": "markdown",
    +    ".mjs": "javascript",
    +    ".py": "python",
    +    ".rb": "ruby",
    +    ".rs": "rust",
    +    ".sh": "shell",
    +    ".sql": "sql",
    +    ".svg": "xml",
    +    ".toml": "toml",
    +    ".ts": "typescript",
    +    ".tsx": "tsx",
    +    ".txt": "text",
    +    ".xml": "xml",
    +    ".yaml": "yaml",
    +    ".yml": "yaml",
    +    ".zsh": "shell",
    +}
    +_FS_MIME_TYPES = {
    +    ".avi": "video/x-msvideo",
    +    ".bmp": "image/bmp",
    +    ".flac": "audio/flac",
    +    ".gif": "image/gif",
    +    ".jpeg": "image/jpeg",
    +    ".jpg": "image/jpeg",
    +    ".m4a": "audio/mp4",
    +    ".mkv": "video/x-matroska",
    +    ".mov": "video/quicktime",
    +    ".mp3": "audio/mpeg",
    +    ".mp4": "video/mp4",
    +    ".ogg": "audio/ogg",
    +    ".opus": "audio/ogg; codecs=opus",
    +    ".png": "image/png",
    +    ".svg": "image/svg+xml",
    +    ".wav": "audio/wav",
    +    ".webm": "video/webm",
    +    ".webp": "image/webp",
    +}
    +
    +
    +def _fs_path(raw_path: str) -> Path:
    +    raw = str(raw_path or "").strip()
    +    if not raw:
    +        raise HTTPException(status_code=400, detail="Path is required")
    +    if "\0" in raw:
    +        raise HTTPException(status_code=400, detail="Invalid path")
    +    try:
    +        if raw.lower().startswith("file:"):
    +            parsed = urllib.parse.urlparse(raw)
    +            if parsed.netloc and parsed.netloc not in {"", "localhost"}:
    +                raise ValueError
    +            raw = urllib.request.url2pathname(parsed.path)
    +        candidate = Path(raw).expanduser()
    +        if not candidate.is_absolute():
    +            candidate = Path.cwd() / candidate
    +        return candidate.resolve(strict=False)
    +    except (OSError, RuntimeError, ValueError):
    +        raise HTTPException(status_code=400, detail="Invalid path")
    +
    +
    +def _fs_mime_type(path: Path) -> str:
    +    suffix = path.suffix.lower()
    +    if suffix in _FS_MIME_TYPES:
    +        return _FS_MIME_TYPES[suffix]
    +    guessed, _ = mimetypes.guess_type(str(path))
    +    return guessed or "application/octet-stream"
    +
    +
    +def _fs_looks_binary(data: bytes) -> bool:
    +    if not data:
    +        return False
    +    if b"\0" in data:
    +        return True
    +    suspicious = sum(1 for byte in data if byte < 32 and byte not in {9, 10, 13})
    +    return suspicious / len(data) > 0.12
    +
    +
    +def _fs_regular_file(path: Path) -> tuple[Path, os.stat_result]:
    +    target = _fs_path(str(path))
    +    try:
    +        st = target.stat()
    +    except FileNotFoundError:
    +        raise HTTPException(status_code=404, detail="File not found")
    +    except NotADirectoryError:
    +        raise HTTPException(status_code=404, detail="File not found")
    +    except PermissionError:
    +        raise HTTPException(status_code=403, detail="File is not readable")
    +    except OSError as exc:
    +        raise HTTPException(status_code=400, detail=str(exc) or "Invalid path")
    +    if stat.S_ISDIR(st.st_mode):
    +        raise HTTPException(status_code=400, detail="Path points to a directory")
    +    if not stat.S_ISREG(st.st_mode):
    +        raise HTTPException(status_code=400, detail="Only regular files can be read")
    +    return target, st
    +
    +
    +def _fs_find_git_root(start: Path) -> str | None:
    +    directory = start
    +    for _ in range(50):
    +        try:
    +            if (directory / ".git").exists():
    +                return str(directory)
    +        except OSError:
    +            return None
    +        parent = directory.parent
    +        if parent == directory:
    +            return None
    +        directory = parent
    +    return None
    +
    +
    +def _fs_default_cwd() -> str:
    +    cfg_terminal = load_config().get("terminal") or {}
    +    raw = str(cfg_terminal.get("cwd") or os.environ.get("TERMINAL_CWD") or "").strip()
    +    if raw and raw not in {".", "auto", "cwd"}:
    +        try:
    +            candidate = Path(raw).expanduser().resolve(strict=False)
    +            if candidate.is_dir():
    +                return str(candidate)
    +        except (OSError, RuntimeError):
    +            pass
    +    return str(Path.cwd())
    +
    +
    +def _fs_git_branch(cwd: str) -> str:
    +    try:
    +        result = subprocess.run(
    +            ["git", "-C", cwd, "branch", "--show-current"],
    +            capture_output=True,
    +            text=True,
    +            timeout=2,
    +            check=False,
    +        )
    +        return result.stdout.strip() if result.returncode == 0 else ""
    +    except Exception:
    +        return ""
    +
    +
     def _media_serve_roots() -> list[Path]:
         """Directories ``GET /api/media`` is allowed to read from.
     
    ```

    ```diff
    @@ -1264,6 +1436,87 @@ async def delete_managed_file(payload: ManagedFileDelete, request: Request):
         return {"ok": True, "path": display_path, **_managed_response_meta(policy)}
     
     
    [redacted:email]("/api/fs/list")
    +async def fs_list(path: str):
    +    target = _fs_path(path)
    +    try:
    +        entries = []
    +        with os.scandir(target) as scan:
    +            for entry in scan:
    +                if entry.name in _FS_READDIR_HIDDEN:
    +                    continue
    +                entries.append({
    +                    "name": entry.name,
    +                    "path": str(target / entry.name),
    +                    "isDirectory": entry.is_dir(follow_symlinks=False),
    +                })
    +        entries.sort(key=lambda item: (not item["isDirectory"], item["name"].lower(), item["name"]))
    +        return {"entries": entries}
    +    except FileNotFoundError:
    +        return {"entries": [], "error": "ENOENT"}
    +    except NotADirectoryError:
    +        return {"entries": [], "error": "ENOTDIR"}
    +    except PermissionError:
    +        return {"entries": [], "error": "EACCES"}
    +    except OSError as exc:
    +        return {"entries": [], "error": getattr(exc, "strerror", None) or "read-error"}
    +
    +
    [redacted:email]("/api/fs/read-text")
    +async def fs_read_text(path: str):
    +    target, st = _fs_regular_file(_fs_path(path))
    +    if st.st_size > _FS_TEXT_SOURCE_MAX_BYTES:
    +        raise HTTPException(status_code=413, detail="File too large")
    +    bytes_to_read = min(st.st_size, _FS_TEXT_PREVIEW_MAX_BYTES)
    +    try:
    +        with target.open("rb") as handle:
    +            data = handle.read(bytes_to_read)
    +    except PermissionError:
    +        raise HTTPException(status_code=403, detail="File is not readable")
    +    except OSError as exc:
    +        raise HTTPException(status_code=400, detail=str(exc) or "File read failed")
    +    return {
    +        "binary": _fs_looks_binary(data[:4096]),
    +        "byteSize": st.st_size,
    +        "language": _FS_PREVIEW_LANGUAGE_BY_EXT.get(target.suffix.lower(), "text"),
    +        "mimeType": _fs_mime_type(target),
    +        "path": str(target),
    +        "text": data.decode("utf-8", errors="replace"),
    +        "truncated": st.st_size > _FS_TEXT_PREVIEW_MAX_BYTES,
    +    }
    +
    +
    [redacted:email]("/api/fs/read-data-url")
    +async def fs_read_data_url(path: str):
    +    target, st = _fs_regular_file(_fs_path(path))
    +    if st.st_size > _FS_DATA_URL_MAX_BYTES:
    +        raise HTTPException(status_code=413, detail="File too large")
    +    try:
    +        encoded = base64.b64encode(target.read_bytes()).decode("ascii")
    +    except PermissionError:
    +        raise HTTPException(status_code=403, detail="File is not readable")
    +    except OSError as exc:
    +        raise HTTPException(status_code=400, detail=str(exc) or "File read failed")
    +    return {"dataUrl": f"data:{_fs_mime_type(target)};base64,{encoded}"}
    +
    +
    [redacted:email]("/api/fs/git-root")
    +async def fs_git_root(path: str):
    +    target = _fs_path(path)
    +    try:
    +        st = target.stat()
    +        start = target if stat.S_ISDIR(st.st_mode) else target.parent
    +    except OSError:
    +        start = target
    +    return {"root": _fs_find_git_root(start)}
    +
    +
    [redacted:email]("/api/fs/default-cwd")
    +async def fs_default_cwd():
    +    cwd = _fs_default_cwd()
    +    return {"cwd": cwd, "branch": _fs_git_branch(cwd)}
    +
    +
     @app.get("/api/status")
     async def get_status():
         current_ver, latest_ver = check_config_version()
    ```
  - `tests/hermes_cli/test_web_server_fs.py`

    ```diff
    @@ -0,0 +1,188 @@
    +import base64
    +from pathlib import Path
    +
    +import pytest
    +
    +from hermes_cli import web_server
    +
    +pytest.importorskip("starlette.testclient")
    +from starlette.testclient import TestClient
    +
    +
    [redacted:email]
    +def client(monkeypatch):
    +    previous_auth_required = getattr(web_server.app.state, "auth_required", None)
    +    web_server.app.state.auth_required = False
    +    test_client = TestClient(web_server.app)
    +    test_client.headers[web_server._SESSION_HEADER_NAME] = web_server._SESSION_TOKEN
    +    try:
    +        yield test_client
    +    finally:
    +        if previous_auth_required is None:
    +            try:
    +                delattr(web_server.app.state, "auth_required")
    +            except AttributeError:
    +                pass
    +        else:
    +            web_server.app.state.auth_required = previous_auth_required
    +
    +
    +def test_fs_list_sorts_and_hides_noise(client, tmp_path):
    +    root = tmp_path / "project"
    +    root.mkdir()
    +    (root / "b.txt").write_text("b")
    +    (root / "a_dir").mkdir()
    +    (root / "a.txt").write_text("a")
    +    (root / "node_modules").mkdir()
    +    (root / ".git").mkdir()
    +
    +    response = client.get("/api/fs/list", params={"path": str(root)})
    +
    +    assert response.status_code == 200
    +    entries = response.json()["entries"]
    +    assert [entry["name"] for entry in entries] == ["a_dir", "a.txt", "b.txt"]
    +    assert entries[0] == {"name": "a_dir", "path": str(root / "a_dir"), "isDirectory": True}
    +    assert all(entry["name"] not in {".git", "node_modules"} for entry in entries)
    +
    +
    +def test_fs_list_accepts_relative_paths(client, tmp_path, monkeypatch):
    +    monkeypatch.chdir(tmp_path)
    +    (tmp_path / "rel").mkdir()
    +    (tmp_path / "rel" / "file.txt").write_text("ok")
    +
    +    response = client.get("/api/fs/list", params={"path": "rel"})
    +
    +    assert response.status_code == 200
    +    assert response.json()["entries"] == [
    +        {"name": "file.txt", "path": str(tmp_path / "rel" / "file.txt"), "isDirectory": False}
    +    ]
    +
    +
    +def test_fs_list_missing_path_returns_structured_error(client, tmp_path):
    +    response = client.get("/api/fs/list", params={"path": str(tmp_path / "missing")})
    +
    +    assert response.status_code == 200
    +    assert response.json() == {"entries": [], "error": "ENOENT"}
    +
    +
    +def test_fs_read_text_matches_preview_shape_and_truncates(client, tmp_path, monkeypatch):
    +    monkeypatch.setattr(web_server, "_FS_TEXT_SOURCE_MAX_BYTES", 32)
    +    monkeypatch.setattr(web_server, "_FS_TEXT_PREVIEW_MAX_BYTES", 5)
    +    target = tmp_path / "sample.py"
    +    target.write_text("print('hello')")
    +
    +    response = client.get("/api/fs/read-text", params={"path": str(target)})
    +
    +    assert response.status_code == 200
    +    assert response.json() == {
    +        "binary": False,
    +        "byteSize": 14,
    +        "language": "python",
    +        "mimeType": "text/x-python",
    +        "path": str(target),
    +        "text": "print",
    +        "truncated": True,
    +    }
    +
    +
    +def test_fs_read_text_rejects_source_over_cap(client, tmp_path, monkeypatch):
    +    monkeypatch.setattr(web_server, "_FS_TEXT_SOURCE_MAX_BYTES", 4)
    +    target = tmp_path / "large.txt"
    +    target.write_text("12345")
    +
    +    response = client.get("/api/fs/read-text", params={"path": str(target)})
    +
    +    assert response.status_code == 413
    +
    +
    +def test_fs_read_text_flags_binary(client, tmp_path):
    +    target = tmp_path / "blob.bin"
    +    target.write_bytes(b"hello\x00world")
    +
    +    response = client.get("/api/fs/read-text", params={"path": str(target)})
    +
    +    assert response.status_code == 200
    +    body = response.json()
    +    assert body["binary"] is True
    +    assert body["text"].startswith("hello")
    +
    +
    +def test_fs_read_data_url_returns_capped_data_url(client, tmp_path, monkeypatch):
    +    monkeypatch.setattr(web_server, "_FS_DATA_URL_MAX_BYTES", 16)
    +    target = tmp_path / "image.png"
    +    target.write_bytes(b"pngbytes")
    +
    +    response = client.get("/api/fs/read-data-url", params={"path": str(target)})
    +
    +    assert response.status_code == 200
    +    assert response.json() == {"dataUrl": "data:image/png;base64," + base64.b64encode(b"pngbytes").decode("ascii")}
    +
    +
    +def test_fs_read_data_url_rejects_over_cap(client, tmp_path, monkeypatch):
    +    monkeypatch.setattr(web_server, "_FS_DATA_URL_MAX_BYTES", 3)
    +    target = tmp_path / "image.png"
    +    target.write_bytes(b"1234")
    +
    +    response = client.get("/api/fs/read-data-url", params={"path": str(target)})
    +
    +    assert response.status_code == 413
    +
    +
    +def test_fs_git_root_for_nested_file(client, tmp_path):
    +    (tmp_path / ".git").mkdir()
    +    nested = tmp_path / "pkg" / "mod"
    +    nested.mkdir(parents=True)
    +    target = nested / "file.py"
    +    target.write_text("x")
    +
    +    response = client.get("/api/fs/git-root", params={"path": str(target)})
    +
    +    assert response.status_code == 200
    +    assert response.json() == {"root": str(tmp_path)}
    +
    +
    +def test_fs_git_root_returns_null_outside_repo(client, tmp_path):
    +    response = client.get("/api/fs/git-root", params={"path": str(tmp_path)})
    +
    +    assert response.status_code == 200
    +    assert response.json() == {"root": None}
    +
    +
    +def test_fs_default_cwd_prefers_existing_terminal_cwd(client, tmp_path, monkeypatch):
    +    monkeypatch.setattr(web_server, "load_config", lambda: {"terminal": {"cwd": str(tmp_path)}})
    +    monkeypatch.setenv("TERMINAL_CWD", str(tmp_path / "env"))
    +    monkeypatch.setattr(web_server.Path, "cwd", lambda: tmp_path / "process")
    +    monkeypatch.setattr(web_server, "_fs_git_branch", lambda cwd: "main")
    +
    +    response = client.get("/api/fs/default-cwd")
    +
    +    assert response.status_code == 200
    +    assert response.json() == {"cwd": str(tmp_path), "branch": "main"}
    +
    +
    +def test_fs_default_cwd_falls_back_when_terminal_cwd_is_invalid(client, tmp_path, monkeypatch):
    +    fallback = tmp_path / "backend"
    +    fallback.mkdir()
    +    monkeypatch.setattr(web_server, "load_config", lambda: {"terminal": {"cwd": "/client/missing"}})
    +    monkeypatch.setenv("TERMINAL_CWD", "/client/missing")
    +    monkeypatch.setattr(web_server.Path, "cwd", lambda: fallback)
    +    monkeypatch.setattr(web_server, "_fs_git_branch", lambda cwd: "")
    +
    +    response = client.get("/api/fs/default-cwd")
    +
    +    assert response.status_code == 200
    +    assert response.json() == {"cwd": str(fallback), "branch": ""}
    +
    +
    +def test_fs_endpoints_require_auth(tmp_path):
    +    client = TestClient(web_server.app)
    +    target = tmp_path / "secret.txt"
    +    target.write_text("secret")
    +
    +    list_response = client.get("/api/fs/list", params={"path": str(tmp_path)})
    +    read_response = client.get("/api/fs/read-text", params={"path": str(target)})
    +    default_response = client.get("/api/fs/default-cwd")
    +
    +    assert list_response.status_code == 401
    +    assert read_response.status_code == 401
    +    assert default_response.status_code == 401
    ```
- **#68130: feat(desktop): SSH remote-backend connection mode**. merged to main · fix tier `verified`
  - maintainer direction: category `merged`; implication `superseded`
  - files: `apps/desktop/electron/connection-apply.test.ts`, `apps/desktop/electron/connection-apply.ts`, `apps/desktop/electron/connection-config.test.ts`, `apps/desktop/electron/connection-config.ts`, `apps/desktop/electron/desktop-installation.test.ts`, `apps/desktop/electron/desktop-installation.ts`, `apps/desktop/electron/main.ts`, `apps/desktop/electron/preload.ts`, `apps/desktop/electron/remote-lifecycle.test.ts`, `apps/desktop/electron/remote-lifecycle.ts`, `apps/desktop/electron/ssh-bootstrap-coordinator.test.ts`, `apps/desktop/electron/ssh-bootstrap-coordinator.ts`, `apps/desktop/electron/ssh-config.test.ts`, `apps/desktop/electron/ssh-config.ts`, `apps/desktop/electron/ssh-connection.test.ts`, `apps/desktop/electron/ssh-connection.ts`, `apps/desktop/electron/windows-remote-lifecycle.test.ts`, `apps/desktop/electron/windows-remote-lifecycle.ts`, `apps/desktop/electron/windows-remote-live.test.ts`, `apps/desktop/src/app/contrib/wiring.tsx` (+28 more)
  - fix hunks:
  - `apps/desktop/electron/connection-apply.test.ts`

    ```diff
    @@ -0,0 +1,100 @@
    +import { describe, expect, it, vi } from 'vitest'
    +
    +import { applyConnectionChange, commitConnectionFailure, resolveTerminalConnection } from './connection-apply'
    +
    +function deferred() {
    +  let resolve!: () => void
    +
    +  const promise = new Promise<void>(done => {
    +    resolve = done
    +  })
    +
    +  return { promise, resolve }
    +}
    +
    +describe('applyConnectionChange', () => {
    +  it.each([['SSH A to SSH B'], ['SSH to Cloud'], ['Cloud to SSH']])(
    +    'serializes %s behind bootstrap rollback before teardown and apply',
    +    async () => {
    +      const gate = deferred()
    +      const events: string[] = []
    +
    +      const run = applyConnectionChange({
    +        cancelAndWait: async () => {
    +          events.push('cancel')
    +          await gate.promise
    +          events.push('drained')
    +        },
    +        isPrimary: true,
    +        scope: '',
    +        sendApplied: () => events.push('applied'),
    +        stopPool: vi.fn(),
    +        teardownPrimary: async () => {
    +          events.push('primary')
    +        },
    +        teardownSsh: async () => {
    +          events.push('ssh')
    +        }
    +      })
    +
    +      await Promise.resolve()
    +      expect(events).toEqual(['cancel'])
    +      gate.resolve()
    +      await run
    +      expect(events).toEqual(['cancel', 'drained', 'ssh', 'primary', 'applied'])
    +    }
    +  )
    +
    +  it('tears down only a non-primary scope without applying the primary connection', async () => {
    +    const events: string[] = []
    +    await applyConnectionChange({
    +      cancelAndWait: async scope => {
    +        events.push(`cancel:${scope}`)
    +      },
    +      isPrimary: false,
    +      scope: 'worker',
    +      sendApplied: () => events.push('applied'),
    +      stopPool: scope => events.push(`pool:${scope}`),
    +      teardownPrimary: async () => {
    +        events.push('primary')
    +      },
    +      teardownSsh: async scope => {
    +        events.push(`ssh:${scope}`)
    +      }
    +    })
    +    expect(events).toEqual(['cancel:worker', 'ssh:worker', 'pool:worker'])
    +  })
    +})
    +
    +describe('resolveTerminalConnection', () => {
    +  it('joins an in-flight backend before resolving the SSH terminal target', async () => {
    +    const target = { ssh: {}, scope: '' }
    +    const getTarget = vi.fn().mockReturnValueOnce('pending').mockReturnValueOnce(target)
    +    const ensureBackend = vi.fn(async () => undefined)
    +
    +    await expect(resolveTerminalConnection(getTarget, ensureBackend)).resolves.toBe(target)
    +    expect(ensureBackend).toHaveBeenCalledOnce()
    +  })
    +
    +  it('does not start a local terminal while configured SSH remains unavailable', async () => {
    +    await expect(
    +      resolveTerminalConnection(
    +        () => 'pending',
    +        async () => undefined
    +      )
    +    ).rejects.toThrow('not ready')
    +  })
    +})
    +
    +describe('commitConnectionFailure', () => {
    +  it('prevents a stale bootstrap from publishing failure state', () => {
    +    const stale = Promise.resolve('stale')
    +    const current = Promise.resolve('current')
    +    const commit = vi.fn()
    +
    +    expect(commitConnectionFailure(current, stale, commit)).toBe(false)
    +    expect(commit).not.toHaveBeenCalled()
    +    expect(commitConnectionFailure(current, current, commit)).toBe(true)
    +    expect(commit).toHaveBeenCalledOnce()
    +  })
    +})
    ```
  - `apps/desktop/electron/connection-apply.ts`

    ```diff
    @@ -0,0 +1,50 @@
    +async function applyConnectionChange({
    +  cancelAndWait,
    +  isPrimary,
    +  scope,
    +  sendApplied,
    +  stopPool,
    +  teardownPrimary,
    +  teardownSsh
    +}) {
    +  await cancelAndWait(scope)
    +  await teardownSsh(scope)
    +
    +  if (!isPrimary) {
    +    stopPool(scope)
    +
    +    return
    +  }
    +
    +  await teardownPrimary()
    +  sendApplied()
    +}
    +
    +function commitConnectionFailure(current, starting, commit) {
    +  if (current !== starting) {
    +    return false
    +  }
    +
    +  commit()
    +
    +  return true
    +}
    +
    +async function resolveTerminalConnection(getTarget, ensureBackend) {
    +  let target = getTarget()
    +
    +  if (target !== 'pending') {
    +    return target
    +  }
    +
    +  await ensureBackend()
    +  target = getTarget()
    +
    +  if (target === 'pending') {
    +    throw new Error('Remote connection is not ready yet. Try again in a moment.')
    +  }
    +
    +  return target
    +}
    +
    +export { applyConnectionChange, commitConnectionFailure, resolveTerminalConnection }
    ```
  - `apps/desktop/electron/connection-config.test.ts`

    ```diff
    @@ -26,14 +26,19 @@ import {
       gatewayTicketFailure,
       gatewayWsUrlIpcResult,
       isGatewayAuthRejection,
    +  localProfileEntry,
       modeIsRemoteLike,
       normalizeRemoteBaseUrl,
    +  normalizeSshConfig,
       normAuthMode,
       pathWithGlobalRemoteProfile,
    +  profileHasRemoteConnection,
       profileRemoteOverride,
    +  profileSshOverride,
       resolveAuthMode,
       resolveTestWsUrl,
       RT_COOKIE_VARIANTS,
    +  savedProfileSsh,
       tokenPreview
     } from './connection-config'
     
    ```

    ```diff
    @@ -127,6 +132,61 @@ test('profileRemoteOverride tolerates a missing/!object profiles map', () => {
       assert.equal(profileRemoteOverride(null, 'coder'), null)
     })
     
    +test('SSH remains separate from URL-shaped remote modes', () => {
    +  assert.equal(modeIsRemoteLike('ssh'), false)
    +  const config = { profiles: { coder: { mode: 'ssh', host: 'alice@box:2222', keyPath: '/key' } } }
    +  assert.equal(profileRemoteOverride(config, 'coder'), null)
    +  assert.deepEqual(profileSshOverride(config, 'coder'), {
    +    mode: 'ssh',
    +    host: 'box',
    +    user: 'alice',
    +    port: 2222,
    +    keyPath: '/key'
    +  })
    +})
    +
    +test('normalizeSshConfig handles IPv6 and strict port bounds', () => {
    +  assert.deepEqual(normalizeSshConfig({ mode: 'ssh', host: '::1', port: 22 }), {
    +    mode: 'ssh',
    +    host: '::1'
    +  })
    +  assert.deepEqual(normalizeSshConfig({ mode: 'ssh', host: '[::1]:2222' }), {
    +    mode: 'ssh',
    +    host: '::1',
    +    port: 2222
    +  })
    +  assert.deepEqual(normalizeSshConfig({ mode: 'ssh', host: 'box', port: '2222junk' }), {
    +    mode: 'ssh',
    +    host: 'box'
    +  })
    +  assert.deepEqual(normalizeSshConfig({ mode: 'ssh', host: 'box', port: 65536 }), {
    +    mode: 'ssh',
    +    host: 'box'
    +  })
    +})
    +
    +test('localProfileEntry preserves inactive SSH drafts but drops Cloud state', () => {
    +  const ssh = { mode: 'ssh', host: 'box', user: 'alice', remoteHermesPath: '/hermes' }
    +  assert.deepEqual(localProfileEntry(ssh), { mode: 'local', savedSsh: ssh })
    +  assert.deepEqual(localProfileEntry({ mode: 'local', savedSsh: ssh }), {
    +    mode: 'local',
    +    savedSsh: ssh
    +  })
    +  assert.equal(localProfileEntry({ mode: 'cloud', url: 'https://agent' }), null)
    +})
    +
    +test('saved SSH drafts are inactive and explicit overrides take precedence', () => {
    +  const saved = { mode: 'ssh', host: 'saved' }
    +  const config: any = { profiles: { coder: { mode: 'local', savedSsh: saved } } }
    +  assert.deepEqual(savedProfileSsh(config, 'coder'), saved)
    +  assert.equal(profileSshOverride(config, 'coder'), null)
    +  assert.equal(profileHasRemoteConnection(config, 'coder'), false)
    +
    +  config.profiles.coder = { mode: 'ssh', host: 'active' }
    +  assert.deepEqual(profileSshOverride(config, 'coder'), { mode: 'ssh', host: 'active' })
    +  assert.equal(profileHasRemoteConnection(config, 'coder'), true)
    +})
    +
     // --- pathWithGlobalRemoteProfile ---
     
     test('pathWithGlobalRemoteProfile appends profile in global remote mode', () => {
    ```
  - `apps/desktop/electron/connection-config.ts`

    ```diff
    @@ -203,6 +203,127 @@ function modeIsRemoteLike(mode) {
       return mode === 'remote' || mode === 'cloud'
     }
     
    +function normalizeSshConfig(entry) {
    +  if (!entry || typeof entry !== 'object' || entry.mode !== 'ssh') {
    +    return null
    +  }
    +
    +  let host = String(entry.host || '').trim()
    +
    +  if (!host) {
    +    return null
    +  }
    +
    +  let parsedUser
    +  let parsedPort
    +  const at = host.indexOf('@')
    +
    +  if (at > 0) {
    +    parsedUser = host.slice(0, at)
    +    host = host.slice(at + 1)
    +  }
    +
    +  const bracketed = /^\[([^\]]+)](?::(\d+))?$/.exec(host)
    +
    +  if (bracketed) {
    +    host = bracketed[1]
    +
    +    if (bracketed[2]) {
    +      parsedPort = Number(bracketed[2])
    +    }
    +  } else if ((host.match(/:/g) || []).length === 1) {
    +    const [name, rawPort] = host.split(':')
    +
    +    if (/^\d+$/.test(rawPort)) {
    +      host = name
    +      parsedPort = Number(rawPort)
    +    }
    +  }
    +
    +  if (!host) {
    +    return null
    +  }
    +
    +  const out: any = { mode: 'ssh', host }
    +  const user = String(entry.user || '').trim() || parsedUser || ''
    +
    +  if (user) {
    +    out.user = user
    +  }
    +
    +  const rawExplicitPort = String(entry.port ?? '').trim()
    +  const explicitPort = /^\d+$/.test(rawExplicitPort) ? Number(rawExplicitPort) : null
    +  const port = explicitPort ?? parsedPort
    +
    +  if (Number.isInteger(port) && port > 0 && port <= 65535 && port !== 22) {
    +    out.port = port
    +  }
    +
    +  const keyPath = String(entry.keyPath || '').trim()
    +
    +  if (keyPath) {
    +    out.keyPath = keyPath
    +  }
    +
    +  const remoteHermesPath = String(entry.remoteHermesPath || '').trim()
    +
    +  if (remoteHermesPath) {
    +    out.remoteHermesPath = remoteHermesPath
    +  }
    +
    +  return out
    +}
    +
    +function profileSshOverride(config, profile) {
    +  const key = connectionScopeKey(profile)
    +  const entry = key ? config?.profiles?.[key] : null
    +
    +  return normalizeSshConfig(entry)
    +}
    +
    +function savedProfileSsh(config, profile) {
    +  const key = connectionScopeKey(profile)
    +  const entry = key ? config?.profiles?.[key] : null
    +
    +  if (!entry || entry.mode !== 'local') {
    +    return null
    +  }
    +
    +  return normalizeSshConfig(entry.savedSsh)
    +}
    +
    +function profileHasRemoteConnection(config, profile) {
    +  return Boolean(profileRemoteOverride(config, profile) || profileSshOverride(config, profile))
    +}
    +
    +function localProfileEntry(existing) {
    +  const ssh = normalizeSshConfig(existing) || normalizeSshConfig(existing?.savedSsh)
    +
    +  return ssh ? { mode: 'local', savedSsh: ssh } : null
    +}
    +
    +function hostLabelFromBaseUrl(baseUrl) {
    +  const raw = String(baseUrl || '').trim()
    +
    +  if (!raw) {
    +    return null
    +  }
    +
    +  try {
    +    const parsed = new URL(raw)
    +
    +    if (!parsed.hostname) {
    +      return null
    +    }
    +
    +    return parsed.port && parsed.port !== '80' && parsed.port !== '443'
    +      ? `${parsed.hostname}:${parsed.port}`
    +      : parsed.hostname
    +  } catch {
    +    return null
    +  }
    +}
    +
     /**
      * Select a profile's explicit remote override from a connection config, or null
      * when it has none (so the caller falls back to env → global remote → local).
    ```

    ```diff
    @@ -372,15 +493,21 @@ export {
       cookiesHaveSession,
       gatewayTicketFailure,
       gatewayWsUrlIpcResult,
    +  hostLabelFromBaseUrl,
       isGatewayAuthRejection,
    +  localProfileEntry,
       modeIsRemoteLike,
       normalizeRemoteBaseUrl,
    +  normalizeSshConfig,
       normAuthMode,
       pathWithGlobalRemoteProfile,
       PRIVY_SESSION_COOKIE_VARIANTS,
    +  profileHasRemoteConnection,
       profileRemoteOverride,
    +  profileSshOverride,
       resolveAuthMode,
       resolveTestWsUrl,
       RT_COOKIE_VARIANTS,
    +  savedProfileSsh,
       tokenPreview
     }
    ```
  - `apps/desktop/electron/desktop-installation.test.ts`

    ```diff
    @@ -0,0 +1,105 @@
    +import assert from 'node:assert/strict'
    +import fs from 'node:fs'
    +import os from 'node:os'
    +import path from 'node:path'
    +
    +import { test } from 'vitest'
    +
    +import { loadOrCreateInstallationId, parseInstallationId, sshOwnershipId } from './desktop-installation'
    +
    +const ID_A = '11111111-1111-4111-8111-111111111111'
    +const ID_B = '22222222-2222-4222-8222-222222222222'
    +
    +function withTempDir(run) {
    +  const directory = fs.mkdtempSync(path.join(os.tmpdir(), 'hermes-installation-'))
    +
    +  try {
    +    return run(directory)
    +  } finally {
    +    fs.rmSync(directory, { recursive: true, force: true })
    +  }
    +}
    +
    +test('parseInstallationId accepts only a version-4 UUID record', () => {
    +  assert.equal(parseInstallationId(JSON.stringify({ installationId: ID_A.toUpperCase() })), ID_A)
    +  assert.equal(parseInstallationId(JSON.stringify({ installationId: 'not-an-id' })), '')
    +  assert.equal(parseInstallationId('{}'), '')
    +  assert.equal(parseInstallationId('{'), '')
    +})
    +
    +test('loadOrCreateInstallationId persists and reuses one installation ID', () =>
    +  withTempDir(directory => {
    +    const filePath = path.join(directory, 'desktop-installation.json')
    +    assert.equal(
    +      loadOrCreateInstallationId(filePath, () => ID_A),
    +      ID_A
    +    )
    +    assert.equal(
    +      loadOrCreateInstallationId(filePath, () => ID_B),
    +      ID_A
    +    )
    +    assert.equal(fs.statSync(filePath).mode & 0o777, 0o600)
    +  }))
    +
    +test('loadOrCreateInstallationId tightens an existing identity file', () =>
    +  withTempDir(directory => {
    +    const filePath = path.join(directory, 'desktop-installation.json')
    +    fs.writeFileSync(filePath, JSON.stringify({ installationId: ID_A }), { mode: 0o644 })
    +    assert.equal(
    +      loadOrCreateInstallationId(filePath, () => ID_B),
    +      ID_A
    +    )
    +
    +    if (process.platform !== 'win32') {
    +      assert.equal(fs.statSync(filePath).mode & 0o777, 0o600)
    +    }
    +  }))
    +
    +test('loadOrCreateInstallationId replaces a malformed existing record', () =>
    +  withTempDir(directory => {
    +    const filePath = path.join(directory, 'desktop-installation.json')
    +    fs.writeFileSync(filePath, '{', { mode: 0o600 })
    +    assert.equal(
    +      loadOrCreateInstallationId(filePath, () => ID_A),
    +      ID_A
    +    )
    +    assert.equal(JSON.parse(fs.readFileSync(filePath, 'utf8')).installationId, ID_A)
    +  }))
    +
    +test('loadOrCreateInstallationId replaces an existing symlink', () =>
    +  withTempDir(directory => {
    +    if (process.platform === 'win32') {
    +      return
    +    }
    +
    +    const target = path.join(directory, 'target.json')
    +    const filePath = path.join(directory, 'desktop-installation.json')
    +    fs.writeFileSync(target, JSON.stringify({ installationId: ID_B }), { mode: 0o600 })
    +    fs.symlinkSync(target, filePath)
    +    assert.equal(
    +      loadOrCreateInstallationId(filePath, () => ID_A),
    +      ID_A
    +    )
    +    assert.equal(fs.lstatSync(filePath).isSymbolicLink(), false)
    +    assert.equal(JSON.parse(fs.readFileSync(target, 'utf8')).installationId, ID_B)
    +  }))
    +
    +test('loadOrCreateInstallationId replaces a malformed destination without a repair lock', () =>
    +  withTempDir(directory => {
    +    const filePath = path.join(directory, 'desktop-installation.json')
    +    fs.writeFileSync(filePath, '{', { mode: 0o600 })
    +    assert.equal(
    +      loadOrCreateInstallationId(filePath, () => ID_A),
    +      ID_A
    +    )
    +    assert.equal(fs.existsSync(`${filePath}.lock`), false)
    +  }))
    +
    +test('sshOwnershipId is stable, scoped, and does not disclose the UUID', () => {
    +  const global = sshOwnershipId(ID_A, '')
    +  assert.match(global, /^[0-9a-f]{32}$/)
    +  assert.equal(global, sshOwnershipId(ID_A, ''))
    +  assert.notEqual(global, sshOwnershipId(ID_A, 'worker'))
    +  assert.ok(!global.includes(ID_A.slice(0, 8)))
    +  assert.throws(() => sshOwnershipId('bad', ''))
    +})
    ```
  - `apps/desktop/electron/desktop-installation.ts`

    ```diff
    @@ -0,0 +1,137 @@
    +import crypto from 'node:crypto'
    +import fs from 'node:fs'
    +import path from 'node:path'
    +
    +const INSTALLATION_ID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i
    +
    +function parseInstallationId(raw) {
    +  try {
    +    const value = JSON.parse(String(raw || ''))?.installationId
    +
    +    return INSTALLATION_ID_RE.test(value) ? value.toLowerCase() : ''
    +  } catch {
    +    return ''
    +  }
    +}
    +
    +function readInstallationId(filePath) {
    +  try {
    +    const stat = fs.lstatSync(filePath)
    +
    +    if (!stat.isFile() || stat.isSymbolicLink()) {
    +      return ''
    +    }
    +
    +    if (typeof process.getuid === 'function' && stat.uid !== process.getuid()) {
    +      return ''
    +    }
    +
    +    if (process.platform !== 'win32' && (stat.mode & 0o777) !== 0o600) {
    +      fs.chmodSync(filePath, 0o600)
    +    }
    +
    +    return parseInstallationId(fs.readFileSync(filePath, 'utf8'))
    +  } catch {
    +    return ''
    +  }
    +}
    +
    +function waitForRepair() {
    +  const buffer = new SharedArrayBuffer(4)
    +  Atomics.wait(new Int32Array(buffer), 0, 0, 25)
    +}
    +
    +function loadOrCreateInstallationId(filePath, randomUUID = crypto.randomUUID) {
    +  const existing = readInstallationId(filePath)
    +
    +  if (existing) {
    +    return existing
    +  }
    +
    +  fs.mkdirSync(path.dirname(filePath), { recursive: true })
    +  const installationId = randomUUID().toLowerCase()
    +
    +  if (!INSTALLATION_ID_RE.test(installationId)) {
    +    throw new Error('Could not generate a valid desktop installation ID.')
    +  }
    +
    +  const repairPath = `${filePath}.repair.lock`
    +
    +  for (let attempt = 0; attempt < 40; attempt++) {
    +    let repairFd
    +
    +    try {
    +      repairFd = fs.openSync(repairPath, 'wx', 0o600)
    +    } catch (error: any) {
    +      if (error?.code !== 'EEXIST') {
    +        throw error
    +      }
    +
    +      const winner = readInstallationId(filePath)
    +
    +      if (winner) {
    +        return winner
    +      }
    +
    +      waitForRepair()
    +
    +      continue
    +    }
    +
    +    try {
    +      const winner = readInstallationId(filePath)
    +
    +      if (winner) {
    +        return winner
    +      }
    +
    +      try {
    +        const stat = fs.lstatSync(filePath)
    +
    +        if (!stat.isFile() && !stat.isSymbolicLink()) {
    +          throw new Error('Desktop installation ID path is not a regular file.')
    +        }
    +
    +        if (!stat.isSymbolicLink() && typeof process.getuid === 'function' && stat.uid !== process.getuid()) {
    +          throw new Error('Desktop installation ID is owned by another user.')
    +        }
    +
    +        fs.unlinkSync(filePath)
    +      } catch (error: any) {
    +        if (error?.code !== 'ENOENT') {
    +          throw error
    +        }
    +      }
    +
    +      fs.writeFileSync(filePath, JSON.stringify({ installationId }), { encoding: 'utf8', flag: 'wx', mode: 0o600 })
    +
    +      return installationId
    +    } finally {
    +      if (repairFd !== undefined) {
    +        fs.closeSync(repairFd)
    +      }
    +
    +      try {
    +        fs.unlinkSync(repairPath)
    +      } catch {
    +        void 0
    +      }
    +    }
    +  }
    +
    +  throw new Error('Could not repair the desktop installation ID.')
    +}
    +
    +function sshOwnershipId(installationId, scope) {
    +  if (!INSTALLATION_ID_RE.test(String(installationId || ''))) {
    +    throw new Error('Desktop installation ID is invalid.')
    +  }
    +
    +  return crypto
    +    .createHash('sha256')
    +    .update(`${installationId}\0${String(scope || '')}`)
    +    .digest('hex')
    +    .slice(0, 32)
    +}
    +
    +export { INSTALLATION_ID_RE, loadOrCreateInstallationId, parseInstallationId, readInstallationId, sshOwnershipId }
    ```
  - `apps/desktop/electron/main.ts`

    ```diff
    @@ -39,6 +39,7 @@ import { waitForDashboardPortAnnouncement } from './backend-ready'
     import { shouldLatchBackendStartFailure } from './backend-start-failure'
     import { detectRemoteDisplay, isWindowsBinaryPathInWsl, isWslEnvironment } from './bootstrap-platform'
     import { runBootstrap } from './bootstrap-runner'
    +import { applyConnectionChange, resolveTerminalConnection } from './connection-apply'
     import {
       authModeFromStatus,
       buildGatewayWsUrl,
    ```

    ```diff
    @@ -49,16 +50,23 @@ import {
       cookiesHaveSession,
       gatewayTicketFailure,
       gatewayWsUrlIpcResult,
    +  hostLabelFromBaseUrl,
    +  localProfileEntry,
       modeIsRemoteLike,
       normalizeRemoteBaseUrl,
    +  normalizeSshConfig,
       normAuthMode,
       pathWithGlobalRemoteProfile,
    +  profileHasRemoteConnection,
       profileRemoteOverride,
    +  profileSshOverride,
       resolveAuthMode,
       resolveTestWsUrl,
    +  savedProfileSsh,
       tokenPreview
     } from './connection-config'
     import { adoptServedDashboardToken } from './dashboard-token'
    +import { loadOrCreateInstallationId, sshOwnershipId } from './desktop-installation'
     import {
       buildPosixCleanupScript,
       buildWindowsCleanupScript,
    ```

    ```diff
    @@ -111,6 +119,7 @@ import { ensureMainWindow } from './main-window-lifecycle'
     import { serializeJsonBody, setJsonRequestHeaders } from './oauth-net-request'
     import { createKeepAwake } from './power-save'
     import { decideProfileDeleteAction, profileNameFromDeleteRequest, resolveRouteProfile } from './profile-delete-routing'
    +import * as remoteLifecycle from './remote-lifecycle'
     import { RemoteLivenessTracker, RemoteRevalidationCoordinator, revalidateRemoteConnection } from './remote-liveness'
     import {
       buildSessionWindowUrl,
    ```

    ```diff
    @@ -121,6 +130,15 @@ import {
       SESSION_WINDOW_MIN_WIDTH
     } from './session-windows'
     import { ensureSpawnHelperExecutable } from './spawn-helper-perms'
    +import { createBootstrapCoordinator, sshConfigFingerprint } from './ssh-bootstrap-coordinator'
    +import { collectSshConfigHosts, parseSshGOutput } from './ssh-config'
    +import {
    +  buildInteractiveSshArgs,
    +  createSshProbeConnection,
    +  pickLocalPort,
    +  redactSecrets,
    +  SshConnection
    +} from './ssh-connection'
     import { nativeOverlayWidth as computeNativeOverlayWidth, macTitleBarOverlayHeight } from './titlebar-overlay-width'
     import { resolveBehindCount, shouldCountCommits } from './update-count'
     import { readLiveUpdateMarker, writeUpdateMarker } from './update-marker'
    ```

    ```diff
    @@ -151,6 +169,12 @@ import {
       getVenvSitePackagesEntries,
       resolveVenvHermesCommand
     } from './windows-hermes-path'
    +import {
    +  buildWindowsInteractiveCommand,
    +  connectWindowsRemote,
    +  detectRemotePlatform,
    +  helper
    +} from './windows-remote-lifecycle'
     import {
       alreadyHasNoSandbox,
       buildNoSandboxRelaunchArgs,
    ```

    ```diff
    @@ -507,6 +531,7 @@ const BOOTSTRAP_COMPLETE_MARKER = path.join(ACTIVE_HERMES_ROOT, '.hermes-bootstr
     const BOOTSTRAP_MARKER_SCHEMA_VERSION = 1
     
     const DESKTOP_CONNECTION_CONFIG_PATH = path.join(app.getPath('userData'), 'connection.json')
    +const DESKTOP_INSTALLATION_PATH = path.join(app.getPath('userData'), 'desktop-installation.json')
     const DESKTOP_UPDATE_CONFIG_PATH = path.join(app.getPath('userData'), 'updates.json')
     const DESKTOP_WINDOW_STATE_PATH = path.join(app.getPath('userData'), 'window-state.json')
     // active-profile.json records which Hermes profile the desktop launches its
    ```

    ```diff
    @@ -4590,18 +4615,36 @@ function closePreviewWatchers() {
       }
     }
     
    -async function waitForHermes(baseUrl, token) {
    +async function waitForHermes(baseUrl, token, signal?) {
       const deadline = Date.now() + 45_000
       let lastError = null
     
       while (Date.now() < deadline) {
    +    if (signal?.aborted) {
    +      const error: any = new Error('SSH bootstrap was superseded by newer connection settings.')
    +      error.kind = 'superseded'
    +      throw error
    +    }
    +
         try {
           await fetchJson(`${baseUrl}/api/status`, token)
     
           return
         } catch (error) {
           lastError = error
    -      await new Promise(resolve => setTimeout(resolve, 500))
    +      await new Promise((resolve, reject) => {
    +        const timer = setTimeout(resolve, 500)
    +        signal?.addEventListener(
    +          'abort',
    +          () => {
    +            clearTimeout(timer)
    +            const aborted: any = new Error('SSH bootstrap was superseded by newer connection settings.')
    +            aborted.kind = 'superseded'
    +            reject(aborted)
    +          },
    +          { once: true }
    +        )
    +      })
         }
       }
     
    ```

    ```diff
    @@ -4936,7 +4979,9 @@ function setAndPersistZoomLevel(window, zoomLevel) {
       // downgrade or JSON read failure still finds a sane value).
       window.webContents
         .executeJavaScript(
    -      `try { localStorage.setItem(${JSON.stringify(ZOOM_STORAGE_KEY)}, ${JSON.stringify(String(next))}) } catch {}`
    +      `try { localStorage.setItem(${JSON.stringify(ZOOM_STORAGE_KEY)}, ${JSON.stringify(String(next))}) } catch {
    +      void 0
    +    }`
         )
         .catch(error => rememberLog(`[zoom] persist failed: ${error?.message || error}`))
     }
    ```

    ```diff
    @@ -6042,16 +6087,39 @@ function sanitizeConnectionProfiles(raw: Record<string, any>) {
           continue
         }
     
    +    if (entry.mode === 'ssh') {
    +      const ssh = normalizeSshConfig(entry)
    +
    +      if (ssh) {
    +        if (entry.token && typeof entry.token === 'object') {
    +          ssh.token = [redacted:secret-assignment]
    +        }
    +
    +        out[name] = ssh
    +      }
    +
    +      continue
    +    }
    +
         const cleaned: {
           mode: 'remote' | 'local' | 'cloud'
           url?: string
           authMode?: string
           token?: object
           org?: string
    +      savedSsh?: object
         } = {
           mode: modeIsRemoteLike(entry.mode) ? entry.mode : 'local'
         }
     
    +    if (cleaned.mode === 'local') {
    +      const savedSsh = normalizeSshConfig(entry.savedSsh)
    +
    +      if (savedSsh) {
    +        cleaned.savedSsh = savedSsh
    +      }
    +    }
    +
         const url = String(entry.url || '').trim()
     
         if (url) {
    ```

    ```diff
    @@ -6109,7 +6177,7 @@ function readDesktopConnectionConfig() {
           // backward compatibility with configs written before OAuth support.
           remote.authMode = remote.authMode === 'oauth' ? 'oauth' : 'token'
           config = {
    -        mode: modeIsRemoteLike(parsed.mode) ? parsed.mode : 'local',
    +        mode: parsed.mode === 'ssh' ? 'ssh' : modeIsRemoteLike(parsed.mode) ? parsed.mode : 'local',
             remote,
             // Per-profile remote overrides: each profile may point at its own
             // backend (local spawn or its own remote URL). Preserved verbatim so
    ```

    ```diff
    @@ -6176,15 +6244,15 @@ async function sanitizeDesktopConnectionConfig(config = readDesktopConnectionCon
       const block = key ? scoped || {} : config.remote || {}
     
       const envOverride = key ? false : Boolean(process.env.HERMES_DESKTOP_REMOTE_URL)
    +  const savedMode = key ? scoped?.mode : config.mode
    +  const ssh = savedMode === 'ssh' ? normalizeSshConfig(block) : null
    +
    +  const savedSsh = savedMode === 'local' ? (key ? savedProfileSsh(config, key) : normalizeSshConfig(block)) : null
     
       const remoteToken = [redacted:secret-assignment]
       const authMode = normAuthMode(block.authMode)
       const remoteUrl = envOverride ? String(process.env.HERMES_DESKTOP_REMOTE_URL || '') : String(block.url || '')
    -  // The env override forces a plain remote connection. Otherwise reflect the
    -  // saved mode, preserving 'cloud' (a Hermes Cloud connection — Q6) so the UI
    -  // reopens into the cloud picker; any non-remote-like value collapses to local.
    -  const savedMode = key ? scoped?.mode : config.mode
    -  const mode = envOverride ? 'remote' : modeIsRemoteLike(savedMode) ? savedMode : 'local'
    +  const mode = envOverride ? 'remote' : savedMode === 'ssh' ? 'ssh' : modeIsRemoteLike(savedMode) ? savedMode : 'local'
     
       let remoteOauthConnected = false
     
    ```

    ```diff
    @@ -6212,6 +6280,11 @@ async function sanitizeDesktopConnectionConfig(config = readDesktopConnectionCon
         cloudOrg: mode === 'cloud' ? String(block.org || '') : '',
         remoteTokenPreview: [redacted:secret-assignment]
         remoteTokenSet: [redacted:secret-assignment]
    +    sshHost: (ssh || savedSsh)?.host || '',
    +    sshUser: (ssh || savedSsh)?.user || '',
    +    sshPort: (ssh || savedSsh)?.port || null,
    +    sshKeyPath: (ssh || savedSsh)?.keyPath || '',
    +    sshRemoteHermesPath: (ssh || savedSsh)?.remoteHermesPath || '',
         // The env override only forces the global/primary connection; a per-profile
         // scope is never overridden by HERMES_DESKTOP_REMOTE_URL.
         envOverride
    ```

    ```diff
    @@ -6250,7 +6323,7 @@ function coerceDesktopConnectionConfig(input: any = {}, existing = readDesktopCo
       // 'cloud' and 'remote' both persist a remote-shaped block; 'cloud' is
       // remembered as its own provenance (Q6) and resolves to remote downstream.
       // Anything else collapses to local.
    -  const mode = modeIsRemoteLike(input.mode) ? input.mode : 'local'
    +  const mode = input.mode === 'ssh' ? 'ssh' : modeIsRemoteLike(input.mode) ? input.mode : 'local'
       const remoteLike = modeIsRemoteLike(mode)
     
       // The block being edited: a per-profile entry or the global remote block.
    ```

    ```diff
    @@ -6263,7 +6336,8 @@ function coerceDesktopConnectionConfig(input: any = {}, existing = readDesktopCo
       // block. (remote↔local toggles still preserve a real remote URL as before.)
       const existingMode = key ? existing.profiles?.[key]?.mode : existing.mode
       const leavingCloud = existingMode === 'cloud' && mode !== 'cloud'
    -  const existingBlock = leavingCloud ? {} : rawExistingBlock
    +  const leavingSsh = rawExistingBlock.mode === 'ssh' && mode !== 'ssh' && mode !== 'local'
    +  const existingBlock = leavingCloud || leavingSsh ? {} : rawExistingBlock
       const remoteUrl = String(input.remoteUrl ?? existingBlock.url ?? '').trim()
       // authMode: explicit input wins; otherwise inherit the saved value, default 'token'.
       const authMode = resolveAuthMode(input.remoteAuthMode, existingBlock.authMode)
    ```

    ```diff
    @@ -6279,6 +6353,22 @@ function coerceDesktopConnectionConfig(input: any = {}, existing = readDesktopCo
           : { encoding: 'plain', value: incomingToken }
         : existingBlock.token
     
    +  if (mode === 'ssh') {
    +    const sshBlock = buildSshBlock(input, savedProfileSsh(existing, key) || rawExistingBlock)
    +
    +    if (key) {
    +      const profiles = { ...(existing.profiles || {}), [key]: sshBlock }
    +
    +      return {
    +        mode: existing.mode === 'ssh' || modeIsRemoteLike(existing.mode) ? existing.mode : 'local',
    +        remote: existing.remote || {},
    +        profiles
    +      }
    +    }
    +
    +    return { mode: 'ssh', remote: sshBlock, profiles: existing.profiles || {} }
    +  }
    +
       if (key) {
         // Per-profile scope: a remote/cloud entry pins this profile to its own
         // backend; a local entry clears the override so the profile inherits the
    ```

    ```diff
    @@ -6288,11 +6378,17 @@ function coerceDesktopConnectionConfig(input: any = {}, existing = readDesktopCo
         if (remoteLike) {
           profiles[key] = { mode, ...buildRemoteBlock(remoteUrl, authMode, nextToken, cloudOrg) }
         } else {
    -      delete profiles[key]
    +      const localEntry = localProfileEntry(rawExistingBlock)
    +
    +      if (localEntry) {
    +        profiles[key] = localEntry
    +      } else {
    +        delete profiles[key]
    +      }
         }
     
         return {
    -      mode: modeIsRemoteLike(existing.mode) ? existing.mode : 'local',
    +      mode: existing.mode === 'ssh' || modeIsRemoteLike(existing.mode) ? existing.mode : 'local',
           remote: existing.remote || {},
           profiles
         }
    ```

    ```diff
    @@ -6300,19 +6396,62 @@ function coerceDesktopConnectionConfig(input: any = {}, existing = readDesktopCo
     
       const nextRemote = remoteLike
         ? buildRemoteBlock(remoteUrl, authMode, nextToken, cloudOrg)
    -    : { url: remoteUrl ? normalizeRemoteBaseUrl(remoteUrl) : remoteUrl, authMode, token: nextToken }
    +    : existingMode === 'ssh'
    +      ? rawExistingBlock
    +      : { url: remoteUrl ? normalizeRemoteBaseUrl(remoteUrl) : remoteUrl, authMode, token: nextToken }
     
       // Preserve per-profile overrides when saving the global connection.
       return { mode, remote: nextRemote, profiles: existing.profiles || {} }
     }
     
    +// Build an SSH connection block from a save payload, preserving an
    +// already-adopted dashboard token from the existing block (the token is minted
    +// + reconciled at bootstrap, never user-entered). `mode: 'ssh'` is stamped so
    +// normalizeSshConfig/profileSshOverride recognize it.
    +function buildSshBlock(input: any, existingBlock: any = {}) {
    +  // `??` (not `||`) so an explicit '' (user CLEARED the field) wins over the
    +  // saved value; only a truly absent (undefined) field inherits.
    +  const merged = normalizeSshConfig({
    +    mode: 'ssh',
    +    host: input.sshHost ?? existingBlock.host,
    +    user: input.sshUser ?? existingBlock.user,
    +    port: input.sshPort ?? existingBlock.port,
    +    keyPath: input.sshKeyPath ?? existingBlock.keyPath,
    +    remoteHermesPath: input.sshRemoteHermesPath ?? existingBlock.remoteHermesPath
    +  })
    +
    +  if (!merged) {
    +    throw new Error('SSH host is required.')
    +  }
    +
    +  // Carry forward an already-adopted dashboard token unless the host changed
    +  // (a different host invalidates the old dashboard's token).
    +  if (existingBlock.token && existingBlock.host === merged.host) {
    +    merged.token = [redacted:secret-assignment]
    +  }
    +
    +  return merged
    +}
    +
     // Build a remote backend connection descriptor from an already-resolved remote
     // config. Handles both auth models (OAuth ws-ticket vs static session token)
     // and is shared by the per-profile, env, and global resolution paths. `token`
     // is the DECRYPTED static token (or null in OAuth mode). `source` is a label
     // for diagnostics ('profile' | 'env' | 'settings').
    -async function buildRemoteConnection(rawUrl, authMode, token, source) {
    +async function buildRemoteConnection(
    +  rawUrl,
    +  authMode,
    +  token,
    +  source,
    +  remoteHost?,
    +  remoteKind = 'url',
    +  remoteIdentity?
    +) {
       const baseUrl = normalizeRemoteBaseUrl(rawUrl)
    +  // For token/oauth remotes the meaningful host is the real backend URL; for
    +  // SSH remotes the caller passes the entered/resolved host explicitly (the
    +  // baseUrl is a 127.0.0.1 tunnel and would be useless in the pill).
    +  const host = remoteHost || hostLabelFromBaseUrl(baseUrl)
     
       if (authMode === 'oauth') {
         // OAuth gateway: auth comes from the session cookies in the OAuth
    ```

    ```diff
    @@ -6350,6 +6489,9 @@ async function buildRemoteConnection(rawUrl, authMode, token, source) {
           mode: 'remote',
           source,
           authMode: 'oauth',
    +      remoteHost: host || undefined,
    +      remoteIdentity,
    +      remoteKind,
           // No static token in OAuth mode; REST is cookie-authed via the partition.
           token: null,
           wsUrl: buildGatewayWsUrlWithTicket(baseUrl, ticket)
    ```

    ```diff
    @@ -6368,11 +6510,288 @@ async function buildRemoteConnection(rawUrl, authMode, token, source) {
         mode: 'remote',
         source,
         authMode: 'token',
    +    remoteHost: host || undefined,
    +    remoteIdentity,
    +    remoteKind,
         token,
         wsUrl: buildGatewayWsUrl(baseUrl, token)
       }
     }
     
    +const sshConnections = new Map<string, any>()
    +const desktopInstallationId = loadOrCreateInstallationId(DESKTOP_INSTALLATION_PATH)
    +
    +const sshBootstrapCoordinator = createBootstrapCoordinator()
    +
    +let sshQuitTeardownDone = false
    +
    +function sshScopeKey(profile) {
    +  return connectionScopeKey(profile) || ''
    +}
    +
    +function sshOwnershipKey(profile) {
    +  return sshOwnershipId(desktopInstallationId, sshScopeKey(profile))
    +}
    +
    +function sshRememberLog(chunk) {
    +  rememberLog(redactSecrets(String(chunk == null ? '' : chunk)))
    +}
    +
    +async function sshProbeReuseProof(baseUrl, token, spawnNonce) {
    +  try {
    +    const proof: any = await fetchJson(`${baseUrl}/api/ssh/ownership`, token)
    +
    +    return proof?.ok === true && proof.sshOwnerNonce === spawnNonce && proof.protocolVersion === 1
    +      ? 'authenticated-ok'
    +      : 'authenticated-stale'
    +  } catch (error: any) {
    +    if (/^(401|403|404):/.test(String(error?.message || ''))) {
    +      return 'authenticated-stale'
    +    }
    +
    +    throw error
    +  }
    +}
    +
    +async function teardownSshConnection(profile) {
    +  const scope = sshScopeKey(profile)
    +  const state = sshConnections.get(scope)
    +
    +  if (!state) {
    +    return
    +  }
    +
    +  sshConnections.delete(scope)
    +
    +  for (const [id, info] of [...terminalSessions.entries()]) {
    +    if (info.sshScope === scope) {
    +      disposeTerminalSession(id)
    +    }
    +  }
    +
    +  try {
    +    if (state.localPort && state.remotePort) {
    +      await state.ssh.cancelForward(state.localPort, state.remotePort)
    +    }
    +  } catch {
    +    // best effort
    +  }
    +
    +  try {
    +    await state.ssh.close()
    +  } catch {
    +    // best effort
    +  }
    +}
    +
    +// CRITICAL: this must mirror resolveRemoteBackend's precedence, not just return
    +// any cached SSH state. A per-profile token/OAuth override wins over a global
    +// SSH connection — so if the active profile resolves to a NON-SSH backend, the
    +// terminal must NOT fall through to a global SSH host.
    +function activeSshTerminalTarget() {
    +  const profile = primaryProfileKey()
    +  const config = readDesktopConnectionConfig()
    +
    +  if (profileSshOverride(config, profile)) {
    +    const scope = sshScopeKey(profile)
    +    const state = sshConnections.get(scope)
    +
    +    return state && state.ssh ? { ssh: state.ssh, scope } : 'pending'
    +  }
    +
    +  if (profileRemoteOverride(config, profile)) {
    +    return null
    +  }
    +
    +  if (process.env.HERMES_DESKTOP_REMOTE_URL) {
    +    return null
    +  }
    +
    +  if (config.mode === 'ssh') {
    +    const state = sshConnections.get('')
    +
    +    return state && state.ssh ? { ssh: state.ssh, scope: '' } : 'pending'
    +  }
    +
    +  return null
    +}
    +
    +function effectiveSshConfigFingerprint(sshConfig) {
    +  const ssh =
    +    process.platform === 'win32'
    +      ? path.join(process.env.SystemRoot || 'C:\\Windows', 'System32', 'OpenSSH', 'ssh.exe')
    +      : 'ssh'
    +
    +  const args = ['-G']
    +
    +  if (sshConfig.port) {
    +    args.push('-p', String(sshConfig.port))
    +  }
    +
    +  if (sshConfig.keyPath) {
    +    args.push('-i', sshConfig.keyPath)
    +  }
    +
    +  args.push('--', sshConfig.user ? `${sshConfig.user}@${sshConfig.host}` : sshConfig.host)
    +  const output = execFileSync(ssh, args, { encoding: 'utf8', timeout: 10_000, windowsHide: true })
    +
    +  return crypto.createHash('sha256').update(output).digest('hex')
    +}
    +
    +async function bootstrapSshConnection(profile, sshConfig, reuseToken, source) {
    +  const scope = sshScopeKey(profile)
    +  const effectiveConfigFingerprint = effectiveSshConfigFingerprint(sshConfig)
    +  const resolvedConfig = { ...sshConfig, effectiveConfigFingerprint }
    +  const fingerprint = sshConfigFingerprint(scope, resolvedConfig)
    +
    +  return sshBootstrapCoordinator.start(scope, fingerprint, lease =>
    +    bootstrapSshConnectionInner(profile, resolvedConfig, reuseToken, source, fingerprint, lease)
    +  )
    +}
    +
    +async function bootstrapSshConnectionInner(profile, sshConfig, reuseToken, source, fingerprint, lease) {
    +  const scope = sshScopeKey(profile)
    +  const hostLabel = sshConfig.user ? `${sshConfig.user}@${sshConfig.host}` : sshConfig.host
    +  const existing = sshConnections.get(scope)
    +
    +  if (existing && existing.fingerprint !== fingerprint) {
    +    await teardownSshConnection(profile)
    +  }
    +
    +  let ssh = sshConnections.get(scope)?.ssh
    +
    +  if (ssh && !(await ssh.isAlive())) {
    +    try {
    +      await ssh.close()
    +    } catch {
    +      void 0
    +    }
    +
    +    ssh = null
    +    sshConnections.delete(scope)
    +  }
    +
    +  const created = !ssh
    +
    +  let removeForceCleanup = () => {}
    +
    +  if (created) {
    +    ssh = new SshConnection(
    +      { host: sshConfig.host, user: sshConfig.user, port: sshConfig.port, keyPath: sshConfig.keyPath },
    +      {
    +        rememberLog: sshRememberLog,
    +        ownershipId: sshOwnershipKey(profile),
    +        scope,
    +        effectiveConfigFingerprint: sshConfig.effectiveConfigFingerprint
    +      }
    +    )
    +    removeForceCleanup = lease.onForceCleanup(() => ssh.close())
    +    await ssh.open()
    +  }
    +
    +  let result
    +
    +  try {
    +    const platform = await detectRemotePlatform(ssh, sshConfig.remoteHermesPath || '')
    +    const lifecycle = platform.os === 'Windows' ? connectWindowsRemote : remoteLifecycle.connect
    +    result = await lifecycle({
    +      ssh,
    +      profile: connectionScopeKey(profile) || '',
    +      remoteHermesPath: sshConfig.remoteHermesPath || '',
    +      ownershipId: sshOwnershipKey(profile),
    +      reuseToken: reuseToken || '',
    +      forward: (localPort, remotePort) => ssh.forward(localPort, remotePort),
    +      cancelForward: (localPort, remotePort) => ssh.cancelForward(localPort, remotePort),
    +      pickLocalPort,
    +      waitForHermes: (baseUrl, token) => waitForHermes(baseUrl, token, lease.signal),
    +      probeReuseProof: sshProbeReuseProof,
    +      adoptServedToken: [redacted:secret-assignment]
    +      rememberLog: sshRememberLog,
    +      signal: lease.signal
    +    })
    +  } catch (error: any) {
    +    if (created) {
    +      try {
    +        await ssh.close()
    +      } catch {
    +        void 0
    +      }
    +    }
    +
    +    const err = new Error(error.message) as any
    +    err.sshError = error.kind || 'unknown'
    +    err.isSshBootstrap = true
    +    throw err
    +  }
    +
    +  try {
    +    lease.assertCurrent()
    +  } catch (error) {
    +    try {
    +      await ssh.cancelForward(result.localPort, result.remotePort)
    +      await ssh.close()
    +    } catch {
    +      void 0
    +    }
    +
    +    throw error
    +  }
    +
    +  persistSshConnectionToken(profile, source, result.token)
    +
    +  removeForceCleanup()
    +  sshConnections.set(scope, {
    +    ssh,
    +    fingerprint,
    +    localPort: result.localPort,
    +    remotePort: result.remotePort,
    +    pid: result.pid,
    +    host: sshConfig.host,
    +    hostLabel,
    +    hermesVersion: result.hermesVersion || '',
    +    remotePlatform: result.platform?.os || '',
    +    reused: result.reused
    +  })
    +
    +  sshRememberLog(
    +    `[ssh] connection ${result.reused ? 'REUSED' : 'spawned'} dashboard: ` +
    +      `${result.hermesVersion || 'hermes (version unknown)'} at ${result.hermesPath || '?'}`
    +  )
    +
    +  const connection = await buildRemoteConnection(
    +    result.baseUrl,
    +    'token',
    +    result.token,
    +    source,
    +    hostLabel,
    +    'ssh',
    +    result.ownershipId
    +  )
    +
    +  return { ...connection, remoteHermesVersion: result.hermesVersion || '' }
    +}
    +
    +function persistSshConnectionToken(profile, source, token) {
    +  try {
    +    const config = readDesktopConnectionConfig()
    +    const encrypted = encryptDesktopSecret(token)
    +
    +    if (source === 'profile') {
    +      const key = connectionScopeKey(profile)
    +
    +      if (key && config.profiles?.[key]?.mode === 'ssh') {
    +        config.profiles[key].token = encrypted
    +        writeDesktopConnectionConfig(config)
    +      }
    +    } else if (config.mode === 'ssh' && config.remote) {
    +      config.remote.token = encrypted
    +      writeDesktopConnectionConfig(config)
    +    }
    +  } catch (error: any) {
    +    sshRememberLog(`[ssh] could not persist served token: [redacted:secret-assignment]
    +  }
    +}
    +
     // Resolve the remote backend for a given profile, or null when that profile
     // should run a LOCAL backend. Precedence:
     //   1. explicit per-profile remote override (connection.json `profiles[name]`)
    ```

    ```diff
    @@ -6386,12 +6805,27 @@ async function resolveRemoteBackend(profile) {
       // 1. Per-profile override — "a profile with its own remote host". Wins even
       //    over the env override so an explicitly-configured profile always
       //    reaches its intended backend.
    +  const sshOverride = profileSshOverride(config, profile)
    +
    +  if (sshOverride) {
    +    const reuseToken = [redacted:secret-assignment]
    +
    +    return bootstrapSshConnection(profile, sshOverride, reuseToken, 'profile')
    +  }
    +
       const override = profileRemoteOverride(config, profile)
     
       if (override) {
         const token = [redacted:secret-assignment] === 'oauth' ? null : decryptDesktopSecret(override.token)
     
    -    return buildRemoteConnection(override.url, override.authMode, token, 'profile')
    +    return buildRemoteConnection(
    +      override.url,
    +      override.authMode,
    +      token,
    +      'profile',
    +      undefined,
    +      config.profiles?.[connectionScopeKey(profile)]?.mode === 'cloud' ? 'cloud' : 'url'
    +    )
       }
     
       // 2. Env override (global, token-auth only).
    ```

    ```diff
    @@ -6409,7 +6843,20 @@ async function resolveRemoteBackend(profile) {
         return buildRemoteConnection(rawEnvUrl, 'token', rawEnvToken, 'env')
       }
     
    -  // 3. Global remote (or cloud — cloud resolves to a remote backend, Q6).
    +  // 3. Global remote.
    +  if (config.mode === 'ssh') {
    +    const ssh = normalizeSshConfig({ mode: 'ssh', ...(config.remote || {}) })
    +
    +    if (!ssh) {
    +      throw new Error('SSH remote mode is selected but no host is configured.')
    +    }
    +
    +    const reuseToken = [redacted:secret-assignment]
    +
    +    return bootstrapSshConnection(null, ssh, reuseToken, 'settings')
    +  }
    +
    +  // Cloud resolves through the existing URL/OAuth path.
       if (!modeIsRemoteLike(config.mode)) {
         return null
       }
    ```

    ```diff
    @@ -6417,7 +6864,14 @@ async function resolveRemoteBackend(profile) {
       const authMode = normAuthMode(config.remote?.authMode)
       const token = authMode === 'oauth' ? null : decryptDesktopSecret(config.remote?.token)
     
    -  return buildRemoteConnection(config.remote?.url, authMode, token, 'settings')
    +  return buildRemoteConnection(
    +    config.remote?.url,
    +    authMode,
    +    token,
    +    'settings',
    +    undefined,
    +    config.mode === 'cloud' ? 'cloud' : 'url'
    +  )
     }
     
     // A remote profile's sessions live on its remote host's state.db, not on a local
    ```

    ```diff
    @@ -6425,13 +6879,13 @@ async function resolveRemoteBackend(profile) {
     // not the local-disk fast path. These three helpers drive that (see
     // interceptSessionReadForRemote).
     function profileHasRemoteOverride(profile) {
    -  return Boolean(profileRemoteOverride(readDesktopConnectionConfig(), profile))
    +  return profileHasRemoteConnection(readDesktopConnectionConfig(), profile)
     }
     
     function configuredRemoteProfileNames() {
       const config = readDesktopConnectionConfig()
     
    -  return Object.keys(config.profiles || {}).filter(name => profileRemoteOverride(config, name))
    +  return Object.keys(config.profiles || {}).filter(name => profileHasRemoteConnection(config, name))
     }
     
     // True when the app is in app-global remote mode (Settings → "All profiles" →
    ```

    ```diff
    @@ -6443,7 +6897,9 @@ function globalRemoteActive() {
         return true
       }
     
    -  return modeIsRemoteLike(readDesktopConnectionConfig().mode)
    +  const mode = readDesktopConnectionConfig().mode
    +
    +  return modeIsRemoteLike(mode) || mode === 'ssh'
     }
     
     // True when the PRIMARY profile's backend resolves to a remote/cloud host —
    ```

    ```diff
    @@ -6538,6 +6994,90 @@ async function probeRemoteAuthMode(rawUrl) {
     }
     
     async function testDesktopConnectionConfig(input: any = {}) {
    +  if (input.mode === 'ssh') {
    +    const sshConfig = normalizeSshConfig({
    +      mode: 'ssh',
    +      host: input.sshHost,
    +      user: input.sshUser,
    +      port: input.sshPort,
    +      keyPath: input.sshKeyPath,
    +      remoteHermesPath: input.sshRemoteHermesPath
    +    })
    +
    +    if (!sshConfig) {
    +      return { reachable: false, sshError: 'unreachable', error: 'SSH host is required.' }
    +    }
    +
    +    const ssh = createSshProbeConnection(
    +      { host: sshConfig.host, user: sshConfig.user, port: sshConfig.port, keyPath: sshConfig.keyPath },
    +      { rememberLog: sshRememberLog }
    +    )
    +
    +    try {
    +      // One bounded retry on TIMEOUT only: a cold Windows backend's first
    +      // PowerShell exec can exceed the budget (observed live), and a timeout is
    +      // indeterminate — unlike auth/host-key/unreachable, which are verdicts.
    +      let attempt = 0
    +
    +      for (;;) {
    +        try {
    +          await ssh.open()
    +          const platform: any = await detectRemotePlatform(ssh, sshConfig.remoteHermesPath || '')
    +          let hermesPath
    +          let hermesVersion
    +          let supported
    +
    +          if (platform.os === 'Windows') {
    +            const runtime = platform
    +            hermesPath = runtime.hermesPath
    +            const inspection = await helper(ssh, runtime, 'inspect', [runtime.hermesPath])
    +            hermesVersion = inspection.version
    +            supported = inspection.supported
    +          } else {
    +            hermesPath = await remoteLifecycle.locateHermes(ssh, sshConfig.remoteHermesPath || '')
    +            hermesVersion = await remoteLifecycle.probeHermesVersion(ssh, hermesPath)
    +            supported = await remoteLifecycle.remoteSupportsSshOwnership(ssh, hermesPath)
    +          }
    +
    +          if (!supported) {
    +            return {
    +              reachable: false,
    +              sshError: 'update-required',
    +              error: 'Update Hermes on the remote host before connecting with Desktop SSH.'
    +            }
    +          }
    +
    +          return {
    +            reachable: true,
    +            sshError: null,
    +            error: null,
    +            remotePlatform: `${platform.os}/${platform.arch}`,
    +            remoteHermesPath: hermesPath,
    +            remoteHermesVersion: hermesVersion,
    +            host: sshConfig.user ? `${sshConfig.user}@${sshConfig.host}` : sshConfig.host
    +          }
    +        } catch (error: any) {
    +          if (error?.kind === 'timeout' && attempt === 0) {
    +            attempt += 1
    +            sshRememberLog('[ssh] test probe timed out once; retrying')
    +
    +            continue
    +          }
    +
    +          throw error
    +        }
    +      }
    +    } catch (error: any) {
    +      return { reachable: false, sshError: error.kind || 'unknown', error: error.message }
    +    } finally {
    +      try {
    +        await ssh.close()
    +      } catch {
    +        void 0
    +      }
    +    }
    +  }
    +
       const config = coerceDesktopConnectionConfig(input, readDesktopConnectionConfig(), { persistToken: false })
       const key = connectionScopeKey(input.profile)
       // The block under test: a per-profile entry or the global remote. Coerce has
    ```

    ```diff
    @@ -7063,6 +7603,9 @@ async function startHermes() {
             mode: 'remote',
             source: remote.source,
             authMode: remote.authMode || 'token',
    +        remoteHost: remote.remoteHost,
    +        remoteKind: remote.remoteKind,
    +        remoteHermesVersion: remote.remoteHermesVersion,
             token: [redacted:secret-assignment]
             wsUrl: remote.wsUrl,
             logs: hermesLog.slice(-80),
    ```

    ```diff
    @@ -7864,8 +8407,8 @@ ipcMain.handle('hermes:connection:revalidate', async () => {
       // Main and every session pop-out have their own renderer reconnect loop but
       // share this primary connection. Coalesce simultaneous requests so one outage
       // produces one failure observation rather than exhausting the whole streak.
    -  return remoteRevalidation.run(connectionPromise, () =>
    -    revalidateRemoteConnection({
    +  return remoteRevalidation.run(connectionPromise, async () => {
    +    const result = await revalidateRemoteConnection({
           connectionPromise,
           currentConnectionPromise: () => backendConnectionState.getPromise(),
           log: rememberLog,
    ```

    ```diff
    @@ -7873,7 +8416,22 @@ ipcMain.handle('hermes:connection:revalidate', async () => {
           resetConnection: resetHermesConnection,
           tracker: remoteLiveness
         })
    -  )
    +
    +    // A rebuilt SSH connection must also tear down its tunnel/master before the
    +    // renderer re-dials (which only happens after this handler resolves), so the
    +    // fresh bootstrap can't reattach to a dying transport.
    +    if (result.rebuilt) {
    +      const conn = await connectionPromise.catch(() => null)
    +
    +      if (conn?.remoteKind === 'ssh') {
    +        const profile = primaryProfileKey()
    +        await sshBootstrapCoordinator.cancelAndWait(sshScopeKey(profile))
    +        await teardownSshConnection(profile)
    +      }
    +    }
    +
    +    return result
    +  })
     })
     ipcMain.handle('hermes:backend:touch', async (_event, profile) => {
       touchPoolBackend(profile)
    ```

    ```diff
    @@ -8103,6 +8661,50 @@ ipcMain.handle('hermes:bootstrap:get', async () => getBootstrapState())
     ipcMain.handle('hermes:connection-config:get', async (_event, profile) =>
       sanitizeDesktopConnectionConfig(readDesktopConnectionConfig(), profile)
     )
    +ipcMain.handle('hermes:ssh-config:hosts', async () => ({ hosts: collectSshConfigHosts() }))
    +ipcMain.handle('hermes:ssh-config:resolve', async (_event, host) => {
    +  const value = String(host || '').trim()
    +
    +  if (!value) {
    +    throw new Error('SSH host is required.')
    +  }
    +
    +  const ssh =
    +    process.platform === 'win32'
    +      ? path.join(process.env.SystemRoot || 'C:\\Windows', 'System32', 'OpenSSH', 'ssh.exe')
    +      : 'ssh'
    +
    +  return new Promise((resolve, reject) => {
    +    const child = spawn(ssh, ['-G', '--', value], hiddenWindowsChildOptions({ stdio: ['ignore', 'pipe', 'pipe'] }))
    +    let stdout = ''
    +    let stderr = ''
    +
    +    const timer = setTimeout(() => {
    +      child.kill()
    +      reject(new Error('SSH config resolution timed out.'))
    +    }, 10_000)
    +
    +    child.stdout.on('data', chunk => {
    +      stdout += String(chunk)
    +    })
    +    child.stderr.on('data', chunk => {
    +      stderr += String(chunk)
    +    })
    +    child.once('error', error => {
    +      clearTimeout(timer)
    +      reject(error)
    +    })
    +    child.once('close', code => {
    +      clearTimeout(timer)
    +
    +      if (code !== 0) {
    +        reject(new Error(stderr.trim() || 'Could not resolve SSH host.'))
    +      } else {
    +        resolve(parseSshGOutput(stdout))
    +      }
    +    })
    +  })
    +})
     ipcMain.handle('hermes:connection-config:test', async (_event, payload) => testDesktopConnectionConfig(payload))
     ipcMain.handle('hermes:connection-config:probe', async (_event, rawUrl) => probeRemoteAuthMode(rawUrl))
     ipcMain.handle('hermes:connection-config:oauth-login', async (_event, rawUrl) => {
    ```

    ```diff
    @@ -8164,19 +8766,17 @@ ipcMain.handle('hermes:connection-config:apply', async (_event, payload) => {
       writeDesktopConnectionConfig(config)
     
       const key = connectionScopeKey(payload?.profile)
    -
    -  if (key && key !== primaryProfileKey()) {
    -    // Editing a NON-primary profile's connection: don't disturb the window's
    -    // primary backend. Drop the profile's pooled backend so the next switch
    -    // re-resolves against the new remote/local target.
    -    stopPoolBackend(key)
    -  } else {
    -    // Global / primary connection: soft re-home. Tear down the window backend
    -    // without resetting boot UI or reloading — the shell stays, the renderer
    -    // wipes session lists (skeletons) and re-dials on hermes:connection:applied.
    -    await teardownPrimaryBackendAndWait({ soft: true })
    -    sendConnectionApplied()
    -  }
    +  const scope = key || ''
    +
    +  await applyConnectionChange({
    +    cancelAndWait: value => sshBootstrapCoordinator.cancelAndWait(value),
    +    isPrimary: !key || key === primaryProfileKey(),
    +    scope,
    +    sendApplied: sendConnectionApplied,
    +    stopPool: stopPoolBackend,
    +    teardownPrimary: () => teardownPrimaryBackendAndWait({ soft: true }),
    +    teardownSsh: value => teardownSshConnection(value || null)
    +  })
     
       return sanitizeDesktopConnectionConfig(config, payload?.profile)
     })
    ```

    ```diff
    @@ -9254,15 +9854,30 @@ ipcMain.handle('hermes:terminal:start', async (event, payload = {}) => {
       const cols = Math.max(2, Number.parseInt(String(payload?.cols || 80), 10) || 80)
       const rows = Math.max(2, Number.parseInt(String(payload?.rows || 24), 10) || 24)
     
    -  const ptyProcess = nodePty.spawn(command, args, {
    -    cols,
    -    cwd,
    -    env: terminalShellEnv(),
    -    name: 'xterm-256color',
    -    rows
    -  })
    +  const sshTarget = await resolveTerminalConnection(activeSshTerminalTarget, () => ensureBackend(primaryProfileKey()))
    +  const remote = Boolean(sshTarget)
    +  const remoteState = remote ? sshConnections.get(sshTarget.scope) : null
    +
    +  const remoteCommand =
    +    remoteState?.remotePlatform === 'Windows'
    +      ? buildWindowsInteractiveCommand(String(payload?.cwd || '').trim())
    +      : undefined
    +
    +  const ptyProcess = remote
    +    ? nodePty.spawn(
    +        process.platform === 'win32'
    +          ? path.join(process.env.SystemRoot || 'C:\\Windows', 'System32', 'OpenSSH', 'ssh.exe')
    +          : 'ssh',
    +        buildInteractiveSshArgs(sshTarget.ssh, String(payload?.cwd || '').trim(), undefined, remoteCommand),
    +        { cols, cwd: app.getPath('home'), env: terminalShellEnv(), name: 'xterm-256color', rows }
    +      )
    +    : nodePty.spawn(command, args, { cols, cwd, env: terminalShellEnv(), name: 'xterm-256color', rows })
     
    -  terminalSessions.set(id, { pty: ptyProcess, webContentsId: event.sender.id })
    +  terminalSessions.set(id, {
    +    pty: ptyProcess,
    +    webContentsId: event.sender.id,
    +    ...(remote ? { sshScope: sshTarget.scope, remoteCwd: String(payload?.cwd || '') } : {})
    +  })
     
       const send = (suffix, payload) => {
         if (event.sender.isDestroyed()) {
    ```

    ```diff
    @@ -9279,7 +9894,7 @@ ipcMain.handle('hermes:terminal:start', async (event, payload = {}) => {
       })
       event.sender.once('destroyed', () => disposeTerminalSession(id))
     
    -  return { cwd, id, shell: name }
    +  return { cwd: remote ? null : cwd, id, shell: remote ? 'ssh' : name }
     })
     
     ipcMain.handle('hermes:terminal:write', (_event, id, data) => {
    ```

    ```diff
    @@ -9315,7 +9930,7 @@ ipcMain.handle('hermes:terminal:cwd', async (_event, id) => {
         return null
       }
     
    -  return readProcessCwd(sessionInfo.pty.pid)
    +  return sessionInfo.sshScope !== undefined ? null : readProcessCwd(sessionInfo.pty.pid)
     })
     
     ipcMain.handle('hermes:terminal:dispose', (_event, id) => disposeTerminalSession(String(id || '')))
    ```

    ```diff
    @@ -9808,7 +10423,24 @@ function configureSpellChecker() {
       }
     }
     
    -app.on('before-quit', () => {
    +app.on('before-quit', event => {
    +  if ((sshConnections.size > 0 || sshBootstrapCoordinator.promises().length > 0) && !sshQuitTeardownDone) {
    +    event.preventDefault()
    +    sshBootstrapCoordinator.cancelAll()
    +    const scopes = [...sshConnections.keys()]
    +
    +    const pending = Promise.allSettled([
    +      ...scopes.map(scope => teardownSshConnection(scope || null)),
    +      ...sshBootstrapCoordinator.promises()
    +    ])
    +
    +    void Promise.race([pending, new Promise(resolve => setTimeout(resolve, 4_000))]).then(async () => {
    +      await sshBootstrapCoordinator.forceCleanupAll()
    +      sshQuitTeardownDone = true
    +      app.quit()
    +    })
    +  }
    +
       // Clean quit mid-boot should not trip next-launch --no-sandbox (#38216).
       // FATAL GPU aborts skip before-quit, leaving the `booting` marker in place.
       // Keyed on sticky (not active): a manual --no-sandbox run still records a
    ```
  - `apps/desktop/electron/preload.ts`

    ```diff
    @@ -41,6 +41,8 @@ contextBridge.exposeInMainWorld('hermesDesktop', {
       saveConnectionConfig: payload => ipcRenderer.invoke('hermes:connection-config:save', payload),
       applyConnectionConfig: payload => ipcRenderer.invoke('hermes:connection-config:apply', payload),
       testConnectionConfig: payload => ipcRenderer.invoke('hermes:connection-config:test', payload),
    +  sshConfigHosts: () => ipcRenderer.invoke('hermes:ssh-config:hosts'),
    +  sshResolveHost: host => ipcRenderer.invoke('hermes:ssh-config:resolve', host),
       probeConnectionConfig: remoteUrl => ipcRenderer.invoke('hermes:connection-config:probe', remoteUrl),
       oauthLoginConnectionConfig: remoteUrl => ipcRenderer.invoke('hermes:connection-config:oauth-login', remoteUrl),
       oauthLogoutConnectionConfig: remoteUrl => ipcRenderer.invoke('hermes:connection-config:oauth-logout', remoteUrl),
    ```
  - `apps/desktop/electron/remote-lifecycle.test.ts`

    ```diff
    @@ -0,0 +1,1017 @@
    +import assert from 'node:assert/strict'
    +
    +import { test } from 'vitest'
    +
    +import {
    +  buildSpawnCommand,
    +  cleanupStale,
    +  connect,
    +  expandRemotePath,
    +  fingerprintToken,
    +  isForwardBindCollision,
    +  locateHermes,
    +  LOCKFILE_SCHEMA_VERSION,
    +  lockfilePath,
    +  openForward,
    +  ownershipDirectory,
    +  pidIsOurDashboard,
    +  probeRemotePlatform,
    +  PROTOCOL_VERSION,
    +  readLockfile,
    +  READY_RE,
    +  remotePidAlive,
    +  remoteSupportsSshOwnership,
    +  scrapeReadyPort,
    +  spawnLogPath,
    +  spawnRemoteDashboard,
    +  validateRemotePath,
    +  writeLockfile
    +} from './remote-lifecycle'
    +
    +const OWNERSHIP_ID = '0123456789abcdef0123456789abcdef'
    +const SPAWN_NONCE = '0123456789abcdef'
    +
    +function ownedLock(over: any = {}) {
    +  return {
    +    schemaVersion: LOCKFILE_SCHEMA_VERSION,
    +    protocolVersion: PROTOCOL_VERSION,
    +    ownershipId: OWNERSHIP_ID,
    +    spawnNonce: SPAWN_NONCE,
    +    pid: 333,
    +    port: 40000,
    +    profile: '',
    +    hermesPath: '~/.local/bin/hermes',
    +    hermesHome: '~/.hermes',
    +    logPath: spawnLogPath(OWNERSHIP_ID, SPAWN_NONCE),
    +    tokenFingerprint: [redacted:secret-assignment]'stored-token'),
    +    startedAt: '2026-07-14T00:00:00.000Z',
    +    ...over
    +  }
    +}
    +
    +// A fake SshConnection whose exec() is matched against an ordered list of
    +// [regex|fn, response|fn] rules. First match wins; unmatched commands return ''.
    +function fakeSsh(rules: any[] = []) {
    +  const calls: string[] = []
    +
    +  return {
    +    calls,
    +    async exec(cmd) {
    +      calls.push(cmd)
    +
    +      for (const [matcher, resp] of rules) {
    +        const hit = typeof matcher === 'function' ? matcher(cmd) : matcher.test(cmd)
    +
    +        if (hit) {
    +          const out = typeof resp === 'function' ? resp(cmd) : resp
    +
    +          if (out instanceof Error) {
    +            throw out
    +          }
    +
    +          return out
    +        }
    +      }
    +
    +      return ''
    +    }
    +  }
    +}
    +
    +test('locateHermes prefers the explicit profile path when executable', async () => {
    +  const ssh = fakeSsh([[/\[ -x .*\/opt\/hermes/, 'OK']])
    +  assert.equal(await locateHermes(ssh, '/opt/hermes'), '/opt/hermes')
    +})
    +
    +test('locateHermes throws (no silent fallback) when an EXPLICIT path is not executable', async () => {
    +  // command -v WOULD find a different install, but an explicit path must not
    +  // silently fall back to it — that is the "connected to the wrong hermes" bug.
    +  const ssh = fakeSsh([
    +    [/command -v hermes/, '/home/u/.local/bin/hermes\n'],
    +    [/\[ -x .*\.local\/bin\/hermes/, 'OK']
    +  ])
    +
    +  await assert.rejects(
    +    () => locateHermes(ssh, '/bad/path/hermes'),
    +    (err: any) => {
    +      assert.equal(err.kind, 'hermes-not-found')
    +      assert.match(err.message, /\/bad\/path\/hermes/)
    +
    +      return true
    +    }
    +  )
    +})
    +
    +test('locateHermes falls back to the login-shell command -v probe', async () => {
    +  const ssh = fakeSsh([
    +    [/command -v hermes/, '/home/u/.local/bin/hermes\n'],
    +    [/\[ -x .*\.local\/bin\/hermes/, 'OK']
    +  ])
    +
    +  assert.equal(await locateHermes(ssh, ''), '/home/u/.local/bin/hermes')
    +})
    +
    +test('locateHermes canonicalizes an installer wrapper to its executable target', async () => {
    +  const ssh = fakeSsh([
    +    [/command -v hermes/, '/home/u/.local/bin/hermes\n'],
    +    [/\[ -x .*\.local\/bin\/hermes/, 'OK'],
    +    [/python3 -c/, '/home/u/.hermes/hermes-agent/venv/bin/hermes\n']
    +  ])
    +
    +  assert.equal(await locateHermes(ssh, ''), '/home/u/.hermes/hermes-agent/venv/bin/hermes')
    +})
    +
    +test('locateHermes falls back to ~/.local/bin/hermes when the login-shell probe misses', async () => {
    +  // ~/.local/bin is the non-root installer's command location (scripts/install.sh).
    +  const ssh = fakeSsh([
    +    [/command -v hermes/, ''],
    +    [/\[ -x .*\.local\/bin\/hermes/, 'OK']
    +  ])
    +
    +  assert.equal(await locateHermes(ssh, ''), '~/.local/bin/hermes')
    +})
    +
    +test('locateHermes tries the conventional venv path last', async () => {
    +  const ssh = fakeSsh([[/\[ -x .*venv\/bin\/hermes/, 'OK']])
    +  assert.equal(await locateHermes(ssh, ''), '~/.hermes/hermes-agent/venv/bin/hermes')
    +})
    +
    +test('locateHermes throws a hermes-not-found error with an install hint', async () => {
    +  const ssh = fakeSsh([]) // nothing is executable
    +  await assert.rejects(
    +    () => locateHermes(ssh, ''),
    +    (err: any) => {
    +      assert.equal(err.kind, 'hermes-not-found')
    +      assert.match(err.message, /install/i)
    +
    +      return true
    +    }
    +  )
    +})
    +
    +test('locateHermes uses a login shell for the command -v probe', async () => {
    +  const ssh = fakeSsh([
    +    [/command -v hermes/, '/x/hermes'],
    +    [/\[ -x/, 'OK']
    +  ])
    +
    +  await locateHermes(ssh, '')
    +  assert.ok(
    +    ssh.calls.some(c => /bash -lc/.test(c)),
    +    'must probe in a login shell (PATH pitfall)'
    +  )
    +})
    +
    +test('probeRemotePlatform accepts Linux and macOS', async () => {
    +  assert.deepEqual(await probeRemotePlatform(fakeSsh([[/uname/, 'Linux\nx86_64']])), {
    +    os: 'Linux',
    +    arch: 'x86_64'
    +  })
    +  assert.deepEqual(await probeRemotePlatform(fakeSsh([[/uname/, 'Darwin\narm64']])), {
    +    os: 'Darwin',
    +    arch: 'arm64'
    +  })
    +})
    +
    +test('probeRemotePlatform rejects unsupported remote platforms', async () => {
    +  await assert.rejects(
    +    () => probeRemotePlatform(fakeSsh([[/uname/, 'MINGW64_NT\nx86_64']])),
    +    (err: any) => {
    +      assert.equal(err.kind, 'unsupported-platform')
    +
    +      return true
    +    }
    +  )
    +})
    +
    +test('ownership paths are isolated by ownership ID and spawn nonce', () => {
    +  assert.equal(ownershipDirectory(OWNERSHIP_ID), `~/.hermes/desktop-ssh/${OWNERSHIP_ID}`)
    +  assert.equal(lockfilePath(OWNERSHIP_ID), `~/.hermes/desktop-ssh/${OWNERSHIP_ID}/backend.lock.json`)
    +  assert.equal(spawnLogPath(OWNERSHIP_ID, SPAWN_NONCE), `~/.hermes/desktop-ssh/${OWNERSHIP_ID}/${SPAWN_NONCE}.log`)
    +})
    +
    +test('readLockfile returns null for missing, empty, malformed, or wrong-schema', async () => {
    +  assert.equal(await readLockfile(fakeSsh([[/cat/, '']]), OWNERSHIP_ID), null)
    +  assert.equal(await readLockfile(fakeSsh([[/cat/, 'not json']]), OWNERSHIP_ID), null)
    +  assert.equal(await readLockfile(fakeSsh([[/cat/, JSON.stringify({ schemaVersion: 999 })]]), OWNERSHIP_ID), null)
    +  const good = ownedLock({ pid: 1, port: 2 })
    +  assert.deepEqual(await readLockfile(fakeSsh([[/cat/, JSON.stringify(good)]]), OWNERSHIP_ID), good)
    +})
    +
    +test('writeLockfile mkdir -ps and stamps the schema version', async () => {
    +  const ssh = fakeSsh([])
    +  await writeLockfile(ssh, OWNERSHIP_ID, ownedLock({ pid: 7, port: 9 }))
    +  const cmd = ssh.calls.join('\n')
    +  assert.match(cmd, /mkdir -p/)
    +  assert.match(cmd, new RegExp(`"schemaVersion":${LOCKFILE_SCHEMA_VERSION}`))
    +})
    +
    +test('remotePidAlive maps kill -0 ALIVE/DEAD', async () => {
    +  assert.equal(await remotePidAlive(fakeSsh([[/kill -0/, 'ALIVE']]), 123), true)
    +  assert.equal(await remotePidAlive(fakeSsh([[/kill -0/, 'DEAD']]), 123), false)
    +  assert.equal(await remotePidAlive(fakeSsh([]), null), false)
    +})
    +
    +test('metadata and process proof transport failures remain indeterminate', async () => {
    +  const failure = new Error('connection reset')
    +  await assert.rejects(
    +    () => readLockfile(fakeSsh([[/cat/, failure]]), OWNERSHIP_ID),
    +    (error: any) => error.kind === 'transient-transport-error'
    +  )
    +  await assert.rejects(
    +    () => remotePidAlive(fakeSsh([[/kill -0/, failure]]), 123),
    +    (error: any) => error.kind === 'transient-transport-error'
    +  )
    +  await assert.rejects(
    +    () => pidIsOurDashboard(fakeSsh([[/print\("OWNED"/, failure]]), 5, SPAWN_NONCE, '/x/hermes'),
    +    (error: any) => error.kind === 'transient-transport-error'
    +  )
    +})
    +
    +test('pidIsOurDashboard requires the exact serve ownership nonce', async () => {
    +  const ours = `/x/hermes serve --isolated --ssh-owner-nonce ${SPAWN_NONCE}`
    +  assert.equal(await pidIsOurDashboard(fakeSsh([[/print\("OWNED"/, 'OWNED\n']]), 5, SPAWN_NONCE, '/x/hermes'), true)
    +  assert.equal(
    +    await pidIsOurDashboard(
    +      fakeSsh([[/print\("OWNED"/, command => (command.includes('fedcba9876543210') ? 'FOREIGN\n' : 'OWNED\n')]]),
    +      5,
    +      'fedcba9876543210',
    +      '/x/hermes'
    +    ),
    +    false
    +  )
    +  assert.equal(await pidIsOurDashboard(fakeSsh([[/print\("OWNED"/, 'FOREIGN\n']]), 5, SPAWN_NONCE, '/x/hermes'), false)
    +})
    +
    +test('cleanupStale kills ONLY a provably-ours pid, always drops the lockfile', async () => {
    +  const notOurs = fakeSsh([[/print\("OWNED"/, 'FOREIGN\n']])
    +  await cleanupStale(notOurs, OWNERSHIP_ID, {
    +    pid: 5,
    +    spawnNonce: SPAWN_NONCE,
    +    hermesPath: '/x/hermes',
    +    logPath: spawnLogPath(OWNERSHIP_ID, SPAWN_NONCE)
    +  })
    +  assert.ok(!notOurs.calls.some(c => /kill 5\b/.test(c)), 'must not kill a pid that is not our dashboard')
    +  assert.ok(notOurs.calls.some(c => /rm -f/.test(c)))
    +
    +  const ours = fakeSsh([[/print\("OWNED"/, 'OWNED\n']])
    +  await cleanupStale(ours, OWNERSHIP_ID, {
    +    pid: 9,
    +    spawnNonce: SPAWN_NONCE,
    +    hermesPath: '/x/hermes',
    +    logPath: spawnLogPath(OWNERSHIP_ID, SPAWN_NONCE)
    +  })
    +  assert.ok(ours.calls.some(c => /kill 9\b/.test(c)))
    +  assert.ok(ours.calls.some(c => /rm -f/.test(c)))
    +})
    +
    +test('buildSpawnCommand is headless serve, detached, token not in argv', () => {
    +  const cmd = buildSpawnCommand('/x/hermes', 'work', { logPath: spawnLogPath(OWNERSHIP_ID, SPAWN_NONCE) })
    +  assert.match(cmd, /serve --isolated/)
    +  assert.match(cmd, /--host 127\.0\.0\.1 --port 0/)
    +  assert.doesNotMatch(cmd, /--skip-build|--no-open/)
    +  assert.doesNotMatch(cmd, /\bdashboard\b/)
    +  assert.match(cmd, /--profile/)
    +  assert.match(cmd, /work/)
    +  assert.match(cmd, /setsid/)
    +  assert.match(cmd, /<\/dev\/null/)
    +  assert.match(cmd, /echo \$!/)
    +  assert.ok(!cmd.includes('tok_secret_value'), 'token must not appear in spawn command')
    +  assert.ok(!cmd.includes('HERMES_DASHBOARD_SESSION_TOKEN'), 'token env var must not appear')
    +})
    +
    +test('buildSpawnCommand always uses serve (legacy dashboard path removed)', () => {
    +  const cmd = buildSpawnCommand('/x/hermes', 'work', { logPath: spawnLogPath(OWNERSHIP_ID, SPAWN_NONCE) })
    +  assert.match(cmd, /serve --isolated/)
    +  assert.match(cmd, /--host 127\.0\.0\.1 --port 0/)
    +  assert.doesNotMatch(cmd, /dashboard/)
    +  assert.doesNotMatch(cmd, /--skip-build/)
    +  assert.match(cmd, /setsid/)
    +})
    +
    +test('spawnRemoteDashboard returns exact ownership artifacts', async () => {
    +  const ssh = fakeSsh([
    +    [/grep -q ssh-session-token-file/, 'YES\n'],
    +    [/python3 -c/, ''],
    +    [/printf '%s\\n'/, ''],
    +    [/setsid|nohup/, '4242\n']
    +  ])
    +
    +  const { pid, spawnNonce, logPath } = await spawnRemoteDashboard(ssh, {
    +    hermesPath: '/x/hermes',
    +    profile: '',
    +    token: 'tk',
    +    ownershipId: OWNERSHIP_ID
    +  })
    +
    +  assert.equal(pid, 4242)
    +  assert.match(spawnNonce, /^[0-9a-f]{16}$/)
    +  assert.equal(logPath, spawnLogPath(OWNERSHIP_ID, spawnNonce))
    +})
    +
    +test('spawnRemoteDashboard always spawns serve (legacy dashboard path removed)', async () => {
    +  const ssh = fakeSsh([
    +    [/grep -q ssh-session-token-file/, 'YES\n'],
    +    [/python3 -c/, ''],
    +    [/printf '%s\\n'/, ''],
    +    [/setsid|nohup/, '4242\n']
    +  ])
    +
    +  await spawnRemoteDashboard(ssh, { hermesPath: '/x/hermes', profile: '', token: 'tk', ownershipId: OWNERSHIP_ID })
    +  const spawn = ssh.calls.find(c => /setsid|nohup/.test(c))
    +  assert.match(spawn, /serve --isolated/)
    +  assert.doesNotMatch(spawn, /\bdashboard\b/)
    +})
    +
    +test('READY_RE accepts both serve and dashboard sentinels', () => {
    +  assert.equal(READY_RE.exec('HERMES_BACKEND_READY port=4321')?.[1], '4321')
    +  assert.equal(READY_RE.exec('HERMES_DASHBOARD_READY port=8765')?.[1], '8765')
    +})
    +
    +test('spawnRemoteDashboard rejects when no pid is returned', async () => {
    +  const ssh = fakeSsh([
    +    [/grep -q ssh-session-token-file/, 'YES\n'],
    +    [/python3 -c/, ''],
    +    [/printf '%s\\n'/, ''],
    +    [/setsid|nohup/, 'not-a-pid']
    +  ])
    +
    +  await assert.rejects(
    +    () => spawnRemoteDashboard(ssh, { hermesPath: '/x/hermes', profile: '', token: 't', ownershipId: OWNERSHIP_ID }),
    +    (err: any) => {
    +      assert.equal(err.kind, 'spawn-failed')
    +
    +      return true
    +    }
    +  )
    +})
    +
    +test('scrapeReadyPort reads only the named spawn log', async () => {
    +  const logPath = spawnLogPath(OWNERSHIP_ID, SPAWN_NONCE)
    +  const ssh = fakeSsh([[/cat/, 'some noise\nHERMES_DASHBOARD_READY port=51234\n']])
    +  const port = await scrapeReadyPort(ssh, logPath, { timeoutMs: 1000 })
    +  assert.equal(port, 51234)
    +  assert.ok(ssh.calls.every(call => !call.includes('desktop-ssh.log')))
    +})
    +
    +test('scrapeReadyPort times out and reports a dead spawn', async () => {
    +  // never emits a READY line
    +  const ssh = fakeSsh([[/cat .*\.log/, 'still starting...']])
    +  await assert.rejects(
    +    () => scrapeReadyPort(ssh, spawnLogPath(OWNERSHIP_ID, SPAWN_NONCE), { timeoutMs: 60 }),
    +    (err: any) => {
    +      assert.equal(err.kind, 'ready-timeout')
    +
    +      return true
    +    }
    +  )
    +  // dead process before announcement → spawn-failed
    +  await assert.rejects(
    +    () =>
    +      scrapeReadyPort(fakeSsh([[/cat/, '']]), spawnLogPath(OWNERSHIP_ID, SPAWN_NONCE), {
    +        timeoutMs: 1000,
    +        isAlive: async () => false
    +      }),
    +    (err: any) => {
    +      assert.equal(err.kind, 'spawn-failed')
    +
    +      return true
    +    }
    +  )
    +})
    +
    +function connectDeps(ssh, over: any = {}) {
    +  return {
    +    ssh,
    +    ownershipId: OWNERSHIP_ID,
    +    profile: '',
    +    forward: async () => {},
    +    cancelForward: async () => {},
    +    pickLocalPort: async () => 50001,
    +    waitForHermes: async () => {},
    +    probeReuseProof: async () => 'authenticated-ok',
    +    adoptServedToken: async (_baseUrl, spawn) => spawn || 'served-token',
    +    rememberLog: () => {},
    +    readyTimeoutMs: 2000,
    +    ...over
    +  }
    +}
    +
    +test('connect() spawns fresh when there is no lockfile, adopts the served token', async () => {
    +  const ssh = fakeSsh([
    +    [/uname/, 'Linux\nx86_64'],
    +    [/\[ -x/, 'OK'],
    +    [/cat .*lock\.json/, ''], // no lockfile
    +    [/grep -q ssh-session-token-file/, 'YES\n'],
    +    [/python3 -c/, ''], // token file write
    +    [/printf '%s\\n'/, ''],
    +    [/setsid/, '777\n'],
    +    [/kill -0 777/, 'ALIVE'],
    +    [/cat .*\.log/, 'HERMES_DASHBOARD_READY port=51999\n']
    +  ])
    +
    +  const result = await connect(connectDeps(ssh, { adoptServedToken: async () => 'the-served-token' }))
    +  assert.equal(result.reused, false)
    +  assert.equal(result.remotePort, 51999)
    +  assert.equal(result.localPort, 50001)
    +  assert.equal(result.pid, 777)
    +  assert.equal(result.token, 'the-served-token')
    +  assert.equal(result.baseUrl, 'http://127.0.0.1:50001')
    +  assert.equal(result.tokenFingerprint, fingerprintToken('the-served-token'))
    +})
    +
    +test('connect() reuses a healthy dashboard when fingerprint + probe pass', async () => {
    +  const reuseToken = '[redacted:secret-assignment]'
    +  const lock = ownedLock({ tokenFingerprint: [redacted:secret-assignment] })
    +
    +  const ssh = fakeSsh([
    +    [/uname/, 'Linux\nx86_64'],
    +    [/\[ -x/, 'OK'],
    +    [/cat .*lock\.json/, JSON.stringify(lock)],
    +    [/kill -0/, 'ALIVE'],
    +    [/print\("OWNED"/, 'OWNED\n']
    +  ])
    +
    +  const result = await connect(connectDeps(ssh, { reuseToken, adoptServedToken: async (_b, t) => t }))
    +  assert.equal(result.reused, true)
    +  assert.equal(result.pid, 333)
    +  assert.equal(result.remotePort, 40000)
    +  // never spawned
    +  assert.ok(!ssh.calls.some(c => /setsid/.test(c)), 'reuse path must not spawn a new dashboard')
    +})
    +
    +test('connect() respawns when the lockfile hermesPath differs from the resolved path', async () => {
    +  const reuseToken = '[redacted:secret-assignment]'
    +  const lock = ownedLock({ hermesPath: '/old/stale/hermes', tokenFingerprint: [redacted:secret-assignment] })
    +
    +  const ssh = fakeSsh([
    +    [/uname/, 'Linux\nx86_64'],
    +    [/\[ -x/, 'OK'],
    +    [/cat .*lock\.json/, JSON.stringify(lock)],
    +    [/kill -0/, 'ALIVE'],
    +    [/print\("OWNED"/, 'FOREIGN\n'],
    +    [/--version/, 'Hermes Agent v0.18.2\n'],
    +    [/grep -q ssh-session-token-file/, 'YES\n'],
    +    [/python3 -c/, ''],
    +    [/setsid/, '890\n'],
    +    [/cat .*\.log/, 'HERMES_DASHBOARD_READY port=52050\n']
    +  ])
    +
    +  const result = await connect(
    +    connectDeps(ssh, { reuseToken, remoteHermesPath: '/new/hermes', adoptServedToken: async () => 'fresh' })
    +  )
    +
    +  assert.equal(result.reused, false, 'must respawn, not reuse the old-path dashboard')
    +  assert.ok(
    +    ssh.calls.some(c => /setsid/.test(c)),
    +    'a fresh dashboard must be spawned'
    +  )
    +})
    +
    +test('connect() respawns when the lockfile protocolVersion is incompatible', async () => {
    +  const reuseToken = '[redacted:secret-assignment]'
    +
    +  const lock = {
    +    schemaVersion: LOCKFILE_SCHEMA_VERSION,
    +    protocolVersion: PROTOCOL_VERSION + 99,
    +    pid: 333,
    +    port: 40000,
    +    tokenFingerprint: [redacted:secret-assignment]
    +  }
    +
    +  const ssh = fakeSsh([
    +    [/uname/, 'Linux\nx86_64'],
    +    [/\[ -x/, 'OK'],
    +    [/cat .*lock\.json/, JSON.stringify(lock)],
    +    [/kill -0 333/, 'ALIVE'],
    +    [/print\("OWNED"/, 'FOREIGN\n'],
    +    [/grep -q ssh-session-token-file/, 'YES\n'],
    +    [/python3 -c/, ''],
    +    [/setsid/, '901\n'],
    +    [/kill -0 901/, 'ALIVE'],
    +    [/cat .*\.log/, 'HERMES_DASHBOARD_READY port=44100\n']
    +  ])
    +
    +  const result = await connect(connectDeps(ssh, { reuseToken, adoptServedToken: async () => 'fresh' }))
    +  assert.equal(result.reused, false, 'incompatible protocol must force a fresh spawn, not a reattach')
    +  assert.equal(result.pid, 901)
    +})
    +
    +test('connect() fresh spawn writes hermesHome + protocolVersion into the lockfile', async () => {
    +  const writes: string[] = []
    +
    +  const ssh = fakeSsh([
    +    [/uname/, 'Linux\nx86_64'],
    +    [/\[ -x/, 'OK'],
    +    [/cat .*lock\.json/, ''], // no lockfile
    +    [/HERMES_HOME/, '/home/alice/.hermes\n'],
    +    [/grep -q ssh-session-token-file/, 'YES\n'],
    +    [/python3 -c/, ''],
    +    [/printf '%s\\n'/, ''],
    +    [/setsid/, '700\n'],
    +    [/kill -0 700/, 'ALIVE'],
    +    [/cat .*\.log/, 'HERMES_DASHBOARD_READY port=45500\n'],
    +    [
    +      /printf '%s' '/,
    +      c => {
    +        writes.push(c)
    +
    +        return ''
    +      }
    +    ]
    +  ])
    +
    +  await connect(connectDeps(ssh, { adoptServedToken: async () => 'fresh' }))
    +  const lockWrite = writes.find(c => c.includes('schemaVersion')) || ''
    +  assert.match(lockWrite, new RegExp(`"protocolVersion":${PROTOCOL_VERSION}`))
    +  assert.match(lockWrite, /"hermesHome":"\/home\/alice\/\.hermes"/)
    +})
    +
    +test('connect() respawns when the lockfile pid is dead (killed dashboard)', async () => {
    +  const lock = ownedLock({ tokenFingerprint: [redacted:secret-assignment]'t') })
    +
    +  const ssh = fakeSsh([
    +    [/uname/, 'Linux\nx86_64'],
    +    [/\[ -x/, 'OK'],
    +    [/cat .*lock\.json/, JSON.stringify(lock)],
    +    [/kill -0 333/, 'DEAD'],
    +    [/print\("OWNED"/, 'FOREIGN\n'],
    +    [/grep -q ssh-session-token-file/, 'YES\n'],
    +    [/python3 -c/, ''],
    +    [/setsid/, '888\n'],
    +    [/kill -0 888/, 'ALIVE'],
    +    [/cat .*\.log/, 'HERMES_DASHBOARD_READY port=42000\n']
    +  ])
    +
    +  const result = await connect(connectDeps(ssh, { reuseToken: 't', adoptServedToken: async () => 'fresh' }))
    +  assert.equal(result.reused, false)
    +  assert.equal(result.pid, 888)
    +  assert.equal(result.remotePort, 42000)
    +  assert.ok(
    +    !ssh.calls.some(command => command.includes('pid=333') && command.includes('print("OWNED"')),
    +    'a dead pid has no process identity to verify'
    +  )
    +})
    +
    +test('connect() respawns when the dashboard is wedged (alive pid, probe fails)', async () => {
    +  const reuseToken = '[redacted:secret-assignment]'
    +
    +  const lock = {
    +    schemaVersion: LOCKFILE_SCHEMA_VERSION,
    +    protocolVersion: PROTOCOL_VERSION,
    +    pid: 333,
    +    port: 40000,
    +    tokenFingerprint: [redacted:secret-assignment]
    +  }
    +
    +  const ssh = fakeSsh([
    +    [/uname/, 'Linux\nx86_64'],
    +    [/\[ -x/, 'OK'],
    +    [/cat .*lock\.json/, JSON.stringify(lock)],
    +    [/kill -0/, 'ALIVE'],
    +    [/print\("OWNED"/, 'FOREIGN\n'],
    +    [/grep -q ssh-session-token-file/, 'YES\n'],
    +    [/python3 -c/, ''],
    +    [/setsid/, '999\n'],
    +    [/kill -0 999/, 'ALIVE'],
    +    [/cat .*\.log/, 'HERMES_DASHBOARD_READY port=43000\n']
    +  ])
    +
    +  const result = await connect(
    +    connectDeps(ssh, {
    +      reuseToken,
    +      probeReuseProof: async () => 'authenticated-stale',
    +      adoptServedToken: async () => 'fresh'
    +    })
    +  )
    +
    +  assert.equal(result.reused, false)
    +  assert.equal(result.pid, 999)
    +  assert.equal(result.remotePort, 43000)
    +})
    +
    +test('connect() aborts on an unsupported remote platform before doing anything else', async () => {
    +  const ssh = fakeSsh([[/uname/, 'SunOS\nsun4v']])
    +  await assert.rejects(
    +    () => connect(connectDeps(ssh)),
    +    (err: any) => {
    +      assert.equal(err.kind, 'unsupported-platform')
    +
    +      return true
    +    }
    +  )
    +  assert.ok(!ssh.calls.some(c => /setsid/.test(c)))
    +})
    +
    +test('openForward retries bind collisions only', async () => {
    +  const ports = [41001, 41002]
    +  const calls: number[] = []
    +
    +  const localPort = await openForward(
    +    {
    +      pickLocalPort: async () => ports.shift(),
    +      forward: async port => {
    +        calls.push(port)
    +
    +        if (calls.length === 1) {
    +          throw new Error('bind: Address already in use')
    +        }
    +      }
    +    },
    +    9119
    +  )
    +
    +  assert.equal(localPort, 41002)
    +  assert.deepEqual(calls, [41001, 41002])
    +  assert.equal(isForwardBindCollision(new Error('Permission denied')), false)
    +})
    +
    +test('connect() preserves an owned backend when a reuse transport throws', async () => {
    +  const reuseToken = '[redacted:secret-assignment]'
    +  const lock = ownedLock({ tokenFingerprint: [redacted:secret-assignment] })
    +
    +  const ssh = fakeSsh([
    +    [/uname/, 'Linux\nx86_64'],
    +    [/\[ -x/, 'OK'],
    +    [/cat .*lock\.json/, JSON.stringify(lock)],
    +    [/kill -0/, 'ALIVE'],
    +    [/print\("OWNED"/, 'OWNED\n']
    +  ])
    +
    +  await assert.rejects(
    +    () =>
    +      connect(
    +        connectDeps(ssh, {
    +          reuseToken,
    +          forward: async () => {
    +            throw new Error('network reset')
    +          }
    +        })
    +      ),
    +    /network reset/
    +  )
    +  assert.ok(!ssh.calls.some(cmd => /kill 333\b/.test(cmd)))
    +})
    +
    +test('validateRemotePath accepts absolute POSIX paths', () => {
    +  assert.doesNotThrow(() => validateRemotePath('/usr/bin/hermes'))
    +  assert.doesNotThrow(() => validateRemotePath('/home/user/.hermes/hermes-agent/venv/bin/hermes'))
    +})
    +
    +test('validateRemotePath accepts ~/ prefix paths', () => {
    +  assert.doesNotThrow(() => validateRemotePath('~/bin/hermes'))
    +  assert.doesNotThrow(() => validateRemotePath('~/.hermes/logs/desktop-ssh.log'))
    +  assert.doesNotThrow(() => validateRemotePath('~'))
    +})
    +
    +test('validateRemotePath accepts paths with spaces and quotes', () => {
    +  assert.doesNotThrow(() => validateRemotePath('/home/user/my project/hermes'))
    +  assert.doesNotThrow(() => validateRemotePath("~/path with 'quotes'/file"))
    +  assert.doesNotThrow(() => validateRemotePath('/path with "double quotes"/file'))
    +})
    +
    +test('validateRemotePath rejects relative paths', () => {
    +  assert.throws(() => validateRemotePath('hermes'), /absolute|relative/i)
    +  assert.throws(() => validateRemotePath('./bin/hermes'), /absolute|relative/i)
    +  assert.throws(() => validateRemotePath('../etc/passwd'), /absolute|relative/i)
    +})
    +
    +test('validateRemotePath rejects NUL and newline', () => {
    +  assert.throws(() => validateRemotePath('/usr/bin/hermes\x00'), /unsafe/i)
    +  assert.throws(() => validateRemotePath('/usr/bin/hermes\n'), /unsafe/i)
    +  assert.throws(() => validateRemotePath('/usr/bin/hermes\r'), /unsafe/i)
    +})
    +
    +test('validateRemotePath preserves shell metacharacters as path data', () => {
    +  for (const p of ['/usr/$(whoami)/hermes', '/usr/`id`/hermes', '/usr/a;b|c&d<e>f']) {
    +    assert.doesNotThrow(() => validateRemotePath(p))
    +    assert.match(expandRemotePath(p), /^'/)
    +  }
    +})
    +
    +test('expandRemotePath expands ~/ to "$HOME"/', () => {
    +  const result = expandRemotePath('~/.hermes/logs/desktop-ssh.log')
    +  assert.match(result, /\$HOME/)
    +  assert.ok(!result.includes('eval'), 'must not use eval')
    +  assert.ok(!result.includes('echo'), 'must not use echo for expansion')
    +})
    +
    +test('expandRemotePath returns quoted absolute paths unchanged', () => {
    +  const result = expandRemotePath('/usr/local/bin/hermes')
    +  assert.ok(result.includes('/usr/local/bin/hermes'))
    +  assert.ok(!result.includes('eval'))
    +})
    +
    +test('expandRemotePath preserves spaces as data', () => {
    +  const result = expandRemotePath('/home/user/my project/hermes')
    +  assert.ok(result.includes('my project'), 'spaces must be preserved, not split')
    +})
    +
    +test('buildSpawnCommand does not embed the token in the command string', () => {
    +  const cmd = buildSpawnCommand('/x/hermes', 'work', { logPath: spawnLogPath(OWNERSHIP_ID, SPAWN_NONCE) })
    +  assert.ok(!cmd.includes('super_secret_token_value'), 'token must not appear in the spawn command')
    +  assert.ok(!cmd.includes('HERMES_DASHBOARD_SESSION_TOKEN'), 'env var name must not appear')
    +})
    +
    +test('buildSpawnCommand includes --ssh-session-token-file when tokenFilePath is provided', () => {
    +  const cmd = buildSpawnCommand('/x/hermes', 'work', {
    +    tokenFilePath: [redacted:secret-assignment]
    +    logPath: spawnLogPath(OWNERSHIP_ID, SPAWN_NONCE),
    +    spawnNonce: SPAWN_NONCE
    +  })
    +
    +  assert.match(cmd, /--ssh-session-token-file/)
    +  assert.match(cmd, /\.hermes\/desktop-ssh\//)
    +})
    +
    +test('buildSpawnCommand always uses serve, never dashboard', () => {
    +  const cmd = buildSpawnCommand('/x/hermes', '', { logPath: spawnLogPath(OWNERSHIP_ID, SPAWN_NONCE) })
    +  assert.match(cmd, /serve --isolated/)
    +  assert.doesNotMatch(cmd, /\bdashboard\b/)
    +  assert.doesNotMatch(cmd, /--skip-build/)
    +  assert.doesNotMatch(cmd, /--no-open/)
    +})
    +
    +test('spawnRemoteDashboard removes a token file when upload reporting fails', async () => {
    +  const failure = new Error('channel closed')
    +
    +  const ssh = fakeSsh([
    +    [/grep -q ssh-session-token-file/, 'YES\n'],
    +    [command => /python3 -c/.test(command) && !/rm -f/.test(command), failure],
    +    [/rm -f/, '']
    +  ])
    +
    +  await assert.rejects(
    +    () => spawnRemoteDashboard(ssh, { hermesPath: '/x/hermes', profile: '', token: 'tok', ownershipId: OWNERSHIP_ID }),
    +    /channel closed/
    +  )
    +  assert.ok(ssh.calls.some(command => /rm -f .*\.token/.test(command)))
    +})
    +
    +test('spawnRemoteDashboard streams the token over stdin, not argv/env', async () => {
    +  const stdinCalls: string[] = []
    +  const calls: string[] = []
    +
    +  const ssh = {
    +    calls,
    +    async exec(cmd, opts?) {
    +      calls.push(cmd)
    +
    +      if (opts?.stdinData) {
    +        stdinCalls.push(opts.stdinData)
    +      }
    +
    +      if (/grep -q ssh-session-token-file/.test(cmd)) {
    +        return 'YES\n'
    +      }
    +
    +      if (/python3 -c/.test(cmd)) {
    +        return ''
    +      }
    +
    +      if (/setsid|nohup/.test(cmd)) {
    +        return '4242\n'
    +      }
    +
    +      if (/printf '%s\\n'/.test(cmd)) {
    +        return ''
    +      }
    +
    +      return ''
    +    }
    +  }
    +
    +  const { pid } = await spawnRemoteDashboard(ssh as any, {
    +    hermesPath: '/x/hermes',
    +    profile: '',
    +    token: '[redacted:secret-assignment]',
    +    ownershipId: OWNERSHIP_ID
    +  })
    +
    +  assert.equal(pid, 4242)
    +  assert.ok(stdinCalls.length > 0, 'token must be sent via stdin')
    +  assert.ok(
    +    stdinCalls.some(d => d === 'secret_token_val'),
    +    'stdin must contain the token'
    +  )
    +
    +  for (const cmd of calls) {
    +    assert.ok(!cmd.includes('secret_token_val'), `token leaked into command: ${cmd}`)
    +  }
    +})
    +
    +test('spawnRemoteDashboard upload uses exclusive-create and O_NOFOLLOW', async () => {
    +  const calls: string[] = []
    +
    +  const ssh = {
    +    calls,
    +    async exec(cmd, opts?) {
    +      calls.push(cmd)
    +
    +      if (/grep -q ssh-session-token-file/.test(cmd)) {
    +        return 'YES\n'
    +      }
    +
    +      if (/python3 -c/.test(cmd)) {
    +        return ''
    +      }
    +
    +      if (/setsid|nohup/.test(cmd)) {
    +        return '4242\n'
    +      }
    +
    +      if (/printf '%s\\n'/.test(cmd)) {
    +        return ''
    +      }
    +
    +      return ''
    +    }
    +  }
    +
    +  await spawnRemoteDashboard(ssh as any, {
    +    hermesPath: '/x/hermes',
    +    profile: '',
    +    token: 'tk',
    +    ownershipId: OWNERSHIP_ID
    +  })
    +  const uploadCmd = calls.find(c => /python3 -c/.test(c))
    +  assert.ok(uploadCmd, 'must use python3 -c for token upload')
    +  assert.match(uploadCmd, /O_EXCL/, 'upload must use O_EXCL to reject existing files')
    +  assert.match(uploadCmd, /O_NOFOLLOW/, 'upload must use O_NOFOLLOW to reject symlinks')
    +  assert.match(uploadCmd, /O_WRONLY/, 'upload must open write-only')
    +  assert.match(uploadCmd, /dir_fd=dd/, 'upload must create relative to the opened parent directory')
    +  assert.match(uploadCmd, /os\.fstat\(dd\)/, 'upload must validate the opened parent directory')
    +  assert.ok(!uploadCmd.includes('tk'), 'token must not appear in the upload command')
    +})
    +
    +test('readLockfile rejects lock with non-integer pid', async () => {
    +  const lock = { schemaVersion: LOCKFILE_SCHEMA_VERSION, pid: 'not-a-number', port: 8080 }
    +  assert.equal(await readLockfile(fakeSsh([[/cat/, JSON.stringify(lock)]]), OWNERSHIP_ID), null)
    +})
    +
    +test('readLockfile rejects lock with pid <= 0', async () => {
    +  const lock = { schemaVersion: LOCKFILE_SCHEMA_VERSION, pid: -1, port: 8080 }
    +  assert.equal(await readLockfile(fakeSsh([[/cat/, JSON.stringify(lock)]]), OWNERSHIP_ID), null)
    +})
    +
    +test('readLockfile rejects lock with port out of range', async () => {
    +  const lock = { schemaVersion: LOCKFILE_SCHEMA_VERSION, pid: 100, port: 99999 }
    +  assert.equal(await readLockfile(fakeSsh([[/cat/, JSON.stringify(lock)]]), OWNERSHIP_ID), null)
    +  const lock2 = { schemaVersion: LOCKFILE_SCHEMA_VERSION, pid: 100, port: 0 }
    +  assert.equal(await readLockfile(fakeSsh([[/cat/, JSON.stringify(lock2)]]), OWNERSHIP_ID), null)
    +})
    +
    +test('readLockfile accepts a complete owned lock', async () => {
    +  const lock = ownedLock({ pid: 42, port: 51234 })
    +  const result = await readLockfile(fakeSsh([[/cat/, JSON.stringify(lock)]]), OWNERSHIP_ID)
    +  assert.deepEqual(result, lock)
    +})
    +
    +test('connect() reuse path does not write a token file', async () => {
    +  const reuseToken = '[redacted:secret-assignment]'
    +  const lock = ownedLock({ tokenFingerprint: [redacted:secret-assignment] })
    +
    +  const ssh = fakeSsh([
    +    [/uname/, 'Linux\nx86_64'],
    +    [/\[ -x/, 'OK'],
    +    [/cat .*lock\.json/, JSON.stringify(lock)],
    +    [/kill -0/, 'ALIVE'],
    +    [/print\("OWNED"/, 'OWNED\n']
    +  ])
    +
    +  const result = await connect(connectDeps(ssh, { reuseToken, adoptServedToken: async (_b, t) => t }))
    +  assert.equal(result.reused, true)
    +  assert.ok(!ssh.calls.some(c => /sys\.stdin\.buffer\.read/.test(c)), 'reuse must not upload a token file')
    +})
    +
    +test('spawnRemoteDashboard fails with update-required when remote lacks --ssh-session-token-file', async () => {
    +  const ssh = fakeSsh([[/--ssh-session-token-file/, 'NO\n']])
    +
    +  await assert.rejects(
    +    () => spawnRemoteDashboard(ssh, { hermesPath: '/x/hermes', profile: '', token: 'tk', ownershipId: OWNERSHIP_ID }),
    +    (err: any) => {
    +      assert.match(err.message, /update|upgrade/i)
    +      assert.equal(err.kind, 'update-required')
    +
    +      return true
    +    }
    +  )
    +})
    +
    +test('readLockfile rejects a log path outside the exact ownership and spawn path', async () => {
    +  const lock = ownedLock({ logPath: '~/.hermes/desktop-ssh/other.log' })
    +  const ssh = fakeSsh([[/cat .*lock\.json/, JSON.stringify(lock)]])
    +  assert.equal(await readLockfile(ssh, OWNERSHIP_ID), null)
    +})
    +
    +test('cleanupStale never deletes a lock-supplied unexpected log path', async () => {
    +  const ssh = fakeSsh([[/print\("OWNED"/, 'OWNED\n']])
    +  await cleanupStale(ssh, OWNERSHIP_ID, ownedLock({ logPath: '~/.hermes/unrelated.log' }))
    +  assert.ok(!ssh.calls.some(command => command.includes('unrelated.log')))
    +})
    +
    +test('pidIsOurDashboard requires an exact nonce option value', async () => {
    +  const prefix = `/x/hermes serve --isolated --ssh-owner-nonce ${SPAWN_NONCE}ff`
    +  const suffix = `/x/hermes serve --isolated --ssh-owner-nonce xx${SPAWN_NONCE}`
    +  assert.equal(await pidIsOurDashboard(fakeSsh([[/print\("OWNED"/, 'FOREIGN\n']]), 5, SPAWN_NONCE, '/x/hermes'), false)
    +  assert.equal(await pidIsOurDashboard(fakeSsh([[/print\("OWNED"/, 'FOREIGN\n']]), 5, SPAWN_NONCE, '/x/hermes'), false)
    +})
    +
    +test('connect removes the token file when a fresh backend fails after returning a pid', async () => {
    +  const ssh = fakeSsh([
    +    [/uname/, 'Linux\nx86_64'],
    +    [/\[ -x/, 'OK'],
    +    [/cat .*lock\.json/, ''],
    +    [/grep -q ssh-session-token-file/, 'YES\n'],
    +    [/python3 -c/, ''],
    +    [/setsid/, '999\n'],
    +    [/kill -0 999/, 'DEAD']
    +  ])
    +
    +  await assert.rejects(() => connect(connectDeps(ssh)), /exited before announcing/i)
    +  assert.ok(ssh.calls.some(command => /rm -f .*\.token/.test(command)))
    +})
    +
    +test('connect preserves an exact-owned backend when reuse proof transport fails', async () => {
    +  const reuseToken = '[redacted:secret-assignment]'
    +  const lock = ownedLock({ tokenFingerprint: [redacted:secret-assignment] })
    +
    +  const ssh = fakeSsh([
    +    [/uname/, 'Linux\nx86_64'],
    +    [/\[ -x/, 'OK'],
    +    [/cat .*lock\.json/, JSON.stringify(lock)],
    +    [/kill -0/, 'ALIVE'],
    +    [/print\("OWNED"/, 'OWNED\n']
    +  ])
    +
    +  await assert.rejects(
    +    () =>
    +      connect(
    +        connectDeps(ssh, {
    +          reuseToken,
    +          probeReuseProof: async () => {
    +            throw new Error('connection reset')
    +          }
    +        })
    +      ),
    +    (error: any) => error.kind === 'transient-transport-error'
    +  )
    +  assert.ok(!ssh.calls.some(command => /kill 333\b/.test(command)))
    +  assert.ok(!ssh.calls.some(command => /rm -f .*backend\.lock\.json/.test(command)))
    +})
    +
    +test('connect replaces an exact-owned backend only after authenticated stale proof', async () => {
    +  const reuseToken = '[redacted:secret-assignment]'
    +  const lock = ownedLock({ tokenFingerprint: [redacted:secret-assignment] })
    +
    +  const ssh = fakeSsh([
    +    [/uname/, 'Linux\nx86_64'],
    +    [/\[ -x/, 'OK'],
    +    [/cat .*lock\.json/, JSON.stringify(lock)],
    +    [/kill -0 333/, 'ALIVE'],
    +    [/print\("OWNED"/, 'OWNED\n'],
    +    [/grep -q ssh-session-token-file/, 'YES\n'],
    +    [/python3 -c/, ''],
    +    [/setsid/, '999\n'],
    +    [/kill -0 999/, 'ALIVE'],
    +    [/cat .*\.log/, 'HERMES_DASHBOARD_READY port=43000\n']
    +  ])
    +
    +  const result = await connect(
    +    connectDeps(ssh, {
    +      reuseToken,
    +      probeReuseProof: async (_baseUrl, token, nonce) => {
    +        assert.equal(token, reuseToken)
    +        assert.equal(nonce, SPAWN_NONCE)
    +
    +        return 'authenticated-stale'
    +      },
    +      adoptServedToken: async () => 'fresh'
    +    })
    +  )
    +
    +  assert.equal(result.reused, false)
    +  assert.ok(ssh.calls.some(command => /kill 333\b/.test(command)))
    +})
    +
    +test('remote SSH ownership capability requires both secure bootstrap flags', async () => {
    +  let helpProbe = ''
    +
    +  const supported = fakeSsh([
    +    [
    +      /serve --help/,
    +      command => {
    +        helpProbe = command
    +
    +        return 'YES\n'
    +      }
    +    ]
    +  ])
    +
    +  assert.equal(await remoteSupportsSshOwnership(supported, '/x/hermes'), true)
    +  assert.match(helpProbe, /ssh-session-token-file/)
    +  assert.match(helpProbe, /ssh-owner-nonce/)
    +
    +  const unsupported = fakeSsh([[/serve --help/, 'NO\n']])
    +  assert.equal(await remoteSupportsSshOwnership(unsupported, '/x/hermes'), false)
    +})
    ```
  - `apps/desktop/electron/remote-lifecycle.ts`

    ```diff
    @@ -0,0 +1,906 @@
    +/**
    + * remote-lifecycle.ts
    + *
    + * Pure, electron-free remote Hermes dashboard lifecycle over SSH for Desktop
    + * SSH remote mode. Composes an SshConnection (injected) with HTTP probes
    + * through the established tunnel (injected fetch) and the served-token adoption
    + * step (injected). Knows how to:
    + *
    + *   - locate the Hermes install on the remote (login-shell probe),
    + *   - gate the remote platform to Linux/macOS via `uname`,
    + *   - reuse an existing desktop-dedicated dashboard via a lockfile + an
    + *     AUTHENTICATED /api/status probe (pid liveness alone is insufficient),
    + *   - spawn a fresh detached `--isolated --port 0` dashboard and scrape its
    + *     `HERMES_DASHBOARD_READY port=<n>` readiness line,
    + *   - adopt the token the dashboard actually serves (served-token adoption),
    + *   - clean up a stale dashboard only when it is provably ours.
    + *
    + * No `import 'electron'` so it's unit-testable with `node --test`. main.ts wires
    + * the real SshConnection, fetch, adoptServedDashboardToken, and waitForHermes in.
    + *
    + * The minted HERMES_DASHBOARD_SESSION_TOKEN is the SPAWN credential. After
    + * readiness the caller runs served-token adoption against the tunneled baseUrl
    + * and the SERVED token's fingerprint is what lands in the lockfile — so the
    + * reuse probe checks the credential that actually authenticates /api/ws, not
    + * the minted one (which the dashboard may regen).
    + */
    +
    +import crypto from 'node:crypto'
    +
    +const LOCKFILE_SCHEMA_VERSION = 2
    +// Bumped when the desktop<->dashboard reuse contract changes in a way that makes
    +// an old running dashboard unsafe to reattach to (token handling, readiness/spawn
    +// args, served-token reconciliation). A mismatch forces a clean respawn.
    +const PROTOCOL_VERSION = 1
    +const READY_RE = /^HERMES_(?:BACKEND|DASHBOARD)_READY port=(\d+)/m
    +const REMOTE_LOCK_DIR = '~/.hermes/desktop-ssh'
    +const SUPPORTED_REMOTE_OS = new Set(['Linux', 'Darwin'])
    +const DEFAULT_READY_TIMEOUT_MS = 45_000
    +const READY_POLL_INTERVAL_MS = 750
    +
    +function mintToken() {
    +  return crypto.randomBytes(32).toString('hex')
    +}
    +
    +// Fingerprint a token for the lockfile — never store the raw secret on the
    +// remote. SHA256, truncated.
    +function fingerprintToken(token) {
    +  return crypto
    +    .createHash('sha256')
    +    .update(String(token || ''))
    +    .digest('hex')
    +    .slice(0, 32)
    +}
    +
    +function validateOwnershipId(ownershipId) {
    +  const value = String(ownershipId || '')
    +
    +  if (!/^[0-9a-f]{32}$/.test(value)) {
    +    throw new Error('SSH ownership ID is invalid.')
    +  }
    +
    +  return value
    +}
    +
    +function validateSpawnNonce(spawnNonce) {
    +  const value = String(spawnNonce || '')
    +
    +  if (!/^[0-9a-f]{16}$/.test(value)) {
    +    throw new Error('SSH spawn nonce is invalid.')
    +  }
    +
    +  return value
    +}
    +
    +function ownershipDirectory(ownershipId) {
    +  return `${REMOTE_LOCK_DIR}/${validateOwnershipId(ownershipId)}`
    +}
    +
    +function lockfilePath(ownershipId) {
    +  return `${ownershipDirectory(ownershipId)}/backend.lock.json`
    +}
    +
    +function spawnLogPath(ownershipId, spawnNonce) {
    +  return `${ownershipDirectory(ownershipId)}/${validateSpawnNonce(spawnNonce)}.log`
    +}
    +
    +// shell-single-quote a value for safe interpolation into a remote command.
    +function shq(value) {
    +  return `'${String(value).replace(/'/g, `'\\''`)}'`
    +}
    +
    +function validateRemotePath(p) {
    +  const s = String(p || '')
    +
    +  if (!s) {
    +    throw new Error('Remote path must not be empty.')
    +  }
    +
    +  // eslint-disable-next-line no-control-regex -- deliberately reject NUL in remote paths
    +  if (/[\x00\n\r]/.test(s)) {
    +    throw new Error('Unsafe remote path: contains NUL or newline.')
    +  }
    +
    +  if (s === '~' || s.startsWith('~/') || s.startsWith('/')) {
    +    return
    +  }
    +
    +  throw new Error(`Remote path must be absolute or start with ~/: "${s}"`)
    +}
    +
    +function expandRemotePath(p) {
    +  validateRemotePath(p)
    +
    +  if (p === '~') {
    +    return '"$HOME"'
    +  }
    +
    +  if (p.startsWith('~/')) {
    +    return '"$HOME"' + shq(p.slice(1))
    +  }
    +
    +  return shq(p)
    +}
    +
    +// Resolve the remote hermes executable. An EXPLICIT path is honored strictly
    +// (throws a path-naming error if not executable — never silently falls back to a
    +// different install). A BLANK path auto-detects: login-shell `command -v` (a
    +// non-login `ssh host cmd` PATH misses user installs), then known install paths.
    +async function locateHermes(ssh, remoteHermesPath) {
    +  const resolveLauncher = async (candidate: string) => {
    +    const script =
    +      'import os,shlex,sys\n' +
    +      `p=os.path.expanduser(${shq(candidate)})\n` +
    +      'out=p\n' +
    +      'try:\n' +
    +      ' data=open(p,"r",encoding="utf-8",errors="ignore").read(4096)\n' +
    +      ' for line in data.splitlines():\n' +
    +      '  words=shlex.split(line)\n' +
    +      '  if len(words)>1 and words[0]=="exec":\n' +
    +      '   target=os.path.expanduser(words[1])\n' +
    +      '   if os.path.isabs(target) and os.access(target,os.X_OK):out=target\n' +
    +      '   break\n' +
    +      'except (OSError,ValueError):pass\n' +
    +      'print(out)'
    +
    +    const resolved = (await ssh.exec(`python3 -c ${shq(script)}`)).trim()
    +
    +    return resolved || candidate
    +  }
    +
    +  const isExecutable = async (candidate: string) => {
    +    try {
    +      validateRemotePath(candidate)
    +      const ok = (await ssh.exec(`[ -x ${expandRemotePath(candidate)} ] && echo OK || true`)).trim()
    +
    +      return ok === 'OK'
    +    } catch {
    +      return false
    +    }
    +  }
    +
    +  if (remoteHermesPath) {
    +    if (await isExecutable(remoteHermesPath)) {
    +      return resolveLauncher(remoteHermesPath)
    +    }
    +
    +    const err: any = new Error(
    +      `The Hermes path you set is not an executable on the remote host: "${remoteHermesPath}". ` +
    +        'Check the path (it must be the full path to the `hermes` binary on the remote, e.g. ' +
    +        '~/hermes-agent/.venv/bin/hermes), or clear it to auto-detect.'
    +    )
    +
    +    err.kind = 'hermes-not-found'
    +    throw err
    +  }
    +
    +  const candidates: string[] = []
    +
    +  try {
    +    const found = (await ssh.exec(`bash -lc ${shq('command -v hermes')}`)).trim()
    +
    +    if (found) {
    +      candidates.push(found.split('\n').pop().trim())
    +    }
    +  } catch {
    +    // ignore
    +  }
    +
    +  // Fallback candidates when the login-shell probe misses: the installer's
    +  // command locations (scripts/install.sh) — per-user, root/FHS, legacy venv.
    +  candidates.push('~/.local/bin/hermes')
    +  candidates.push('/usr/local/bin/hermes')
    +  candidates.push('~/.hermes/hermes-agent/venv/bin/hermes')
    +
    +  for (const candidate of candidates) {
    +    if (!candidate) {
    +      continue
    +    }
    +
    +    if (await isExecutable(candidate)) {
    +      return resolveLauncher(candidate)
    +    }
    +  }
    +
    +  const err: any = new Error(
    +    'Hermes is not installed on the remote host (could not find a `hermes` executable). ' +
    +      'Install it on the remote with:  curl -fsSL https://hermes-agent.nousresearch.com/install.sh | sh  ' +
    +      '— or set the Hermes path explicitly in the SSH connection settings.'
    +  )
    +
    +  err.kind = 'hermes-not-found'
    +  throw err
    +}
    +
    +// Probe the resolved binary's version string (first line of `<hermes> --version`,
    +// e.g. "Hermes Agent v0.18.2 ..."), or '' on failure. Surfaces WHICH hermes a
    +// connection uses, so a stale/unexpected install is visible.
    +async function probeHermesVersion(ssh, hermesPath) {
    +  try {
    +    const out = (await ssh.exec(`${expandRemotePath(hermesPath)} --version 2>&1`)).trim()
    +
    +    return (out.split('\n')[0] || '').trim()
    +  } catch {
    +    return ''
    +  }
    +}
    +
    +async function probeRemotePlatform(ssh) {
    +  const out = (await ssh.exec('uname -s; uname -m')).trim().split('\n')
    +  const osName = (out[0] || '').trim()
    +  const arch = (out[1] || '').trim()
    +
    +  if (!SUPPORTED_REMOTE_OS.has(osName)) {
    +    const err: any = new Error(
    +      `Unsupported remote platform "${osName || 'unknown'}". Hermes Desktop SSH mode supports Linux, macOS, and Windows remote hosts.`
    +    )
    +
    +    err.kind = 'unsupported-platform'
    +    throw err
    +  }
    +
    +  return { os: osName, arch }
    +}
    +
    +// The HERMES_HOME the remote dashboard will use (explicit env wins, else
    +// ~/.hermes). Recorded in the lockfile so a future reuse can tell it's the same
    +// state store; best-effort.
    +async function probeRemoteHermesHome(ssh) {
    +  try {
    +    const out = (await ssh.exec('echo "${HERMES_HOME:-$HOME/.hermes}"')).trim().split('\n').pop()
    +
    +    return out || '~/.hermes'
    +  } catch (cause) {
    +    const error: any = new Error('Could not resolve the remote Hermes home.')
    +    error.kind = 'transient-transport-error'
    +    error.cause = cause
    +    throw error
    +  }
    +}
    +
    +async function readLockfile(ssh, ownershipId) {
    +  const lpath = lockfilePath(ownershipId)
    +  let raw
    +
    +  try {
    +    raw = await ssh.exec(`if [ ! -e ${expandRemotePath(lpath)} ]; then exit 0; fi; cat ${expandRemotePath(lpath)}`)
    +  } catch (cause) {
    +    const error: any = new Error('Could not read the SSH backend ownership record.')
    +    error.kind = 'transient-transport-error'
    +    error.cause = cause
    +    throw error
    +  }
    +
    +  const text = String(raw || '').trim()
    +
    +  if (!text) {
    +    return null
    +  }
    +
    +  let parsed
    +
    +  try {
    +    parsed = JSON.parse(text)
    +  } catch {
    +    return null
    +  }
    +
    +  if (!parsed || parsed.schemaVersion !== LOCKFILE_SCHEMA_VERSION) {
    +    return null
    +  }
    +
    +  const pid = parsed.pid
    +  const port = parsed.port
    +
    +  if (!Number.isInteger(pid) || pid <= 0 || pid > 4194304) {
    +    return null
    +  }
    +
    +  // port 0 = spawn-in-progress record (written before readiness); valid
    +  // ownership proof for cleanup, but never reusable.
    +  if (!Number.isInteger(port) || port < 0 || port > 65535) {
    +    return null
    +  }
    +
    +  if (parsed.ownershipId !== ownershipId || !/^[0-9a-f]{16}$/.test(parsed.spawnNonce || '')) {
    +    return null
    +  }
    +
    +  if (!/^[0-9a-f]{32}$/.test(parsed.tokenFingerprint || '')) {
    +    return null
    +  }
    +
    +  if (parsed.protocolVersion !== PROTOCOL_VERSION) {
    +    return null
    +  }
    +
    +  if (parsed.logPath !== spawnLogPath(ownershipId, parsed.spawnNonce)) {
    +    return null
    +  }
    +
    +  for (const field of ['profile', 'hermesPath', 'hermesHome', 'logPath', 'startedAt']) {
    +    if (typeof parsed[field] !== 'string' || parsed[field].length > 1024) {
    +      return null
    +    }
    +  }
    +
    +  return parsed
    +}
    +
    +async function writeLockfile(ssh, ownershipId, lock) {
    +  const directory = ownershipDirectory(ownershipId)
    +  const lpath = lockfilePath(ownershipId)
    +  const temporaryPath = `${directory}/.${crypto.randomBytes(8).toString('hex')}.lock.tmp`
    +  const json = JSON.stringify({ ...lock, schemaVersion: LOCKFILE_SCHEMA_VERSION })
    +  await ssh.exec(
    +    `umask 077 && mkdir -p ${expandRemotePath(directory)} && ` +
    +      `printf '%s' ${shq(json)} > ${expandRemotePath(temporaryPath)} && ` +
    +      `mv -f ${expandRemotePath(temporaryPath)} ${expandRemotePath(lpath)}`
    +  )
    +}
    +
    +async function removeLockfile(ssh, ownershipId) {
    +  const lpath = lockfilePath(ownershipId)
    +
    +  try {
    +    await ssh.exec(`rm -f ${expandRemotePath(lpath)}`)
    +  } catch {
    +    // best effort
    +  }
    +}
    +
    +async function remotePidAlive(ssh, pid) {
    +  if (!pid || !Number.isInteger(Number(pid))) {
    +    return false
    +  }
    +
    +  try {
    +    const out = (await ssh.exec(`kill -0 ${Number(pid)} 2>/dev/null && echo ALIVE || echo DEAD`)).trim()
    +
    +    return out === 'ALIVE'
    +  } catch (cause) {
    +    const error: any = new Error('Could not verify the SSH backend process.')
    +    error.kind = 'transient-transport-error'
    +    error.cause = cause
    +    throw error
    +  }
    +}
    +
    +// A pid is "provably ours" only if its remote cmdline carries our dashboard
    +// args — never kill a pid we can't positively identify as our dashboard.
    +async function pidIsOurDashboard(ssh, pid, spawnNonce, hermesPath = '') {
    +  if (!pid || !/^[0-9a-f]{16}$/.test(String(spawnNonce || '')) || !hermesPath) {
    +    return false
    +  }
    +
    +  try {
    +    const script =
    +      'import os,shlex,subprocess,sys\n' +
    +      `pid=${Number(pid)}\n` +
    +      `expected=os.path.expanduser(${shq(hermesPath)})\n` +
    +      `nonce=${shq(spawnNonce)}\n` +
    +      'try:\n' +
    +      ' raw=open(f"/proc/{pid}/cmdline","rb").read()\n' +
    +      ' args=[x.decode("utf-8","surrogateescape") for x in raw.split(b"\\0") if x]\n' +
    +      'except OSError:\n' +
    +      ' line=subprocess.check_output(["ps","-o","command=","-p",str(pid)],text=True).strip()\n' +
    +      ' args=shlex.split(line)\n' +
    +      'ok=False\n' +
    +      'try:\n' +
    +      ' serve=args.index("serve")\n' +
    +      ' owner=args.index("--ssh-owner-nonce",serve+1)\n' +
    +      ' direct=args[0]==expected\n' +
    +      ' python_entry=len(args)>1 and args[1]==expected and os.path.basename(args[0]).startswith("python")\n' +
    +      ' ok=(direct or python_entry) and "--isolated" in args[serve+1:] and args[owner+1]==nonce\n' +
    +      'except (ValueError,IndexError):pass\n' +
    +      'print("OWNED" if ok else "FOREIGN")'
    +
    +    const out = await ssh.exec(`python3 -c ${shq(script)}`)
    +
    +    return String(out || '').trim() === 'OWNED'
    +  } catch (cause) {
    +    const error: any = new Error('Could not verify SSH backend process ownership.')
    +    error.kind = 'transient-transport-error'
    +    error.cause = cause
    +    throw error
    +  }
    +}
    +
    +// Kill the stale dashboard ONLY if provably ours, then drop the lockfile.
    +async function cleanupStale(ssh, ownershipId, lock, pidAlive = true) {
    +  if (pidAlive && lock && (await pidIsOurDashboard(ssh, lock.pid, lock.spawnNonce, lock.hermesPath))) {
    +    try {
    +      const result = (
    +        await ssh.exec(
    +          `kill ${Number(lock.pid)} && ` +
    +            `i=0; while kill -0 ${Number(lock.pid)} 2>/dev/null; do ` +
    +            `i=$((i+1)); [ "$i" -ge 50 ] && exit 1; sleep 0.1; done`
    +        )
    +      ).trim()
    +
    +      void result
    +    } catch (cause) {
    +      const error: any = new Error('Could not terminate the stale SSH backend.')
    +      error.kind = 'transient-transport-error'
    +      error.cause = cause
    +      throw error
    +    }
    +  }
    +
    +  const expectedLogPath = lock?.spawnNonce ? spawnLogPath(ownershipId, lock.spawnNonce) : ''
    +
    +  if (lock?.logPath === expectedLogPath) {
    +    try {
    +      await ssh.exec(`rm -f ${expandRemotePath(lock.logPath)}`)
    +    } catch {
    +      void 0
    +    }
    +  }
    +
    +  await removeLockfile(ssh, ownershipId)
    +}
    +
    +// Detach so the backend survives the SSH channel closing: setsid (Linux)
    +// starts a new session; macOS has no setsid, so fall back to nohup (HUP-immune;
    +// fd-detachment is already handled by </dev/null + redirect + &).
    +function buildSpawnCommand(hermesPath, profile, opts: any = {}) {
    +  const hermes = expandRemotePath(hermesPath)
    +  const profileArgs = profile ? `--profile ${shq(profile)} ` : ''
    +  const logPath = expandRemotePath(opts.logPath)
    +  const tokenFilePath = [redacted:secret-assignment]
    +  const tokenArg = tokenFilePath ? ` --ssh-session-token-file ${expandRemotePath(tokenFilePath)}` : ''
    +  const ownerArg = opts.spawnNonce ? ` --ssh-owner-nonce ${validateSpawnNonce(opts.spawnNonce)}` : ''
    +  const subCmd = `serve --isolated --host 127.0.0.1 --port 0${tokenArg}${ownerArg}`
    +  const dashCmd = `env HERMES_DESKTOP=1 ${hermes} ${profileArgs}${subCmd}`
    +
    +  return (
    +    `mkdir -p "$(dirname ${logPath})" && ` +
    +    `"$(command -v setsid || echo nohup)" sh -c ${shq(`${dashCmd} </dev/null >> ${logPath} 2>&1 & echo $!`)}`
    +  )
    +}
    +
    +async function remoteSupportsSshOwnership(ssh, hermesPath) {
    +  const hermes = expandRemotePath(hermesPath)
    +
    +  const out = await ssh.exec(
    +    `help="$(${hermes} serve --help 2>&1)"; ` +
    +      `printf '%s' "$help" | grep -q ssh-session-token-file && ` +
    +      `printf '%s' "$help" | grep -q ssh-owner-nonce && echo YES || echo NO`
    +  )
    +
    +  return String(out || '')
    +    .trim()
    +    .endsWith('YES')
    +}
    +
    +async function scrapeReadyPort(ssh, logPath, { timeoutMs = DEFAULT_READY_TIMEOUT_MS, isAlive, signal }: any = {}) {
    +  const deadline = Date.now() + timeoutMs
    +  const remoteLog = expandRemotePath(logPath)
    +
    +  while (Date.now() < deadline) {
    +    assertNotAborted(signal)
    +
    +    if (isAlive && !(await isAlive())) {
    +      const err: any = new Error('Remote dashboard process exited before announcing its port.')
    +      err.kind = 'spawn-failed'
    +      throw err
    +    }
    +
    +    let tail
    +
    +    try {
    +      tail = await ssh.exec(`cat ${remoteLog} 2>/dev/null || true`)
    +    } catch {
    +      tail = ''
    +    }
    +
    +    const m = READY_RE.exec(String(tail || ''))
    +
    +    if (m) {
    +      return parseInt(m[1], 10)
    +    }
    +
    +    await new Promise(r => setTimeout(r, READY_POLL_INTERVAL_MS))
    +  }
    +
    +  const err: any = new Error(`Timed out waiting for the remote dashboard to announce its port (${timeoutMs}ms).`)
    +  err.kind = 'ready-timeout'
    +  throw err
    +}
    +
    +async function spawnRemoteDashboard(ssh, { hermesPath, profile, token, ownershipId }) {
    +  if (!(await remoteSupportsSshOwnership(ssh, hermesPath))) {
    +    const err: any = new Error(
    +      'The remote Hermes install does not support --ssh-session-token-file and --ssh-owner-nonce. ' +
    +        'Update Hermes on the remote host to continue using Desktop SSH mode.'
    +    )
    +
    +    err.kind = 'update-required'
    +    throw err
    +  }
    +
    +  const spawnNonce = crypto.randomBytes(8).toString('hex')
    +  const tokenDir = [redacted:secret-assignment]
    +  const tokenFilePath = [redacted:secret-assignment]
    +  const logPath = spawnLogPath(ownershipId, spawnNonce)
    +
    +  const tokenUploadPy =
    +    'import os,sys,stat\n' +
    +    `p=os.path.expanduser(${shq(tokenFilePath)})\n` +
    +    'd=os.path.dirname(p)\n' +
    +    'n=os.path.basename(p)\n' +
    +    'os.makedirs(d,mode=0o700,exist_ok=True)\n' +
    +    'df=os.O_RDONLY|getattr(os,"O_DIRECTORY",0)|getattr(os,"O_NOFOLLOW",0)\n' +
    +    'dd=os.open(d,df)\n' +
    +    'try:\n' +
    +    ' s=os.fstat(dd)\n' +
    +    ' if not stat.S_ISDIR(s.st_mode):raise SystemExit("unsafe token directory")\n' +
    +    ' if hasattr(os,"getuid") and s.st_uid!=os.getuid():raise SystemExit("token directory owner mismatch")\n' +
    +    ' if (s.st_mode&0o777)!=0o700:os.fchmod(dd,0o700)\n' +
    +    ' fl=os.O_WRONLY|os.O_CREAT|os.O_EXCL|getattr(os,"O_NOFOLLOW",0)\n' +
    +    ' now=__import__("time").time()\n' +
    +    ' for stale in os.listdir(dd):\n' +
    +    '  if stale.endswith(".token") and len(stale)==22:\n' +
    +    '   try:\n' +
    +    '    ss=os.stat(stale,dir_fd=dd,follow_symlinks=False)\n' +
    +    '    if stat.S_ISREG(ss.st_mode) and now-ss.st_mtime>3600:os.unlink(stale,dir_fd=dd)\n' +
    +    '   except OSError:pass\n' +
    +    ' fd=os.open(n,fl,0o600,dir_fd=dd)\n' +
    +    ' try:os.write(fd,sys.stdin.buffer.read())\n' +
    +    ' except BaseException:\n' +
    +    '  try:os.unlink(n,dir_fd=dd)\n' +
    +    '  except OSError:pass\n' +
    +    '  raise\n' +
    +    ' finally:os.close(fd)\n' +
    +    'finally:os.close(dd)'
    +
    +  try {
    +    await ssh.exec(`python3 -c ${shq(tokenUploadPy)}`, { stdinData: token })
    +  } catch (error) {
    +    try {
    +      await ssh.exec(`rm -f ${expandRemotePath(tokenFilePath)}`)
    +    } catch {
    +      void 0
    +    }
    +
    +    throw error
    +  }
    +
    +  let out
    +
    +  try {
    +    out = await ssh.exec(buildSpawnCommand(hermesPath, profile, { spawnNonce, tokenFilePath, logPath }))
    +  } catch (error) {
    +    try {
    +      await ssh.exec(`rm -f ${expandRemotePath(tokenFilePath)}`)
    +    } catch {
    +      void 0
    +    }
    +
    +    throw error
    +  }
    +
    +  const pid = parseInt(
    +    String(out || '')
    +      .trim()
    +      .split('\n')
    +      .pop(),
    +    10
    +  )
    +
    +  if (!Number.isInteger(pid) || pid <= 0) {
    +    try {
    +      await ssh.exec(`rm -f ${expandRemotePath(tokenFilePath)}`)
    +    } catch {
    +      void 0
    +    }
    +
    +    const err: any = new Error('Failed to launch the remote dashboard (no pid returned).')
    +    err.kind = 'spawn-failed'
    +    throw err
    +  }
    +
    +  return { pid, spawnNonce, logPath, tokenFilePath }
    +}
    +
    +// Best-effort forward teardown when a reuse attempt fails mid-flight, so we
    +// don't leak a forward before respawning. `deps.cancelForward` is optional.
    +async function cancelForwardSafe(deps, localPort, remotePort) {
    +  if (typeof deps.cancelForward !== 'function') {
    +    return
    +  }
    +
    +  try {
    +    await deps.cancelForward(localPort, remotePort)
    +  } catch {
    +    // best effort
    +  }
    +}
    +
    +function assertNotAborted(signal) {
    +  if (signal?.aborted) {
    +    const error: any = new Error('SSH bootstrap was cancelled.')
    +    error.kind = 'superseded'
    +    throw error
    +  }
    +}
    +
    +function isForwardBindCollision(error) {
    +  return /address already in use|cannot listen to port|bind.*failed/i.test(String(error?.message || error || ''))
    +}
    +
    +async function openForward(deps, remotePort, attempts = 3) {
    +  let lastError
    +
    +  for (let attempt = 0; attempt < attempts; attempt++) {
    +    const localPort = await deps.pickLocalPort()
    +
    +    try {
    +      await deps.forward(localPort, remotePort)
    +
    +      return localPort
    +    } catch (error) {
    +      lastError = error
    +
    +      if (!isForwardBindCollision(error) || attempt === attempts - 1) {
    +        throw error
    +      }
    +    }
    +  }
    +
    +  throw lastError
    +}
    +
    +/**
    + * Establish (or reuse) a remote dashboard and a tunnel to it. `deps` injects the
    + * opened SshConnection, forward/pickLocalPort/waitForHermes, a token-gated
    + * probeReuseProof, and adoptServedToken. Returns the connection descriptor
    + * { baseUrl, token, tokenFingerprint, remotePort, localPort, pid, reused, platform }.
    + */
    +async function adoptOwnedServedToken(adoptServedToken, baseUrl, expectedToken, ssh, pid, label) {
    +  const token = await adoptServedToken(baseUrl, expectedToken, {
    +    childAlive: () => true,
    +    label
    +  })
    +
    +  if (!(await remotePidAlive(ssh, pid))) {
    +    const error: any = new Error(`${label} exited while its served token was being resolved.`)
    +    error.kind = token === expectedToken ? 'spawn-failed' : 'foreign-backend'
    +    throw error
    +  }
    +
    +  return token
    +}
    +
    +async function connect(deps) {
    +  const {
    +    ssh,
    +    profile = '',
    +    remoteHermesPath = '',
    +    ownershipId,
    +    forward,
    +    pickLocalPort,
    +    waitForHermes,
    +    probeReuseProof,
    +    adoptServedToken,
    +    rememberLog = () => {},
    +    readyTimeoutMs = DEFAULT_READY_TIMEOUT_MS,
    +    signal
    +  } = deps
    +
    +  const log = msg => rememberLog(`[ssh-lifecycle] ${msg}`)
    +
    +  assertNotAborted(signal)
    +  const platform = await probeRemotePlatform(ssh)
    +  log(`remote platform ${platform.os}/${platform.arch}`)
    +  const hermesPath = await locateHermes(ssh, remoteHermesPath)
    +  log(`located hermes at ${hermesPath}`)
    +  const hermesVersion = await probeHermesVersion(ssh, hermesPath)
    +
    +  if (hermesVersion) {
    +    log(`remote hermes version: ${hermesVersion}`)
    +  }
    +
    +  const reuseToken = [redacted:secret-assignment] || ''
    +  const hermesHome = await probeRemoteHermesHome(ssh)
    +  const lock = await readLockfile(ssh, ownershipId)
    +
    +  if (lock) {
    +    const pidAlive = await remotePidAlive(ssh, lock.pid)
    +    const owned = pidAlive && (await pidIsOurDashboard(ssh, lock.pid, lock.spawnNonce, lock.hermesPath))
    +
    +    const reusable =
    +      pidAlive &&
    +      owned &&
    +      lock.port > 0 &&
    +      Boolean(reuseToken) &&
    +      lock.tokenFingerprint === fingerprintToken(reuseToken) &&
    +      lock.hermesPath === hermesPath &&
    +      lock.hermesHome === hermesHome
    +
    +    if (reusable) {
    +      assertNotAborted(signal)
    +      const localPort = await openForward(deps, lock.port)
    +
    +      try {
    +        const baseUrl = `http://127.0.0.1:${localPort}`
    +        let reuseClassification
    +
    +        try {
    +          reuseClassification = await probeReuseProof(baseUrl, reuseToken, lock.spawnNonce)
    +        } catch (cause) {
    +          const error: any = new Error('Could not verify the existing SSH backend.')
    +          error.kind = 'transient-transport-error'
    +          error.cause = cause
    +          throw error
    +        }
    +
    +        if (reuseClassification === 'authenticated-stale') {
    +          assertNotAborted(signal)
    +          await cancelForwardSafe(deps, localPort, lock.port)
    +          await cleanupStale(ssh, ownershipId, lock)
    +        } else if (reuseClassification === 'authenticated-ok') {
    +          const token = await adoptOwnedServedToken(
    +            adoptServedToken,
    +            baseUrl,
    +            reuseToken,
    +            ssh,
    +            lock.pid,
    +            'reused remote dashboard'
    +          )
    +
    +          assertNotAborted(signal)
    +          log(`reusing remote dashboard pid=${lock.pid} port=${lock.port}`)
    +
    +          return {
    +            baseUrl,
    +            token,
    +            tokenFingerprint: [redacted:secret-assignment]
    +            remotePort: lock.port,
    +            localPort,
    +            pid: lock.pid,
    +            reused: true,
    +            platform,
    +            hermesPath,
    +            hermesVersion,
    +            ownershipId,
    +            spawnNonce: lock.spawnNonce,
    +            logPath: lock.logPath
    +          }
    +        } else {
    +          const error: any = new Error('SSH reuse proof returned an invalid classification.')
    +          error.kind = 'transient-transport-error'
    +          throw error
    +        }
    +      } catch (error) {
    +        await cancelForwardSafe(deps, localPort, lock.port)
    +        throw error
    +      }
    +    } else {
    +      assertNotAborted(signal)
    +      await cleanupStale(ssh, ownershipId, lock, pidAlive)
    +    }
    +  }
    +
    +  assertNotAborted(signal)
    +  const spawnToken = [redacted:secret-assignment]
    +
    +  const { pid, spawnNonce, logPath, tokenFilePath } = await spawnRemoteDashboard(ssh, {
    +    hermesPath,
    +    profile,
    +    token: [redacted:secret-assignment]
    +    ownershipId
    +  })
    +
    +  log(`spawned remote dashboard pid=${pid}`)
    +
    +  const ownedSpawn = {
    +    ownershipId,
    +    spawnNonce,
    +    pid,
    +    port: 0,
    +    profile,
    +    hermesPath,
    +    hermesHome,
    +    logPath,
    +    tokenFingerprint: [redacted:secret-assignment]
    +    protocolVersion: PROTOCOL_VERSION,
    +    startedAt: new Date().toISOString()
    +  }
    +
    +  let localPort = 0
    +  let remotePort = 0
    +
    +  try {
    +    // Write the ownership record IMMEDIATELY (port=0): a supersede between
    +    // spawn and readiness whose cleanup cannot reach the box must not leave a
    +    // lockless orphan — the next connect reaps it by exact ownership via this
    +    // record. Inside the try: if this write itself fails, the catch still
    +    // kills the just-spawned process via the in-memory record.
    +    await writeLockfile(ssh, ownershipId, ownedSpawn)
    +    remotePort = await scrapeReadyPort(ssh, logPath, {
    +      timeoutMs: readyTimeoutMs,
    +      isAlive: () => remotePidAlive(ssh, pid),
    +      signal
    +    })
    +    assertNotAborted(signal)
    +    log(`remote dashboard bound port ${remotePort}`)
    +
    +    localPort = await openForward(deps, remotePort)
    +    assertNotAborted(signal)
    +    const baseUrl = `http://127.0.0.1:${localPort}`
    +    await waitForHermes(baseUrl, spawnToken)
    +    assertNotAborted(signal)
    +
    +    const token = await adoptOwnedServedToken(adoptServedToken, baseUrl, spawnToken, ssh, pid, 'remote dashboard')
    +
    +    assertNotAborted(signal)
    +    const tokenFingerprint = [redacted:secret-assignment]
    +    await writeLockfile(ssh, ownershipId, { ...ownedSpawn, port: remotePort, tokenFingerprint })
    +    assertNotAborted(signal)
    +
    +    return {
    +      baseUrl,
    +      token,
    +      tokenFingerprint,
    +      remotePort,
    +      localPort,
    +      pid,
    +      reused: false,
    +      platform,
    +      hermesPath,
    +      hermesVersion,
    +      ownershipId,
    +      spawnNonce,
    +      logPath
    +    }
    +  } catch (error) {
    +    if (localPort && remotePort) {
    +      await cancelForwardSafe(deps, localPort, remotePort)
    +    }
    +
    +    try {
    +      await ssh.exec(`rm -f ${expandRemotePath(tokenFilePath)}`)
    +    } catch {
    +      void 0
    +    }
    +
    +    await cleanupStale(ssh, ownershipId, ownedSpawn)
    +    throw error
    +  }
    +}
    +
    +export {
    +  adoptOwnedServedToken,
    +  buildSpawnCommand,
    +  cleanupStale,
    +  connect,
    +  DEFAULT_READY_TIMEOUT_MS,
    +  expandRemotePath,
    +  fingerprintToken,
    +  isForwardBindCollision,
    +  locateHermes,
    +  LOCKFILE_SCHEMA_VERSION,
    +  lockfilePath,
    +  mintToken,
    +  openForward,
    +  ownershipDirectory,
    +  pidIsOurDashboard,
    +  probeHermesVersion,
    +  probeRemoteHermesHome,
    +  probeRemotePlatform,
    +  PROTOCOL_VERSION,
    +  readLockfile,
    +  READY_RE,
    +  REMOTE_LOCK_DIR,
    +  remotePidAlive,
    +  remoteSupportsSshOwnership,
    +  removeLockfile,
    +  scrapeReadyPort,
    +  shq,
    +  spawnLogPath,
    +  spawnRemoteDashboard,
    +  SUPPORTED_REMOTE_OS,
    +  validateRemotePath,
    +  writeLockfile
    +}
    ```
  - `apps/desktop/electron/ssh-bootstrap-coordinator.test.ts`

    ```diff
    @@ -0,0 +1,192 @@
    +import assert from 'node:assert/strict'
    +
    +import { test } from 'vitest'
    +
    +import { createBootstrapCoordinator, sshConfigFingerprint } from './ssh-bootstrap-coordinator'
    +
    +function deferred() {
    +  let resolve
    +  let reject
    +
    +  const promise = new Promise((ok, fail) => {
    +    resolve = ok
    +    reject = fail
    +  })
    +
    +  return { promise, reject, resolve }
    +}
    +
    +const config = { host: 'box', user: 'alice', port: 22, keyPath: '/key', remoteHermesPath: '/hermes' }
    +
    +test('sshConfigFingerprint covers scope and every connection field', () => {
    +  const base = sshConfigFingerprint('', config)
    +  assert.equal(base, sshConfigFingerprint('', { ...config }))
    +
    +  for (const [field, value] of Object.entries({
    +    host: 'other',
    +    user: 'bob',
    +    port: 2222,
    +    keyPath: '/other',
    +    remoteHermesPath: '/other-hermes',
    +    effectiveConfigFingerprint: 'changed-config'
    +  })) {
    +    assert.notEqual(base, sshConfigFingerprint('', { ...config, [field]: value }))
    +  }
    +
    +  assert.notEqual(base, sshConfigFingerprint('profile', config))
    +})
    +
    +test('same scope and fingerprint share one bootstrap', async () => {
    +  const coordinator = createBootstrapCoordinator()
    +  const gate = deferred()
    +  let runs = 0
    +
    +  const first = coordinator.start('', 'same', async () => {
    +    runs++
    +
    +    return gate.promise
    +  })
    +
    +  const second = coordinator.start('', 'same', async () => {
    +    runs++
    +
    +    return 'wrong'
    +  })
    +
    +  assert.equal(first, second)
    +  gate.resolve('done')
    +  assert.equal(await second, 'done')
    +  assert.equal(runs, 1)
    +})
    +
    +test('changed fingerprint waits for old rollback before starting', async () => {
    +  const coordinator = createBootstrapCoordinator()
    +  const gate = deferred()
    +  const events: string[] = []
    +  let oldLease
    +
    +  const oldPromise = coordinator.start('', 'old', async lease => {
    +    oldLease = lease
    +    events.push('old-start')
    +    await gate.promise
    +    events.push('old-rollback')
    +    lease.assertCurrent()
    +  })
    +
    +  await Promise.resolve()
    +
    +  const newPromise = coordinator.start('', 'new', async lease => {
    +    events.push('new-start')
    +    lease.assertCurrent()
    +
    +    return 'new'
    +  })
    +
    +  assert.equal(oldLease.signal.aborted, true)
    +  await Promise.resolve()
    +  assert.deepEqual(events, ['old-start'])
    +  gate.resolve()
    +  await assert.rejects(oldPromise, (error: any) => error.kind === 'superseded')
    +  assert.equal(await newPromise, 'new')
    +  assert.deepEqual(events, ['old-start', 'old-rollback', 'new-start'])
    +})
    +
    +test('forceCleanupAll runs registered pending resource cleanup', async () => {
    +  const coordinator = createBootstrapCoordinator()
    +  const gate = deferred()
    +  let cleaned = 0
    +
    +  const promise = coordinator.start('', 'x', async lease => {
    +    lease.onForceCleanup(async () => {
    +      cleaned++
    +    })
    +    await gate.promise
    +  })
    +
    +  await Promise.resolve()
    +  await coordinator.forceCleanupAll()
    +  assert.equal(cleaned, 1)
    +  gate.resolve()
    +  await promise
    +})
    +
    +test('cancelAll invalidates every pending scope and exposes promises for quit', async () => {
    +  const coordinator = createBootstrapCoordinator()
    +  const gates = [deferred(), deferred()]
    +
    +  const promises = gates.map((gate, index) =>
    +    coordinator.start(String(index), 'x', async lease => {
    +      await gate.promise
    +      lease.assertCurrent()
    +    })
    +  )
    +
    +  assert.equal(coordinator.promises().length, 2)
    +  coordinator.cancelAll()
    +  gates.forEach(gate => gate.resolve())
    +  const results = await Promise.allSettled(promises)
    +  assert.ok(results.every(result => result.status === 'rejected' && (result.reason as any).kind === 'superseded'))
    +})
    +
    +test('cancelAndWait drains only the requested scope', async () => {
    +  const coordinator = createBootstrapCoordinator()
    +  const firstGate = deferred()
    +  const secondGate = deferred()
    +
    +  const first = coordinator.start('first', 'x', async lease => {
    +    await firstGate.promise
    +    lease.assertCurrent()
    +  })
    +
    +  const second = coordinator.start('second', 'x', async lease => {
    +    await secondGate.promise
    +    lease.assertCurrent()
    +
    +    return 'second'
    +  })
    +
    +  await Promise.resolve()
    +  let drained = false
    +
    +  const drain = coordinator.cancelAndWait('first').then(() => {
    +    drained = true
    +  })
    +
    +  await Promise.resolve()
    +  assert.equal(drained, false)
    +  firstGate.resolve()
    +  await drain
    +  await assert.rejects(first, (error: any) => error.kind === 'superseded')
    +  assert.equal(coordinator.pending.has('second'), true)
    +  secondGate.resolve()
    +  assert.equal(await second, 'second')
    +})
    +
    +test('a generation started during cancelAndWait cannot run before the drain completes', async () => {
    +  const coordinator = createBootstrapCoordinator()
    +  const oldGate = deferred()
    +  const events: string[] = []
    +
    +  const old = coordinator.start('scope', 'old', async lease => {
    +    events.push('old-start')
    +    await oldGate.promise
    +    lease.assertCurrent()
    +  })
    +
    +  await Promise.resolve()
    +  const drain = coordinator.cancelAndWait('scope')
    +
    +  const next = coordinator.start('scope', 'new', async () => {
    +    events.push('new-start')
    +
    +    return 'new'
    +  })
    +
    +  await Promise.resolve()
    +  assert.deepEqual(events, ['old-start'])
    +  oldGate.resolve()
    +  await drain
    +  await assert.rejects(old, (error: any) => error.kind === 'superseded')
    +  assert.equal(await next, 'new')
    +  assert.deepEqual(events, ['old-start', 'new-start'])
    +})
    ```
  - `apps/desktop/electron/ssh-bootstrap-coordinator.ts`

    ```diff
    @@ -0,0 +1,130 @@
    +import crypto from 'node:crypto'
    +
    +function sshConfigFingerprint(scope, config) {
    +  const parts = [
    +    scope,
    +    config.host,
    +    config.user,
    +    config.port,
    +    config.keyPath,
    +    config.remoteHermesPath,
    +    config.effectiveConfigFingerprint
    +  ]
    +
    +  return crypto
    +    .createHash('sha256')
    +    .update(JSON.stringify(parts.map(value => value ?? '')))
    +    .digest('hex')
    +}
    +
    +function createBootstrapCoordinator() {
    +  const active = new Set<any>()
    +  const pending = new Map<string, any>()
    +  const generations = new Map<string, number>()
    +  const drains = new Map<string, Promise<void>>()
    +
    +  function start(scope, fingerprint, run) {
    +    const current = pending.get(scope)
    +
    +    if (current?.fingerprint === fingerprint) {
    +      return current.promise
    +    }
    +
    +    current?.controller.abort()
    +
    +    const generation = (generations.get(scope) || 0) + 1
    +    generations.set(scope, generation)
    +    const controller = new AbortController()
    +    const forceCleanups = new Set<() => any>()
    +
    +    const lease = {
    +      signal: controller.signal,
    +      onForceCleanup(cleanup) {
    +        forceCleanups.add(cleanup)
    +
    +        return () => forceCleanups.delete(cleanup)
    +      },
    +      isCurrent: () => !controller.signal.aborted && generations.get(scope) === generation,
    +      assertCurrent() {
    +        if (!this.isCurrent()) {
    +          const error: any = new Error('SSH bootstrap was superseded by newer connection settings.')
    +          error.kind = 'superseded'
    +          throw error
    +        }
    +      }
    +    }
    +
    +    const drain = drains.get(scope) || Promise.resolve()
    +    const predecessor = current ? Promise.allSettled([current.promise, drain]) : drain
    +    const entry: any = { controller, fingerprint, forceCleanups, generation, promise: null, scope }
    +
    +    const promise = predecessor
    +      .then(() => {
    +        lease.assertCurrent()
    +
    +        return run(lease)
    +      })
    +      .finally(() => {
    +        forceCleanups.clear()
    +        active.delete(entry)
    +
    +        if (pending.get(scope)?.generation === generation) {
    +          pending.delete(scope)
    +        }
    +      })
    +
    +    entry.promise = promise
    +    active.add(entry)
    +    pending.set(scope, entry)
    +
    +    return promise
    +  }
    +
    +  function cancel(scope) {
    +    pending.get(scope)?.controller.abort()
    +  }
    +
    +  async function cancelAndWait(scope) {
    +    let release
    +
    +    const barrier = new Promise<void>(resolve => {
    +      release = resolve
    +    })
    +
    +    drains.set(scope, barrier)
    +    const entries = [...active].filter(entry => entry.scope === scope)
    +
    +    for (const entry of entries) {
    +      entry.controller.abort()
    +    }
    +
    +    try {
    +      await Promise.allSettled(entries.map(entry => entry.promise))
    +    } finally {
    +      if (drains.get(scope) === barrier) {
    +        drains.delete(scope)
    +      }
    +
    +      release()
    +    }
    +  }
    +
    +  function cancelAll() {
    +    for (const entry of active) {
    +      entry.controller.abort()
    +    }
    +  }
    +
    +  async function forceCleanupAll() {
    +    const cleanups = [...active].flatMap(entry => [...entry.forceCleanups])
    +    await Promise.allSettled(cleanups.map(cleanup => cleanup()))
    +  }
    +
    +  function promises() {
    +    return [...active].map(entry => entry.promise)
    +  }
    +
    +  return { active, cancel, cancelAll, cancelAndWait, forceCleanupAll, pending, promises, start }
    +}
    +
    +export { createBootstrapCoordinator, sshConfigFingerprint }
    ```
  - `apps/desktop/electron/ssh-config.test.ts`

    ```diff
    @@ -0,0 +1,104 @@
    +import assert from 'node:assert/strict'
    +
    +import { test } from 'vitest'
    +
    +import { collectSshConfigHosts, parseSshConfigHosts, parseSshConfigIncludes, parseSshGOutput } from './ssh-config'
    +
    +test('parseSshConfigHosts keeps literal aliases and drops wildcard/negated patterns', () => {
    +  const cfg = [
    +    'Host devbox',
    +    '  HostName 10.0.0.5',
    +    'Host *.internal prod !staging glob*',
    +    'Host alpha beta',
    +    '# Host commented-out',
    +    'host lower-case'
    +  ].join('\n')
    +
    +  assert.deepEqual(parseSshConfigHosts(cfg), ['devbox', 'prod', 'alpha', 'beta', 'lower-case'])
    +})
    +
    +test('parseSshConfigHosts de-duplicates', () => {
    +  assert.deepEqual(parseSshConfigHosts('Host box\nHost box\nHost box other'), ['box', 'other'])
    +})
    +
    +test('parseSshConfigIncludes extracts include tokens', () => {
    +  const cfg = 'Include ~/.ssh/config.d/*\nInclude work_hosts personal_hosts\n# Include ignored'
    +  assert.deepEqual(parseSshConfigIncludes(cfg), ['~/.ssh/config.d/*', 'work_hosts', 'personal_hosts'])
    +})
    +
    +test('collectSshConfigHosts follows Include directives (read-only)', () => {
    +  const files = {
    +    '/home/u/.ssh/config': 'Host main\nInclude work\nInclude ~/abs_inc',
    +    '/home/u/.ssh/work': 'Host work-box\nInclude nested',
    +    '/home/u/.ssh/nested': 'Host deep',
    +    '/home/u/abs_inc': 'Host home-abs'
    +  }
    +
    +  const hosts = collectSshConfigHosts('/home/u/.ssh/config', {
    +    homeDir: '/home/u',
    +    readFile: p => files[p] ?? null
    +  })
    +
    +  assert.deepEqual(hosts.sort(), ['deep', 'home-abs', 'main', 'work-box'].sort())
    +})
    +
    +test('collectSshConfigHosts tolerates a missing config file', () => {
    +  assert.deepEqual(collectSshConfigHosts('/nope/config', { homeDir: '/home/u', readFile: () => null }), [])
    +})
    +
    +test('collectSshConfigHosts does not loop on a self-include cycle', () => {
    +  const files = {
    +    '/home/u/.ssh/config': 'Host a\nInclude loop',
    +    '/home/u/.ssh/loop': 'Host b\nInclude config' // points back at config
    +  }
    +
    +  const hosts = collectSshConfigHosts('/home/u/.ssh/config', {
    +    homeDir: '/home/u',
    +    readFile: p => files[p] ?? null
    +  })
    +
    +  assert.deepEqual(hosts.sort(), ['a', 'b'])
    +})
    +
    +test('collectSshConfigHosts expands globbed includes via injected globSync', () => {
    +  const files = {
    +    '/home/u/.ssh/config': 'Host root\nInclude config.d/*',
    +    '/home/u/.ssh/config.d/10-work': 'Host work',
    +    '/home/u/.ssh/config.d/20-home': 'Host home'
    +  }
    +
    +  const hosts = collectSshConfigHosts('/home/u/.ssh/config', {
    +    homeDir: '/home/u',
    +    readFile: p => files[p] ?? null,
    +    globSync: pattern =>
    +      pattern.endsWith('config.d/*') ? ['/home/u/.ssh/config.d/10-work', '/home/u/.ssh/config.d/20-home'] : [pattern]
    +  })
    +
    +  assert.deepEqual(hosts.sort(), ['home', 'root', 'work'].sort())
    +})
    +
    +test('parseSshGOutput pulls hostname/user/port/identityfile', () => {
    +  const out = [
    +    'host devbox',
    +    'hostname 10.0.0.5',
    +    'user alice',
    +    'port 2222',
    +    'identityfile ~/.ssh/id_ed25519',
    +    'forwardagent no'
    +  ].join('\n')
    +
    +  assert.deepEqual(parseSshGOutput(out), {
    +    hostname: '10.0.0.5',
    +    user: 'alice',
    +    port: 2222,
    +    identityFile: '~/.ssh/id_ed25519'
    +  })
    +})
    +
    +test('parseSshGOutput takes the FIRST identityfile and tolerates missing keys', () => {
    +  const out = 'hostname box\nidentityfile ~/.ssh/a\nidentityfile ~/.ssh/b'
    +  const parsed = parseSshGOutput(out)
    +  assert.equal(parsed.identityFile, '~/.ssh/a')
    +  assert.equal(parsed.user, null)
    +  assert.equal(parsed.port, null)
    +})
    ```
  - `apps/desktop/electron/ssh-config.ts`

    ```diff
    @@ -0,0 +1,175 @@
    +/**
    + * ssh-config.ts
    + *
    + * Pure, electron-free helpers for reading the user's OpenSSH client config:
    + * `Host` aliases for the settings UI's suggestions, `Include` traversal
    + * (read-only), and `ssh -G` output parsing. No `import 'electron'` so it's
    + * unit-testable without Electron; main.ts wires the fs + `ssh -G` exec in.
    + */
    +
    +import fs from 'node:fs'
    +import os from 'node:os'
    +import path from 'node:path'
    +
    +function parseSshConfigHosts(text) {
    +  const hosts: string[] = []
    +  const seen = new Set()
    +
    +  for (const rawLine of String(text || '').split('\n')) {
    +    const line = rawLine.trim()
    +
    +    if (!line || line.startsWith('#')) {
    +      continue
    +    }
    +
    +    const m = /^host\s+(.+)$/i.exec(line)
    +
    +    if (!m) {
    +      continue
    +    }
    +
    +    for (const pattern of m[1].split(/\s+/)) {
    +      if (!pattern || pattern.includes('*') || pattern.includes('?') || pattern.startsWith('!')) {
    +        continue
    +      }
    +
    +      if (!seen.has(pattern)) {
    +        seen.add(pattern)
    +        hosts.push(pattern)
    +      }
    +    }
    +  }
    +
    +  return hosts
    +}
    +
    +function parseSshConfigIncludes(text) {
    +  const includes: string[] = []
    +
    +  for (const rawLine of String(text || '').split('\n')) {
    +    const line = rawLine.trim()
    +
    +    if (!line || line.startsWith('#')) {
    +      continue
    +    }
    +
    +    const m = /^include\s+(.+)$/i.exec(line)
    +
    +    if (!m) {
    +      continue
    +    }
    +
    +    for (const token of m[1].split(/\s+/)) {
    +      if (token) {
    +        includes.push(token)
    +      }
    +    }
    +  }
    +
    +  return includes
    +}
    +
    +function collectSshConfigHosts(rootPath = '', deps: any = {}) {
    +  const readFile =
    +    deps.readFile ||
    +    (p => {
    +      try {
    +        return fs.readFileSync(p, 'utf8')
    +      } catch {
    +        return null
    +      }
    +    })
    +
    +  const homeDir = deps.homeDir || os.homedir()
    +  const root = rootPath || path.join(homeDir, '.ssh', 'config')
    +  const sshDir = path.join(homeDir, '.ssh')
    +
    +  const out: string[] = []
    +  const seen = new Set()
    +  const visited = new Set()
    +
    +  const resolveIncludePath = token => {
    +    if (token.startsWith('~/')) {
    +      return path.join(homeDir, token.slice(2))
    +    }
    +
    +    if (path.isAbsolute(token)) {
    +      return token
    +    }
    +
    +    return path.join(sshDir, token)
    +  }
    +
    +  const walk = (filePath, depth) => {
    +    if (depth > 8 || visited.has(filePath)) {
    +      return
    +    }
    +
    +    visited.add(filePath)
    +    const text = readFile(filePath)
    +
    +    if (text == null) {
    +      return
    +    }
    +
    +    for (const host of parseSshConfigHosts(text)) {
    +      if (!seen.has(host)) {
    +        seen.add(host)
    +        out.push(host)
    +      }
    +    }
    +
    +    for (const token of parseSshConfigIncludes(text)) {
    +      const target = resolveIncludePath(token)
    +      const expanded = deps.globSync ? deps.globSync(target) : [target]
    +
    +      for (const p of expanded) {
    +        walk(p, depth + 1)
    +      }
    +    }
    +  }
    +
    +  walk(root, 0)
    +
    +  return out
    +}
    +
    +function parseSshGOutput(text) {
    +  const out: { hostname: string | null; user: string | null; port: number | null; identityFile: string | null } = {
    +    hostname: null,
    +    user: null,
    +    port: null,
    +    identityFile: null
    +  }
    +
    +  for (const rawLine of String(text || '').split('\n')) {
    +    const line = rawLine.trim()
    +
    +    if (!line) {
    +      continue
    +    }
    +
    +    const sp = line.indexOf(' ')
    +
    +    if (sp === -1) {
    +      continue
    +    }
    +
    +    const key = line.slice(0, sp).toLowerCase()
    +    const value = line.slice(sp + 1).trim()
    +
    +    if (key === 'hostname' && !out.hostname) {
    +      out.hostname = value
    +    } else if (key === 'user' && !out.user) {
    +      out.user = value
    +    } else if (key === 'port' && !out.port) {
    +      out.port = Number.parseInt(value, 10) || null
    +    } else if (key === 'identityfile' && !out.identityFile) {
    +      out.identityFile = value
    +    }
    +  }
    +
    +  return out
    +}
    +
    +export { collectSshConfigHosts, parseSshConfigHosts, parseSshConfigIncludes, parseSshGOutput }
    ```
  - `apps/desktop/electron/ssh-connection.test.ts`

    ```diff
    @@ -0,0 +1,866 @@
    +import assert from 'node:assert/strict'
    +import { EventEmitter } from 'node:events'
    +import fs from 'node:fs'
    +import os from 'node:os'
    +import path from 'node:path'
    +
    +import { test } from 'vitest'
    +
    +import {
    +  baseSshOptions,
    +  buildControlArgs,
    +  buildExecArgs,
    +  buildInteractiveSshArgs,
    +  buildMasterArgs,
    +  classifySshError,
    +  controlSocketPath,
    +  createSshProbeConnection,
    +  forwardSpec,
    +  hostArgs,
    +  redactSecrets,
    +  runSsh,
    +  SSH_ERROR,
    +  SshConnection,
    +  sshErrorMessage,
    +  stopTunnelChild,
    +  target,
    +  validateSshTarget
    +} from './ssh-connection'
    +
    +test('redactSecrets scrubs the spawn-time session token env var', () => {
    +  const line = 'setsid env HERMES_DASHBOARD_SESSION_TOKEN=[redacted:secret-assignment] HERMES_DESKTOP=1 hermes dashboard'
    +  const out = redactSecrets(line)
    +  assert.ok(!out.includes('abc123deadbeef'))
    +  assert.match(out, /HERMES_DASHBOARD_SESSION_TOKEN=[redacted:secret-assignment]
    +  // non-secret env vars are preserved
    +  assert.match(out, /HERMES_DESKTOP=1/)
    +})
    +
    +test('redactSecrets scrubs ?token= and ?ticket= URL params', () => {
    +  assert.match(redactSecrets('ws://127.0.0.1:5000/api/ws?token=supersecret'), /\?token=[redacted:secret-assignment]
    +  assert.match(redactSecrets('ws://127.0.0.1:5000/api/ws?ticket=onetimeticket'), /\?ticket=<redacted>/)
    +  assert.match(redactSecrets('GET /x?a=1&token=zzz HTTP'), /&token=[redacted:secret-assignment]
    +  assert.ok(!redactSecrets('?token=supersecret').includes('supersecret'))
    +})
    +
    +test('redactSecrets scrubs Authorization and X-Hermes-Session-Token headers', () => {
    +  assert.match(redactSecrets('Authorization: Bearer tok_9999'), /Authorization: Bearer <redacted>/)
    +  assert.ok(!redactSecrets('Authorization: Bearer tok_9999').includes('tok_9999'))
    +  assert.match(redactSecrets('X-Hermes-Session-Token: [redacted:secret-assignment]'), /X-Hermes-Session-Token: [redacted:secret-assignment]
    +  assert.ok(!redactSecrets('X-Hermes-Session-Token: [redacted:secret-assignment]').includes('hdr_888'))
    +})
    +
    +test('redactSecrets handles null/undefined and non-secret text untouched', () => {
    +  assert.equal(redactSecrets(null), '')
    +  assert.equal(redactSecrets(undefined), '')
    +  assert.equal(redactSecrets('uname -s -m'), 'uname -s -m')
    +})
    +
    +test('controlSocketPath is stable, short, and host-distinct', () => {
    +  const a = controlSocketPath('me', 'box1', 22, '/tmp/d')
    +  const a2 = controlSocketPath('me', 'box1', 22, '/tmp/d')
    +  const b = controlSocketPath('me', 'box2', 22, '/tmp/d')
    +  assert.equal(a, a2, 'same triple → same socket (ControlMaster reuse)')
    +  assert.notEqual(a, b, 'different host → different socket')
    +  // 16 hex chars + .sock keeps the basename short for sun_path 104-byte limit
    +  assert.match(a, /\/[0-9a-f]{16}\.sock$/)
    +})
    +
    +test('controlSocketPath default base stays under sun_path even with the temp-listener suffix', () => {
    +  // OpenSSH binds a temporary listener at `<ControlPath>.<16 random chars>` (a
    +  // 17-byte suffix) while opening the master. The macOS regression was the
    +  // default base under os.tmpdir() (/var/folders/.../T/) pushing it over 104.
    +  const p = controlSocketPath('hermes', 'remote-build-server', 22) // no baseDir → default
    +  const worstCase = `${p}.0123456789abcdef` // mimic the .<16-char> temp suffix
    +  assert.ok(
    +    worstCase.length <= 104,
    +    `default control socket + temp suffix must fit sun_path (got ${worstCase.length}: ${worstCase})`
    +  )
    +  // And it must NOT live under the deeply-nested macOS per-user temp dir.
    +  assert.ok(!p.includes('/var/folders/'), 'default base must not be os.tmpdir() on macOS')
    +})
    +
    +test('baseSshOptions carries the house ControlMaster/BatchMode/accept-new policy', () => {
    +  const opts = baseSshOptions('/tmp/x.sock', 15000)
    +  const joined = opts.join(' ')
    +  assert.match(joined, /ControlPath=\/tmp\/x\.sock/)
    +  assert.match(joined, /ControlMaster=auto/)
    +  assert.match(joined, /ControlPersist=\d+/)
    +  assert.match(joined, /BatchMode=yes/)
    +  assert.match(joined, /StrictHostKeyChecking=accept-new/)
    +  assert.match(joined, /ExitOnForwardFailure=yes/)
    +  assert.match(joined, /ConnectTimeout=15/)
    +  assert.ok(!joined.includes('StrictHostKeyChecking=no'), 'never disables host-key checking')
    +})
    +
    +test('hostArgs adds -p only for non-default port and -i only with a key', () => {
    +  assert.deepEqual(hostArgs({ port: 22 }), [])
    +  assert.deepEqual(hostArgs({ port: 2222 }), ['-p', '2222'])
    +  assert.deepEqual(hostArgs({ port: 22, keyPath: '/k' }), ['-i', '/k'])
    +  assert.deepEqual(hostArgs({ port: 2200, keyPath: '/k' }), ['-p', '2200', '-i', '/k'])
    +})
    +
    +test('target builds user@host or bare host', () => {
    +  assert.equal(target('me', 'box'), 'me@box')
    +  assert.equal(target('', 'box'), 'box')
    +})
    +
    +test('buildExecArgs ends with host then the remote command', () => {
    +  const conn = { user: 'me', host: 'box', port: 22, keyPath: '', controlPath: '/tmp/x.sock' }
    +  const args = buildExecArgs(conn, 'command -v hermes', 15000)
    +  assert.equal(args[args.length - 1], 'command -v hermes')
    +  assert.equal(args[args.length - 2], 'me@box')
    +  assert.ok(args.includes('BatchMode=yes'))
    +})
    +
    +test('buildControlArgs places -O <op> first and never appends a remote command', () => {
    +  const conn = { user: 'me', host: 'box', port: 2222, keyPath: '/k', controlPath: '/tmp/x.sock' }
    +  const args = buildControlArgs(conn, 'forward', ['-L', forwardSpec(5000, 6000)], 15000)
    +  assert.equal(args[0], '-O')
    +  assert.equal(args[1], 'forward')
    +  assert.ok(args.includes('-L'))
    +  assert.ok(args.includes('127.0.0.1:5000:127.0.0.1:6000'))
    +  assert.equal(args[args.length - 1], 'me@box')
    +})
    +
    +test('buildMasterArgs requests a backgrounded master (-M -N -f)', () => {
    +  const conn = { user: 'me', host: 'box', port: 22, keyPath: '', controlPath: '/tmp/x.sock' }
    +  const args = buildMasterArgs(conn, 15000)
    +  assert.ok(args.includes('-M'))
    +  assert.ok(args.includes('-N'))
    +  assert.ok(args.includes('-f'))
    +})
    +
    +test('forwardSpec binds the local end to 127.0.0.1 only', () => {
    +  assert.equal(forwardSpec(5000, 6000), '127.0.0.1:5000:127.0.0.1:6000')
    +  assert.ok(forwardSpec(5000, 6000).startsWith('127.0.0.1:'))
    +  assert.ok(!forwardSpec(5000, 6000).startsWith('0.0.0.0'))
    +})
    +
    +test('buildInteractiveSshArgs requests a PTY, reuses the control master, execs a login shell', () => {
    +  const conn = { user: 'me', host: 'box', port: 22, keyPath: '', controlPath: '/tmp/x.sock' }
    +  const args = buildInteractiveSshArgs(conn, '', 15000)
    +  assert.equal(args[0], '-tt', 'forces a PTY so the remote sees a real terminal')
    +  assert.ok(args.join(' ').includes('ControlPath=/tmp/x.sock'), 'reuses the existing master (no new auth)')
    +  assert.equal(args[args.length - 2], 'me@box')
    +  assert.equal(args[args.length - 1], 'exec "$SHELL" -l')
    +})
    +
    +test('buildInteractiveSshArgs cds into the remote cwd (best-effort) before the shell', () => {
    +  const conn = { user: 'me', host: 'box', port: 22, keyPath: '', controlPath: '/tmp/x.sock' }
    +  const args = buildInteractiveSshArgs(conn, '/home/me/project', 15000)
    +  const remoteCmd = args[args.length - 1]
    +  assert.match(remoteCmd, /^cd '\/home\/me\/project' 2>\/dev\/null; exec "\$SHELL" -l$/)
    +})
    +
    +test('buildInteractiveSshArgs single-quotes a cwd with quotes safely', () => {
    +  const conn = { user: 'me', host: 'box', port: 22, keyPath: '', controlPath: '/tmp/x.sock' }
    +  const args = buildInteractiveSshArgs(conn, "/tmp/a'b", 15000)
    +  // the embedded quote must be escaped, not break out of the quoting
    +  assert.ok(args[args.length - 1].startsWith("cd '/tmp/a'"))
    +  assert.ok(args[args.length - 1].includes('exec "$SHELL" -l'))
    +})
    +
    +test('classifySshError detects a changed host key (fail-closed)', () => {
    +  assert.equal(
    +    classifySshError('@@@@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @@@@'),
    +    SSH_ERROR.HOST_KEY_CHANGED
    +  )
    +  assert.equal(classifySshError('Host key verification failed.'), SSH_ERROR.HOST_KEY_CHANGED)
    +  assert.equal(classifySshError('Offending ECDSA key in /home/u/.ssh/known_hosts:5'), SSH_ERROR.HOST_KEY_CHANGED)
    +})
    +
    +test('classifySshError detects auth failure', () => {
    +  assert.equal(classifySshError('Permission denied (publickey).'), SSH_ERROR.AUTH_FAILED)
    +  assert.equal(classifySshError('Too many authentication failures'), SSH_ERROR.AUTH_FAILED)
    +})
    +
    +test('classifySshError detects unreachable', () => {
    +  assert.equal(classifySshError('ssh: Could not resolve hostname nope'), SSH_ERROR.UNREACHABLE)
    +  assert.equal(classifySshError('connect to host x port 22: Connection refused'), SSH_ERROR.UNREACHABLE)
    +})
    +
    +test('sshErrorMessage gives actionable guidance for auth and host-key-change', () => {
    +  const conn = { user: 'me', host: 'box', port: 22 }
    +  assert.match(sshErrorMessage(SSH_ERROR.AUTH_FAILED, conn, 'Permission denied'), /ssh-agent|ssh-add|IdentityFile/)
    +  assert.match(sshErrorMessage(SSH_ERROR.HOST_KEY_CHANGED, conn, 'CHANGED'), /ssh-keygen -R box/)
    +})
    +
    +// A fake child process that emits a scripted result on next tick.
    +function fakeChild({ code = 0, stdout = '', stderr = '', errorEvent = null, hang = false }: any = {}) {
    +  const child: any = new EventEmitter()
    +  child.stdout = new EventEmitter()
    +  child.stderr = new EventEmitter()
    +
    +  child.kill = () => {
    +    child._killed = true
    +  }
    +
    +  if (hang) {
    +    return child // never emits close → drives the timeout path
    +  }
    +
    +  process.nextTick(() => {
    +    if (errorEvent) {
    +      child.emit('error', errorEvent)
    +
    +      return
    +    }
    +
    +    if (stdout) {
    +      child.stdout.emit('data', Buffer.from(stdout))
    +    }
    +
    +    if (stderr) {
    +      child.stderr.emit('data', Buffer.from(stderr))
    +    }
    +
    +    child.emit('close', code)
    +  })
    +
    +  return child
    +}
    +
    +// Build a spawnFn that returns scripted children per ssh invocation, recording
    +// the args it was called with.
    +function scriptedSpawn(scripts) {
    +  const calls: any[] = []
    +  let i = 0
    +
    +  const fn: any = (_cmd, args) => {
    +    calls.push(args)
    +    const script = typeof scripts === 'function' ? scripts(args, i) : scripts[Math.min(i, scripts.length - 1)]
    +    i += 1
    +
    +    return fakeChild(script || {})
    +  }
    +
    +  fn.calls = calls
    +
    +  return fn
    +}
    +
    +test('open() establishes the master when not already alive', async () => {
    +  // `-O check` fails first (not alive) → master opens (code 0). Track which
    +  // ssh ops ran rather than re-probing with the same always-failing check.
    +  const ops: string[] = []
    +
    +  const spawnFn = scriptedSpawn(args => {
    +    ops.push(args.includes('check') ? 'check' : args.includes('-M') ? 'master' : 'other')
    +
    +    if (args.includes('check')) {
    +      return { code: 255, stderr: 'no control path' }
    +    }
    +
    +    return { code: 0 }
    +  })
    +
    +  const conn = new SshConnection({ host: 'box', user: 'me' }, { spawnFn, controlDir: '/tmp/d' })
    +  await conn.open()
    +  assert.deepEqual(ops, ['check', 'master'], 'probes liveness first, then opens the master')
    +})
    +
    +test('open() is a no-op when the master is already alive and execs verify', async () => {
    +  const ops: string[] = []
    +
    +  const spawnFn = scriptedSpawn(args => {
    +    ops.push(args.includes('check') ? 'check' : args.includes('exit 0') ? 'verify' : 'master')
    +
    +    return { code: 0 } // check succeeds → alive; verify exec succeeds → trusted
    +  })
    +
    +  const conn = new SshConnection({ host: 'box', user: 'me' }, { spawnFn, controlDir: '/tmp/d' })
    +  await conn.open()
    +  assert.deepEqual(ops, ['check', 'verify'], 'alive master is exec-verified, then trusted without reopening')
    +})
    +
    +test('open() evicts a wedged master (check passes, exec hangs) and dials fresh', async () => {
    +  // The macOS mode-switch wedge: ControlPersist master answers -O check but
    +  // every exec through it hangs. open() must verify, evict (-O exit), and
    +  // establish a fresh master instead of trusting the corpse.
    +  const ops: string[] = []
    +
    +  const spawnFn = scriptedSpawn(args => {
    +    if (args.includes('check')) {
    +      ops.push('check')
    +
    +      return { code: 0 }
    +    }
    +
    +    if (args.includes('exit 0')) {
    +      ops.push('verify')
    +
    +      return { hang: true }
    +    }
    +
    +    if (args.includes('-O')) {
    +      ops.push('evict')
    +
    +      return { code: 0 }
    +    }
    +
    +    ops.push('master')
    +
    +    return { code: 0 }
    +  })
    +
    +  const conn = new SshConnection({ host: 'box', user: 'me' }, { spawnFn, controlDir: '/tmp/d', connectTimeoutMs: 50 })
    +
    +  await conn.open()
    +  assert.deepEqual(
    +    ops,
    +    ['check', 'verify', 'evict', 'master'],
    +    'wedged master: verified, evicted, then a fresh master is dialed'
    +  )
    +})
    +
    +test('close() removes the control socket when -O exit fails', async () => {
    +  const dir = path.join(os.tmpdir(), `hermes-ssh-close-${process.pid}-${Date.now()}`)
    +  fs.mkdirSync(dir, { recursive: true, mode: 0o700 })
    +
    +  const spawnFn = scriptedSpawn(args => {
    +    if (args.includes('check')) {
    +      return { code: 255 }
    +    } // not alive → open dials master
    +
    +    if (args.includes('-M')) {
    +      return { code: 0 }
    +    }
    +
    +    return { code: 255, stderr: 'mux: master gone' } // -O exit fails
    +  })
    +
    +  const conn = new SshConnection({ host: 'box', user: 'me' }, { spawnFn, controlDir: dir })
    +  await conn.open()
    +  fs.writeFileSync(conn.controlPath, '') // simulate the lingering socket file
    +  await conn.close()
    +  assert.ok(!fs.existsSync(conn.controlPath), 'failed -O exit drops the socket so the next open dials fresh')
    +  fs.rmSync(dir, { recursive: true, force: true })
    +})
    +
    +test('open() creates the control-socket directory if it does not exist', async () => {
    +  const dir = path.join(os.tmpdir(), `hermes-ssh-test-${process.pid}-${Date.now()}`)
    +  assert.ok(!fs.existsSync(dir), 'precondition: control dir absent')
    +  const spawnFn = scriptedSpawn(args => (args.includes('check') ? { code: 255 } : { code: 0 }))
    +  const conn = new SshConnection({ host: 'box', user: 'me' }, { spawnFn, controlDir: dir })
    +
    +  try {
    +    await conn.open()
    +    assert.ok(fs.existsSync(dir), 'open() created the control-socket directory before spawning ssh')
    +  } finally {
    +    try {
    +      fs.rmSync(dir, { recursive: true, force: true })
    +    } catch {
    +      /* ignore */
    +    }
    +  }
    +})
    +
    +test('open() surfaces a classified auth error', async () => {
    +  const spawnFn = scriptedSpawn(args => {
    +    if (args.includes('check')) {
    +      return { code: 255 }
    +    }
    +
    +    return { code: 255, stderr: 'Permission denied (publickey).' }
    +  })
    +
    +  const conn = new SshConnection({ host: 'box', user: 'me' }, { spawnFn, controlDir: '/tmp/d' })
    +  await assert.rejects(
    +    () => conn.open(),
    +    (err: any) => {
    +      assert.equal(err.kind, SSH_ERROR.AUTH_FAILED)
    +      assert.match(err.message, /ssh-agent|ssh-add/)
    +
    +      return true
    +    }
    +  )
    +})
    +
    +test('exec() returns stdout on success and rejects (classified) on failure', async () => {
    +  const okSpawn = scriptedSpawn([{ code: 0, stdout: 'Linux\n' }])
    +  const conn = new SshConnection({ host: 'box', user: 'me' }, { spawnFn: okSpawn, controlDir: '/tmp/d' })
    +  assert.equal((await conn.exec('uname -s')).trim(), 'Linux')
    +
    +  const failSpawn = scriptedSpawn([{ code: 1, stderr: 'ssh: Could not resolve hostname box' }])
    +  const conn2 = new SshConnection({ host: 'box', user: 'me' }, { spawnFn: failSpawn, controlDir: '/tmp/d' })
    +  await assert.rejects(
    +    () => conn2.exec('uname -s'),
    +    (err: any) => {
    +      assert.equal(err.kind, SSH_ERROR.UNREACHABLE)
    +
    +      return true
    +    }
    +  )
    +})
    +
    +test('exec() treats a hung ssh as a timeout (half-open connection)', async () => {
    +  const spawnFn = scriptedSpawn([{ hang: true }])
    +  const conn = new SshConnection({ host: 'box', user: 'me' }, { spawnFn, controlDir: '/tmp/d' })
    +  await assert.rejects(
    +    () => conn.exec('uname -s', { timeoutMs: 30 }),
    +    (err: any) => {
    +      assert.equal(err.kind, SSH_ERROR.TIMEOUT)
    +
    +      return true
    +    }
    +  )
    +})
    +
    +test('forward() issues -O forward with a loopback-bound -L spec', async () => {
    +  const spawnFn = scriptedSpawn([{ code: 0 }])
    +  const conn = new SshConnection({ host: 'box', user: 'me' }, { spawnFn, controlDir: '/tmp/d' })
    +  await conn.forward(5000, 6000)
    +  const args = spawnFn.calls[0]
    +  assert.equal(args[0], '-O')
    +  assert.equal(args[1], 'forward')
    +  assert.ok(args.includes('127.0.0.1:5000:127.0.0.1:6000'))
    +})
    +
    +test('lifecycle logging passes through redaction', async () => {
    +  const logs: string[] = []
    +  const spawnFn = scriptedSpawn(args => (args.includes('check') ? { code: 255 } : { code: 0 }))
    +
    +  const conn = new SshConnection(
    +    { host: 'box', user: 'me' },
    +    { spawnFn, controlDir: '/tmp/d', rememberLog: l => logs.push(l) }
    +  )
    +
    +  await conn.open()
    +
    +  // none of the emitted log lines may carry a raw token-shaped secret
    +  for (const line of logs) {
    +    assert.ok(!/token=[redacted:secret-assignment]
    +  }
    +
    +  assert.ok(logs.some(l => l.includes('[ssh]')))
    +})
    +
    +test('no-mux: ssh args carry no ControlMaster/ControlPath options', async () => {
    +  const spawnFn = scriptedSpawn({ code: 0 })
    +  const conn = new SshConnection({ host: 'box', user: 'me' }, { spawnFn, mux: false })
    +  await conn.open()
    +
    +  for (const args of spawnFn.calls) {
    +    assert.ok(!args.some(a => /ControlMaster|ControlPath|ControlPersist/.test(a)), `mux option leaked: ${args}`)
    +  }
    +})
    +
    +test('no-mux: open() verifies auth with a one-shot exec, no -M master', async () => {
    +  const spawnFn = scriptedSpawn({ code: 0 })
    +  const conn = new SshConnection({ host: 'box', user: 'me' }, { spawnFn, mux: false })
    +  await conn.open()
    +  assert.ok(!spawnFn.calls.some(args => args.includes('-M')), 'no master should be spawned')
    +  assert.ok(
    +    spawnFn.calls.some(args => args[args.length - 1] === 'exit 0'),
    +    'liveness/openness via one-shot exec'
    +  )
    +})
    +
    +test('SSH probe never creates or closes a ControlMaster', async () => {
    +  const spawnFn = scriptedSpawn({ code: 0 })
    +  const conn = createSshProbeConnection({ host: 'box', user: 'me' }, { spawnFn })
    +  await conn.open()
    +  await conn.close()
    +  const args = spawnFn.calls.flat()
    +  assert.ok(!args.includes('-M'))
    +  assert.ok(!args.includes('-O'))
    +  assert.ok(!args.some(value => /Control(?:Master|Path|Persist)/.test(value)))
    +})
    +
    +test('no-mux: open() classifies auth failure', async () => {
    +  const spawnFn = scriptedSpawn([{ code: 255, stderr: 'me@box: Permission denied (publickey).' }])
    +  const conn = new SshConnection({ host: 'box', user: 'me' }, { spawnFn, mux: false })
    +  await assert.rejects(conn.open(), (err: any) => err.kind === 'auth-failed')
    +})
    +
    +test('no-mux: forward spawns a persistent -N -L child; cancel + close kill it', async () => {
    +  // Real listener stands in for the tunnel's local end so waitForLocalPort sees it.
    +  const net = await import('node:net')
    +  const srv = net.createServer()
    +  await new Promise<void>(r => srv.listen(0, '127.0.0.1', () => r()))
    +  const localPort = (srv.address() as any).port
    +  const tunnels: any[] = []
    +
    +  const spawnFn: any = (_cmd, args) => {
    +    const child: any = new EventEmitter()
    +    child.stderr = new EventEmitter()
    +    child.exitCode = null
    +
    +    child.kill = () => {
    +      child._killed = true
    +      child.exitCode = 0
    +      process.nextTick(() => child.emit('exit', 0))
    +
    +      return true
    +    }
    +
    +    if (args.includes('-N')) {
    +      tunnels.push({ args, child })
    +      process.nextTick(() =>
    +        child.stderr.emit('data', Buffer.from(`Local forwarding listening on 127.0.0.1 port ${localPort}.`))
    +      )
    +    } else {
    +      process.nextTick(() => child.emit('close', 0))
    +    }
    +
    +    if (!args.includes('-N')) {
    +      child.stdout = new EventEmitter()
    +      process.nextTick(() => child.emit('close', 0))
    +    }
    +
    +    return child
    +  }
    +
    +  const conn = new SshConnection({ host: 'box', user: 'me' }, { spawnFn, mux: false })
    +  await conn.forward(localPort, 9119)
    +  assert.equal(tunnels.length, 1, 'one persistent tunnel child')
    +  assert.ok(tunnels[0].args.includes('-L'), 'tunnel child carries -L spec')
    +  assert.ok(!tunnels[0].args.some(a => /ControlPath/.test(a)))
    +
    +  await conn.cancelForward(localPort, 9119)
    +  assert.ok(tunnels[0].child._killed, 'cancelForward kills the tunnel child')
    +
    +  conn._opened = true
    +  await conn.close() // no-mux close never runs ssh -O exit; must not throw
    +  srv.close()
    +})
    +
    +test('no-mux: forward fails fast when the tunnel child dies (bad spec/auth)', async () => {
    +  const spawnFn: any = (_cmd, args) => {
    +    const child: any = new EventEmitter()
    +    child.stderr = new EventEmitter()
    +    child.exitCode = null
    +
    +    child.kill = () => {}
    +
    +    if (args.includes('-N')) {
    +      process.nextTick(() => {
    +        child.stderr.emit('data', Buffer.from('Permission denied (publickey).'))
    +        child.exitCode = 255
    +      })
    +    }
    +
    +    return child
    +  }
    +
    +  const conn = new SshConnection({ host: 'box', user: 'me' }, { spawnFn, mux: false, forwardTimeoutMs: 2000 })
    +  await assert.rejects(conn.forward(1, 9119), (err: any) => err.kind === 'auth-failed')
    +})
    +
    +test('no-mux: an unrelated listener cannot mask a delayed bind failure', async () => {
    +  const net = await import('node:net')
    +  const srv = net.createServer()
    +  await new Promise<void>(resolve => srv.listen(0, '127.0.0.1', resolve))
    +  const localPort = (srv.address() as any).port
    +
    +  const spawnFn: any = (_cmd, args) => {
    +    const child: any = new EventEmitter()
    +    child.stderr = new EventEmitter()
    +    child.exitCode = null
    +
    +    child.kill = () => {}
    +
    +    if (args.includes('-N')) {
    +      setTimeout(() => {
    +        child.stderr.emit('data', Buffer.from(`bind [127.0.0.1]:${localPort}: Address already in use`))
    +        child.exitCode = 255
    +        child.emit('exit', 255)
    +      }, 20)
    +    }
    +
    +    return child
    +  }
    +
    +  const conn = new SshConnection({ host: 'box' }, { spawnFn, mux: false, forwardTimeoutMs: 1000 })
    +  await assert.rejects(conn.forward(localPort, 9119), /address already in use/i)
    +  srv.close()
    +})
    +
    +test('no-mux: tunnel death after readiness makes the connection unhealthy', async () => {
    +  const net = await import('node:net')
    +  const srv = net.createServer()
    +  await new Promise<void>(resolve => srv.listen(0, '127.0.0.1', resolve))
    +  const localPort = (srv.address() as any).port
    +  let tunnel
    +
    +  const spawnFn: any = (_cmd, args) => {
    +    const child: any = new EventEmitter()
    +    child.stdout = new EventEmitter()
    +    child.stderr = new EventEmitter()
    +    child.exitCode = null
    +
    +    child.kill = () => {}
    +
    +    if (args.includes('-N')) {
    +      tunnel = child
    +      process.nextTick(() =>
    +        child.stderr.emit('data', Buffer.from(`Local forwarding listening on 127.0.0.1 port ${localPort}.`))
    +      )
    +    } else {
    +      process.nextTick(() => child.emit('close', 0))
    +    }
    +
    +    return child
    +  }
    +
    +  const conn = new SshConnection({ host: 'box' }, { spawnFn, mux: false })
    +  await conn.open()
    +  await conn.forward(localPort, 9119)
    +  tunnel.emit('exit', 255)
    +  assert.equal(await conn.isAlive(), false)
    +  srv.close()
    +})
    +
    +test('validateSshTarget rejects a host starting with a dash (option injection)', () => {
    +  assert.throws(() => validateSshTarget('-oProxyCommand=evil', '', 22), /unsafe/i)
    +  assert.throws(() => validateSshTarget('--version', '', 22), /unsafe/i)
    +})
    +
    +test('validateSshTarget rejects control characters in host', () => {
    +  assert.throws(() => validateSshTarget('host\x00evil', '', 22), /unsafe/i)
    +  assert.throws(() => validateSshTarget('host\nnewline', '', 22), /unsafe/i)
    +  assert.throws(() => validateSshTarget('host\ttab', '', 22), /unsafe/i)
    +})
    +
    +test('validateSshTarget rejects control characters in user', () => {
    +  assert.throws(() => validateSshTarget('box', 'me\x00root', 22), /unsafe/i)
    +  assert.throws(() => validateSshTarget('box', '-oForward=yes', 22), /unsafe/i)
    +})
    +
    +test('validateSshTarget rejects ports outside 1-65535', () => {
    +  assert.throws(() => validateSshTarget('box', '', 0), /port/i)
    +  assert.throws(() => validateSshTarget('box', '', 65536), /port/i)
    +  assert.throws(() => validateSshTarget('box', '', -1), /port/i)
    +  assert.throws(() => validateSshTarget('box', '', NaN), /port/i)
    +})
    +
    +test('validateSshTarget accepts valid targets', () => {
    +  assert.doesNotThrow(() => validateSshTarget('my-host.example.com', 'alice', 22))
    +  assert.doesNotThrow(() => validateSshTarget('192.168.1.1', '', 2222))
    +  assert.doesNotThrow(() => validateSshTarget('::1', 'root', 22))
    +})
    +
    +test('SshConnection constructor rejects hostile host/user/port', () => {
    +  assert.throws(() => new SshConnection({ host: '-oProxyCommand=evil' }), /unsafe/i)
    +  assert.throws(() => new SshConnection({ host: 'box', user: '-oForward' }), /unsafe/i)
    +  assert.throws(() => new SshConnection({ host: 'box', port: 99999 }), /port/i)
    +})
    +
    +test('buildExecArgs inserts -- before the destination', () => {
    +  const conn = { user: 'me', host: 'box', port: 22, keyPath: '', controlPath: '/tmp/x.sock' }
    +  const args = buildExecArgs(conn, 'uname -s', 15000)
    +  const ddIdx = args.indexOf('--')
    +  assert.ok(ddIdx >= 0, 'must contain --')
    +  assert.equal(args[ddIdx + 1], 'me@box', '-- immediately precedes the destination')
    +  assert.equal(args[ddIdx + 2], 'uname -s', 'remote command follows destination')
    +})
    +
    +test('buildMasterArgs inserts -- before the destination', () => {
    +  const conn = { user: 'me', host: 'box', port: 22, keyPath: '', controlPath: '/tmp/x.sock' }
    +  const args = buildMasterArgs(conn, 15000)
    +  const ddIdx = args.indexOf('--')
    +  assert.ok(ddIdx >= 0, 'must contain --')
    +  assert.equal(args[ddIdx + 1], 'me@box')
    +})
    +
    +test('buildControlArgs inserts -- before the destination', () => {
    +  const conn = { user: 'me', host: 'box', port: 22, keyPath: '', controlPath: '/tmp/x.sock' }
    +  const args = buildControlArgs(conn, 'check', [], 15000)
    +  const ddIdx = args.indexOf('--')
    +  assert.ok(ddIdx >= 0, 'must contain --')
    +  assert.equal(args[ddIdx + 1], 'me@box')
    +})
    +
    +test('buildInteractiveSshArgs inserts -- before the destination', () => {
    +  const conn = { user: 'me', host: 'box', port: 22, keyPath: '', controlPath: '/tmp/x.sock' }
    +  const args = buildInteractiveSshArgs(conn, '', 15000)
    +  const ddIdx = args.indexOf('--')
    +  assert.ok(ddIdx >= 0, 'must contain --')
    +  assert.equal(args[ddIdx + 1], 'me@box')
    +})
    +
    +test('hostArgs rejects a keyPath with control characters', () => {
    +  assert.throws(() => hostArgs({ keyPath: '/tmp/key\x00inject' }), /unsafe/i)
    +})
    +
    +test('hostArgs rejects a keyPath starting with a dash', () => {
    +  assert.throws(() => hostArgs({ keyPath: '-oProxyCommand=evil' }), /unsafe/i)
    +})
    +
    +test('hostArgs accepts valid key paths', () => {
    +  assert.deepEqual(hostArgs({ keyPath: '/home/user/.ssh/id_ed25519' }), ['-i', '/home/user/.ssh/id_ed25519'])
    +  assert.deepEqual(hostArgs({ keyPath: '~/.ssh/id_rsa' }), ['-i', '~/.ssh/id_rsa'])
    +})
    +
    +test('runSsh delivers stdinData to the child and does not log it', async () => {
    +  let stdinWritten = ''
    +
    +  const spawnFn: any = (_cmd, _args, opts) => {
    +    const child: any = new EventEmitter()
    +    child.stdout = new EventEmitter()
    +    child.stderr = new EventEmitter()
    +
    +    child.kill = () => {}
    +    child.stdin = {
    +      end(data) {
    +        stdinWritten = String(data)
    +      }
    +    }
    +    assert.equal(opts.stdio[0], 'pipe', 'stdin must be pipe when stdinData is provided')
    +    process.nextTick(() => child.emit('close', 0))
    +
    +    return child
    +  }
    +
    +  await runSsh(['host', 'cat'], { timeoutMs: 5000, spawnFn, stdinData: 'secret-token-value' })
    +  assert.equal(stdinWritten, 'secret-token-value', 'stdinData must be written to child.stdin')
    +})
    +
    +test('open() rejects a control-dir that is a symlink', async () => {
    +  const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'ssh-test-'))
    +  const real = path.join(tmp, 'real')
    +  const link = path.join(tmp, 'link')
    +  fs.mkdirSync(real, { mode: 0o700 })
    +  fs.symlinkSync(real, link)
    +  const spawnFn = scriptedSpawn(args => (args.includes('check') ? { code: 255 } : { code: 0 }))
    +  const conn = new SshConnection({ host: 'box', user: 'me' }, { spawnFn, controlDir: link })
    +  await assert.rejects(conn.open(), /symlink|unsafe/i)
    +  fs.rmSync(tmp, { recursive: true, force: true })
    +})
    +
    +test('open() enforces 0700 on an existing control dir with lax permissions', async () => {
    +  if (process.platform === 'win32') {
    +    return
    +  }
    +
    +  const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'ssh-test-'))
    +  const dir = path.join(tmp, 'ctrl')
    +  fs.mkdirSync(dir, { mode: 0o755 })
    +  const spawnFn = scriptedSpawn(args => (args.includes('check') ? { code: 255 } : { code: 0 }))
    +  const conn = new SshConnection({ host: 'box', user: 'me' }, { spawnFn, controlDir: dir })
    +  await conn.open()
    +  const stat = fs.statSync(dir)
    +  assert.equal(stat.mode & 0o777, 0o700, 'control dir must be tightened to 0700')
    +  fs.rmSync(tmp, { recursive: true, force: true })
    +})
    +
    +test('control socket identity separates installation scope and key identity', () => {
    +  const base = controlSocketPath('me', 'box', 22, '/tmp/d', {
    +    ownershipId: 'installation-a',
    +    scope: 'primary',
    +    keyPath: '/keys/id'
    +  })
    +
    +  assert.equal(
    +    base,
    +    controlSocketPath('me', 'box', 22, '/tmp/d', {
    +      ownershipId: 'installation-a',
    +      scope: 'primary',
    +      keyPath: '/keys/./id'
    +    })
    +  )
    +  assert.notEqual(
    +    base,
    +    controlSocketPath('me', 'box', 22, '/tmp/d', {
    +      ownershipId: 'installation-a',
    +      scope: 'worker',
    +      keyPath: '/keys/id'
    +    })
    +  )
    +  assert.notEqual(
    +    base,
    +    controlSocketPath('me', 'box', 22, '/tmp/d', {
    +      ownershipId: 'installation-b',
    +      scope: 'primary',
    +      keyPath: '/keys/id'
    +    })
    +  )
    +  assert.notEqual(
    +    base,
    +    controlSocketPath('me', 'box', 22, '/tmp/d', {
    +      ownershipId: 'installation-a',
    +      scope: 'primary',
    +      keyPath: '/keys/other'
    +    })
    +  )
    +  assert.notEqual(
    +    base,
    +    controlSocketPath('me', 'box', 22, '/tmp/d', {
    +      ownershipId: 'installation-a',
    +      scope: 'primary',
    +      keyPath: '/keys/id',
    +      effectiveConfigFingerprint: 'changed-config'
    +    })
    +  )
    +})
    +
    +test('closing one scope addresses only that scope control master', async () => {
    +  const firstSpawn = scriptedSpawn({ code: 0 })
    +  const secondSpawn = scriptedSpawn({ code: 0 })
    +
    +  const first = new SshConnection(
    +    { host: 'box', user: 'me' },
    +    {
    +      spawnFn: firstSpawn,
    +      controlDir: '/tmp/d',
    +      ownershipId: 'installation',
    +      scope: 'first'
    +    }
    +  )
    +
    +  const second = new SshConnection(
    +    { host: 'box', user: 'me' },
    +    {
    +      spawnFn: secondSpawn,
    +      controlDir: '/tmp/d',
    +      ownershipId: 'installation',
    +      scope: 'second'
    +    }
    +  )
    +
    +  first._opened = true
    +  second._opened = true
    +  await first.close()
    +  assert.notEqual(first.controlPath, second.controlPath)
    +  assert.ok(firstSpawn.calls[0].includes(`ControlPath=${first.controlPath}`))
    +  assert.ok(!firstSpawn.calls[0].includes(`ControlPath=${second.controlPath}`))
    +  assert.equal(second._opened, true)
    +})
    +
    +test('failed ControlMaster close disowns the master instead of retrying it', async () => {
    +  // Old contract kept _opened=true for a retry — which left wedged ControlPersist
    +  // masters trusted and reattachable (the macOS mode-switch livelock). New
    +  // contract: a master that refuses -O exit is disowned — socket dropped,
    +  // connection marked closed — so the next open dials fresh.
    +  const spawnFn = scriptedSpawn([{ code: 255, stderr: 'master refused exit' }])
    +  const conn = new SshConnection({ host: 'box', user: 'me' }, { spawnFn, controlDir: '/tmp/d' })
    +  conn._opened = true
    +  await conn.close()
    +  assert.equal(conn._opened, false)
    +  assert.equal(spawnFn.calls.length, 1)
    +})
    +
    +test('stopTunnelChild waits for process exit', async () => {
    +  const child: any = new EventEmitter()
    +  child.exitCode = null
    +
    +  child.kill = () => {
    +    process.nextTick(() => {
    +      child.exitCode = 0
    +      child.emit('exit', 0)
    +    })
    +
    +    return true
    +  }
    +
    +  let stopped = false
    +
    +  const stopping = stopTunnelChild(child).then(() => {
    +    stopped = true
    +  })
    +
    +  assert.equal(stopped, false)
    +  await stopping
    +  assert.equal(stopped, true)
    +})
    ```
  - `apps/desktop/electron/ssh-connection.ts`

    ```diff
    @@ -0,0 +1,921 @@
    +/**
    + * ssh-connection.ts
    + *
    + * Pure, electron-free OpenSSH ControlMaster connection manager for Desktop SSH
    + * remote mode. Uses the system `ssh` client (not a JS SSH library) so it
    + * inherits ~/.ssh/config, the agent, jump hosts (ProxyJump), and hardware keys
    + * for free — the same rationale as tools/environments/ssh.py.
    + *
    + * No `import 'electron'` so it is unit-testable without Electron. main.ts
    + * wires it into the electron-coupled lifecycle.
    + *
    + * Conventions mirrored from tools/environments/ssh.py:
    + *   - ControlMaster=auto + ControlPersist so one TCP/auth handshake is reused
    + *     across exec/forward operations.
    + *   - Hashed control-socket filename under a short tmpdir to stay under the
    + *     104-byte sun_path limit macOS enforces on Unix domain sockets.
    + *   - BatchMode=yes for every programmatic invocation — a spawned ssh must
    + *     never hang on an interactive prompt (passphrase / 2FA). If auth needs
    + *     interactivity we fail fast and tell the user to load the key into their
    + *     agent.
    + *
    + * Host-key policy: StrictHostKeyChecking=accept-new (trust-on-first-use, log
    + * the fingerprint), never `no`. A host-key *change* fails closed with the
    + * verbatim OpenSSH error surfaced to the UI.
    + *
    + * Every operation is raced against a hard timeout. A half-open TCP connection
    + * after laptop sleep can leave ssh hanging indefinitely rather than erroring;
    + * timeout is treated as connection-dead so the caller does a full reconnect
    + * rather than retrying in place.
    + */
    +
    +import { spawn } from 'node:child_process'
    +import crypto from 'node:crypto'
    +import fs from 'node:fs'
    +import net from 'node:net'
    +import os from 'node:os'
    +import path from 'node:path'
    +
    +const DEFAULT_CONNECT_TIMEOUT_MS = 15_000
    +const DEFAULT_EXEC_TIMEOUT_MS = 20_000
    +const DEFAULT_FORWARD_TIMEOUT_MS = 15_000
    +const CONTROL_PERSIST_SECONDS = 300
    +
    +// eslint-disable-next-line no-control-regex -- deliberately reject control chars in ssh targets
    +const _CONTROL_CHAR_RE = /[\x00-\x1f\x7f]/
    +
    +function validateSshTarget(host, user, port) {
    +  if (!host || typeof host !== 'string') {
    +    throw new Error('Unsafe SSH target: host is required.')
    +  }
    +
    +  if (host.startsWith('-')) {
    +    throw new Error(`Unsafe SSH target: host must not start with a dash ("${host}").`)
    +  }
    +
    +  if (_CONTROL_CHAR_RE.test(host)) {
    +    throw new Error('Unsafe SSH target: host contains control characters.')
    +  }
    +
    +  if (user && _CONTROL_CHAR_RE.test(user)) {
    +    throw new Error('Unsafe SSH target: user contains control characters.')
    +  }
    +
    +  if (user && user.startsWith('-')) {
    +    throw new Error(`Unsafe SSH target: user must not start with a dash ("${user}").`)
    +  }
    +
    +  const p = Number(port)
    +
    +  if (!Number.isInteger(p) || p < 1 || p > 65535) {
    +    throw new Error(`Unsafe SSH port: ${port} (must be 1-65535).`)
    +  }
    +}
    +
    +function validateKeyPath(keyPath) {
    +  if (!keyPath) {
    +    return
    +  }
    +
    +  if (_CONTROL_CHAR_RE.test(keyPath)) {
    +    throw new Error('Unsafe SSH key path: contains control characters.')
    +  }
    +
    +  if (keyPath.startsWith('-')) {
    +    throw new Error(`Unsafe SSH key path: must not start with a dash ("${keyPath}").`)
    +  }
    +}
    +
    +// Token / secret redaction
    +
    +const _REDACTIONS: Array<[RegExp, string]> = [
    +  [/(HERMES_DASHBOARD_SESSION_TOKEN=[redacted:secret-assignment] '$1<redacted>'],
    +  [/(X-Hermes-Session-Token["']?\s*[:=]\s*["']?)([^\s"'&]+)/gi, '$1<redacted>'],
    +  [/(Authorization["']?\s*:\s*Bearer\s+)(\S+)/gi, '$1<redacted>'],
    +  [/([?&](?:token|ticket)=)([^\s&"']+)/gi, '$1<redacted>']
    +]
    +
    +function redactSecrets(text) {
    +  let out = String(text == null ? '' : text)
    +
    +  for (const [re, repl] of _REDACTIONS) {
    +    out = out.replace(re, repl)
    +  }
    +
    +  return out
    +}
    +
    +// Control-socket path
    +
    +// Hash user@host:port to a short, stable, filesystem-safe socket id — stable
    +// across reconnects so ControlMaster reuse works, short so the full path stays
    +// under sun_path's 104-byte limit.
    +//
    +// CRITICAL (macOS): the base dir must be SHORT. os.tmpdir() on macOS is the
    +// per-user `/var/folders/xx/yyyy…/T/` (~49 bytes), and OpenSSH binds a
    +// TEMPORARY listener at `<ControlPath>.<16 random chars>` while establishing
    +// the master — so a path that itself fits 104 still overflows at bind time. We
    +// root under a short per-user base (`~/.hermes/desktop-ssh`) so even worst case
    +// (~72 bytes on macOS) stays clear. Windows has no AF_UNIX sun_path limit.
    +function controlSocketPath(user, host, port, baseDir?, identity: any = {}) {
    +  const dir = baseDir || defaultControlDir()
    +  const keyPathIdentity = path.normalize(String(identity.keyPath || ''))
    +
    +  const parts = [
    +    identity.ownershipId || '',
    +    identity.scope || '',
    +    user || '',
    +    host,
    +    Number(port),
    +    keyPathIdentity,
    +    identity.effectiveConfigFingerprint || ''
    +  ]
    +
    +  const id = crypto.createHash('sha256').update(JSON.stringify(parts)).digest('hex').slice(0, 16)
    +
    +  return path.join(dir, `${id}.sock`)
    +}
    +
    +function defaultControlDir() {
    +  // POSIX: a SHORT, PER-USER base stays under the socket limit AND avoids a
    +  // world-shared /tmp dir (no symlink-hijack surface). Created 0700 in open().
    +  if (process.platform === 'win32') {
    +    return path.join(os.tmpdir(), 'hermes-desktop-ssh')
    +  }
    +
    +  return path.join(os.homedir(), '.hermes', 'desktop-ssh')
    +}
    +
    +// Command construction (pure — the unit tests exercise these directly)
    +
    +// Mux (POSIX): ControlMaster options so exec/forward share one authenticated
    +// connection. No-mux (Windows OpenSSH never implemented mux sockets): plain
    +// per-invocation options — each ssh call authenticates on its own.
    +function baseSshOptions(controlPath, connectTimeoutMs?) {
    +  const connectSecs = Math.max(1, Math.round((connectTimeoutMs ?? DEFAULT_CONNECT_TIMEOUT_MS) / 1000))
    +
    +  const mux = controlPath
    +    ? [
    +        '-o',
    +        `ControlPath=${controlPath}`,
    +        '-o',
    +        'ControlMaster=auto',
    +        '-o',
    +        `ControlPersist=${CONTROL_PERSIST_SECONDS}`
    +      ]
    +    : []
    +
    +  return [
    +    ...mux,
    +    '-o',
    +    'BatchMode=yes',
    +    '-o',
    +    'StrictHostKeyChecking=accept-new',
    +    '-o',
    +    'ExitOnForwardFailure=yes',
    +    '-o',
    +    `ConnectTimeout=${connectSecs}`
    +  ]
    +}
    +
    +// Non-default port and explicit identity file, shared by exec/master/forward.
    +function hostArgs({ port, keyPath }: { port?: number | string; keyPath?: string } = {}) {
    +  const args: string[] = []
    +
    +  if (port && Number(port) !== 22) {
    +    args.push('-p', String(port))
    +  }
    +
    +  if (keyPath) {
    +    validateKeyPath(keyPath)
    +    args.push('-i', keyPath)
    +  }
    +
    +  return args
    +}
    +
    +function target(user, host) {
    +  return user ? `${user}@${host}` : host
    +}
    +
    +function buildExecArgs(conn, remoteCommand, connectTimeoutMs?) {
    +  return [
    +    ...baseSshOptions(conn.controlPath, connectTimeoutMs),
    +    ...hostArgs(conn),
    +    '--',
    +    target(conn.user, conn.host),
    +    remoteCommand
    +  ]
    +}
    +
    +function buildControlArgs(conn, op, extra: string[] = [], connectTimeoutMs?) {
    +  return [
    +    '-O',
    +    op,
    +    ...extra,
    +    ...baseSshOptions(conn.controlPath, connectTimeoutMs),
    +    ...hostArgs(conn),
    +    '--',
    +    target(conn.user, conn.host)
    +  ]
    +}
    +
    +// Open the master explicitly: `-M -N -f` backgrounds ssh once the master is up,
    +// so the spawn resolves when the connection is established (or fails fast under
    +// BatchMode if auth is non-interactive-only).
    +function buildMasterArgs(conn, connectTimeoutMs?) {
    +  return [
    +    '-M',
    +    '-N',
    +    '-f',
    +    ...baseSshOptions(conn.controlPath, connectTimeoutMs),
    +    ...hostArgs(conn),
    +    '--',
    +    target(conn.user, conn.host)
    +  ]
    +}
    +
    +// Interactive `ssh -tt` for the INTERIM remote terminal (SSH mode only). Reuses
    +// the existing ControlMaster socket so NO new auth handshake happens — the
    +// master is already open, so this attaches instantly and never prompts.
    +//
    +// NOTE(remote-terminal): interim until the dashboard /api/terminal WebSocket
    +// lands (specs/desktop-remote-terminal.md); delete this path then.
    +function buildInteractiveSshArgs(conn, remoteCwd, connectTimeoutMs?, remoteCommand?) {
    +  const args = [
    +    '-tt',
    +    ...baseSshOptions(conn.controlPath, connectTimeoutMs),
    +    ...hostArgs(conn),
    +    '--',
    +    target(conn.user, conn.host)
    +  ]
    +
    +  if (remoteCommand) {
    +    args.push(remoteCommand)
    +
    +    return args
    +  }
    +
    +  const cwd = String(remoteCwd || '').trim()
    +
    +  if (cwd) {
    +    const q = `'${cwd.replace(/'/g, `'\\''`)}'`
    +    args.push(`cd ${q} 2>/dev/null; exec "$SHELL" -l`)
    +  } else {
    +    args.push('exec "$SHELL" -l')
    +  }
    +
    +  return args
    +}
    +
    +// Bind the local end to 127.0.0.1 ONLY — never 0.0.0.0 — so the tunnel does not
    +// re-expose the remote dashboard to the client's LAN.
    +function forwardSpec(localPort, remotePort, remoteHost = '127.0.0.1') {
    +  return `127.0.0.1:${localPort}:${remoteHost}:${remotePort}`
    +}
    +
    +// Error classification — distinct, actionable messages for the UI
    +
    +const SSH_ERROR = {
    +  UNREACHABLE: 'unreachable',
    +  AUTH_FAILED: 'auth-failed',
    +  HOST_KEY_CHANGED: 'host-key-changed',
    +  TIMEOUT: 'timeout',
    +  UNKNOWN: 'unknown'
    +}
    +
    +// Order matters: the host-key-change banner also contains "WARNING"/"Offending",
    +// so check it before generic auth.
    +function classifySshError(stderr) {
    +  const text = String(stderr || '')
    +
    +  if (
    +    /REMOTE HOST IDENTIFICATION HAS CHANGED|Host key verification failed|Offending (?:key|ECDSA|RSA|ED25519)/i.test(
    +      text
    +    )
    +  ) {
    +    return SSH_ERROR.HOST_KEY_CHANGED
    +  }
    +
    +  if (
    +    /Permission denied|Too many authentication failures|no matching host key|publickey|password|keyboard-interactive/i.test(
    +      text
    +    )
    +  ) {
    +    return SSH_ERROR.AUTH_FAILED
    +  }
    +
    +  if (
    +    /Could not resolve hostname|Connection refused|Connection timed out|No route to host|Network is unreachable|Operation timed out|port \d+: Connection/i.test(
    +      text
    +    )
    +  ) {
    +    return SSH_ERROR.UNREACHABLE
    +  }
    +
    +  return SSH_ERROR.UNKNOWN
    +}
    +
    +function sshErrorMessage(kind, conn, stderr?) {
    +  const host = target(conn.user, conn.host)
    +
    +  switch (kind) {
    +    case SSH_ERROR.HOST_KEY_CHANGED:
    +      return (
    +        `The host key for ${host} has CHANGED since you last connected. ` +
    +        `This could be a man-in-the-middle attack, or the server was reinstalled. ` +
    +        `SSH refused to connect. Verify the change is expected, then remove the old key ` +
    +        `with \`ssh-keygen -R ${conn.host}\` and reconnect.\n\n${String(stderr || '').trim()}`
    +      )
    +
    +    case SSH_ERROR.AUTH_FAILED:
    +      return (
    +        `SSH authentication to ${host} failed. Desktop runs ssh non-interactively ` +
    +        `(BatchMode), so a key requiring a passphrase or 2FA must be loaded into your ` +
    +        `ssh-agent first (e.g. \`ssh-add ~/.ssh/id_ed25519\`), or set an IdentityFile in ` +
    +        `~/.ssh/config. Original error: ${String(stderr || '').trim()}`
    +      )
    +
    +    case SSH_ERROR.UNREACHABLE:
    +      return `Could not reach ${host} over SSH. Check the host, port, and your network. Original error: ${String(stderr || '').trim()}`
    +
    +    case SSH_ERROR.TIMEOUT:
    +      return `SSH operation to ${host} timed out. The connection may be half-open (e.g. after sleep); reconnecting.`
    +
    +    default:
    +      return `SSH error connecting to ${host}: ${String(stderr || '').trim() || 'unknown failure'}`
    +  }
    +}
    +
    +// Spawn helper — runs an ssh invocation, races it against a hard timeout
    +
    +// Resolves { code, stdout, stderr }. On timeout the child is SIGKILLed and the
    +// promise rejects with err.kind = TIMEOUT. `spawnFn` is injectable for tests.
    +function runSsh(args, { timeoutMs, spawnFn = spawn, stdin = 'ignore', stdinData }: any = {}) {
    +  return new Promise((resolve, reject) => {
    +    const useStdinPipe = stdinData != null || stdin !== 'ignore'
    +    let child
    +
    +    try {
    +      child = spawnFn('ssh', args, { stdio: [useStdinPipe ? 'pipe' : 'ignore', 'pipe', 'pipe'] })
    +    } catch (error) {
    +      reject(error)
    +
    +      return
    +    }
    +
    +    if (stdinData != null && child.stdin) {
    +      child.stdin.end(stdinData)
    +    }
    +
    +    let stdout = ''
    +    let stderr = ''
    +    let settled = false
    +
    +    const timer = setTimeout(() => {
    +      if (settled) {
    +        return
    +      }
    +
    +      settled = true
    +
    +      try {
    +        child.kill('SIGKILL')
    +      } catch {
    +        // already gone
    +      }
    +
    +      const err: any = new Error(`ssh timed out after ${timeoutMs}ms`)
    +      err.kind = SSH_ERROR.TIMEOUT
    +      reject(err)
    +    }, timeoutMs)
    +
    +    child.stdout?.on('data', d => {
    +      stdout += d.toString()
    +    })
    +    child.stderr?.on('data', d => {
    +      stderr += d.toString()
    +    })
    +    child.on('error', error => {
    +      if (settled) {
    +        return
    +      }
    +
    +      settled = true
    +      clearTimeout(timer)
    +      reject(error)
    +    })
    +    child.on('close', code => {
    +      if (settled) {
    +        return
    +      }
    +
    +      settled = true
    +      clearTimeout(timer)
    +      resolve({ code, stdout, stderr })
    +    })
    +  })
    +}
    +
    +function stopTunnelChild(child, timeoutMs = 5_000) {
    +  if (!child || child.exitCode != null || child.signalCode != null) {
    +    return Promise.resolve()
    +  }
    +
    +  return new Promise<void>((resolve, reject) => {
    +    let settled = false
    +
    +    const finish = (error?: unknown) => {
    +      if (settled) {
    +        return
    +      }
    +
    +      settled = true
    +      clearTimeout(timer)
    +      child.off?.('exit', onExit)
    +      child.off?.('error', onError)
    +      error ? reject(error) : resolve()
    +    }
    +
    +    const onExit = () => finish()
    +    const onError = error => finish(error)
    +    const timer = setTimeout(() => finish(new Error('SSH tunnel did not exit after termination.')), timeoutMs)
    +    child.once('exit', onExit)
    +    child.once('error', onError)
    +
    +    try {
    +      if (!child.kill()) {
    +        finish(new Error('SSH tunnel termination was refused.'))
    +      }
    +    } catch (error) {
    +      finish(error)
    +    }
    +  })
    +}
    +
    +// SshConnection — the public manager
    +
    +class SshConnection {
    +  host: string
    +  user: string
    +  port: number
    +  keyPath: string
    +  controlPath: string
    +  _spawnFn: any
    +  _log: (msg: string) => void
    +  _connectTimeoutMs: number
    +  _execTimeoutMs: number
    +  _forwardTimeoutMs: number
    +  _opened: boolean
    +  _mux: boolean
    +  _tunnels: Map<string, any>
    +
    +  constructor(cfg, opts: any = {}) {
    +    if (!cfg || !cfg.host) {
    +      throw new Error('SshConnection requires a host.')
    +    }
    +
    +    const port = cfg.port ? Number(cfg.port) : 22
    +    validateSshTarget(cfg.host, cfg.user || '', port)
    +
    +    if (cfg.keyPath) {
    +      validateKeyPath(cfg.keyPath)
    +    }
    +
    +    this.host = cfg.host
    +    this.user = cfg.user || ''
    +    this.port = port
    +    this.keyPath = cfg.keyPath || ''
    +    // Windows OpenSSH has no ControlMaster (mux sockets were never implemented
    +    // on Win32) — fall back to one ssh invocation per operation and a
    +    // persistent `ssh -N -L` child per tunnel. Empty controlPath routes the
    +    // pure builders onto their no-mux form.
    +    this._mux = opts.mux ?? process.platform !== 'win32'
    +    this.controlPath = this._mux
    +      ? controlSocketPath(this.user, this.host, this.port, opts.controlDir, {
    +          keyPath: this.keyPath,
    +          ownershipId: opts.ownershipId,
    +          scope: opts.scope,
    +          effectiveConfigFingerprint: opts.effectiveConfigFingerprint
    +        })
    +      : ''
    +    this._tunnels = new Map()
    +
    +    this._spawnFn = opts.spawnFn || spawn
    +
    +    this._log = typeof opts.rememberLog === 'function' ? opts.rememberLog : () => {}
    +    this._connectTimeoutMs = opts.connectTimeoutMs ?? DEFAULT_CONNECT_TIMEOUT_MS
    +    this._execTimeoutMs = opts.execTimeoutMs ?? DEFAULT_EXEC_TIMEOUT_MS
    +    this._forwardTimeoutMs = opts.forwardTimeoutMs ?? DEFAULT_FORWARD_TIMEOUT_MS
    +    this._opened = false
    +  }
    +
    +  // Lifecycle logging — ALWAYS through redaction.
    +  _logLine(msg) {
    +    this._log(redactSecrets(`[ssh] ${msg}`))
    +  }
    +
    +  _fail(stderrOrErr, fallbackKind = SSH_ERROR.UNKNOWN) {
    +    if (stderrOrErr && stderrOrErr.kind === SSH_ERROR.TIMEOUT) {
    +      const err: any = new Error(sshErrorMessage(SSH_ERROR.TIMEOUT, this))
    +      err.kind = SSH_ERROR.TIMEOUT
    +
    +      return err
    +    }
    +
    +    const stderr = typeof stderrOrErr === 'string' ? stderrOrErr : stderrOrErr?.message || ''
    +    const kind = stderr ? classifySshError(stderr) : fallbackKind
    +    const err: any = new Error(sshErrorMessage(kind, this, stderr))
    +    err.kind = kind
    +
    +    return err
    +  }
    +
    +  // Open the connection. Mux: start the persistent ControlMaster (idempotent —
    +  // a live master is a no-op). No-mux: there is no master; validate auth +
    +  // reachability with a one-shot `ssh true` so failures classify identically.
    +  async open() {
    +    if (await this.isAlive()) {
    +      // -O check passing is not proof the master works: a ControlPersist master
    +      // can survive a failed teardown with wedged channels (observed on macOS
    +      // after a mode switch — check succeeds, every exec times out). Verify with
    +      // a real exec before trusting it; on failure, evict and dial fresh.
    +      if (!this._mux || (await this._verifyMuxChannel())) {
    +        this._opened = true
    +
    +        return
    +      }
    +
    +      this._logLine('existing control master failed exec verification; evicting stale master')
    +      await this._evictStaleMaster()
    +    }
    +
    +    if (!this._mux) {
    +      this._logLine(`connecting (no-mux) to ${target(this.user, this.host)}:${this.port}`)
    +      let result
    +
    +      try {
    +        result = await runSsh(buildExecArgs(this, 'exit 0', this._connectTimeoutMs), {
    +          timeoutMs: this._connectTimeoutMs,
    +          spawnFn: this._spawnFn
    +        })
    +      } catch (error) {
    +        throw this._fail(error, SSH_ERROR.UNREACHABLE)
    +      }
    +
    +      if (result.code !== 0) {
    +        throw this._fail(result.stderr, SSH_ERROR.UNREACHABLE)
    +      }
    +
    +      this._opened = true
    +      this._logLine('connection verified (no-mux; per-operation ssh)')
    +
    +      return
    +    }
    +
    +    const controlDir = path.dirname(this.controlPath)
    +
    +    try {
    +      fs.mkdirSync(controlDir, { recursive: true, mode: 0o700 })
    +    } catch {
    +      void 0
    +    }
    +
    +    if (process.platform !== 'win32') {
    +      const st = fs.lstatSync(controlDir)
    +
    +      if (st.isSymbolicLink()) {
    +        throw new Error(`Unsafe SSH control dir: ${controlDir} is a symlink.`)
    +      }
    +
    +      if (!st.isDirectory()) {
    +        throw new Error(`Unsafe SSH control dir: ${controlDir} is not a directory.`)
    +      }
    +
    +      if (st.uid !== process.getuid!()) {
    +        throw new Error(`Unsafe SSH control dir: ${controlDir} is owned by uid ${st.uid}, not ${process.getuid!()}.`)
    +      }
    +
    +      if ((st.mode & 0o777) !== 0o700) {
    +        fs.chmodSync(controlDir, 0o700)
    +      }
    +    }
    +
    +    const args = buildMasterArgs(this, this._connectTimeoutMs)
    +    this._logLine(`opening control master to ${target(this.user, this.host)}:${this.port}`)
    +    let result
    +
    +    try {
    +      result = await runSsh(args, { timeoutMs: this._connectTimeoutMs, spawnFn: this._spawnFn })
    +    } catch (error) {
    +      throw this._fail(error, SSH_ERROR.UNREACHABLE)
    +    }
    +
    +    if (result.code !== 0) {
    +      throw this._fail(result.stderr, SSH_ERROR.UNREACHABLE)
    +    }
    +
    +    this._opened = true
    +    this._logLine('control master established')
    +  }
    +
    +  // Liveness. Mux: `-O check` against the master socket. No-mux: a cheap
    +  // one-shot exec — "alive" means "we can still authenticate and run".
    +  async isAlive() {
    +    if ([...this._tunnels.values()].some(tunnel => tunnel.alive === false)) {
    +      return false
    +    }
    +
    +    const args = this._mux
    +      ? buildControlArgs(this, 'check', [], this._connectTimeoutMs)
    +      : buildExecArgs(this, 'exit 0', this._connectTimeoutMs)
    +
    +    try {
    +      const result: any = await runSsh(args, { timeoutMs: this._connectTimeoutMs, spawnFn: this._spawnFn })
    +
    +      return result.code === 0
    +    } catch {
    +      return false
    +    }
    +  }
    +
    +  // A real exec through the master (`exit 0` works under POSIX shells and
    +  // cmd.exe); a wedged mux hangs to the timeout.
    +  async _verifyMuxChannel() {
    +    try {
    +      const result: any = await runSsh(buildExecArgs(this, 'exit 0', this._connectTimeoutMs), {
    +        timeoutMs: this._connectTimeoutMs,
    +        spawnFn: this._spawnFn
    +      })
    +
    +      return result.code === 0
    +    } catch {
    +      return false
    +    }
    +  }
    +
    +  // -O exit (best-effort) then drop the socket so ControlMaster=auto cannot
    +  // re-attach to the corpse. (The orphaned master process is left to
    +  // ControlPersist; a wedged channel can pin it, but without its socket it is
    +  // inert.)
    +  async _evictStaleMaster() {
    +    try {
    +      await runSsh(buildControlArgs(this, 'exit', [], this._connectTimeoutMs), {
    +        timeoutMs: this._connectTimeoutMs,
    +        spawnFn: this._spawnFn
    +      })
    +    } catch {
    +      void 0
    +    }
    +
    +    try {
    +      fs.unlinkSync(this.controlPath)
    +    } catch (error: any) {
    +      if (error?.code !== 'ENOENT') {
    +        this._logLine(`could not remove stale control socket (${error.code}); a fresh master may not dial`)
    +      }
    +    }
    +  }
    +
    +  // One-shot remote command over the control connection. Resolves stdout;
    +  // rejects with a classified error on non-zero exit or timeout.
    +  async exec(remoteCommand, { timeoutMs, stdinData }: any = {}) {
    +    const args = buildExecArgs(this, remoteCommand, this._connectTimeoutMs)
    +    let result
    +
    +    try {
    +      result = await runSsh(args, {
    +        timeoutMs: timeoutMs ?? this._execTimeoutMs,
    +        spawnFn: this._spawnFn,
    +        ...(stdinData != null ? { stdinData } : {})
    +      })
    +    } catch (error) {
    +      throw this._fail(error)
    +    }
    +
    +    if (result.code !== 0) {
    +      throw this._fail(result.stderr)
    +    }
    +
    +    return result.stdout
    +  }
    +
    +  // Establish a local→remote forward. Mux: `-O forward` against the master.
    +  // No-mux: spawn a persistent `ssh -N -L` child that IS the tunnel; ready when
    +  // the local port accepts. The child dying = tunnel down (isAlive of the
    +  // backend catches it upstream).
    +  async forward(localPort, remotePort, remoteHost = '127.0.0.1') {
    +    const spec = forwardSpec(localPort, remotePort, remoteHost)
    +    this._logLine(`forwarding 127.0.0.1:${localPort} -> ${remoteHost}:${remotePort}`)
    +
    +    if (!this._mux) {
    +      const args = [
    +        ...baseSshOptions('', this._connectTimeoutMs),
    +        ...hostArgs(this),
    +        '-v',
    +        '-N',
    +        '-L',
    +        spec,
    +        '--',
    +        target(this.user, this.host)
    +      ]
    +
    +      const child = this._spawnFn('ssh', args, { stdio: ['ignore', 'ignore', 'pipe'] })
    +      const tunnel = { child, alive: true }
    +      this._tunnels.set(spec, tunnel)
    +      let stderr = ''
    +      let readyConfirmed = false
    +      let readyResolve
    +      let readyReject
    +
    +      const ready = new Promise<void>((resolve, reject) => {
    +        readyResolve = resolve
    +        readyReject = reject
    +      })
    +
    +      const readyPattern = new RegExp(`Local forwarding listening on .* port ${localPort}\\b`)
    +      child.stderr?.on('data', d => {
    +        if (readyConfirmed) {
    +          return
    +        }
    +
    +        stderr = `${stderr}${String(d)}`.slice(-16_384)
    +
    +        if (readyPattern.test(stderr)) {
    +          readyConfirmed = true
    +          readyResolve()
    +        }
    +      })
    +      child.on('error', error => {
    +        tunnel.alive = false
    +        readyReject(error)
    +      })
    +      child.on('exit', code => {
    +        tunnel.alive = false
    +        readyReject(new Error(`tunnel process exited with code ${code}`))
    +      })
    +      child.on('close', code => {
    +        tunnel.alive = false
    +        readyReject(new Error(`tunnel process closed with code ${code}`))
    +      })
    +      let readyTimeout
    +
    +      try {
    +        await Promise.race([
    +          ready,
    +          new Promise((_, reject) => {
    +            readyTimeout = setTimeout(
    +              () => reject(new Error('tunnel did not confirm local forwarding')),
    +              this._forwardTimeoutMs
    +            )
    +          })
    +        ])
    +      } catch (error: any) {
    +        try {
    +          await stopTunnelChild(child)
    +          this._tunnels.delete(spec)
    +        } catch (stopError) {
    +          throw this._fail(stopError, SSH_ERROR.UNKNOWN)
    +        }
    +
    +        throw this._fail(stderr || error, SSH_ERROR.UNKNOWN)
    +      } finally {
    +        clearTimeout(readyTimeout)
    +      }
    +
    +      return
    +    }
    +
    +    const args = buildControlArgs(this, 'forward', ['-L', spec], this._connectTimeoutMs)
    +    let result
    +
    +    try {
    +      result = await runSsh(args, { timeoutMs: this._forwardTimeoutMs, spawnFn: this._spawnFn })
    +    } catch (error) {
    +      throw this._fail(error)
    +    }
    +
    +    if (result.code !== 0) {
    +      throw this._fail(result.stderr)
    +    }
    +  }
    +
    +  // Cancel a previously-established forward. Best-effort: a failure here is
    +  // logged but not thrown (close tears everything down anyway).
    +  async cancelForward(localPort, remotePort, remoteHost = '127.0.0.1') {
    +    const spec = forwardSpec(localPort, remotePort, remoteHost)
    +
    +    if (!this._mux) {
    +      const tunnel = this._tunnels.get(spec)
    +
    +      if (tunnel) {
    +        await stopTunnelChild(tunnel.child)
    +        this._tunnels.delete(spec)
    +        this._logLine(`cancelled forward 127.0.0.1:${localPort}`)
    +      }
    +
    +      return
    +    }
    +
    +    const args = buildControlArgs(this, 'cancel', ['-L', spec], this._connectTimeoutMs)
    +
    +    try {
    +      await runSsh(args, { timeoutMs: this._forwardTimeoutMs, spawnFn: this._spawnFn })
    +      this._logLine(`cancelled forward 127.0.0.1:${localPort}`)
    +    } catch (error: any) {
    +      this._logLine(`cancelForward failed (ignored): ${error.message}`)
    +    }
    +  }
    +
    +  // Tear down. Mux: exit the master (drops every forward with it). No-mux:
    +  // kill the tunnel children. Best-effort; never throws.
    +  async close() {
    +    if (!this._opened) {
    +      return
    +    }
    +
    +    if (!this._mux) {
    +      for (const [spec, tunnel] of this._tunnels) {
    +        await stopTunnelChild(tunnel.child)
    +        this._tunnels.delete(spec)
    +      }
    +
    +      this._opened = false
    +      this._logLine('connection closed (no-mux tunnels killed)')
    +
    +      return
    +    }
    +
    +    const args = buildControlArgs(this, 'exit', [], this._connectTimeoutMs)
    +
    +    try {
    +      const result: any = await runSsh(args, { timeoutMs: this._connectTimeoutMs, spawnFn: this._spawnFn })
    +
    +      if (result.code !== 0) {
    +        throw this._fail(result.stderr)
    +      }
    +
    +      this._logLine('control master closed')
    +    } catch (error: any) {
    +      // A master that refuses -O exit is the wedge that poisons re-attach;
    +      // disown it. (Without its socket the orphan is inert; ControlPersist may
    +      // not reap it if a wedged channel never idles.)
    +      this._logLine(`close failed; removing control socket: ${error.message}`)
    +
    +      try {
    +        fs.unlinkSync(this.controlPath)
    +      } catch {
    +        void 0
    +      }
    +    }
    +
    +    this._opened = false
    +  }
    +}
    +
    +// Free local port for the tunnel's local end. Bind 127.0.0.1:0, read the
    +// kernel-assigned port, release. The benign TOCTOU window (release → forward
    +// grabs it) is caught upstream and retried with a fresh port.
    +
    +function pickLocalPort() {
    +  return new Promise((resolve, reject) => {
    +    const server = net.createServer()
    +    server.unref()
    +    server.on('error', reject)
    +    server.listen(0, '127.0.0.1', () => {
    +      const { port } = server.address() as net.AddressInfo
    +      server.close(() => resolve(port))
    +    })
    +  })
    +}
    +
    +function createSshProbeConnection(config, options: any = {}) {
    +  return new SshConnection(config, { ...options, mux: false })
    +}
    +
    +export {
    +  baseSshOptions,
    +  buildControlArgs,
    +  buildExecArgs,
    +  buildInteractiveSshArgs,
    +  buildMasterArgs,
    +  classifySshError,
    +  CONTROL_PERSIST_SECONDS,
    +  controlSocketPath,
    +  createSshProbeConnection,
    +  DEFAULT_CONNECT_TIMEOUT_MS,
    +  DEFAULT_EXEC_TIMEOUT_MS,
    +  DEFAULT_FORWARD_TIMEOUT_MS,
    +  forwardSpec,
    +  hostArgs,
    +  pickLocalPort,
    +  redactSecrets,
    +  runSsh,
    +  SSH_ERROR,
    +  SshConnection,
    +  sshErrorMessage,
    +  stopTunnelChild,
    +  target,
    +  validateKeyPath,
    +  validateSshTarget
    +}
    ```
  - `apps/desktop/electron/windows-remote-lifecycle.test.ts`

    ```diff
    @@ -0,0 +1,122 @@
    +import assert from 'node:assert/strict'
    +
    +import { test } from 'vitest'
    +
    +import {
    +  buildWindowsInteractiveCommand,
    +  detectRemotePlatform,
    +  encodedPowerShell,
    +  helperCommand,
    +  powerShellCommand,
    +  psLiteral,
    +  validLock
    +} from './windows-remote-lifecycle'
    +
    +const ownershipId = '0123456789abcdef0123456789abcdef'
    +
    +function sshWith(exec) {
    +  return { exec }
    +}
    +
    +test('PowerShell transport uses UTF-16LE encoded commands and literal escaping', () => {
    +  assert.equal(Buffer.from(encodedPowerShell("'ok'"), 'base64').toString('utf16le'), "'ok'")
    +  assert.equal(psLiteral("a'b"), "'a''b'")
    +  assert.match(powerShellCommand('Write-Output ok'), /^powershell\.exe -NoProfile -NonInteractive .* -EncodedCommand /)
    +})
    +
    +test('platform detection preserves POSIX and falls back to Windows PowerShell', async () => {
    +  assert.deepEqual(await detectRemotePlatform(sshWith(async () => 'Linux\nx86_64\n')), { os: 'Linux', arch: 'x86_64' })
    +  const calls: string[] = []
    +
    +  const result = await detectRemotePlatform(
    +    sshWith(async command => {
    +      calls.push(command)
    +
    +      if (command.startsWith('uname ')) {
    +        throw new Error('PowerShell does not recognize uname')
    +      }
    +
    +      return JSON.stringify({
    +        os: 'Windows',
    +        arch: 'ARM64',
    +        hermesHome: 'C:\\h',
    +        hermesPath: 'C:\\h\\hermes.exe',
    +        python: 'C:\\h\\python.exe'
    +      })
    +    })
    +  )
    +
    +  assert.equal(result.os, 'Windows')
    +  assert.match(calls[1], /EncodedCommand/)
    +})
    +
    +test('platform detection surfaces transport failures as themselves, not unsupported-platform', async () => {
    +  // A dead/unauthorized host is a connectivity verdict; only a host that answers
    +  // neither probe is an unsupported platform.
    +  const transportErr: any = new Error('SSH connection timed out')
    +  transportErr.kind = 'timeout'
    +  await assert.rejects(
    +    detectRemotePlatform(
    +      sshWith(async () => {
    +        throw transportErr
    +      })
    +    ),
    +    (err: any) => err.kind === 'timeout'
    +  )
    +  // Probe genuinely failing on a reachable host still classifies unsupported,
    +  // and carries the probe detail for diagnosis.
    +  await assert.rejects(
    +    detectRemotePlatform(
    +      sshWith(async command => {
    +        if (command.startsWith('uname ')) {
    +          throw new Error('not recognized')
    +        }
    +
    +        throw new Error('Hermes is not installed on the remote Windows host.')
    +      })
    +    ),
    +    (err: any) => err.kind === 'unsupported-platform' && /Hermes is not installed/.test(err.message)
    +  )
    +})
    +
    +test('helper command uses the fixed remote Python entry point and quotes path data', () => {
    +  const command = helperCommand({ python: "C:\\Program Files\\Hermes's\\python.exe" }, 'inspect', [
    +    'C:\\x y\\hermes.exe'
    +  ])
    +
    +  const encoded = command.split(' ').pop()!
    +  const script = Buffer.from(encoded, 'base64').toString('utf16le')
    +  assert.match(script, /-m' 'hermes_cli\.windows_ssh_runtime' 'inspect'/)
    +  assert.match(script, /Hermes''s/)
    +  assert.match(script, /C:\\x y\\hermes\.exe/)
    +})
    +
    +test('Windows lock validation is scoped and exact', () => {
    +  const lock = {
    +    schemaVersion: 2,
    +    protocolVersion: 1,
    +    ownershipId,
    +    spawnNonce: '0123456789abcdef',
    +    pid: 10,
    +    creationTimeNs: '1784219690452757504',
    +    port: 1234,
    +    tokenFingerprint: 'a'.repeat(32),
    +    hermesPath: 'C:\\h\\hermes.exe',
    +    hermesHome: 'C:\\h'
    +  }
    +
    +  assert.equal(validLock(lock, ownershipId), true)
    +  assert.equal(validLock({ ...lock, ownershipId: 'b'.repeat(32) }, ownershipId), false)
    +  assert.equal(validLock({ ...lock, creationTimeNs: '0' }, ownershipId), false)
    +  // port 0 = spawn-in-progress record: valid ownership proof (cleanup can act
    +  // on it) but the reuse gate must reject it separately.
    +  assert.equal(validLock({ ...lock, port: 0 }, ownershipId), true)
    +  assert.equal(validLock({ ...lock, port: -1 }, ownershipId), false)
    +})
    +
    +test('Windows integrated terminal uses encoded PowerShell and preserves cwd as literal data', () => {
    +  const command = buildWindowsInteractiveCommand("C:\\Users\\O'Brien\\repo")
    +  const script = Buffer.from(command.split(' ').pop()!, 'base64').toString('utf16le')
    +  assert.match(script, /Set-Location -LiteralPath 'C:\\Users\\O''Brien\\repo'/)
    +  assert.match(script, /powershell\.exe -NoLogo/)
    +})
    ```
  - `apps/desktop/electron/windows-remote-lifecycle.ts`

    ```diff
    @@ -0,0 +1,455 @@
    +import crypto from 'node:crypto'
    +
    +import { redactSecrets, SSH_ERROR } from './ssh-connection'
    +
    +const LOCKFILE_SCHEMA_VERSION = 2
    +const PROTOCOL_VERSION = 1
    +const READY_RE = /^HERMES_(?:BACKEND|DASHBOARD)_READY port=(\d+)/gm
    +const READY_POLL_INTERVAL_MS = 750
    +
    +function psLiteral(value) {
    +  return `'${String(value).replace(/'/g, "''")}'`
    +}
    +
    +function encodedPowerShell(script) {
    +  return Buffer.from(script, 'utf16le').toString('base64')
    +}
    +
    +function powerShellCommand(script) {
    +  return `powershell.exe -NoProfile -NonInteractive -ExecutionPolicy Bypass -EncodedCommand ${encodedPowerShell(script)}`
    +}
    +
    +async function probeWindowsRemote(ssh, explicitHermesPath = '') {
    +  const explicit = psLiteral(explicitHermesPath)
    +
    +  const script = [
    +    '$ErrorActionPreference="Stop"',
    +    `$explicit=${explicit}`,
    +    '$hermesHome=$env:HERMES_HOME',
    +    'if(-not $hermesHome){$hermesHome=Join-Path $env:LOCALAPPDATA "hermes"}',
    +    '$candidates=@()',
    +    'if($explicit){$candidates+=$explicit}',
    +    '$cmd=Get-Command hermes.exe -ErrorAction SilentlyContinue',
    +    'if($cmd){$candidates+=$cmd.Source}',
    +    '$candidates+=(Join-Path $hermesHome "hermes-agent\\venv\\Scripts\\hermes.exe")',
    +    '$candidates+=(Join-Path $HOME "hermes-agent\\.venv\\Scripts\\hermes.exe")',
    +    '$hermes=$candidates|Where-Object{Test-Path -LiteralPath $_ -PathType Leaf}|Select-Object -First 1',
    +    'if(-not $hermes){throw "Hermes is not installed on the remote Windows host."}',
    +    'if($explicit -and $hermes -ne $explicit){throw "The configured Hermes path is not an executable file."}',
    +    '$python=Join-Path (Split-Path $hermes) "python.exe"',
    +    'if(-not (Test-Path -LiteralPath $python -PathType Leaf)){throw "The remote Hermes Python runtime was not found."}',
    +    '[ordered]@{os="Windows";arch=$env:PROCESSOR_ARCHITECTURE;hermesHome=$hermesHome;hermesPath=$hermes;python=$python}|ConvertTo-Json -Compress'
    +  ].join(';')
    +
    +  return JSON.parse((await ssh.exec(powerShellCommand(script))).trim())
    +}
    +
    +const TRANSPORT_KINDS = new Set([
    +  SSH_ERROR.AUTH_FAILED,
    +  SSH_ERROR.HOST_KEY_CHANGED,
    +  SSH_ERROR.TIMEOUT,
    +  SSH_ERROR.UNREACHABLE
    +])
    +
    +async function detectRemotePlatform(ssh, explicitHermesPath = '') {
    +  try {
    +    const output = (await ssh.exec('uname -s; uname -m')).trim().split('\n')
    +
    +    if (output[0] === 'Linux' || output[0] === 'Darwin') {
    +      return { os: output[0], arch: output[1] || '' }
    +    }
    +  } catch (error: any) {
    +    // uname failing is the expected Windows fall-through; a TRANSPORT failure
    +    // (auth/host-key/timeout/unreachable) is not a platform verdict — surface it
    +    // as itself instead of letting the probe chain end in 'unsupported-platform'.
    +    if (TRANSPORT_KINDS.has(error?.kind)) {
    +      throw error
    +    }
    +  }
    +
    +  try {
    +    return await probeWindowsRemote(ssh, explicitHermesPath)
    +  } catch (cause: any) {
    +    if (TRANSPORT_KINDS.has(cause?.kind)) {
    +      throw cause
    +    }
    +
    +    // detail is remote-controlled output headed for the UI: redact + strip control chars.
    +    const detail = redactSecrets(String(cause?.message || cause || ''))
    +      // eslint-disable-next-line no-control-regex -- deliberately strip control chars from remote output
    +      .replace(/[\x00-\x1f\x7f]/g, ' ')
    +      .trim()
    +
    +    const error: any = new Error(
    +      `The remote operating system is not supported by Desktop SSH.${detail ? ` (probe: ${detail.slice(0, 300)})` : ''}`
    +    )
    +
    +    error.kind = 'unsupported-platform'
    +    error.cause = cause
    +    throw error
    +  }
    +}
    +
    +function helperCommand(runtime, operation, args = []) {
    +  const argv = [runtime.python, '-m', 'hermes_cli.windows_ssh_runtime', operation, ...args]
    +
    +  const script = [
    +    '$ErrorActionPreference="Stop"',
    +    `& ${argv.map(psLiteral).join(' ')}`,
    +    'if($LASTEXITCODE -ne 0){exit $LASTEXITCODE}'
    +  ].join(';')
    +
    +  return powerShellCommand(script)
    +}
    +
    +async function helper(ssh, runtime, operation, args = [], stdinData?) {
    +  const output = await ssh.exec(helperCommand(runtime, operation, args), stdinData == null ? {} : { stdinData })
    +
    +  const lines = String(output || '')
    +    .replace(/^\uFEFF/, '')
    +    .trim()
    +    .split(/\r?\n/)
    +    .filter(Boolean)
    +
    +  const parsed = JSON.parse(lines[lines.length - 1] || 'null')
    +
    +  if (parsed?.error) {
    +    throw new Error(parsed.error)
    +  }
    +
    +  return parsed
    +}
    +
    +function fingerprintToken(token) {
    +  return crypto
    +    .createHash('sha256')
    +    .update(String(token || ''))
    +    .digest('hex')
    +    .slice(0, 32)
    +}
    +
    +function validLock(lock, ownershipId) {
    +  // port 0 = spawn-in-progress record (written before readiness); a valid
    +  // ownership proof for cleanup, but never reusable.
    +  return Boolean(
    +    lock &&
    +    lock.schemaVersion === LOCKFILE_SCHEMA_VERSION &&
    +    lock.protocolVersion === PROTOCOL_VERSION &&
    +    lock.ownershipId === ownershipId &&
    +    /^[0-9a-f]{16}$/.test(lock.spawnNonce || '') &&
    +    Number.isInteger(lock.pid) &&
    +    lock.pid > 0 &&
    +    /^[0-9]{10,20}$/.test(lock.creationTimeNs || '') &&
    +    Number.isInteger(lock.port) &&
    +    lock.port >= 0 &&
    +    lock.port <= 65535 &&
    +    /^[0-9a-f]{32}$/.test(lock.tokenFingerprint || '') &&
    +    typeof lock.hermesPath === 'string' &&
    +    typeof lock.hermesHome === 'string'
    +  )
    +}
    +
    +function assertCurrent(signal) {
    +  if (signal?.aborted) {
    +    const error: any = new Error('SSH bootstrap was cancelled.')
    +    error.kind = 'superseded'
    +    throw error
    +  }
    +}
    +
    +async function processState(ssh, runtime, lock) {
    +  return helper(ssh, runtime, 'process-state', [
    +    String(lock.pid),
    +    String(lock.creationTimeNs),
    +    lock.hermesPath,
    +    lock.spawnNonce
    +  ])
    +}
    +
    +async function cleanupOwned(ssh, runtime, ownershipId, lock) {
    +  const attempt = async fn => {
    +    try {
    +      await fn()
    +    } catch {
    +      void 0
    +    }
    +  }
    +
    +  if (lock) {
    +    const state = await processState(ssh, runtime, lock)
    +
    +    if (state.alive && state.owned) {
    +      // Deliberately not attempt()-wrapped: a thrown terminate must abort before
    +      // remove-lock, or a live backend is orphaned with no lock to reclaim it.
    +      await helper(ssh, runtime, 'terminate', [
    +        String(lock.pid),
    +        String(lock.creationTimeNs),
    +        lock.hermesPath,
    +        lock.spawnNonce
    +      ])
    +    }
    +
    +    if (lock.spawnNonce) {
    +      await attempt(() => helper(ssh, runtime, 'remove-token', [ownershipId, lock.spawnNonce]))
    +      await attempt(() => helper(ssh, runtime, 'remove-log', [ownershipId, lock.spawnNonce]))
    +    }
    +  }
    +
    +  await attempt(() => helper(ssh, runtime, 'remove-lock', [ownershipId]))
    +}
    +
    +async function waitReady(ssh, runtime, ownershipId, lock, timeoutMs, signal) {
    +  const deadline = Date.now() + timeoutMs
    +
    +  while (Date.now() < deadline) {
    +    assertCurrent(signal)
    +    let state
    +
    +    try {
    +      state = await processState(ssh, runtime, lock)
    +    } catch {
    +      await new Promise(resolve => setTimeout(resolve, READY_POLL_INTERVAL_MS))
    +
    +      continue
    +    }
    +
    +    if (!state.indeterminate && (!state.alive || !state.owned)) {
    +      let detail = ''
    +
    +      try {
    +        detail = (await helper(ssh, runtime, 'read-log', [ownershipId, lock.spawnNonce]))?.content || ''
    +      } catch {
    +        void 0
    +      }
    +
    +      const error: any = new Error(
    +        `Remote Windows backend exited before announcing its port. state=${JSON.stringify(state)} ${detail.slice(-2000)}`
    +      )
    +
    +      error.kind = 'spawn-failed'
    +      throw error
    +    }
    +
    +    let content = ''
    +
    +    try {
    +      content = (await helper(ssh, runtime, 'read-log', [ownershipId, lock.spawnNonce]))?.content || ''
    +    } catch {
    +      void 0
    +    }
    +
    +    let port
    +
    +    for (const match of content.matchAll(READY_RE)) {
    +      port = Number(match[1])
    +    }
    +
    +    if (port) {
    +      return port
    +    }
    +
    +    await new Promise(resolve => setTimeout(resolve, READY_POLL_INTERVAL_MS))
    +  }
    +
    +  const error: any = new Error(`Timed out waiting for the remote Windows backend (${timeoutMs}ms).`)
    +  error.kind = 'ready-timeout'
    +  throw error
    +}
    +
    +async function connectWindowsRemote(deps) {
    +  const {
    +    ssh,
    +    ownershipId,
    +    profile = '',
    +    remoteHermesPath = '',
    +    reuseToken = '',
    +    signal,
    +    pickLocalPort,
    +    forward,
    +    cancelForward,
    +    waitForHermes,
    +    probeReuseProof,
    +    rememberLog = () => {},
    +    readyTimeoutMs = 45_000
    +  } = deps
    +
    +  assertCurrent(signal)
    +  const runtime = await probeWindowsRemote(ssh, remoteHermesPath)
    +  const inspection = await helper(ssh, runtime, 'inspect', [runtime.hermesPath])
    +
    +  if (!inspection.supported) {
    +    const error: any = new Error('Update Hermes on the remote Windows host before connecting with Desktop SSH.')
    +    error.kind = 'update-required'
    +    throw error
    +  }
    +
    +  runtime.hermesPath = inspection.path
    +  const hermesVersion = inspection.version || ''
    +  rememberLog(`[ssh-lifecycle] remote platform Windows/${runtime.arch}`)
    +  rememberLog(`[ssh-lifecycle] located hermes at ${runtime.hermesPath}`)
    +
    +  const lock = await helper(ssh, runtime, 'read-lock', [ownershipId])
    +
    +  if (validLock(lock, ownershipId)) {
    +    const state = await processState(ssh, runtime, lock)
    +
    +    if (state.indeterminate) {
    +      const error: any = new Error('Could not determine the state of the existing remote backend.')
    +      error.kind = 'transient-transport-error'
    +      throw error
    +    }
    +
    +    const reusable =
    +      state.alive &&
    +      state.owned &&
    +      lock.port > 0 &&
    +      Boolean(reuseToken) &&
    +      lock.tokenFingerprint === fingerprintToken(reuseToken) &&
    +      lock.hermesPath === runtime.hermesPath &&
    +      lock.hermesHome === runtime.hermesHome
    +
    +    if (reusable) {
    +      const localPort = await pickLocalPort()
    +      await forward(localPort, lock.port)
    +
    +      try {
    +        const baseUrl = `http://127.0.0.1:${localPort}`
    +        const classification = await probeReuseProof(baseUrl, reuseToken, lock.spawnNonce)
    +
    +        if (classification === 'authenticated-ok') {
    +          return {
    +            baseUrl,
    +            token: [redacted:secret-assignment]
    +            remotePort: lock.port,
    +            localPort,
    +            pid: lock.pid,
    +            reused: true,
    +            platform: { os: 'Windows', arch: runtime.arch },
    +            hermesPath: runtime.hermesPath,
    +            hermesVersion,
    +            ownershipId,
    +            spawnNonce: lock.spawnNonce,
    +            creationTimeNs: lock.creationTimeNs
    +          }
    +        }
    +
    +        if (classification !== 'authenticated-stale') {
    +          throw new Error('Invalid SSH reuse classification.')
    +        }
    +
    +        await cancelForward(localPort, lock.port)
    +        await cleanupOwned(ssh, runtime, ownershipId, lock)
    +      } catch (error) {
    +        await cancelForward(localPort, lock.port)
    +        throw error
    +      }
    +    } else {
    +      await cleanupOwned(ssh, runtime, ownershipId, lock)
    +    }
    +  } else if (lock) {
    +    await helper(ssh, runtime, 'remove-lock', [ownershipId])
    +  }
    +
    +  assertCurrent(signal)
    +  const token = [redacted:secret-assignment]'hex')
    +  const spawnNonce = crypto.randomBytes(8).toString('hex')
    +  await helper(ssh, runtime, 'upload-token', [ownershipId, spawnNonce], token)
    +  let spawned
    +
    +  try {
    +    spawned = await helper(
    +      ssh,
    +      runtime,
    +      'spawn',
    +      [],
    +      JSON.stringify({ ownershipId, spawnNonce, profile, hermesPath: runtime.hermesPath })
    +    )
    +  } catch (error) {
    +    await helper(ssh, runtime, 'remove-token', [ownershipId, spawnNonce])
    +    throw error
    +  }
    +
    +  const owned = {
    +    schemaVersion: LOCKFILE_SCHEMA_VERSION,
    +    protocolVersion: PROTOCOL_VERSION,
    +    ownershipId,
    +    spawnNonce,
    +    pid: spawned.pid,
    +    creationTimeNs: spawned.creationTimeNs,
    +    port: 0,
    +    profile,
    +    hermesPath: runtime.hermesPath,
    +    hermesHome: runtime.hermesHome,
    +    tokenFingerprint: [redacted:secret-assignment]
    +    startedAt: new Date().toISOString()
    +  }
    +
    +  let localPort = 0
    +  let remotePort = 0
    +
    +  try {
    +    // Write the ownership record IMMEDIATELY (port=0): if this attempt is
    +    // superseded before readiness and cleanup cannot reach the box, the next
    +    // connect still finds the lock and reaps the process by exact ownership.
    +    // Inside the try: if this write itself fails, the catch still kills the
    +    // just-spawned process via the in-memory record.
    +    await helper(ssh, runtime, 'write-lock', [ownershipId], JSON.stringify(owned))
    +    remotePort = await waitReady(ssh, runtime, ownershipId, owned, readyTimeoutMs, signal)
    +    localPort = await pickLocalPort()
    +    await forward(localPort, remotePort)
    +    const baseUrl = `http://127.0.0.1:${localPort}`
    +    await waitForHermes(baseUrl, token)
    +    assertCurrent(signal)
    +    await helper(ssh, runtime, 'write-lock', [ownershipId], JSON.stringify({ ...owned, port: remotePort }))
    +
    +    return {
    +      baseUrl,
    +      token,
    +      remotePort,
    +      localPort,
    +      pid: spawned.pid,
    +      reused: false,
    +      platform: { os: 'Windows', arch: runtime.arch },
    +      hermesPath: runtime.hermesPath,
    +      hermesVersion,
    +      ownershipId,
    +      spawnNonce,
    +      creationTimeNs: spawned.creationTimeNs
    +    }
    +  } catch (error) {
    +    if (localPort && remotePort) {
    +      await cancelForward(localPort, remotePort)
    +    }
    +
    +    await cleanupOwned(ssh, runtime, ownershipId, owned)
    +    throw error
    +  }
    +}
    +
    +function buildWindowsInteractiveCommand(remoteCwd = '') {
    +  const cwd = String(remoteCwd || '').trim()
    +  const script = ['$ErrorActionPreference="Stop"']
    +
    +  if (cwd) {
    +    script.push(
    +      `if(Test-Path -LiteralPath ${psLiteral(cwd)} -PathType Container){Set-Location -LiteralPath ${psLiteral(cwd)}}`
    +    )
    +  }
    +
    +  script.push('$host.UI.RawUI.WindowTitle="Hermes SSH"', 'powershell.exe -NoLogo')
    +
    +  return powerShellCommand(script.join(';'))
    +}
    +
    +export {
    +  buildWindowsInteractiveCommand,
    +  connectWindowsRemote,
    +  detectRemotePlatform,
    +  encodedPowerShell,
    +  helper,
    +  helperCommand,
    +  powerShellCommand,
    +  probeWindowsRemote,
    +  psLiteral,
    +  validLock
    +}
    ```
  - `apps/desktop/electron/windows-remote-live.test.ts`

    ```diff
    @@ -0,0 +1,106 @@
    +import assert from 'node:assert/strict'
    +
    +import { test } from 'vitest'
    +
    +import { pickLocalPort, SshConnection } from './ssh-connection'
    +import { connectWindowsRemote } from './windows-remote-lifecycle'
    +
    +// Live test against a real Windows host over SSH. Opt-in: set the env trio to
    +// your test rig; skipped everywhere else (CI, other machines).
    +//   HERMES_WIN_SSH_HOST   ssh alias/host of the Windows box
    +//   HERMES_WIN_SSH_USER   remote user
    +//   HERMES_WIN_SSH_HERMES absolute path to the remote hermes.exe under test
    +const liveHost = process.env.HERMES_WIN_SSH_HOST || ''
    +const liveUser = process.env.HERMES_WIN_SSH_USER || ''
    +const configuredHermes = process.env.HERMES_WIN_SSH_HERMES || ''
    +const ownershipId = '89abcdef0123456789abcdef01234567'
    +
    +function fetchJson(url, token, path) {
    +  return fetch(`${url}${path}`, { headers: { 'X-Hermes-Session-Token': token } }).then(async response => {
    +    if (!response.ok) {
    +      throw new Error(`${response.status}: ${await response.text()}`)
    +    }
    +
    +    return response.json()
    +  })
    +}
    +
    +test.skipIf(!liveHost || !liveUser || !configuredHermes)(
    +  'live Windows remote lifecycle spawns, authenticates, reuses, and cleans exact ownership',
    +  async () => {
    +    const ssh = new SshConnection({ host: liveHost, user: liveUser, port: 22, keyPath: '' }, { mux: true })
    +    await ssh.open()
    +
    +    const common = {
    +      ssh,
    +      ownershipId,
    +      profile: '',
    +      remoteHermesPath: configuredHermes,
    +      pickLocalPort,
    +      forward: (local, remote) => ssh.forward(local, remote),
    +      cancelForward: (local, remote) => ssh.cancelForward(local, remote),
    +      waitForHermes: async (baseUrl, token) => {
    +        for (let i = 0; i < 40; i++) {
    +          try {
    +            await fetchJson(baseUrl, token, '/api/status')
    +
    +            return
    +          } catch {
    +            void 0
    +          }
    +
    +          await new Promise(resolve => setTimeout(resolve, 250))
    +        }
    +
    +        throw new Error('status timeout')
    +      },
    +      probeReuseProof: async (baseUrl, token, nonce) => {
    +        const body: any = await fetchJson(baseUrl, token, '/api/ssh/ownership')
    +
    +        return body.sshOwnerNonce === nonce ? 'authenticated-ok' : 'authenticated-stale'
    +      },
    +      rememberLog: () => {}
    +    }
    +
    +    let first
    +    let second
    +
    +    try {
    +      first = await connectWindowsRemote(common)
    +      assert.equal(first.platform.os, 'Windows')
    +      assert.equal(first.reused, false)
    +      const status: any = await fetchJson(first.baseUrl, first.token, '/api/status')
    +      assert.ok(status)
    +      await ssh.cancelForward(first.localPort, first.remotePort)
    +      second = await connectWindowsRemote({ ...common, reuseToken: [redacted:secret-assignment] })
    +      assert.equal(second.reused, true)
    +      assert.equal(second.pid, first.pid)
    +      assert.equal(second.spawnNonce, first.spawnNonce)
    +    } finally {
    +      if (second) {
    +        await ssh.cancelForward(second.localPort, second.remotePort)
    +      }
    +
    +      const runtimeScript = `& '${configuredHermes.replace('hermes.exe', 'python.exe')}' -m hermes_cli.windows_ssh_runtime read-lock '${ownershipId}'`
    +
    +      const lock: any = JSON.parse(
    +        await ssh.exec(`powershell.exe -NoProfile -NonInteractive -Command "${runtimeScript}"`)
    +      )
    +
    +      if (lock) {
    +        const python = configuredHermes.replace('hermes.exe', 'python.exe')
    +        const terminate = `& '${python}' -m hermes_cli.windows_ssh_runtime terminate '${lock.pid}' '${lock.creationTimeNs}' '${lock.hermesPath}' '${lock.spawnNonce}'`
    +        await ssh.exec(`powershell.exe -NoProfile -NonInteractive -Command "${terminate}"`)
    +        await ssh.exec(
    +          `powershell.exe -NoProfile -NonInteractive -Command "& '${python}' -m hermes_cli.windows_ssh_runtime remove-lock '${ownershipId}'"`
    +        )
    +        await ssh.exec(
    +          `powershell.exe -NoProfile -NonInteractive -Command "& '${python}' -m hermes_cli.windows_ssh_runtime remove-log '${ownershipId}' '${lock.spawnNonce}'"`
    +        )
    +      }
    +
    +      await ssh.close()
    +    }
    +  },
    +  90_000
    +)
    ```
  - `apps/desktop/src/app/contrib/wiring.tsx`

    ```diff
    @@ -71,7 +71,9 @@ import { ModelVisibilityOverlay } from '../model-visibility-overlay'
     import { PetGenerateOverlay } from '../pet-generate/pet-generate-overlay'
     import { FileActionDialogs } from '../right-sidebar/file-actions'
     import { RemoteFolderPicker } from '../right-sidebar/files/remote-picker'
    +import { resetProjectTreeState } from '../right-sidebar/files/use-project-tree'
     import { PersistentTerminal } from '../right-sidebar/terminal/persistent'
    +import { closeAllTerminals } from '../right-sidebar/terminal/terminals'
     import { CRON_ROUTE, routeSessionId, sessionRoute, SETTINGS_ROUTE, syncWorkspaceIsPage } from '../routes'
     import { SessionPickerOverlay } from '../session-picker-overlay'
     import { SessionSwitcher } from '../session-switcher'
    ```

    ```diff
    @@ -173,6 +175,7 @@ export function ContribWiring({ children }: { children: ReactNode }) {
         openCommandCenterSection,
         openStarmap,
         profilesOpen,
    +    resetOverlayReturnRoute,
         settingsOpen,
         starmapOpen,
         toggleCommandCenter
    ```

    ```diff
    @@ -632,6 +635,12 @@ export function ContribWiring({ children }: { children: ReactNode }) {
       )
     
       useGatewayBoot({
    +    beforeConnectionSwitch: () => {
    +      startFreshSessionDraft({ preserveRoute: true, workspaceTarget: null })
    +      resetOverlayReturnRoute()
    +      resetProjectTreeState()
    +      closeAllTerminals()
    +    },
         handleGatewayEvent: handleGatewayEventWithPlugins,
         onConnectionReady: c => {
           connectionRef.current = c
    ```
  - `apps/desktop/src/app/gateway/hooks/use-gateway-boot.test.tsx`

    ```diff
    @@ -18,6 +18,7 @@ import { useGatewayBoot } from './use-gateway-boot'
     // post-boot reconnect loop.
     
     type Listener = (ev: unknown) => void
    +let connectionApplied: null | (() => void) = null
     
     // Minimal WebSocket stand-in implementing only what json-rpc-gateway.connect()
     // touches: readyState, add/removeEventListener('open'|'error'|'close'), close().
    ```

    ```diff
    @@ -97,7 +98,13 @@ function fakeDesktop() {
         })),
         onBootProgress: vi.fn(() => () => undefined),
         onBackendExit: vi.fn(() => () => undefined),
    -    onConnectionApplied: vi.fn(() => () => undefined),
    +    onConnectionApplied: vi.fn(callback => {
    +      connectionApplied = callback
    +
    +      return () => {
    +        connectionApplied = null
    +      }
    +    }),
         onPowerResume: vi.fn(() => () => undefined),
         onWindowStateChanged: vi.fn(() => () => undefined),
         touchBackend: vi.fn(async () => undefined),
    ```

    ```diff
    @@ -105,8 +112,12 @@ function fakeDesktop() {
       }
     }
     
    -function Harness({ refreshSessions }: { refreshSessions?: () => Promise<void> } = {}) {
    +function Harness({
    +  beforeConnectionSwitch = () => undefined,
    +  refreshSessions
    +}: { beforeConnectionSwitch?: () => void; refreshSessions?: () => Promise<void> } = {}) {
       useGatewayBoot({
    +    beforeConnectionSwitch,
         handleGatewayEvent: () => undefined,
         onConnectionReady: () => undefined,
         onGatewayReady: () => undefined,
    ```

    ```diff
    @@ -123,6 +134,7 @@ beforeEach(() => {
       vi.useFakeTimers()
       FakeWebSocket.mode = 'open'
       FakeWebSocket.instances = []
    +  connectionApplied = null
       ;(globalThis as { WebSocket: unknown }).WebSocket = FakeWebSocket
       ;(window as { hermesDesktop?: unknown }).hermesDesktop = fakeDesktop()
       $gatewayState.set('idle')
    ```

    ```diff
    @@ -199,6 +211,18 @@ describe('useGatewayBoot remote reconnect loop (real hook, fake socket)', () =>
         expect($desktopBoot.get().error).toBeTruthy()
       })
     
    +  it('resets the old machine context before connecting an applied gateway', async () => {
    +    const beforeConnectionSwitch = vi.fn()
    +    render(<Harness beforeConnectionSwitch={beforeConnectionSwitch} />)
    +    await flushAsync()
    +    expect(connectionApplied).not.toBeNull()
    +
    +    act(() => connectionApplied?.())
    +    expect(beforeConnectionSwitch).toHaveBeenCalledTimes(1)
    +    await flushAsync()
    +    expect($gatewayState.get()).toBe('open')
    +  })
    +
       it('a remote that drops post-boot keeps looping with NO boot.error (the dead-end CONNECTING combo)', async () => {
         render(<Harness />)
         await flushAsync()
    ```
  - `apps/desktop/src/app/gateway/hooks/use-gateway-boot.ts`

    ```diff
    @@ -48,6 +48,7 @@ import type { RpcEvent } from '@/types/hermes'
     const RECONNECT_ESCALATE_AFTER = 6
     
     interface GatewayBootOptions {
    +  beforeConnectionSwitch: () => void
       handleGatewayEvent: (event: RpcEvent) => void
       onConnectionReady: (
         connection: Awaited<ReturnType<NonNullable<typeof window.hermesDesktop>['getConnection']>> | null
    ```

    ```diff
    @@ -58,6 +59,7 @@ interface GatewayBootOptions {
     }
     
     export function useGatewayBoot({
    +  beforeConnectionSwitch,
       handleGatewayEvent,
       onConnectionReady,
       onGatewayReady,
    ```

    ```diff
    @@ -65,6 +67,7 @@ export function useGatewayBoot({
       refreshSessions
     }: GatewayBootOptions) {
       const callbacksRef = useRef({
    +    beforeConnectionSwitch,
         handleGatewayEvent,
         onConnectionReady,
         onGatewayReady,
    ```

    ```diff
    @@ -73,6 +76,7 @@ export function useGatewayBoot({
       })
     
       callbacksRef.current = {
    +    beforeConnectionSwitch,
         handleGatewayEvent,
         onConnectionReady,
         onGatewayReady,
    ```

    ```diff
    @@ -265,6 +269,7 @@ export function useGatewayBoot({
           reconnectAttempt = 0
           escalated = false
           reauthNotified = false
    +      callbacksRef.current.beforeConnectionSwitch()
           wipeSessionListsForGatewaySwitch()
     
           try {
    ```
  - `apps/desktop/src/app/session/hooks/use-session-actions.test.tsx`

    ```diff
    @@ -90,9 +90,11 @@ function storedSession(overrides: Partial<SessionInfo> = {}): SessionInfo {
     }
     
     function Harness({
    +  navigate = vi.fn(),
       onReady,
       requestGateway
     }: {
    +  navigate?: ReturnType<typeof vi.fn>
       onReady: (handle: HarnessHandle) => void
       requestGateway: <T>(method: string, params?: Record<string, unknown>) => Promise<T>
     }) {
    ```

    ```diff
    @@ -106,7 +108,7 @@ function Harness({
         ensureSessionState: () => ({}) as ClientSessionState,
         getRouteToken: () => 'token',
         getRoutedStoredSessionId: () => null,
    -    navigate: vi.fn() as never,
    +    navigate: navigate as never,
         requestGateway,
         resetViewSync: vi.fn(),
         runtimeIdByStoredSessionIdRef: ref(new Map<string, string>()),
    ```

    ```diff
    @@ -404,6 +406,25 @@ async function createWith(
       return createParams
     }
     
    +describe('startFreshSessionDraft', () => {
    +  afterEach(() => cleanup())
    +
    +  it('can reset machine-bound session state without closing the current overlay route', async () => {
    +    const navigate = vi.fn()
    +    const requestGateway = vi.fn(async () => ({}) as never)
    +    let handle: HarnessHandle | null = null
    +
    +    render(<Harness navigate={navigate} onReady={value => (handle = value)} requestGateway={requestGateway} />)
    +    await waitFor(() => expect(handle).not.toBeNull())
    +
    +    act(() => handle!.startFreshSessionDraft({ preserveRoute: true, workspaceTarget: null }))
    +
    +    expect(navigate).not.toHaveBeenCalled()
    +    expect($currentCwd.get()).toBe('')
    +    expect($newChatWorkspaceTarget.get()).toBeNull()
    +  })
    +})
    +
     describe('createBackendSessionForSend profile routing', () => {
       afterEach(() => {
         cleanup()
    ```
  - `apps/desktop/src/app/session/hooks/use-session-actions/index.ts`

    ```diff
    @@ -177,6 +177,7 @@ async function desktopSessionCreateParams(cwd: string): Promise<Record<string, u
     }
     
     interface FreshSessionDraftOptions {
    +  preserveRoute?: boolean
       replaceRoute?: boolean
       workspaceTarget?: NewChatWorkspaceTarget
     }
    ```

    ```diff
    @@ -270,6 +271,7 @@ export function useSessionActions({
       const startFreshSessionDraft = useCallback(
         (options: boolean | FreshSessionDraftOptions = false) => {
           const draftOptions = typeof options === 'boolean' ? { replaceRoute: options } : options
    +      const preserveRoute = draftOptions.preserveRoute ?? false
           const replaceRoute = draftOptions.replaceRoute ?? false
     
           const hasWorkspaceTarget =
    ```

    ```diff
    @@ -290,7 +292,11 @@ export function useSessionActions({
           // rebind race, so leaving the old id here could revive it on a very fast
           // New Chat -> Enter sequence.
           onFreshDraftRouteIntent?.()
    -      navigate(NEW_CHAT_ROUTE, { replace: replaceRoute })
    +
    +      if (!preserveRoute) {
    +        navigate(NEW_CHAT_ROUTE, { replace: replaceRoute })
    +      }
    +
           setActiveSessionId(null)
           activeSessionIdRef.current = null
           setSelectedStoredSessionId(null)
    ```
  - `apps/desktop/src/app/settings/gateway-settings.tsx`

    ```diff
    @@ -3,11 +3,24 @@ import { useEffect, useMemo, useRef, useState } from 'react'
     
     import { Button } from '@/components/ui/button'
     import { Input } from '@/components/ui/input'
    +import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'
     import { Tip } from '@/components/ui/tooltip'
     import type { DesktopAuthProvider, DesktopCloudAgent, DesktopCloudOrg, DesktopConnectionProbeResult } from '@/global'
     import { useI18n } from '@/i18n'
     import { ExternalLink } from '@/lib/external-link'
    -import { AlertCircle, Check, Cloud, FileText, Globe, HelpCircle, Loader2, LogIn, Monitor, RefreshCw } from '@/lib/icons'
    +import {
    +  AlertCircle,
    +  Check,
    +  Cloud,
    +  FileText,
    +  Globe,
    +  HelpCircle,
    +  Loader2,
    +  LogIn,
    +  Monitor,
    +  RefreshCw,
    +  Terminal
    +} from '@/lib/icons'
     import { selectableCardClass } from '@/lib/selectable-card'
     import { cn } from '@/lib/utils'
     import { notify, notifyError } from '@/store/notifications'
    ```

    ```diff
    @@ -15,8 +28,9 @@ import { $profiles, refreshActiveProfile } from '@/store/profile'
     
     import { CONTROL_TEXT } from './constants'
     import { EmptyState, ListRow, LoadingState, Pill, SettingsContent } from './primitives'
    +import { enrichSelectedSshHost, selectSshHost } from './ssh-host-selection'
     
    -type Mode = 'local' | 'remote' | 'cloud'
    +type Mode = 'local' | 'remote' | 'cloud' | 'ssh'
     type AuthMode = 'oauth' | 'token'
     type ProbeStatus = 'idle' | 'probing' | 'done' | 'error'
     // Hermes Cloud discovery lifecycle for the cloud-mode panel.
    ```

    ```diff
    @@ -31,8 +45,15 @@ interface GatewaySettingsState {
       remoteTokenSet: boolean
       remoteUrl: string
       cloudOrg: string
    +  sshHost: string
    +  sshUser: string
    +  sshPort: number | null
    +  sshKeyPath: string
    +  sshRemoteHermesPath: string
     }
     
    +const SSH_HOST_CUSTOM = '__custom__'
    +
     const EMPTY_STATE: GatewaySettingsState = {
       envOverride: false,
       mode: 'local',
    ```

    ```diff
    @@ -41,7 +62,12 @@ const EMPTY_STATE: GatewaySettingsState = {
       remoteTokenPreview: null,
       remoteTokenSet: [redacted:secret-assignment]
       remoteUrl: '',
    -  cloudOrg: ''
    +  cloudOrg: '',
    +  sshHost: '',
    +  sshUser: '',
    +  sshPort: null,
    +  sshKeyPath: '',
    +  sshRemoteHermesPath: ''
     }
     
     export function savedCloudConnectionUrl(config: Pick<GatewaySettingsState, 'mode' | 'remoteUrl'>): string {
    ```

    ```diff
    @@ -128,6 +154,14 @@ export function GatewaySettings({ embedded = false }: { embedded?: boolean } = {
       const [state, setState] = useState<GatewaySettingsState>(EMPTY_STATE)
       const [remoteToken, setRemoteToken] = useState('')
       const [lastTest, setLastTest] = useState<null | string>(null)
    +  const [sshHostSuggestions, setSshHostSuggestions] = useState<string[]>([])
    +  const [sshCustomHost, setSshCustomHost] = useState(false)
    +  const sshResolveSeq = useRef(0)
    +  const sshTestSeq = useRef(0)
    +  const saveSeq = useRef(0)
    +  const signingSeq = useRef(0)
    +  const cloudConnectSeq = useRef(0)
    +  const contextSeq = useRef(0)
       const [connectedCloudUrl, setConnectedCloudUrl] = useState('')
     
       const acceptSavedConfig = (config: GatewaySettingsState) => {
    ```

    ```diff
    @@ -337,6 +371,48 @@ export function GatewaySettings({ embedded = false }: { embedded?: boolean } = {
       // per-profile scopes are the named, non-default profiles.
       const namedProfiles = useMemo(() => profiles.filter(profile => profile.name !== 'default'), [profiles])
     
    +  useEffect(() => {
    +    // One-directional: a saved host that isn't in the suggestions must render
    +    // the free-text input (rehydration). Never force custom OFF here — that
    +    // instantly snapped the just-clicked-Custom (empty-host) input back to the
    +    // dropdown, making a raw-IP host impossible to type. The way back to the
    +    // dropdown is the input's onBlur (empty host + suggestions).
    +    if (state.sshHost && !sshHostSuggestions.includes(state.sshHost)) {
    +      setSshCustomHost(true)
    +    }
    +  }, [state.sshHost, sshHostSuggestions])
    +
    +  useEffect(() => {
    +    if (state.mode !== 'ssh' || !window.hermesDesktop?.sshConfigHosts) {
    +      return
    +    }
    +
    +    let cancelled = false
    +    void window.hermesDesktop
    +      .sshConfigHosts()
    +      .then(result => {
    +        if (!cancelled) {
    +          setSshHostSuggestions(result.hosts)
    +        }
    +      })
    +      .catch(() => {
    +        if (!cancelled) {
    +          setSshHostSuggestions([])
    +        }
    +      })
    +
    +    return () => void (cancelled = true)
    +  }, [state.mode])
    +
    +  useEffect(() => {
    +    contextSeq.current += 1
    +    sshTestSeq.current += 1
    +    saveSeq.current += 1
    +    signingSeq.current += 1
    +    cloudConnectSeq.current += 1
    +    setLastTest(null)
    +  }, [scope, state.mode, state.sshHost, state.sshUser, state.sshPort, state.sshKeyPath, state.sshRemoteHermesPath])
    +
       const oauthConnected = state.remoteOauthConnected
     
       const canUseRemote = useMemo(() => {
    ```

    ```diff
    @@ -356,10 +432,17 @@ export function GatewaySettings({ embedded = false }: { embedded?: boolean } = {
         profile: scope ?? undefined,
         remoteAuthMode: authMode,
         remoteToken: authMode === 'token' ? remoteToken.trim() || undefined : undefined,
    -    remoteUrl: trimmedUrl
    +    remoteUrl: trimmedUrl,
    +    sshHost: state.sshHost.trim(),
    +    sshUser: state.sshUser.trim() || undefined,
    +    sshPort: state.sshPort,
    +    sshKeyPath: state.sshKeyPath.trim() || undefined,
    +    sshRemoteHermesPath: state.sshRemoteHermesPath.trim()
       })
     
       const save = async (apply: boolean) => {
    +    const seq = ++saveSeq.current
    +
         if (state.mode === 'remote' && !canUseRemote) {
           notify({
             kind: 'warning',
    ```

    ```diff
    @@ -377,6 +460,10 @@ export function GatewaySettings({ embedded = false }: { embedded?: boolean } = {
             ? await window.hermesDesktop.applyConnectionConfig(payload())
             : await window.hermesDesktop.saveConnectionConfig(payload())
     
    +      if (seq !== saveSeq.current) {
    +        return
    +      }
    +
           acceptSavedConfig(next)
           setRemoteToken('')
           notify({
    ```

    ```diff
    @@ -385,9 +472,35 @@ export function GatewaySettings({ embedded = false }: { embedded?: boolean } = {
             message: apply ? g.restartingMessage : g.savedMessage
           })
         } catch (err) {
    -      notifyError(err, apply ? g.applyFailed : g.saveFailed)
    +      if (seq !== saveSeq.current) {
    +        return
    +      }
    +
    +      const sshError = err && typeof err === 'object' && 'sshError' in err ? String(err.sshError) : ''
    +
    +      const errors = {
    +        'auth-failed': g.sshErrAuth,
    +        'hermes-not-found': g.sshErrNotInstalled,
    +        'host-key-changed': g.sshErrHostKey,
    +        timeout: g.sshErrTimeout,
    +        unreachable: g.sshErrUnreachable,
    +        'unsupported-platform': g.sshErrPlatform,
    +        'update-required': g.sshErrUpdateRequired
    +      }
    +
    +      if (state.mode === 'ssh' && sshError) {
    +        notify({
    +          kind: 'error',
    +          title: apply ? g.applyFailed : g.saveFailed,
    +          message: (errors as Record<string, string>)[sshError] || g.sshErrUnknown
    +        })
    +      } else {
    +        notifyError(err, apply ? g.applyFailed : g.saveFailed)
    +      }
         } finally {
    -      setSaving(false)
    +      if (seq === saveSeq.current) {
    +        setSaving(false)
    +      }
         }
       }
     
    ```

    ```diff
    @@ -395,6 +508,8 @@ export function GatewaySettings({ embedded = false }: { embedded?: boolean } = {
       // the URL the login window needs), then open the gateway login window and
       // refresh the connection status from the saved config once it completes.
       const signIn = async () => {
    +    const seq = ++signingSeq.current
    +
         if (!trimmedUrl) {
           notify({ kind: 'warning', title: g.incompleteTitle, message: g.enterUrlFirst })
     
    ```

    ```diff
    @@ -413,10 +528,18 @@ export function GatewaySettings({ embedded = false }: { embedded?: boolean } = {
             remoteUrl: trimmedUrl
           })
     
    +      if (seq !== signingSeq.current) {
    +        return
    +      }
    +
           acceptSavedConfig(saved)
     
           const result = await window.hermesDesktop.oauthLoginConnectionConfig(trimmedUrl)
     
    +      if (seq !== signingSeq.current) {
    +        return
    +      }
    +
           if (result.connected) {
             const refreshed = await window.hermesDesktop.getConnectionConfig(scope)
             acceptSavedConfig(refreshed)
    ```

    ```diff
    @@ -429,24 +552,38 @@ export function GatewaySettings({ embedded = false }: { embedded?: boolean } = {
             })
           }
         } catch (err) {
    -      notifyError(err, g.signInFailed)
    +      if (seq === signingSeq.current) {
    +        notifyError(err, g.signInFailed)
    +      }
         } finally {
    -      setSigningIn(false)
    +      if (seq === signingSeq.current) {
    +        setSigningIn(false)
    +      }
         }
       }
     
       const signOut = async () => {
    +    const seq = ++signingSeq.current
         setSigningIn(true)
     
         try {
           await window.hermesDesktop.oauthLogoutConnectionConfig(trimmedUrl || undefined)
           const refreshed = await window.hermesDesktop.getConnectionConfig(scope)
    +
    +      if (seq !== signingSeq.current) {
    +        return
    +      }
    +
           acceptSavedConfig(refreshed)
           notify({ kind: 'success', title: g.signedOutTitle, message: g.signedOutMessage })
         } catch (err) {
    -      notifyError(err, g.signOutFailed)
    +      if (seq === signingSeq.current) {
    +        notifyError(err, g.signOutFailed)
    +      }
         } finally {
    -      setSigningIn(false)
    +      if (seq === signingSeq.current) {
    +        setSigningIn(false)
    +      }
         }
       }
     
    ```

    ```diff
    @@ -458,6 +595,7 @@ export function GatewaySettings({ embedded = false }: { embedded?: boolean } = {
       // needsOrgSelection we surface the org list and show a picker instead.
       const discoverCloud = async (org?: string) => {
         const desktop = window.hermesDesktop
    +    const seq = contextSeq.current
     
         if (!desktop?.cloud) {
           return
    ```

    ```diff
    @@ -468,6 +606,10 @@ export function GatewaySettings({ embedded = false }: { embedded?: boolean } = {
         try {
           const result = await desktop.cloud.discover(org)
     
    +      if (seq !== contextSeq.current) {
    +        return
    +      }
    +
           if ('needsOrgSelection' in result && result.needsOrgSelection) {
             // Multi-org user with no org chosen yet: show the picker. Don't clear a
             // previously-chosen org list on a refresh.
    ```

    ```diff
    @@ -495,6 +637,10 @@ export function GatewaySettings({ embedded = false }: { embedded?: boolean } = {
     
           setCloudDiscover('done')
         } catch (err) {
    +      if (seq !== contextSeq.current) {
    +        return
    +      }
    +
           setCloudAgents([])
           setCloudDiscover('error')
     
    ```

    ```diff
    @@ -579,6 +725,7 @@ export function GatewaySettings({ embedded = false }: { embedded?: boolean } = {
     
       const cloudSignIn = async () => {
         const desktop = window.hermesDesktop
    +    const seq = ++signingSeq.current
     
         if (!desktop?.cloud) {
           return
    ```

    ```diff
    @@ -588,20 +735,30 @@ export function GatewaySettings({ embedded = false }: { embedded?: boolean } = {
     
         try {
           const result = await desktop.cloud.login()
    +
    +      if (seq !== signingSeq.current) {
    +        return
    +      }
    +
           setCloudSignedIn(result.signedIn)
     
           if (result.signedIn) {
             await discoverCloud()
           }
         } catch (err) {
    -      notifyError(err, g.cloudSignInFailed)
    +      if (seq === signingSeq.current) {
    +        notifyError(err, g.cloudSignInFailed)
    +      }
         } finally {
    -      setCloudSigningIn(false)
    +      if (seq === signingSeq.current) {
    +        setCloudSigningIn(false)
    +      }
         }
       }
     
       const cloudSignOut = async () => {
         const desktop = window.hermesDesktop
    +    const seq = ++signingSeq.current
     
         if (!desktop?.cloud) {
           return
    ```

    ```diff
    @@ -611,6 +768,11 @@ export function GatewaySettings({ embedded = false }: { embedded?: boolean } = {
     
         try {
           await desktop.cloud.logout()
    +
    +      if (seq !== signingSeq.current) {
    +        return
    +      }
    +
           setCloudSignedIn(false)
           setCloudAgents([])
           setCloudOrgs([])
    ```

    ```diff
    @@ -618,9 +780,13 @@ export function GatewaySettings({ embedded = false }: { embedded?: boolean } = {
           setCloudDiscover('idle')
           notify({ kind: 'success', title: g.cloudSignedOutTitle, message: g.cloudSignedOutMessage })
         } catch (err) {
    -      notifyError(err, g.signOutFailed)
    +      if (seq === signingSeq.current) {
    +        notifyError(err, g.signOutFailed)
    +      }
         } finally {
    -      setCloudSigningIn(false)
    +      if (seq === signingSeq.current) {
    +        setCloudSigningIn(false)
    +      }
         }
       }
     
    ```

    ```diff
    @@ -628,6 +794,8 @@ export function GatewaySettings({ embedded = false }: { embedded?: boolean } = {
       // prompt — the shared portal session auto-approves), then persist a cloud-mode
       // connection pointed at its dashboardUrl and apply it (soft-reconnects in place).
       const connectCloudAgent = async (agent: DesktopCloudAgent) => {
    +    const seq = contextSeq.current
    +
         if (!agent.dashboardUrl) {
           return
         }
    ```

    ```diff
    @@ -643,6 +811,10 @@ export function GatewaySettings({ embedded = false }: { embedded?: boolean } = {
         try {
           const result = await desktop.cloud.agentSignIn(agent.dashboardUrl)
     
    +      if (seq !== contextSeq.current) {
    +        return
    +      }
    +
           if (!result.connected) {
             notify({
               kind: 'warning',
    ```

    ```diff
    @@ -665,20 +837,113 @@ export function GatewaySettings({ embedded = false }: { embedded?: boolean } = {
             cloudOrg: cloudOrgRef.current ?? undefined
           })
     
    +      if (seq !== contextSeq.current) {
    +        return
    +      }
    +
           acceptSavedConfig(next)
           notify({ kind: 'success', title: g.cloudConnectedTitle, message: g.cloudConnectedTo(agent.name) })
         } catch (err) {
    +      if (seq !== contextSeq.current) {
    +        return
    +      }
    +
           if (err && typeof err === 'object' && 'needsCloudLogin' in err) {
             setCloudSignedIn(false)
           }
     
           notifyError(err, g.cloudConnectFailed)
         } finally {
    -      setCloudConnectingId(null)
    +      if (seq === contextSeq.current) {
    +        setCloudConnectingId(null)
    +      }
    +    }
    +  }
    +
    +  const resolveSshHost = async (host: string) => {
    +    if (!host || !window.hermesDesktop?.sshResolveHost) {
    +      return
    +    }
    +
    +    const seq = ++sshResolveSeq.current
    +
    +    try {
    +      const resolved = await window.hermesDesktop.sshResolveHost(host)
    +
    +      if (seq !== sshResolveSeq.current) {
    +        return
    +      }
    +
    +      setState(current => enrichSelectedSshHost(current, host, resolved))
    +    } catch {
    +      return
    +    }
    +  }
    +
    +  const selectHost = (value: string) => {
    +    if (value === SSH_HOST_CUSTOM) {
    +      setSshCustomHost(true)
    +      setState(current => selectSshHost(current, ''))
    +
    +      return
    +    }
    +
    +    setSshCustomHost(false)
    +    setState(current => selectSshHost(current, value))
    +    void resolveSshHost(value)
    +  }
    +
    +  const testSsh = async () => {
    +    const seq = ++sshTestSeq.current
    +
    +    if (!state.sshHost.trim()) {
    +      notify({ kind: 'warning', title: g.incompleteTitle, message: g.sshIncompleteHost })
    +
    +      return
    +    }
    +
    +    setTesting(true)
    +    setLastTest(null)
    +
    +    try {
    +      const result = await window.hermesDesktop.testConnectionConfig(payload())
    +
    +      if (seq !== sshTestSeq.current) {
    +        return
    +      }
    +
    +      if (!result.reachable) {
    +        const errors = {
    +          'auth-failed': g.sshErrAuth,
    +          'hermes-not-found': g.sshErrNotInstalled,
    +          'host-key-changed': g.sshErrHostKey,
    +          timeout: g.sshErrTimeout,
    +          unreachable: g.sshErrUnreachable,
    +          'unsupported-platform': g.sshErrPlatform,
    +          'update-required': g.sshErrUpdateRequired,
    +          unknown: g.sshErrUnknown
    +        }
    +
    +        throw new Error(errors[result.sshError || 'unknown'] || result.error || g.sshErrUnknown)
    +      }
    +
    +      const message = g.sshReachable(result.host || state.sshHost, result.remotePlatform || '?')
    +      setLastTest(message)
    +      notify({ kind: 'success', title: g.reachableTitle, message })
    +    } catch (err) {
    +      if (seq === sshTestSeq.current) {
    +        notifyError(err, g.testFailed)
    +      }
    +    } finally {
    +      if (seq === sshTestSeq.current) {
    +        setTesting(false)
    +      }
         }
       }
     
       const testRemote = async () => {
    +    const seq = ++sshTestSeq.current
    +
         if (!canUseRemote) {
           notify({
             kind: 'warning',
    ```

    ```diff
    @@ -701,13 +966,21 @@ export function GatewaySettings({ embedded = false }: { embedded?: boolean } = {
             remoteUrl: trimmedUrl
           })
     
    -      const message = g.connectedTo(result.baseUrl, result.version ?? undefined)
    +      if (seq !== sshTestSeq.current) {
    +        return
    +      }
    +
    +      const message = g.connectedTo(result.baseUrl || trimmedUrl, result.version ?? undefined)
           setLastTest(message)
           notify({ kind: 'success', title: g.reachableTitle, message })
         } catch (err) {
    -      notifyError(err, g.testFailed)
    +      if (seq === sshTestSeq.current) {
    +        notifyError(err, g.testFailed)
    +      }
         } finally {
    -      setTesting(false)
    +      if (seq === sshTestSeq.current) {
    +        setTesting(false)
    +      }
         }
       }
     
    ```

    ```diff
    @@ -770,7 +1043,7 @@ export function GatewaySettings({ embedded = false }: { embedded?: boolean } = {
             <div className="text-[length:var(--conversation-caption-font-size)] font-medium text-(--ui-text-secondary)">
               {g.modeTitle}
             </div>
    -        <div className="grid auto-rows-fr grid-cols-1 gap-2 min-[42rem]:grid-cols-3">
    +        <div className="grid auto-rows-fr grid-cols-1 gap-2 sm:grid-cols-2 min-[72rem]:grid-cols-4">
               <ModeCard
                 active={state.mode === 'local'}
                 description={g.localDesc}
    ```

    ```diff
    @@ -796,6 +1069,15 @@ export function GatewaySettings({ embedded = false }: { embedded?: boolean } = {
                 onSelect={() => setState(current => ({ ...current, mode: 'remote' }))}
                 title={g.remoteTitle}
               />
    +          <ModeCard
    +            active={state.mode === 'ssh'}
    +            description={g.sshDesc}
    +            disabled={state.envOverride}
    +            hint={g.sshTrustHint}
    +            icon={Terminal}
    +            onSelect={() => setState(current => ({ ...current, mode: 'ssh' }))}
    +            title={g.sshTitle}
    +          />
             </div>
           </div>
     
    ```

    ```diff
    @@ -1033,6 +1315,109 @@ export function GatewaySettings({ embedded = false }: { embedded?: boolean } = {
             </div>
           ) : null}
     
    +      {state.mode === 'ssh' && !state.envOverride ? (
    +        <div className="mt-5 grid gap-1">
    +          {sshHostSuggestions.length > 0 && !sshCustomHost ? (
    +            <ListRow
    +              action={
    +                <Select
    +                  onValueChange={selectHost}
    +                  value={sshHostSuggestions.includes(state.sshHost) ? state.sshHost : SSH_HOST_CUSTOM}
    +                >
    +                  <SelectTrigger className={cn('h-8', CONTROL_TEXT)}>
    +                    <SelectValue placeholder={g.sshHostPick} />
    +                  </SelectTrigger>
    +                  <SelectContent>
    +                    {sshHostSuggestions.map(host => (
    +                      <SelectItem key={host} value={host}>
    +                        {host}
    +                      </SelectItem>
    +                    ))}
    +                    <SelectItem value={SSH_HOST_CUSTOM}>{g.sshHostCustom}</SelectItem>
    +                  </SelectContent>
    +                </Select>
    +              }
    +              description={g.sshHostPickDesc}
    +              title={g.sshHostPickTitle}
    +            />
    +          ) : (
    +            <ListRow
    +              action={
    +                <Input
    +                  autoFocus={sshCustomHost}
    +                  className={cn('h-8', CONTROL_TEXT)}
    +                  onBlur={() => {
    +                    // Empty host on blur with suggestions available = the user backed
    +                    // out of Custom; return to the dropdown.
    +                    if (!state.sshHost.trim() && sshHostSuggestions.length > 0) {
    +                      setSshCustomHost(false)
    +
    +                      return
    +                    }
    +
    +                    void resolveSshHost(state.sshHost)
    +                  }}
    +                  onChange={event => setState(current => selectSshHost(current, event.target.value))}
    +                  value={state.sshHost}
    +                />
    +              }
    +              description={g.sshHostDesc}
    +              title={g.sshHostTitle}
    +            />
    +          )}
    +          <ListRow
    +            action={
    +              <Input
    +                className={cn('h-8', CONTROL_TEXT)}
    +                onChange={event => setState(current => ({ ...current, sshUser: event.target.value }))}
    +                placeholder={g.sshUserPlaceholder}
    +                value={state.sshUser}
    +              />
    +            }
    +            description={g.sshUserDesc}
    +            title={g.sshUserTitle}
    +          />
    +          <ListRow
    +            action={
    +              <Input
    +                className={cn('h-8', CONTROL_TEXT)}
    +                inputMode="numeric"
    +                onChange={event =>
    +                  setState(current => ({ ...current, sshPort: event.target.value ? Number(event.target.value) : null }))
    +                }
    +                placeholder="22"
    +                value={state.sshPort ?? ''}
    +              />
    +            }
    +            description={g.sshPortDesc}
    +            title={g.sshPortTitle}
    +          />
    +          <ListRow
    +            action={
    +              <Input
    +                className={cn('h-8 font-mono', CONTROL_TEXT)}
    +                onChange={event => setState(current => ({ ...current, sshKeyPath: event.target.value }))}
    +                value={state.sshKeyPath}
    +              />
    +            }
    +            description={g.sshKeyDesc}
    +            title={g.sshKeyTitle}
    +          />
    +          <ListRow
    +            action={
    +              <Input
    +                className={cn('h-8 font-mono', CONTROL_TEXT)}
    +                onChange={event => setState(current => ({ ...current, sshRemoteHermesPath: event.target.value }))}
    +                placeholder={g.sshHermesPathPlaceholder}
    +                value={state.sshRemoteHermesPath}
    +              />
    +            }
    +            description={g.sshHermesPathDesc}
    +            title={g.sshHermesPathTitle}
    +          />
    +        </div>
    +      ) : null}
    +
           {lastTest ? <div className="mt-4 text-xs text-primary">{lastTest}</div> : null}
     
           {/* Test/Save apply to local + remote. Cloud connects via the agent picker
    ```

    ```diff
    @@ -1051,6 +1436,17 @@ export function GatewaySettings({ embedded = false }: { embedded?: boolean } = {
                   {testing ? <Loader2 className="animate-spin" /> : null}
                   {g.testRemote}
                 </Button>
    +          ) : state.mode === 'ssh' ? (
    +            <Button
    +              className="mr-auto"
    +              disabled={testing || !state.sshHost.trim()}
    +              onClick={() => void testSsh()}
    +              size="sm"
    +              variant="text"
    +            >
    +              {testing ? <Loader2 className="animate-spin" /> : null}
    +              {g.sshTestConnection}
    +            </Button>
               ) : null}
               {embedded ? null : (
                 <Button
    ```
  - `apps/desktop/src/app/settings/ssh-host-selection.test.ts`

    ```diff
    @@ -0,0 +1,46 @@
    +import { describe, expect, it } from 'vitest'
    +
    +import { enrichSelectedSshHost, selectSshHost } from './ssh-host-selection'
    +
    +const state = {
    +  mode: 'ssh',
    +  sshHost: 'linux-box',
    +  sshUser: 'operator',
    +  sshPort: 2222,
    +  sshKeyPath: '/keys/linux',
    +  sshRemoteHermesPath: '/opt/hermes'
    +}
    +
    +describe('selectSshHost', () => {
    +  it('clears host-specific fields when the selected host changes', () => {
    +    expect(selectSshHost(state, 'mac-box')).toEqual({
    +      mode: 'ssh',
    +      sshHost: 'mac-box',
    +      sshUser: '',
    +      sshPort: null,
    +      sshKeyPath: '',
    +      sshRemoteHermesPath: ''
    +    })
    +  })
    +
    +  it('preserves state when reselecting the same host', () => {
    +    expect(selectSshHost(state, state.sshHost)).toBe(state)
    +  })
    +
    +  it('enriches only the host that produced the ssh config result', () => {
    +    const selected = selectSshHost(state, 'mac-box')
    +    expect(
    +      enrichSelectedSshHost(selected, 'mac-box', {
    +        identityFile: '~/.ssh/id_ed25519',
    +        port: 22,
    +        user: 'hermes'
    +      })
    +    ).toMatchObject({
    +      sshHost: 'mac-box',
    +      sshUser: 'hermes',
    +      sshPort: null,
    +      sshKeyPath: '~/.ssh/id_ed25519'
    +    })
    +    expect(enrichSelectedSshHost(state, 'mac-box', { user: 'wrong' })).toBe(state)
    +  })
    +})
    ```
  - `apps/desktop/src/app/settings/ssh-host-selection.ts`

    ```diff
    @@ -0,0 +1,43 @@
    +type SshHostState = {
    +  sshHost: string
    +  sshUser: string
    +  sshPort: number | null
    +  sshKeyPath: string
    +  sshRemoteHermesPath: string
    +}
    +
    +type ResolvedSshHost = {
    +  identityFile?: string | null
    +  port?: number | null
    +  user?: string | null
    +}
    +
    +function selectSshHost<T extends SshHostState>(state: T, host: string): T {
    +  if (host === state.sshHost) {
    +    return state
    +  }
    +
    +  return {
    +    ...state,
    +    sshHost: host,
    +    sshUser: '',
    +    sshPort: null,
    +    sshKeyPath: '',
    +    sshRemoteHermesPath: ''
    +  }
    +}
    +
    +function enrichSelectedSshHost<T extends SshHostState>(state: T, host: string, resolved: ResolvedSshHost): T {
    +  if (state.sshHost !== host) {
    +    return state
    +  }
    +
    +  return {
    +    ...state,
    +    sshUser: state.sshUser || resolved.user || '',
    +    sshPort: state.sshPort ?? (resolved.port === 22 ? null : (resolved.port ?? null)),
    +    sshKeyPath: state.sshKeyPath || resolved.identityFile || ''
    +  }
    +}
    +
    +export { enrichSelectedSshHost, selectSshHost }
    ```
  - `apps/desktop/src/app/shell/hooks/use-overlay-routing.ts`

    ```diff
    @@ -47,6 +47,10 @@ export function useOverlayRouting() {
         [navigate]
       )
     
    +  const resetOverlayReturnRoute = useCallback(() => {
    +    returnPathRef.current = NEW_CHAT_ROUTE
    +  }, [])
    +
       const closeOverlayToPreviousRoute = useCallback(
         () => navigate(returnPathRef.current || NEW_CHAT_ROUTE, { replace: true }),
         [navigate]
    ```

    ```diff
    @@ -75,6 +79,7 @@ export function useOverlayRouting() {
         openCommandCenterSection,
         openStarmap,
         profilesOpen,
    +    resetOverlayReturnRoute,
         settingsOpen,
         starmapOpen,
         toggleCommandCenter
    ```
  - `apps/desktop/src/app/shell/hooks/use-statusbar-items.tsx`

    ```diff
    @@ -42,7 +42,7 @@ import {
     } from '@/store/updates'
     import type { StatusResponse } from '@/types/hermes'
     
    -import { CRON_ROUTE } from '../../routes'
    +import { CRON_ROUTE, SETTINGS_ROUTE } from '../../routes'
     import type { StatusbarItem } from '../statusbar-controls'
     
     const EMPTY_USAGE = { calls: 0, input: 0, output: 0, total: 0 } as const
    ```

    ```diff
    @@ -289,8 +289,38 @@ export function useStatusbarItems({
         copy
       ])
     
    +  const connectionItem = useMemo<StatusbarItem | null>(() => {
    +    if (connection?.mode !== 'remote' || !connection.remoteHost) {
    +      return null
    +    }
    +
    +    const ssh = connection.remoteKind === 'ssh'
    +    const cloud = connection.remoteKind === 'cloud'
    +
    +    return {
    +      className: cn(
    +        'px-2 -ml-1 font-medium',
    +        ssh ? 'bg-primary text-primary-foreground' : 'bg-accent text-accent-foreground'
    +      ),
    +      icon: <Terminal className="size-3" />,
    +      id: 'connection',
    +      label: ssh
    +        ? copy.connectionSsh(connection.remoteHost)
    +        : cloud
    +          ? copy.connectionCloud(connection.remoteHost)
    +          : copy.connectionRemote(connection.remoteHost),
    +      title: ssh
    +        ? copy.connectionSshTooltip(connection.remoteHost)
    +        : cloud
    +          ? copy.connectionCloudTooltip(connection.remoteHost)
    +          : copy.connectionRemoteTooltip(connection.remoteHost),
    +      to: `${SETTINGS_ROUTE}?tab=gateway`
    +    }
    +  }, [connection?.mode, connection?.remoteHost, connection?.remoteKind, copy])
    +
       const coreLeftStatusbarItems = useMemo<readonly StatusbarItem[]>(
         () => [
    +      ...(connectionItem ? [connectionItem] : []),
           {
             className: `w-7 justify-center px-0${commandCenterOpen ? ' bg-accent/55 text-foreground' : ''}`,
             icon: <Command className="size-3.5" />,
    ```

    ```diff
    @@ -386,6 +416,7 @@ export function useStatusbarItems({
         [
           agentsOpen,
           commandCenterOpen,
    +      connectionItem,
           copy,
           currentCwd,
           fileMenu.copyPath,
    ```
  - `apps/desktop/src/components/boot-failure-overlay.tsx`

    ```diff
    @@ -13,7 +13,13 @@ import { notify, notifyError } from '@/store/notifications'
     import { $desktopOnboarding } from '@/store/onboarding'
     
     import type { RemoteReauth } from './boot-failure-reauth'
    -import { deriveProviderShape, isRemoteConfig, isRemoteReauthFailure, signInLabel } from './boot-failure-reauth'
    +import {
    +  deriveProviderShape,
    +  isRemoteConfig,
    +  isRemoteReauthFailure,
    +  signInLabel,
    +  sshFailureMessage
    +} from './boot-failure-reauth'
     
     // The recovery "Gateway settings" view embeds the real Settings → Gateway panel
     // (identical URL/auth/test/save controls — no parallel form to drift). Lazy so
    ```

    ```diff
    @@ -44,6 +50,7 @@ export function BootFailureOverlay() {
       const [logs, setLogs] = useState<string[]>([])
       const [showLogs, setShowLogs] = useState(false)
       const [remoteReauth, setRemoteReauth] = useState<RemoteReauth | null>(null)
    +  const [connectionConfig, setConnectionConfig] = useState<DesktopConnectionConfig | null>(null)
       // A remote/cloud backend that failed to boot is fixable from gateway settings,
       // so the escape hatch earns emphasis (local failures keep it as a quiet ghost).
       const [remoteFailure, setRemoteFailure] = useState(false)
    ```

    ```diff
    @@ -75,6 +82,7 @@ export function BootFailureOverlay() {
       useEffect(() => {
         if (!visible) {
           setRemoteReauth(null)
    +      setConnectionConfig(null)
           setRemoteFailure(false)
           setView('recovery')
     
    ```

    ```diff
    @@ -102,6 +110,7 @@ export function BootFailureOverlay() {
             return
           }
     
    +      setConnectionConfig(config)
           setRemoteFailure(isRemoteConfig(config))
     
           if (!isRemoteReauthFailure(config, boot.error)) {
    ```

    ```diff
    @@ -314,7 +323,7 @@ export function BootFailureOverlay() {
     
             <div className="grid gap-4 p-5 pt-0">
               <div className="rounded-2xl border border-destructive/30 bg-destructive/10 px-4 py-3 text-xs text-destructive">
    -            {boot.error}
    +            {sshFailureMessage(connectionConfig, boot.error, t.settings.gateway)}
               </div>
     
               <div className="grid gap-2">
    ```
  - `apps/desktop/src/components/boot-failure-reauth.test.ts`

    ```diff
    @@ -7,7 +7,8 @@ import {
       isRemoteConfig,
       isRemoteReauthError,
       isRemoteReauthFailure,
    -  signInLabel
    +  signInLabel,
    +  sshFailureMessage
     } from './boot-failure-reauth'
     
     function config(overrides: Partial<DesktopConnectionConfig> = {}): DesktopConnectionConfig {
    ```

    ```diff
    @@ -21,6 +22,11 @@ function config(overrides: Partial<DesktopConnectionConfig> = {}): DesktopConnec
         remoteTokenSet: [redacted:secret-assignment]
         remoteUrl: 'https://box:9119',
         cloudOrg: '',
    +    sshHost: '',
    +    sshUser: '',
    +    sshPort: null,
    +    sshKeyPath: '',
    +    sshRemoteHermesPath: '',
         ...overrides
       }
     }
    ```

    ```diff
    @@ -31,8 +37,20 @@ describe('isRemoteConfig', () => {
         expect(isRemoteConfig(config({ mode: 'cloud', remoteOauthConnected: true }))).toBe(true)
       })
     
    -  it('false for local, for a remote with no URL, and for nullish', () => {
    +  it('recognizes SSH as remote recovery without treating it as OAuth reauth', () => {
    +    const ssh = config({ mode: 'ssh' as never, remoteUrl: '', remoteAuthMode: 'token' }) as DesktopConnectionConfig & {
    +      sshHost: string
    +    }
    +
    +    ssh.sshHost = 'remote-box'
    +
    +    expect(isRemoteConfig(ssh)).toBe(true)
    +    expect(isRemoteReauthFailure(ssh, 'SSH authentication failed.')).toBe(false)
    +  })
    +
    +  it('false for local, incomplete SSH, a remote with no URL, and nullish', () => {
         expect(isRemoteConfig(config({ mode: 'local' }))).toBe(false)
    +    expect(isRemoteConfig(config({ mode: 'ssh' as never, remoteUrl: '' }))).toBe(false)
         expect(isRemoteConfig(config({ remoteUrl: '' }))).toBe(false)
         expect(isRemoteConfig(null)).toBe(false)
       })
    ```

    ```diff
    @@ -93,6 +111,16 @@ describe('isRemoteReauthError', () => {
       })
     })
     
    +describe('sshFailureMessage', () => {
    +  it('localizes SSH failures without changing non-SSH errors', () => {
    +    const copy = { sshErrAuth: 'localized auth', sshErrUnknown: 'localized unknown' }
    +    const ssh = config({ mode: 'ssh', sshHost: 'box', remoteUrl: '' })
    +    expect(sshFailureMessage(ssh, 'SSH authentication failed', copy)).toBe('localized auth')
    +    expect(sshFailureMessage(ssh, 'unexpected failure', copy)).toBe('localized unknown')
    +    expect(sshFailureMessage(config(), 'raw remote error', copy)).toBe('raw remote error')
    +  })
    +})
    +
     describe('deriveProviderShape', () => {
       it('generic copy when there are no providers', () => {
         expect(deriveProviderShape([])).toEqual({ isPassword: [redacted:secret-assignment] providerLabel: 'your identity provider' })
    ```
  - `apps/desktop/src/components/boot-failure-reauth.ts`

    ```diff
    @@ -31,7 +31,16 @@ const DEFAULT_SIGN_IN_COPY: SignInCopy = {
     // Gateway (edit URL / token / sign in) — the local Retry/Repair buttons target
     // the bundled backend and can't help. Drives the escape-hatch emphasis.
     export function isRemoteConfig(config: DesktopConnectionConfig | null | undefined): boolean {
    -  return Boolean(config && (config.mode === 'remote' || config.mode === 'cloud') && config.remoteUrl)
    +  if (!config) {
    +    return false
    +  }
    +
    +  const ssh = config as DesktopConnectionConfig & { sshHost?: string }
    +
    +  return (
    +    ((config.mode === 'remote' || config.mode === 'cloud') && Boolean(config.remoteUrl)) ||
    +    ((config.mode as string) === 'ssh' && Boolean(ssh.sshHost))
    +  )
     }
     
     // True when a boot error is auth-shaped — the refresh token was rejected or the
    ```

    ```diff
    @@ -55,6 +64,59 @@ export function isRemoteReauthError(error: string | null | undefined): boolean {
     // — see isRemoteReauthError). Only re-establishing the remote session fixes it;
     // the local Retry/Repair buttons can't. 'cloud' counts as remote (it resolves to
     // a remote oauth backend), so a lapsed cloud session is the same failure.
    +export function sshFailureMessage(
    +  config: DesktopConnectionConfig | null | undefined,
    +  error: string | null | undefined,
    +  copy: {
    +    sshErrAuth?: string
    +    sshErrHostKey?: string
    +    sshErrNotInstalled?: string
    +    sshErrPlatform?: string
    +    sshErrTimeout?: string
    +    sshErrUpdateRequired?: string
    +    sshErrUnreachable?: string
    +    sshErrUnknown?: string
    +  }
    +): string {
    +  const raw = String(error || '')
    +
    +  if (config?.mode !== 'ssh') {
    +    return raw
    +  }
    +
    +  const text = raw.toLowerCase()
    +
    +  if (text.includes('host key')) {
    +    return copy.sshErrHostKey || raw
    +  }
    +
    +  if (text.includes('auth')) {
    +    return copy.sshErrAuth || raw
    +  }
    +
    +  if (text.includes('not installed') || text.includes('not found')) {
    +    return copy.sshErrNotInstalled || raw
    +  }
    +
    +  if (text.includes('unsupported')) {
    +    return copy.sshErrPlatform || raw
    +  }
    +
    +  if (text.includes('timed out') || text.includes('timeout')) {
    +    return copy.sshErrTimeout || raw
    +  }
    +
    +  if (text.includes('update')) {
    +    return copy.sshErrUpdateRequired || raw
    +  }
    +
    +  if (text.includes('unreachable') || text.includes('could not reach')) {
    +    return copy.sshErrUnreachable || raw
    +  }
    +
    +  return copy.sshErrUnknown || raw
    +}
    +
     export function isRemoteReauthFailure(
       config: DesktopConnectionConfig | null | undefined,
       error?: string | null
    ```
  - `apps/desktop/src/global.d.ts`

    ```diff
    @@ -60,6 +60,8 @@ declare global {
           saveConnectionConfig: (payload: DesktopConnectionConfigInput) => Promise<DesktopConnectionConfig>
           applyConnectionConfig: (payload: DesktopConnectionConfigInput) => Promise<DesktopConnectionConfig>
           testConnectionConfig: (payload: DesktopConnectionConfigInput) => Promise<DesktopConnectionTestResult>
    +      sshConfigHosts: () => Promise<DesktopSshHostsResult>
    +      sshResolveHost: (host: string) => Promise<DesktopSshResolveResult>
           probeConnectionConfig: (remoteUrl: string) => Promise<DesktopConnectionProbeResult>
           oauthLoginConnectionConfig: (remoteUrl: string) => Promise<DesktopOauthLoginResult>
           oauthLogoutConnectionConfig: (remoteUrl?: string) => Promise<DesktopOauthLogoutResult>
    ```

    ```diff
    @@ -395,6 +397,10 @@ export interface HermesConnection {
       // (cloud-auto-discovery Q3/Q6), so this never carries 'cloud'.
       mode?: 'local' | 'remote'
       authMode?: 'oauth' | 'token'
    +  remoteHost?: string
    +  remoteIdentity?: string
    +  remoteKind?: 'cloud' | 'ssh' | 'url'
    +  remoteHermesVersion?: string
       nativeOverlayWidth: number
       source?: 'env' | 'local' | 'settings'
       token: string
    ```

    ```diff
    @@ -430,7 +436,7 @@ export interface DesktopConnectionConfig {
       // remoteAuthMode 'oauth') but is remembered as cloud so settings reopens into
       // the cloud picker. Resolution treats cloud exactly as remote
       // (cloud-auto-discovery Q3/Q6).
    -  mode: 'local' | 'remote' | 'cloud'
    +  mode: 'local' | 'remote' | 'cloud' | 'ssh'
       // The profile this config describes, or null for the global/default
       // connection. Per-profile entries let a profile point at its own backend.
       profile: null | string
    ```

    ```diff
    @@ -443,10 +449,15 @@ export interface DesktopConnectionConfig {
       // connected instance was discovered under, so Settings → Gateway can reopen
       // into that org. Empty string for remote/local.
       cloudOrg: string
    +  sshHost: string
    +  sshUser: string
    +  sshPort: number | null
    +  sshKeyPath: string
    +  sshRemoteHermesPath: string
     }
     
     export interface DesktopConnectionConfigInput {
    -  mode: 'local' | 'remote' | 'cloud'
    +  mode: 'local' | 'remote' | 'cloud' | 'ssh'
       // When set, the save/apply/test targets this profile's per-profile remote
       // override instead of the global connection.
       profile?: null | string
    ```

    ```diff
    @@ -456,12 +467,44 @@ export interface DesktopConnectionConfigInput {
       // For a 'cloud' connection: the selected Hermes Cloud org (slug or id) to
       // persist so Settings can reopen into it. Ignored for remote/local modes.
       cloudOrg?: string
    +  sshHost?: string
    +  sshUser?: string
    +  sshPort?: number | null
    +  sshKeyPath?: string
    +  sshRemoteHermesPath?: string
     }
     
     export interface DesktopConnectionTestResult {
    -  baseUrl: string
    -  ok: boolean
    -  version: string | null
    +  baseUrl?: string
    +  ok?: boolean
    +  version?: string | null
    +  reachable?: boolean
    +  sshError?:
    +    | 'auth-failed'
    +    | 'hermes-not-found'
    +    | 'host-key-changed'
    +    | 'timeout'
    +    | 'unreachable'
    +    | 'unsupported-platform'
    +    | 'update-required'
    +    | 'unknown'
    +    | null
    +  error?: string | null
    +  host?: string
    +  remoteHermesPath?: string
    +  remoteHermesVersion?: string
    +  remotePlatform?: string
    +}
    +
    +export interface DesktopSshResolveResult {
    +  hostname: string | null
    +  identityFile: string | null
    +  port: number | null
    +  user: string | null
    +}
    +
    +export interface DesktopSshHostsResult {
    +  hosts: string[]
     }
     
     export interface DesktopAuthProvider {
    ```
  - `apps/desktop/src/i18n/en.ts`

    ```diff
    @@ -645,7 +645,44 @@ export const en: Translations = {
           signOutFailed: 'Sign-out failed',
           testFailed: 'Remote gateway test failed',
           applyFailed: 'Could not apply gateway settings',
    -      saveFailed: 'Could not save gateway settings'
    +      saveFailed: 'Could not save gateway settings',
    +      sshTitle: 'Connect via SSH',
    +      sshDesc:
    +        'Hermes is launched on the remote over SSH and tunneled to this app — nothing to start or expose yourself. Requires working key-based SSH access to the host.',
    +      sshTrustHint: 'The first presented host key is trusted and pinned; later changes fail closed.',
    +      sshHostTitle: 'Host',
    +      sshHostDesc: 'user@host, or a Host alias from ~/.ssh/config.',
    +      sshHostPick: 'Select a host…',
    +      sshHostPickTitle: 'Host',
    +      sshHostPickDesc: 'A Host alias from ~/.ssh/config, or Custom to type one.',
    +      sshHostCustom: 'Custom (enter manually)…',
    +      sshUserTitle: 'User',
    +      sshUserDesc: 'Blank = ~/.ssh/config or your current user.',
    +      sshUserPlaceholder: 'from ~/.ssh/config',
    +      sshPortTitle: 'Port',
    +      sshPortDesc: 'Blank = 22 or the ~/.ssh/config port.',
    +      sshKeyTitle: 'Identity file',
    +      sshKeyDesc: 'Private key path. Blank = ssh-agent or ~/.ssh/config.',
    +      sshHermesPathTitle: 'Hermes path (optional)',
    +      sshHermesPathDesc: 'Full path to the remote hermes binary. Blank = auto-detect.',
    +      sshHermesPathPlaceholder: 'auto-detect',
    +      sshTestConnection: 'Test SSH',
    +      sshConnect: 'Connect',
    +      sshButtonsHint: 'Save applies on the next launch. Connect reconnects now.',
    +      sshReachable: (host, platform) => `Reachable: ${host} (${platform}) — Hermes found`,
    +      sshIncompleteHost: 'Enter an SSH host before connecting.',
    +      sshErrUnreachable: 'Could not reach that host over SSH. Check the host, port, and your network.',
    +      sshErrAuth:
    +        'SSH authentication failed. Load your key into the ssh-agent (ssh-add) or set an IdentityFile in ~/.ssh/config — Hermes runs ssh non-interactively.',
    +      sshErrHostKey:
    +        'The host key has CHANGED since you last connected. Verify this is expected, then run ssh-keygen -R <host> and reconnect.',
    +      sshErrNotInstalled:
    +        'Hermes is not installed on the remote host. Install it there (curl -fsSL https://hermes-agent.nousresearch.com/install.sh | sh) or set the Hermes path.',
    +      sshErrPlatform:
    +        'Unsupported remote platform. Hermes Desktop SSH mode supports Linux, macOS, and Windows remote hosts.',
    +      sshErrTimeout: 'SSH connection timed out. The host may be unreachable or asleep.',
    +      sshErrUpdateRequired: 'Update Hermes on the remote host before connecting with Desktop SSH.',
    +      sshErrUnknown: 'SSH connection failed.'
         },
         keys: {
           loading: 'Loading API keys and credentials...',
    ```

    ```diff
    @@ -2169,6 +2206,12 @@ export const en: Translations = {
           desktopVersion: version => `Hermes Desktop v${version}`,
           backendVersion: version => `Backend v${version}`,
           clientLabel: version => `client v${version}`,
    +      connectionSsh: host => `SSH: ${host}`,
    +      connectionRemote: host => `Remote: ${host}`,
    +      connectionCloud: host => `Cloud: ${host}`,
    +      connectionCloudTooltip: host => `Connected to Hermes Cloud at ${host} · click to manage`,
    +      connectionSshTooltip: host => `Connected over SSH to ${host} · click to manage`,
    +      connectionRemoteTooltip: host => `Connected to remote backend ${host} · click to manage`,
           backendLabel: version => `backend v${version}`,
           commit: sha => `commit ${sha}`,
           branch: branch => `branch ${branch}`,
    ```
  - `apps/desktop/src/i18n/ja.ts`

    ```diff
    @@ -717,7 +717,44 @@ export const ja = defineLocale({
           signOutFailed: 'サインアウトに失敗しました',
           testFailed: 'リモートゲートウェイのテストに失敗しました',
           applyFailed: 'ゲートウェイ設定を適用できませんでした',
    -      saveFailed: 'ゲートウェイ設定を保存できませんでした'
    +      saveFailed: 'ゲートウェイ設定を保存できませんでした',
    +      sshTitle: 'SSH で接続',
    +      sshDesc:
    +        'Hermes は SSH 経由でリモート上に起動され、このアプリにトンネルされます。リモート側で何かを起動・公開する必要はありません。ホストへの鍵ベースの SSH アクセスが前提です。',
    +      sshTrustHint: '初回に提示されたホスト鍵を信頼して固定し、以後の変更は拒否します。',
    +      sshHostTitle: 'ホスト',
    +      sshHostDesc: 'user@host、または ~/.ssh/config の Host エイリアス。',
    +      sshHostPick: 'ホストを選択…',
    +      sshHostPickTitle: 'ホスト',
    +      sshHostPickDesc: '~/.ssh/config の Host エイリアス、または「カスタム」で手入力。',
    +      sshHostCustom: 'カスタム（手入力）…',
    +      sshUserTitle: 'ユーザー',
    +      sshUserDesc: '空欄 = ~/.ssh/config または現在のユーザー。',
    +      sshUserPlaceholder: '~/.ssh/config から',
    +      sshPortTitle: 'ポート',
    +      sshPortDesc: '空欄 = 22 または ~/.ssh/config のポート。',
    +      sshKeyTitle: '鍵ファイル',
    +      sshKeyDesc: '秘密鍵のパス。空欄 = ssh-agent または ~/.ssh/config。',
    +      sshHermesPathTitle: 'Hermes パス（任意）',
    +      sshHermesPathDesc: 'リモートの hermes バイナリへのフルパス。空欄 = 自動検出。',
    +      sshHermesPathPlaceholder: '自動検出',
    +      sshTestConnection: 'SSH をテスト',
    +      sshConnect: '接続',
    +      sshButtonsHint: '「保存」は次回起動時に適用され、「接続」は今すぐ再接続します。',
    +      sshReachable: (host, platform) => `接続可能: ${host}（${platform}）— Hermes を検出`,
    +      sshIncompleteHost: '接続する前に SSH ホストを入力してください。',
    +      sshErrUnreachable: 'SSH でそのホストに到達できませんでした。ホスト、ポート、ネットワークを確認してください。',
    +      sshErrAuth:
    +        'SSH 認証に失敗しました。鍵を ssh-agent に読み込む（ssh-add）か、~/.ssh/config に IdentityFile を設定してください。Hermes は非対話的に ssh を実行します。',
    +      sshErrHostKey:
    +        '前回の接続以降、ホスト鍵が変更されています。想定どおりか確認し、ssh-keygen -R <host> を実行してから再接続してください。',
    +      sshErrNotInstalled:
    +        'リモートホストに Hermes がインストールされていません。リモートでインストールする（curl -fsSL https://hermes-agent.nousresearch.com/install.sh | sh）か、Hermes パスを設定してください。',
    +      sshErrPlatform:
    +        'サポートされていないリモートプラットフォームです。Hermes Desktop の SSH モードは Linux、macOS、Windows のリモートホストに対応しています。',
    +      sshErrTimeout: 'SSH 接続がタイムアウトしました。ホストが到達不能、またはスリープ中の可能性があります。',
    +      sshErrUpdateRequired: 'Desktop SSH で接続する前に、リモートホストの Hermes を更新してください。',
    +      sshErrUnknown: 'SSH 接続に失敗しました。'
         },
         keys: {
           loading: 'API キーと認証情報を読み込み中...',
    ```

    ```diff
    @@ -2095,6 +2132,12 @@ export const ja = defineLocale({
           desktopVersion: version => `Hermes Desktop v${version}`,
           backendVersion: version => `バックエンド v${version}`,
           clientLabel: version => `クライアント v${version}`,
    +      connectionSsh: host => `SSH: ${host}`,
    +      connectionRemote: host => `リモート: ${host}`,
    +      connectionCloud: host => `クラウド: ${host}`,
    +      connectionCloudTooltip: host => `Hermes Cloud ${host} に接続中 · クリックして管理`,
    +      connectionSshTooltip: host => `SSH 経由で ${host} に接続中 · クリックして管理`,
    +      connectionRemoteTooltip: host => `リモートバックエンド ${host} に接続中 · クリックして管理`,
           backendLabel: version => `バックエンド v${version}`,
           commit: sha => `コミット ${sha}`,
           branch: branch => `ブランチ ${branch}`,
    ```
  - `apps/desktop/src/i18n/types.ts`

    ```diff
    @@ -549,6 +549,38 @@ export interface Translations {
           testFailed: string
           applyFailed: string
           saveFailed: string
    +      sshTitle: string
    +      sshDesc: string
    +      sshTrustHint: string
    +      sshHostTitle: string
    +      sshHostDesc: string
    +      sshHostPick: string
    +      sshHostPickTitle: string
    +      sshHostPickDesc: string
    +      sshHostCustom: string
    +      sshUserTitle: string
    +      sshUserDesc: string
    +      sshUserPlaceholder: string
    +      sshPortTitle: string
    +      sshPortDesc: string
    +      sshKeyTitle: string
    +      sshKeyDesc: string
    +      sshHermesPathTitle: string
    +      sshHermesPathDesc: string
    +      sshHermesPathPlaceholder: string
    +      sshTestConnection: string
    +      sshConnect: string
    +      sshButtonsHint: string
    +      sshReachable: (host: string, platform: string) => string
    +      sshIncompleteHost: string
    +      sshErrUnreachable: string
    +      sshErrAuth: string
    +      sshErrHostKey: string
    +      sshErrNotInstalled: string
    +      sshErrPlatform: string
    +      sshErrTimeout: string
    +      sshErrUpdateRequired: string
    +      sshErrUnknown: string
         }
         keys: {
           loading: string
    ```

    ```diff
    @@ -1797,6 +1829,12 @@ export interface Translations {
           desktopVersion: (version: string) => string
           backendVersion: (version: string) => string
           clientLabel: (version: string) => string
    +      connectionSsh: (host: string) => string
    +      connectionRemote: (host: string) => string
    +      connectionCloud: (host: string) => string
    +      connectionCloudTooltip: (host: string) => string
    +      connectionSshTooltip: (host: string) => string
    +      connectionRemoteTooltip: (host: string) => string
           backendLabel: (version: string) => string
           commit: (sha: string) => string
           branch: (branch: string) => string
    ```
  - `apps/desktop/src/i18n/zh-hant.ts`

    ```diff
    @@ -696,7 +696,42 @@ export const zhHant = defineLocale({
           signOutFailed: '登出失敗',
           testFailed: '遠端閘道測試失敗',
           applyFailed: '無法套用閘道設定',
    -      saveFailed: '無法儲存閘道設定'
    +      saveFailed: '無法儲存閘道設定',
    +      sshTitle: '透過 SSH 連線',
    +      sshDesc:
    +        'Hermes 會透過 SSH 在遠端啟動並以通道連線到本應用程式——無需自行啟動或公開任何服務。前提：已具備到該主機的金鑰 SSH 存取。',
    +      sshTrustHint: '首次提供的主機金鑰會被信任並固定；後續變更將被拒絕。',
    +      sshHostTitle: '主機',
    +      sshHostDesc: 'user@host，或 ~/.ssh/config 中的 Host 別名。',
    +      sshHostPick: '選擇主機…',
    +      sshHostPickTitle: '主機',
    +      sshHostPickDesc: '~/.ssh/config 中的 Host 別名，或選擇「自訂」手動輸入。',
    +      sshHostCustom: '自訂（手動輸入）…',
    +      sshUserTitle: '使用者',
    +      sshUserDesc: '留空 = ~/.ssh/config 或目前使用者。',
    +      sshUserPlaceholder: '來自 ~/.ssh/config',
    +      sshPortTitle: '連接埠',
    +      sshPortDesc: '留空 = 22 或 ~/.ssh/config 中的連接埠。',
    +      sshKeyTitle: '金鑰檔案',
    +      sshKeyDesc: '私密金鑰路徑。留空 = ssh-agent 或 ~/.ssh/config。',
    +      sshHermesPathTitle: 'Hermes 路徑（選用）',
    +      sshHermesPathDesc: '遠端 hermes 執行檔的完整路徑。留空 = 自動偵測。',
    +      sshHermesPathPlaceholder: '自動偵測',
    +      sshTestConnection: '測試 SSH',
    +      sshConnect: '連線',
    +      sshButtonsHint: '「儲存」會在下次啟動時生效，「連線」則立即重新連線。',
    +      sshReachable: (host, platform) => `可連線：${host}（${platform}）——已找到 Hermes`,
    +      sshIncompleteHost: '連線前請輸入 SSH 主機。',
    +      sshErrUnreachable: '無法透過 SSH 連線到該主機。請檢查主機、連接埠和網路。',
    +      sshErrAuth:
    +        'SSH 驗證失敗。請將金鑰載入 ssh-agent（ssh-add），或在 ~/.ssh/config 中設定 IdentityFile——Hermes 以非互動方式執行 ssh。',
    +      sshErrHostKey: '自上次連線以來主機金鑰已變更。請確認這是預期的，然後執行 ssh-keygen -R <host> 並重新連線。',
    +      sshErrNotInstalled:
    +        '遠端主機上未安裝 Hermes。請在遠端安裝（curl -fsSL https://hermes-agent.nousresearch.com/install.sh | sh）或設定 Hermes 路徑。',
    +      sshErrPlatform: '不支援的遠端平台。Hermes Desktop 的 SSH 模式支援 Linux、macOS 和 Windows 遠端主機。',
    +      sshErrTimeout: 'SSH 連線逾時。主機可能無法存取或處於睡眠狀態。',
    +      sshErrUpdateRequired: '使用 Desktop SSH 連線前，請更新遠端主機上的 Hermes。',
    +      sshErrUnknown: 'SSH 連線失敗。'
         },
         keys: {
           loading: '正在載入 API 金鑰和憑證...',
    ```

    ```diff
    @@ -2028,6 +2063,12 @@ export const zhHant = defineLocale({
           desktopVersion: version => `Hermes Desktop v${version}`,
           backendVersion: version => `後端 v${version}`,
           clientLabel: version => `用戶端 v${version}`,
    +      connectionSsh: host => `SSH: ${host}`,
    +      connectionRemote: host => `遠端: ${host}`,
    +      connectionCloud: host => `雲端: ${host}`,
    +      connectionCloudTooltip: host => `已連線到 Hermes Cloud ${host} · 點擊管理`,
    +      connectionSshTooltip: host => `已透過 SSH 連線到 ${host} · 點擊管理`,
    +      connectionRemoteTooltip: host => `已連線到遠端後端 ${host} · 點擊管理`,
           backendLabel: version => `後端 v${version}`,
           commit: sha => `提交 ${sha}`,
           branch: branch => `分支 ${branch}`,
    ```
  - `apps/desktop/src/i18n/zh.ts`

    ```diff
    @@ -839,7 +839,42 @@ export const zh: Translations = {
           signOutFailed: '退出登录失败',
           testFailed: '远程网关测试失败',
           applyFailed: '无法应用网关设置',
    -      saveFailed: '无法保存网关设置'
    +      saveFailed: '无法保存网关设置',
    +      sshTitle: '通过 SSH 连接',
    +      sshDesc:
    +        'Hermes 会通过 SSH 在远程启动并以隧道连接到本应用——无需自行启动或暴露任何服务。前提：已具备到该主机的密钥 SSH 访问。',
    +      sshTrustHint: '首次提供的主机密钥会被信任并固定；后续变更将被拒绝。',
    +      sshHostTitle: '主机',
    +      sshHostDesc: 'user@host，或 ~/.ssh/config 中的 Host 别名。',
    +      sshHostPick: '选择主机…',
    +      sshHostPickTitle: '主机',
    +      sshHostPickDesc: '~/.ssh/config 中的 Host 别名，或选择"自定义"手动输入。',
    +      sshHostCustom: '自定义（手动输入）…',
    +      sshUserTitle: '用户',
    +      sshUserDesc: '留空 = ~/.ssh/config 或当前用户。',
    +      sshUserPlaceholder: '来自 ~/.ssh/config',
    +      sshPortTitle: '端口',
    +      sshPortDesc: '留空 = 22 或 ~/.ssh/config 中的端口。',
    +      sshKeyTitle: '密钥文件',
    +      sshKeyDesc: '私钥路径。留空 = ssh-agent 或 ~/.ssh/config。',
    +      sshHermesPathTitle: 'Hermes 路径（可选）',
    +      sshHermesPathDesc: '远程 hermes 可执行文件的完整路径。留空 = 自动检测。',
    +      sshHermesPathPlaceholder: '自动检测',
    +      sshTestConnection: '测试 SSH',
    +      sshConnect: '连接',
    +      sshButtonsHint: '“保存”将在下次启动时生效，“连接”则立即重新连接。',
    +      sshReachable: (host, platform) => `可连接：${host}（${platform}）——已找到 Hermes`,
    +      sshIncompleteHost: '连接前请输入 SSH 主机。',
    +      sshErrUnreachable: '无法通过 SSH 连接到该主机。请检查主机、端口和网络。',
    +      sshErrAuth:
    +        'SSH 认证失败。请将密钥加载到 ssh-agent（ssh-add），或在 ~/.ssh/config 中设置 IdentityFile——Hermes 以非交互方式运行 ssh。',
    +      sshErrHostKey: '自上次连接以来主机密钥已更改。请确认这是预期的，然后运行 ssh-keygen -R <host> 并重新连接。',
    +      sshErrNotInstalled:
    +        '远程主机上未安装 Hermes。请在远程安装（curl -fsSL https://hermes-agent.nousresearch.com/install.sh | sh）或设置 Hermes 路径。',
    +      sshErrPlatform: '不支持的远程平台。Hermes Desktop 的 SSH 模式支持 Linux、macOS 和 Windows 远程主机。',
    +      sshErrTimeout: 'SSH 连接超时。主机可能无法访问或处于休眠状态。',
    +      sshErrUpdateRequired: '使用 Desktop SSH 连接前，请更新远程主机上的 Hermes。',
    +      sshErrUnknown: 'SSH 连接失败。'
         },
         keys: {
           loading: '正在加载 API 密钥和凭据...',
    ```

    ```diff
    @@ -2339,6 +2374,12 @@ export const zh: Translations = {
           desktopVersion: version => `Hermes Desktop v${version}`,
           backendVersion: version => `后端 v${version}`,
           clientLabel: version => `客户端 v${version}`,
    +      connectionSsh: host => `SSH: ${host}`,
    +      connectionRemote: host => `远程: ${host}`,
    +      connectionCloud: host => `云端: ${host}`,
    +      connectionCloudTooltip: host => `已连接到 Hermes Cloud ${host} · 点击管理`,
    +      connectionSshTooltip: host => `已通过 SSH 连接到 ${host} · 点击管理`,
    +      connectionRemoteTooltip: host => `已连接到远程后端 ${host} · 点击管理`,
           backendLabel: version => `后端 v${version}`,
           commit: sha => `提交 ${sha}`,
           branch: branch => `分支 ${branch}`,
    ```
  - `apps/desktop/src/lib/desktop-fs.test.ts`

    ```diff
    @@ -5,6 +5,7 @@ import { $connection } from '@/store/session'
     import {
       desktopDefaultCwd,
       desktopFileDiff,
    +  desktopFsCacheKey,
       desktopGitRoot,
       readDesktopDir,
       readDesktopFileDataUrl,
    ```

    ```diff
    @@ -122,6 +123,56 @@ describe('desktop filesystem facade', () => {
         expect(api).toHaveBeenCalledWith({ path: '/api/fs/default-cwd', profile: 'remote-docker' })
       })
     
    +  it('keys SSH filesystem caches by stable host identity instead of the forwarded port', () => {
    +    $connection.set({
    +      mode: 'remote',
    +      remoteKind: 'ssh',
    +      remoteHost: 'operator@remote-box',
    +      baseUrl: 'http://127.0.0.1:41001'
    +    } as never)
    +    const first = desktopFsCacheKey()
    +
    +    $connection.set({
    +      mode: 'remote',
    +      remoteKind: 'ssh',
    +      remoteHost: 'operator@remote-box',
    +      baseUrl: 'http://127.0.0.1:52002'
    +    } as never)
    +
    +    expect(desktopFsCacheKey()).toBe(first)
    +    expect(first).toContain('operator@remote-box')
    +    expect(first).not.toContain('41001')
    +  })
    +
    +  it('separates SSH filesystem caches by ownership and profile', () => {
    +    $connection.set({
    +      mode: 'remote',
    +      remoteKind: 'ssh',
    +      remoteHost: 'host-a',
    +      remoteIdentity: 'owner-a',
    +      profile: 'one'
    +    } as never)
    +    const first = desktopFsCacheKey()
    +    $connection.set({
    +      mode: 'remote',
    +      remoteKind: 'ssh',
    +      remoteHost: 'host-a',
    +      remoteIdentity: 'owner-b',
    +      profile: 'one'
    +    } as never)
    +    const otherOwner = desktopFsCacheKey()
    +    $connection.set({
    +      mode: 'remote',
    +      remoteKind: 'ssh',
    +      remoteHost: 'host-a',
    +      remoteIdentity: 'owner-a',
    +      profile: 'two'
    +    } as never)
    +
    +    expect(otherOwner).not.toBe(first)
    +    expect(desktopFsCacheKey()).not.toBe(first)
    +  })
    +
       it('routes file diffs through backend git in remote mode', async () => {
         $connection.set({ mode: 'remote' } as never)
     
    ```
  - `apps/desktop/src/lib/desktop-fs.ts`

    ```diff
    @@ -21,7 +21,12 @@ function connectionCacheKey(connection: HermesConnection | null) {
         return 'local:'
       }
     
    -  return `${connection.mode || 'local'}:${connection.profile || ''}:${connection.baseUrl || ''}`
    +  const target =
    +    connection.remoteKind === 'ssh'
    +      ? connection.remoteIdentity || connection.remoteHost || ''
    +      : connection.baseUrl || ''
    +
    +  return `${connection.mode || 'local'}:${connection.remoteKind || ''}:${connection.profile || ''}:${target}`
     }
     
     export function desktopFsCacheKey() {
    ```
  - `hermes_cli/main.py`

    ```diff
    @@ -391,6 +391,7 @@ def _try_termux_ultrafast_version() -> bool:
     import argparse
     import hashlib
     import json
    +import re
     import shlex
     import shutil
     import stat
    ```

    ```diff
    @@ -12500,8 +12501,97 @@ def _maybe_setup_dashboard_auth_interactively(args) -> None:
         print()
     
     
    +def _read_ssh_session_token_file(path: str) -> str:
    +    """Read and unlink a Desktop SSH token from its private runtime directory."""
    +    if sys.platform == "win32":
    +        from hermes_cli.windows_ssh_runtime import read_token
    +        return read_token(path)
    +
    +    import stat as _stat
    +    from pathlib import Path as _Path
    +    from hermes_constants import get_hermes_home as _get_hermes_home
    +
    +    if not os.path.isabs(path):
    +        raise SystemExit("--ssh-session-token-file must be absolute")
    +
    +    token_path = [redacted:secret-assignment]
    +    token_root = [redacted:secret-assignment] / "desktop-ssh"
    +    try:
    +        relative = token_path.relative_to(token_root)
    +    except ValueError as exc:
    +        raise SystemExit("--ssh-session-token-file must be under the desktop-ssh directory") from exc
    +    if len(relative.parts) != 2 or not re.fullmatch(r"[0-9a-f]{32}", relative.parts[0]):
    +        raise SystemExit("--ssh-session-token-file has an invalid runtime path")
    +    if not re.fullmatch(r"[0-9a-f]{16}\.token", relative.parts[1]):
    +        raise SystemExit("--ssh-session-token-file has an invalid filename")
    +
    +    directory_flags = os.O_RDONLY | getattr(os, "O_DIRECTORY", 0) | getattr(os, "O_NOFOLLOW", 0)
    +    file_flags = os.O_RDONLY | getattr(os, "O_NOFOLLOW", 0)
    +    root_fd = -1
    +    directory_fd = -1
    +    file_fd = -1
    +    try:
    +        try:
    +            root_fd = os.open(token_root, directory_flags)
    +            root_stat = os.fstat(root_fd)
    +            if not _stat.S_ISDIR(root_stat.st_mode):
    +                raise SystemExit("--ssh-session-token-file has an unsafe runtime root")
    +            if hasattr(os, "getuid") and root_stat.st_uid != os.getuid():
    +                raise SystemExit("--ssh-session-token-file runtime root has the wrong owner")
    +            directory_fd = os.open(relative.parts[0], directory_flags, dir_fd=root_fd)
    +            directory_stat = os.fstat(directory_fd)
    +            if not _stat.S_ISDIR(directory_stat.st_mode):
    +                raise SystemExit("--ssh-session-token-file has an unsafe parent directory")
    +            if hasattr(os, "getuid") and directory_stat.st_uid != os.getuid():
    +                raise SystemExit("--ssh-session-token-file parent has the wrong owner")
    +            if (directory_stat.st_mode & 0o777) != 0o700:
    +                raise SystemExit("--ssh-session-token-file parent has unsafe permissions")
    +            file_fd = os.open(relative.parts[1], file_flags, dir_fd=directory_fd)
    +        except SystemExit:
    +            raise
    +        except OSError as exc:
    +            if exc.errno == getattr(__import__("errno"), "ELOOP", -1):
    +                raise SystemExit("--ssh-session-token-file is a symlink") from exc
    +            raise SystemExit("--ssh-session-token-file is not accessible") from exc
    +
    +        file_stat = os.fstat(file_fd)
    +        if not _stat.S_ISREG(file_stat.st_mode):
    +            raise SystemExit("--ssh-session-token-file is not a regular file")
    +        if file_stat.st_size != 64:
    +            raise SystemExit("--ssh-session-token-file contains an invalid token")
    +        if hasattr(os, "getuid") and file_stat.st_uid != os.getuid():
    +            raise SystemExit("--ssh-session-token-file has the wrong owner")
    +        if hasattr(os, "getuid") and (file_stat.st_mode & 0o777) & ~0o600:
    +            raise SystemExit("--ssh-session-token-file has unsafe permissions")
    +
    +        with os.fdopen(file_fd, "r") as token_stream:
    +            file_fd = -1
    +            token = [redacted:secret-assignment]
    +
    +        if not re.fullmatch(r"[0-9a-f]{64}", token):
    +            raise SystemExit("--ssh-session-token-file contains an invalid token")
    +        return token
    +    finally:
    +        if file_fd >= 0:
    +            os.close(file_fd)
    +        if directory_fd >= 0:
    +            try:
    +                os.unlink(relative.parts[1], dir_fd=directory_fd)
    +            except OSError:
    +                pass
    +            os.close(directory_fd)
    +        if root_fd >= 0:
    +            os.close(root_fd)
    +
    +
     def cmd_dashboard(args):
         """Start the web UI server, or (with --stop/--status) manage running ones."""
    +    _token_file = [redacted:secret-assignment] "ssh_session_token_file", None)
    +    if _token_file and (
    +        getattr(args, "status", False) or getattr(args, "stop", False)
    +    ):
    +        raise SystemExit("--ssh-session-token-file cannot be used with --status or --stop")
    +
         # --status: report running dashboards and exit, no deps needed.
         if getattr(args, "status", False):
             count = _report_dashboard_status()
    ```

    ```diff
    @@ -12524,6 +12614,12 @@ def cmd_dashboard(args):
         # ready sentinel. Resolved once and threaded through the re-exec, the
         # build gate, and start_server.
         _headless_backend = getattr(args, "headless_backend", False)
    +    _ssh_owner_nonce = getattr(args, "ssh_owner_nonce", None)
    +    if _ssh_owner_nonce and not re.fullmatch(r"[0-9a-f]{16}", _ssh_owner_nonce):
    +        raise SystemExit("--ssh-owner-nonce must be 16 lowercase hex characters")
    +    _ssh_session_token = None
    +    if _token_file and not _headless_backend:
    +        raise SystemExit("--ssh-session-token-file is only valid with hermes serve")
     
         # ── Unified profile launch routing ────────────────────────────────
         # The dashboard is a MACHINE management surface: it can read/write any
    ```

    ```diff
    @@ -12577,6 +12673,10 @@ def cmd_dashboard(args):
                 "--host", args.host,
                 "--open-profile", _launch_profile,
             ]
    +        if _ssh_owner_nonce:
    +            reexec_argv.extend(["--ssh-owner-nonce", _ssh_owner_nonce])
    +        if _token_file:
    +            reexec_argv.extend(["--ssh-session-token-file", _token_file])
             if args.no_open:
                 reexec_argv.append("--no-open")
             if getattr(args, "insecure", False):
    ```

    ```diff
    @@ -12613,6 +12713,9 @@ def cmd_dashboard(args):
             else:
                 os.execvpe(sys.executable, reexec_argv, env)
     
    +    if _token_file:
    +        _ssh_session_token = [redacted:secret-assignment]
    +
         # Attach gui.log early so dashboard startup/build failures are captured in
         # the same logs directory as every other Hermes surface.
         try:
    ```

    ```diff
    @@ -12753,6 +12856,8 @@ def cmd_dashboard(args):
             allow_public=getattr(args, "insecure", False),
             initial_profile=getattr(args, "open_profile", "") or "",
             headless=_headless_backend,
    +        ssh_session_token=[redacted:secret-assignment]
    +        ssh_owner_nonce=_ssh_owner_nonce,
         )
     
     
    ```
  - `hermes_cli/subcommands/dashboard.py`

    ```diff
    @@ -149,6 +149,20 @@ def build_dashboard_parser(
         serve_parser.add_argument(
             "--no-open", action="store_true", help=argparse.SUPPRESS
         )
    +    serve_parser.add_argument(
    +        "--ssh-session-token-file",
    +        dest="ssh_session_token_file",
    +        metavar="PATH",
    +        default=None,
    +        help="Read a one-shot Desktop SSH session token from PATH",
    +    )
    +    serve_parser.add_argument(
    +        "--ssh-owner-nonce",
    +        dest="ssh_owner_nonce",
    +        metavar="NONCE",
    +        default=None,
    +        help="Identify a Desktop-owned SSH backend process",
    +    )
         # `headless_backend` marks the lean path: desktop/remote clients speak pure
         # JSON-RPC/WS, so `serve` skips the web UI build AND never serves the SPA
         # (cmd_dashboard exports HERMES_SERVE_HEADLESS=1). `dashboard` leaves it
    ```
  - `hermes_cli/web_server.py`

    ```diff
    @@ -280,6 +280,18 @@ def _get_pty_active_session_files(app: "FastAPI") -> dict[str, Path]:
     # ---------------------------------------------------------------------------
     _SESSION_TOKEN = [redacted:secret-assignment]"HERMES_DASHBOARD_SESSION_TOKEN") or secrets.token_urlsafe(32)
     _SESSION_HEADER_NAME = "X-Hermes-Session-Token"
    +_SSH_OWNER_NONCE: Optional[str] = None
    +
    +
    +def _apply_ssh_session_token(token: str) -> None:
    +    global _SESSION_TOKEN
    +    if token:
    +        _SESSION_TOKEN = token
    +
    +
    +def _apply_ssh_owner_nonce(nonce: Optional[str]) -> None:
    +    global _SSH_OWNER_NONCE
    +    _SSH_OWNER_NONCE = nonce
     
     # In-browser Chat tab (/chat, /api/pty, /api/ws, …).  Always enabled: the
     # desktop app and the dashboard's own Chat tab both drive the agent over the
    ```

    ```diff
    @@ -2774,6 +2786,14 @@ def _collect_profile_gateway_topology() -> Dict[str, Any]:
         return {"profiles": profile_names, "gateway_mode": mode, "gateways": gateways}
     
     
    [redacted:email]("/api/ssh/ownership")
    +async def get_ssh_ownership(request: Request):
    +    _require_token(request)
    +    if not _SSH_OWNER_NONCE:
    +        raise HTTPException(status_code=404, detail="SSH ownership is not active")
    +    return {"ok": True, "sshOwnerNonce": _SSH_OWNER_NONCE, "protocolVersion": 1}
    +
    +
     @app.get("/api/status")
     async def get_status(profile: Optional[str] = None):
         status_scope = None
    ```

    ```diff
    @@ -19145,6 +19165,8 @@ def start_server(
         allow_public: bool = False,
         initial_profile: str = "",
         headless: bool = False,
    +    ssh_session_token: [redacted:secret-assignment] = None,
    +    ssh_owner_nonce: Optional[str] = None,
     ):
         """Start the web UI server.
     
    ```

    ```diff
    @@ -19156,7 +19178,13 @@ def start_server(
         ``headless`` is the ``serve`` path: the JSON-RPC/WS backend with no UI
         build and no SPA mount (mount_spa() honours ``HERMES_SERVE_HEADLESS``), so
         the banner announces the bind rather than a browser URL.
    +
    +    ``ssh_session_token`` and ``ssh_owner_nonce`` are process-local Desktop SSH
    +    bootstrap state. Neither is persisted or exported to child processes.
         """
    +    _apply_ssh_session_token(ssh_session_token or "")
    +    _apply_ssh_owner_nonce(ssh_owner_nonce)
    +
         import uvicorn
     
         try:
    ```
  - `hermes_cli/windows_ssh_runtime.py`

    ```diff
    @@ -0,0 +1,505 @@
    +"""Native Windows trust boundary for Desktop SSH backend lifecycle."""
    +
    +from __future__ import annotations
    +
    +import argparse
    +import json
    +import os
    +import re
    +import subprocess
    +import sys
    +from pathlib import Path
    +from typing import Any
    +
    +from hermes_constants import get_hermes_home
    +
    +_HEX32 = re.compile(r"[0-9a-f]{32}\Z")
    +_HEX16 = re.compile(r"[0-9a-f]{16}\Z")
    +_HEX64 = re.compile(r"[0-9a-f]{64}\Z")
    +_MAX_JSON = 1024 * 1024
    +_MAX_LOG = 512 * 1024
    +_OPEN_REPARSE_POINT = 0x00200000
    +_DELETE_ON_CLOSE = 0x04000000
    +_MOVE_REPLACE_EXISTING = 0x00000001
    +_MOVE_WRITE_THROUGH = 0x00000008
    +
    +
    +def _win32() -> tuple[Any, ...]:
    +    if sys.platform != "win32":
    +        raise RuntimeError("Windows SSH runtime is only available on Windows")
    +    import ntsecuritycon
    +    import pywintypes
    +    import win32api
    +    import win32con
    +    import win32file
    +    import win32process
    +    import win32security
    +    return ntsecuritycon, pywintypes, win32api, win32con, win32file, win32process, win32security
    +
    +
    +def _ownership(value: str) -> str:
    +    if not _HEX32.fullmatch(value or ""):
    +        raise ValueError("invalid ownership ID")
    +    return value
    +
    +
    +def _nonce(value: str) -> str:
    +    if not _HEX16.fullmatch(value or ""):
    +        raise ValueError("invalid spawn nonce")
    +    return value
    +
    +
    +def _root() -> Path:
    +    return get_hermes_home() / "desktop-ssh"
    +
    +
    +def _directory(ownership_id: str) -> Path:
    +    return _root() / _ownership(ownership_id)
    +
    +
    +def _token_path(ownership_id: str, spawn_nonce: str) -> Path:
    +    return _directory(ownership_id) / f"{_nonce(spawn_nonce)}.token"
    +
    +
    +def _log_path(ownership_id: str, spawn_nonce: str) -> Path:
    +    return _directory(ownership_id) / f"{_nonce(spawn_nonce)}.log"
    +
    +
    +def _lock_path(ownership_id: str) -> Path:
    +    return _directory(ownership_id) / "backend.lock.json"
    +
    +
    +def _current_sid():
    +    _, _, win32api, win32con, _, _, win32security = _win32()
    +    token = [redacted:secret-assignment] win32con.TOKEN_QUERY)
    +    return win32security.GetTokenInformation(token, win32security.TokenUser)[0]
    +
    +
    +def _system_sid():
    +    return _win32()[6].ConvertStringSidToSid("S-1-5-18")
    +
    +
    +def _security_attributes():
    +    ntsecuritycon, _, _, _, _, _, win32security = _win32()
    +    owner = _current_sid()
    +    acl = win32security.ACL()
    +    for sid in (owner, _system_sid()):
    +        acl.AddAccessAllowedAceEx(win32security.ACL_REVISION, 0, ntsecuritycon.FILE_ALL_ACCESS, sid)
    +    descriptor = win32security.SECURITY_DESCRIPTOR()
    +    descriptor.SetSecurityDescriptorOwner(owner, False)
    +    descriptor.SetSecurityDescriptorDacl(True, acl, False)
    +    # Protect the DACL so inheritable parent ACEs (%LOCALAPPDATA% grants) are not merged in.
    +    descriptor.SetSecurityDescriptorControl(win32security.SE_DACL_PROTECTED, win32security.SE_DACL_PROTECTED)
    +    attributes = win32security.SECURITY_ATTRIBUTES()
    +    attributes.SECURITY_DESCRIPTOR = descriptor
    +    return attributes
    +
    +
    +def _allowed_sids():
    +    win32security = _win32()[6]
    +    return {win32security.ConvertSidToStringSid(_current_sid()),
    +            win32security.ConvertSidToStringSid(_system_sid())}
    +
    +
    +def _verify_security(handle) -> None:
    +    _, _, _, _, _, _, win32security = _win32()
    +    info = win32security.OWNER_SECURITY_INFORMATION | win32security.DACL_SECURITY_INFORMATION
    +    descriptor = win32security.GetSecurityInfo(handle, win32security.SE_FILE_OBJECT, info)
    +    owner = descriptor.GetSecurityDescriptorOwner()
    +    owner_value = win32security.ConvertSidToStringSid(owner)
    +    if owner_value not in _allowed_sids():
    +        raise OSError("Windows SSH runtime object has the wrong owner")
    +    dacl = descriptor.GetSecurityDescriptorDacl()
    +    if dacl is None:
    +        raise OSError("Windows SSH runtime object has a null DACL")
    +    allowed = _allowed_sids()
    +    allow_types = {
    +        win32security.ACCESS_ALLOWED_ACE_TYPE,
    +        win32security.ACCESS_ALLOWED_OBJECT_ACE_TYPE,
    +        getattr(win32security, "ACCESS_ALLOWED_CALLBACK_ACE_TYPE", 9),
    +        getattr(win32security, "ACCESS_ALLOWED_CALLBACK_OBJECT_ACE_TYPE", 11),
    +    }
    +    for index in range(dacl.GetAceCount()):
    +        ace = dacl.GetAce(index)
    +        ace_type = ace[0][0]
    +        mask = ace[1]
    +        sid = ace[-1]
    +        if ace_type in allow_types and mask:
    +            if win32security.ConvertSidToStringSid(sid) not in allowed:
    +                raise OSError("Windows SSH runtime object has a permissive DACL")
    +
    +
    +def _open(path: Path, access: int, creation: int, flags: int, share: int = 0):
    +    _, _, _, _, win32file, _, _ = _win32()
    +    handle = win32file.CreateFile(str(path), access, share, _security_attributes(), creation, flags, None)
    +    try:
    +        actual = win32file.GetFinalPathNameByHandle(handle, 0)
    +        if actual.startswith("\\\\?\\"):
    +            actual = actual[4:]
    +        expected = os.path.abspath(str(path))
    +        if os.path.normcase(actual) != os.path.normcase(expected):
    +            raise OSError("Windows SSH runtime handle escaped its expected path")
    +        attributes = win32file.GetFileInformationByHandle(handle)[0]
    +        if attributes & 0x400:
    +            raise OSError("Windows SSH runtime path contains a reparse point")
    +        _verify_security(handle)
    +        return handle
    +    except BaseException:
    +        win32file.CloseHandle(handle)
    +        raise
    +
    +
    +def _ensure_directory(path: Path) -> None:
    +    _, pywintypes, _, win32con, win32file, _, _ = _win32()
    +    if path.parent != path:
    +        _ensure_directory(path.parent) if path.parent not in (Path(path.anchor), path) and not path.parent.exists() else None
    +    if not path.exists():
    +        try:
    +            win32file.CreateDirectory(str(path), _security_attributes())
    +        except pywintypes.error as exc:
    +            if exc.winerror != 183:
    +                raise
    +    handle = _open(path, win32con.GENERIC_READ | win32con.READ_CONTROL, win32con.OPEN_EXISTING,
    +                   win32con.FILE_FLAG_BACKUP_SEMANTICS | _OPEN_REPARSE_POINT,
    +                   win32con.FILE_SHARE_READ | win32con.FILE_SHARE_WRITE | win32con.FILE_SHARE_DELETE)
    +    win32file.CloseHandle(handle)
    +
    +
    +def _ensure_scope(ownership_id: str) -> Path:
    +    root = _root()
    +    _ensure_directory(root)
    +    directory = _directory(ownership_id)
    +    _ensure_directory(directory)
    +    return directory
    +
    +
    +def upload_token(ownership_id: str, spawn_nonce: str, token: [redacted:secret-assignment] -> dict[str, Any]:
    +    _, _, _, win32con, win32file, _, _ = _win32()
    +    if len(token) != 64 or not _HEX64.fullmatch(token.decode("ascii", errors="ignore")):
    +        raise ValueError("invalid session token")
    +    _ensure_scope(ownership_id)
    +    path = _token_path(ownership_id, spawn_nonce)
    +    try:
    +        handle = _open(path, win32con.GENERIC_WRITE | win32con.READ_CONTROL, win32con.CREATE_NEW,
    +                       win32con.FILE_ATTRIBUTE_NORMAL | _OPEN_REPARSE_POINT)
    +        try:
    +            win32file.WriteFile(handle, token)
    +            win32file.FlushFileBuffers(handle)
    +        finally:
    +            win32file.CloseHandle(handle)
    +    except BaseException:
    +        path.unlink(missing_ok=True)
    +        raise
    +    return {"path": str(path)}
    +
    +
    +def read_token(path_value: str) -> str:
    +    _, _, _, win32con, win32file, _, _ = _win32()
    +    path = Path(path_value)
    +    root = _root()
    +    try:
    +        relative = path.relative_to(root)
    +    except ValueError as exc:
    +        raise SystemExit("--ssh-session-token-file must be under the desktop-ssh directory") from exc
    +    if len(relative.parts) != 2 or not _HEX32.fullmatch(relative.parts[0]) or not re.fullmatch(r"[0-9a-f]{16}\.token", relative.parts[1]):
    +        raise SystemExit("--ssh-session-token-file has an invalid runtime path")
    +    flags = win32con.FILE_ATTRIBUTE_NORMAL | _OPEN_REPARSE_POINT | _DELETE_ON_CLOSE
    +    try:
    +        handle = _open(path, win32con.GENERIC_READ | win32con.READ_CONTROL | win32con.DELETE,
    +                       win32con.OPEN_EXISTING, flags)
    +    except Exception as exc:
    +        raise SystemExit("--ssh-session-token-file is not accessible") from exc
    +    try:
    +        _, data = win32file.ReadFile(handle, 65)
    +    finally:
    +        win32file.CloseHandle(handle)
    +    token = [redacted:secret-assignment]"ascii", errors="ignore")
    +    if len(token) != 64 or not _HEX64.fullmatch(token):
    +        raise SystemExit("--ssh-session-token-file contains an invalid token")
    +    return token
    +
    +
    +def _read_json_stdin() -> dict[str, Any]:
    +    raw = sys.stdin.buffer.read(_MAX_JSON + 1)
    +    if len(raw) > _MAX_JSON:
    +        raise ValueError("runtime payload is too large")
    +    parsed = json.loads(raw)
    +    if not isinstance(parsed, dict):
    +        raise ValueError("runtime payload must be an object")
    +    return parsed
    +
    +
    +def read_lock(ownership_id: str) -> dict[str, Any] | None:
    +    _, pywintypes, _, win32con, win32file, _, _ = _win32()
    +    _ensure_scope(ownership_id)
    +    path = _lock_path(ownership_id)
    +    try:
    +        handle = _open(path, win32con.GENERIC_READ | win32con.READ_CONTROL, win32con.OPEN_EXISTING,
    +                       win32con.FILE_ATTRIBUTE_NORMAL | _OPEN_REPARSE_POINT,
    +                       win32con.FILE_SHARE_READ)
    +    except pywintypes.error as exc:
    +        if exc.winerror in (2, 3):
    +            return None
    +        raise
    +    try:
    +        _, data = win32file.ReadFile(handle, _MAX_JSON + 1)
    +    finally:
    +        win32file.CloseHandle(handle)
    +    if len(data) > _MAX_JSON:
    +        return None
    +    try:
    +        parsed = json.loads(data)
    +    except (UnicodeDecodeError, json.JSONDecodeError):
    +        return None
    +    return parsed if isinstance(parsed, dict) else None
    +
    +
    +def write_lock(ownership_id: str, payload: dict[str, Any]) -> None:
    +    _, _, _, win32con, win32file, _, _ = _win32()
    +    directory = _ensure_scope(ownership_id)
    +    data = json.dumps(payload, separators=(",", ":")).encode()
    +    if len(data) > _MAX_JSON:
    +        raise ValueError("lock payload is too large")
    +    temporary = directory / f".{os.urandom(8).hex()}.lock.tmp"
    +    handle = _open(temporary, win32con.GENERIC_WRITE | win32con.READ_CONTROL, win32con.CREATE_NEW,
    +                   win32con.FILE_ATTRIBUTE_NORMAL | _OPEN_REPARSE_POINT)
    +    try:
    +        win32file.WriteFile(handle, data)
    +        win32file.FlushFileBuffers(handle)
    +    finally:
    +        win32file.CloseHandle(handle)
    +    win32file.MoveFileEx(str(temporary), str(_lock_path(ownership_id)),
    +                         _MOVE_REPLACE_EXISTING | _MOVE_WRITE_THROUGH)
    +
    +
    +def remove_artifact(path: Path) -> bool:
    +    _, pywintypes, _, win32con, win32file, _, _ = _win32()
    +    try:
    +        handle = _open(path, win32con.DELETE | win32con.READ_CONTROL, win32con.OPEN_EXISTING,
    +                       win32con.FILE_ATTRIBUTE_NORMAL | _OPEN_REPARSE_POINT | _DELETE_ON_CLOSE)
    +    except pywintypes.error as exc:
    +        if exc.winerror in (2, 3):
    +            return False
    +        raise
    +    win32file.CloseHandle(handle)
    +    return True
    +
    +
    +def process_state(pid: int, creation_time_ns: int, hermes_path: str, spawn_nonce: str) -> dict[str, Any]:
    +    import psutil
    +    _nonce(spawn_nonce)
    +    try:
    +        process = psutil.Process(pid)
    +    except psutil.NoSuchProcess as exc:
    +        return {"alive": False, "owned": False, "indeterminate": False, "reason": type(exc).__name__}
    +    try:
    +        actual_creation = int(process.create_time() * 1_000_000_000)
    +        argv = process.cmdline()
    +    except psutil.NoSuchProcess as exc:
    +        return {"alive": False, "owned": False, "indeterminate": False, "reason": type(exc).__name__}
    +    except psutil.AccessDenied as exc:
    +        return {"alive": True, "owned": False, "indeterminate": True, "reason": type(exc).__name__}
    +    if actual_creation != creation_time_ns:
    +        return {"alive": False, "owned": False, "indeterminate": False, "reason": "creation-time",
    +                "actualCreationTimeNs": str(actual_creation), "expectedCreationTimeNs": str(creation_time_ns)}
    +    if not argv:
    +        return {"alive": True, "owned": False, "indeterminate": True, "reason": "argv-unavailable"}
    +    expected = os.path.normcase(os.path.abspath(hermes_path))
    +    arg0 = os.path.normcase(os.path.abspath(argv[0]))
    +    # argv[0] is either the hermes exe directly, or (normal case) the base Python
    +    # interpreter -- its exact path varies by venv/uv layout, so match on "a python
    +    # running our module". We launch via `-c` bootstrap, so it shows as
    +    # `-c <bootstrap that runs hermes_cli.main>`; also accept a plain `-m` launch.
    +    # Identity is anchored by the unforgeable creation-time + secret owner-nonce below.
    +    is_python = os.path.basename(arg0).startswith("python")
    +    launches_module = (
    +        argv[1:3] == ["-m", "hermes_cli.main"]
    +        or (len(argv) > 2 and argv[1] == "-c" and "hermes_cli.main" in argv[2])
    +    )
    +    executable_match = arg0 == expected or (is_python and launches_module)
    +    try:
    +        serve = argv.index("serve")
    +        owner = argv.index("--ssh-owner-nonce", serve + 1)
    +        owned = executable_match and "--isolated" in argv[serve + 1:] and argv[owner + 1] == spawn_nonce
    +    except (ValueError, IndexError):
    +        owned = False
    +    return {"alive": process.is_running(), "owned": owned, "indeterminate": False,
    +            "creationTimeNs": str(actual_creation), "reason": "owned" if owned else "argv",
    +            "argv": argv[:20], "expectedExecutable": expected}
    +
    +
    +def terminate_owned(pid: int, creation_time_ns: int, hermes_path: str, spawn_nonce: str) -> bool:
    +    state = process_state(pid, creation_time_ns, hermes_path, spawn_nonce)
    +    if not state["alive"] or not state["owned"]:
    +        return False
    +    import psutil
    +    process = psutil.Process(pid)
    +    if int(process.create_time() * 1_000_000_000) != creation_time_ns:
    +        return False
    +    process.terminate()
    +    try:
    +        process.wait(5)
    +    except psutil.TimeoutExpired:
    +        process.kill()
    +        process.wait(5)
    +    return True
    +
    +
    +def _resolve_direct_interpreter(python_entry: str) -> tuple[str, list[str]]:
    +    """Resolve the venv launcher to the base interpreter it would exec, plus the
    +    sys.path to reproduce. On Windows a venv Scripts\\python.exe is a launcher stub
    +    that spawns the real interpreter as a CHILD (two PIDs); spawning the base
    +    interpreter directly with the launcher's sys.path injected yields ONE process
    +    that both owns the port and is the process we lock.
    +
    +    Also resolves hermes_cli's own location and prepends its parent, because the
    +    launcher finds the module via cwd / an editable-install path hook that a bare
    +    PYTHONPATH does not reproduce."""
    +    query = (
    +        "import sys,json,os,importlib.util as u;"
    +        "s=u.find_spec('hermes_cli');"
    +        "root=os.path.dirname(os.path.dirname(s.origin)) if s and s.origin else '';"
    +        "print(json.dumps({'base':getattr(sys,'_base_executable','') or sys.executable,"
    +        "'path':[p for p in sys.path if p],'root':root}))"
    +    )
    +    out = subprocess.run([python_entry, "-c", query], capture_output=True, text=True, timeout=30)
    +    if out.returncode != 0:
    +        raise ValueError("could not resolve the base Python interpreter")
    +    info = json.loads(out.stdout.strip().splitlines()[-1])
    +    base = info["base"]
    +    if not base or not os.path.isfile(base):
    +        raise ValueError("base Python interpreter was not found")
    +    # drop editable-install finder markers ('__editable__.*.finder.__path_hook__')
    +    # that PYTHONPATH cannot reproduce; keep only real filesystem entries.
    +    py_path = [p for p in info.get("path", []) if os.path.exists(p)]
    +    # the hermes_cli package parent must be explicit -- the launcher resolves it via
    +    # cwd or an editable path hook, neither of which survives a bare PYTHONPATH spawn.
    +    root = info.get("root") or ""
    +    if root and os.path.isdir(root) and root not in py_path:
    +        py_path.insert(0, root)
    +    if not root or not os.path.isdir(root):
    +        raise ValueError("could not locate the hermes_cli package")
    +    return base, py_path
    +
    +
    +def spawn_backend(payload: dict[str, Any]) -> dict[str, Any]:
    +    ownership_id = _ownership(str(payload["ownershipId"]))
    +    spawn_nonce = _nonce(str(payload["spawnNonce"]))
    +    configured_path = str(payload["hermesPath"])
    +    if not os.path.isabs(configured_path):
    +        raise ValueError("Hermes path must be absolute")
    +    hermes_path = os.path.abspath(configured_path)
    +    token_path = [redacted:secret-assignment] spawn_nonce))
    +    log_path = _log_path(ownership_id, spawn_nonce)
    +    profile = str(payload.get("profile") or "")
    +    if len(profile) > 256 or any(ch in profile for ch in "\x00\r\n"):
    +        raise ValueError("invalid profile")
    +    venv_dir = os.path.dirname(hermes_path)
    +    python_entry = os.path.join(venv_dir, "python.exe")
    +    if not os.path.isfile(python_entry):
    +        raise ValueError("Hermes Python runtime was not found")
    +    base_python, sys_path = _resolve_direct_interpreter(python_entry)
    +    # Seed sys.path IN-PROCESS via a -c bootstrap rather than exporting PYTHONPATH:
    +    # PYTHONPATH would be inherited by every subprocess the running backend spawns
    +    # (terminal tool, user scripts), shadowing their imports. This keeps the path
    +    # scoped to the backend process alone.
    +    bootstrap = (
    +        "import sys,runpy;"
    +        f"sys.path[:0]={sys_path!r};"
    +        "runpy.run_module('hermes_cli.main',run_name='__main__',alter_sys=True)"
    +    )
    +    args = [base_python, "-c", bootstrap]
    +    if profile:
    +        args.extend(["--profile", profile])
    +    args.extend(["serve", "--isolated", "--host", "127.0.0.1", "--port", "0",
    +                 "--ssh-session-token-file", token_path, "--ssh-owner-nonce", spawn_nonce])
    +    # VIRTUAL_ENV preserves venv identity; PYTHONPATH is deliberately NOT set (see above).
    +    env = dict(os.environ)
    +    env["VIRTUAL_ENV"] = os.path.dirname(venv_dir)
    +    env.pop("PYTHONPATH", None)
    +    _ensure_scope(ownership_id)
    +    creationflags = 0x00000008 | 0x00000200 | 0x01000000
    +    _, _, _, win32con, win32file, _, _ = _win32()
    +    log_handle = _open(log_path, win32con.GENERIC_WRITE | win32con.READ_CONTROL,
    +                       win32con.CREATE_NEW, win32con.FILE_ATTRIBUTE_NORMAL | _OPEN_REPARSE_POINT,
    +                       win32con.FILE_SHARE_READ | win32con.FILE_SHARE_WRITE)
    +    import msvcrt
    +    log_fd = msvcrt.open_osfhandle(int(log_handle), os.O_WRONLY)
    +    with os.fdopen(log_fd, "wb", buffering=0) as log_stream:
    +        process = subprocess.Popen(args, stdin=subprocess.DEVNULL, stdout=log_stream, stderr=log_stream,
    +                                   close_fds=True, creationflags=creationflags, env=env)
    +    creation_time_ns = int(__import__("psutil").Process(process.pid).create_time() * 1_000_000_000)
    +    return {"pid": process.pid, "creationTimeNs": str(creation_time_ns),
    +            "logPath": str(log_path), "tokenPath": token_path}
    +
    +
    +def inspect_hermes(hermes_path: str) -> dict[str, Any]:
    +    path = os.path.abspath(hermes_path)
    +    if not os.path.isabs(hermes_path) or not os.path.isfile(path):
    +        raise ValueError("Hermes path is not an executable file")
    +    version = subprocess.run([path, "--version"], capture_output=True, text=True, timeout=20)
    +    help_result = subprocess.run([path, "serve", "--help"], capture_output=True, text=True, timeout=20)
    +    help_text = help_result.stdout + help_result.stderr
    +    return {
    +        "path": path,
    +        "version": (version.stdout + version.stderr).splitlines()[0] if version.returncode == 0 else "",
    +        "supported": "--ssh-session-token-file" in help_text and "--ssh-owner-nonce" in help_text,
    +    }
    +
    +
    +def dispatch(argv: list[str]) -> Any:
    +    if not argv:
    +        raise ValueError("missing operation")
    +    operation = argv[0]
    +    if operation == "probe":
    +        import platform
    +        return {"os": "Windows", "arch": platform.machine(), "hermesHome": str(get_hermes_home()), "python": sys.executable}
    +    if operation == "upload-token" and len(argv) == 3:
    +        return upload_token(argv[1], argv[2], sys.stdin.buffer.read(65))
    +    if operation == "read-lock" and len(argv) == 2:
    +        return read_lock(argv[1])
    +    if operation == "write-lock" and len(argv) == 2:
    +        write_lock(argv[1], _read_json_stdin()); return {"ok": True}
    +    if operation == "remove-lock" and len(argv) == 2:
    +        return {"removed": remove_artifact(_lock_path(argv[1]))}
    +    if operation == "remove-token" and len(argv) == 3:
    +        return {"removed": remove_artifact(_token_path(argv[1], argv[2]))}
    +    if operation == "read-log" and len(argv) == 3:
    +        path = _log_path(argv[1], argv[2])
    +        _, pywintypes, _, win32con, win32file, _, _ = _win32()
    +        try:
    +            handle = _open(path, win32con.GENERIC_READ | win32con.READ_CONTROL,
    +                           win32con.OPEN_EXISTING, win32con.FILE_ATTRIBUTE_NORMAL | _OPEN_REPARSE_POINT,
    +                           win32con.FILE_SHARE_READ | win32con.FILE_SHARE_WRITE)
    +        except pywintypes.error as exc:
    +            if exc.winerror in (2, 3):
    +                return {"content": ""}
    +            raise
    +        try:
    +            _, data = win32file.ReadFile(handle, _MAX_LOG)
    +        finally:
    +            win32file.CloseHandle(handle)
    +        return {"content": data.decode(errors="replace")}
    +    if operation == "remove-log" and len(argv) == 3:
    +        return {"removed": remove_artifact(_log_path(argv[1], argv[2]))}
    +    if operation == "spawn":
    +        return spawn_backend(_read_json_stdin())
    +    if operation == "inspect" and len(argv) == 2:
    +        return inspect_hermes(argv[1])
    +    if operation == "process-state" and len(argv) == 5:
    +        return process_state(int(argv[1]), int(argv[2]), argv[3], argv[4])
    +    if operation == "terminate" and len(argv) == 5:
    +        return {"terminated": terminate_owned(int(argv[1]), int(argv[2]), argv[3], argv[4])}
    +    raise ValueError("invalid operation")
    +
    +
    +def main() -> None:
    +    try:
    +        print(json.dumps(dispatch(sys.argv[1:]), separators=(",", ":")))
    +    except Exception as exc:
    +        print(json.dumps({"error": str(exc)}, separators=(",", ":")), file=sys.stderr)
    +        raise SystemExit(1)
    +
    +
    +if __name__ == "__main__":
    +    main()
    ```
  - `pyproject.toml`

    ```diff
    @@ -116,6 +116,10 @@ dependencies = [
       "python-multipart>=0.0.9,<1",
       "ptyprocess>=0.7.0,<1; sys_platform != 'win32'",
       "pywinpty>=2.0.0,<3; sys_platform == 'win32'",
    +  # Desktop SSH's Windows remote runtime (hermes_cli/windows_ssh_runtime.py)
    +  # imports win32security/win32file/etc. directly — declare pywin32 rather than
    +  # relying on the concurrent-log-handler → portalocker transitive chain.
    +  "pywin32>=306,<312; sys_platform == 'win32'",
       # Image resize recovery for the vision tools. Pillow shrinks oversized images
       # (>5 MB or >8000px) at embed time; without it the byte AND pixel-dimension
       # shrink paths no-op, so an oversized image bakes into immutable history and
    ```
  - `tests/hermes_cli/test_ssh_ownership_endpoint.py`

    ```diff
    @@ -0,0 +1,38 @@
    +from fastapi.testclient import TestClient
    +
    +from hermes_cli import web_server
    +
    +
    +def test_ssh_ownership_endpoint_requires_token_and_returns_exact_nonce(monkeypatch):
    +    token = "t" * 64
    +    nonce = "0123456789abcdef"
    +    monkeypatch.setattr(web_server, "_SESSION_TOKEN", token)
    +    monkeypatch.setattr(web_server, "_SSH_OWNER_NONCE", nonce)
    +    web_server.app.state.auth_required = False
    +    client = TestClient(web_server.app)
    +
    +    assert client.get("/api/ssh/ownership").status_code == 401
    +    response = client.get(
    +        "/api/ssh/ownership",
    +        headers={"X-Hermes-Session-Token": token},
    +    )
    +    assert response.status_code == 200
    +    assert response.json() == {
    +        "ok": True,
    +        "sshOwnerNonce": nonce,
    +        "protocolVersion": 1,
    +    }
    +
    +
    +def test_ssh_ownership_endpoint_is_absent_without_owner_nonce(monkeypatch):
    +    token = "t" * 64
    +    monkeypatch.setattr(web_server, "_SESSION_TOKEN", token)
    +    monkeypatch.setattr(web_server, "_SSH_OWNER_NONCE", None)
    +    web_server.app.state.auth_required = False
    +    client = TestClient(web_server.app)
    +
    +    response = client.get(
    +        "/api/ssh/ownership",
    +        headers={"X-Hermes-Session-Token": token},
    +    )
    +    assert response.status_code == 404
    ```
  - `tests/hermes_cli/test_ssh_session_token_parser.py`

    ```diff
    @@ -0,0 +1,94 @@
    +import argparse
    +import os
    +
    +import pytest
    +from hermes_constants import set_hermes_home_override, reset_hermes_home_override
    +
    +from hermes_cli.main import _read_ssh_session_token_file, cmd_dashboard
    +from hermes_cli.subcommands.dashboard import build_dashboard_parser
    +
    +
    +def dashboard_parser():
    +    parser = argparse.ArgumentParser()
    +    subparsers = parser.add_subparsers(dest="command")
    +    build_dashboard_parser(
    +        subparsers,
    +        cmd_dashboard=lambda _args: None,
    +        cmd_dashboard_register=lambda _args: None,
    +    )
    +    return parser
    +
    +
    +def test_serve_help_advertises_secure_ssh_bootstrap_flags(capsys):
    +    with pytest.raises(SystemExit) as exit_info:
    +        dashboard_parser().parse_args(["serve", "--help"])
    +    assert exit_info.value.code == 0
    +    output = capsys.readouterr().out
    +    assert "--ssh-session-token-file PATH" in output
    +    assert "--ssh-owner-nonce NONCE" in output
    +
    +
    +def test_serve_accepts_owner_nonce():
    +    args = dashboard_parser().parse_args(["serve", "--ssh-owner-nonce", "0123456789abcdef"])
    +    assert args.ssh_owner_nonce == "0123456789abcdef"
    +
    +
    [redacted:email]("operation", ["--status", "--stop"])
    +def test_one_shot_token_file_rejects_non_starting_operations(operation):
    +    args = dashboard_parser().parse_args([
    +        "serve", operation, "--ssh-session-token-file", "/tmp/token",
    +    ])
    +    with pytest.raises(SystemExit, match="cannot be used"):
    +        cmd_dashboard(args)
    +
    +
    +def test_token_file_is_read_and_unlinked_through_private_directory(tmp_path, monkeypatch):
    +    home = tmp_path / "home"
    +    hermes_home = home / ".hermes"
    +    token_dir = [redacted:secret-assignment] / "desktop-ssh" / ("a" * 32)
    +    token_dir.mkdir(parents=True, mode=0o700)
    +    token_path = [redacted:secret-assignment] / "0123456789abcdef.token"
    +    token_path.write_text("b" * 64)
    +    token_path.chmod(0o600)
    +    override = set_hermes_home_override(hermes_home)
    +    try:
    +        assert _read_ssh_session_token_file(str(token_path)) == "b" * 64
    +        assert not token_path.exists()
    +    finally:
    +        reset_hermes_home_override(override)
    +
    +
    [redacted:email](os.name == "nt", reason="POSIX symlink contract")
    +def test_token_file_rejects_symlink(tmp_path, monkeypatch):
    +    home = tmp_path / "home"
    +    token_dir = home / ".hermes" / "desktop-ssh" / ("a" * 32)
    +    token_dir.mkdir(parents=True, mode=0o700)
    +    target = tmp_path / "token"
    +    target.write_text("b" * 64)
    +    target.chmod(0o600)
    +    token_path = [redacted:secret-assignment] / "0123456789abcdef.token"
    +    token_path.symlink_to(target)
    +    override = set_hermes_home_override(home / ".hermes")
    +    try:
    +        with pytest.raises(SystemExit, match="symlink|not accessible"):
    +            _read_ssh_session_token_file(str(token_path))
    +        assert not token_path.exists()
    +        assert target.read_text() == "b" * 64
    +    finally:
    +        reset_hermes_home_override(override)
    +
    +
    +def test_token_file_rejects_parent_escape(tmp_path, monkeypatch):
    +    home = tmp_path / "home"
    +    token_root = home / ".hermes" / "desktop-ssh"
    +    token_root.mkdir(parents=True, mode=0o700)
    +    escaped = token_root.parent / "0123456789abcdef.token"
    +    escaped.write_text("b" * 64)
    +    escaped.chmod(0o600)
    +    override = set_hermes_home_override(home / ".hermes")
    +    try:
    +        with pytest.raises(SystemExit, match="invalid runtime path"):
    +            _read_ssh_session_token_file(str(token_root / ".." / escaped.name))
    +        assert escaped.exists()
    +    finally:
    +        reset_hermes_home_override(override)
    ```
  - `tests/test_web_server.py`

    ```diff
    @@ -69,6 +69,22 @@ async def shutdown(self, sockets=None):
         return captured
     
     
    +def test_start_server_applies_process_local_ssh_bootstrap_state(monkeypatch):
    +    captured = _stub_uvicorn(monkeypatch)
    +
    +    web_server.start_server(
    +        host="127.0.0.1",
    +        port=0,
    +        open_browser=False,
    +        ssh_session_token="s" * 64,
    +        ssh_owner_nonce="0123456789abcdef",
    +    )
    +
    +    assert web_server._SESSION_TOKEN == "s" * 64
    +    assert web_server._SSH_OWNER_NONCE == "0123456789abcdef"
    +    assert captured["port"] == 0
    +
    +
     def test_start_server_disables_ws_ping_on_loopback(monkeypatch):
         """Loopback binds (the Desktop case) MUST disable uvicorn's protocol-level
         keepalive ping so an event-loop stall can never trigger a false disconnect.
    ```
  - `uv.lock`

    ```diff
    @@ -1539,6 +1539,7 @@ dependencies = [
         { name = "pyjwt", extra = ["crypto"] },
         { name = "python-dotenv" },
         { name = "python-multipart" },
    +    { name = "pywin32", marker = "sys_platform == 'win32'" },
         { name = "pywinpty", marker = "sys_platform == 'win32'" },
         { name = "pyyaml" },
         { name = "requests" },
    ```

    ```diff
    @@ -1823,6 +1824,7 @@ requires-dist = [
         { name = "python-multipart", marker = "extra == 'web'", specifier = "==0.0.27" },
         { name = "python-telegram-bot", extras = ["webhooks"], marker = "extra == 'messaging'", specifier = "==22.6" },
         { name = "python-telegram-bot", extras = ["webhooks"], marker = "extra == 'termux'", specifier = "==22.6" },
    +    { name = "pywin32", marker = "sys_platform == 'win32'", specifier = ">=306,<312" },
         { name = "pywinpty", marker = "sys_platform == 'win32'", specifier = ">=2.0.0,<3" },
         { name = "pyyaml", specifier = "==6.0.3" },
         { name = "qrcode", marker = "extra == 'dingtalk'", specifier = "==7.4.2" },
    ```
- **#73926: fix(desktop): resolve local plugin root independent of remote backend (#66899)**. merged to main · fix tier `verified`
  - maintainer direction: category `merged`; implication `superseded`
  - files: `apps/desktop/electron/main.ts`, `apps/desktop/electron/preload.ts`, `apps/desktop/src/app/settings/plugins-settings.tsx`, `apps/desktop/src/contrib/runtime-loader.test.ts`, `apps/desktop/src/contrib/runtime-loader.ts`, `apps/desktop/src/global.d.ts`
- **#39122: feat(desktop): remote workspace + terminal over SSH (#38671, #38369, #38464)**. closed without merge
  - maintainer direction: category `implemented_elsewhere`; implication `superseded`; refs `#68130`, `#38671`, `#38369`, `#68130`, `#50707`, `#45893`
- **#42497: fix(desktop): skip remote session cwd in Files panel to prevent ENOENT**. closed without merge
  - maintainer direction: category `superseded_by_pr`; implication `superseded`; refs `8878484f85192a0d443a4c856b8e9f424ac46d2c`
- **#43434: feat(desktop): browse remote backend files**. closed without merge
  - maintainer direction: category `implemented_elsewhere`; implication `superseded`; refs `#42878`
- **#66911: fix(desktop): resolve local plugin root independent of remote backend (#66899)**. closed without merge
  - maintainer direction: category `merged_via`; implication `superseded`; refs `#73926`
- **#68276: fix(desktop): load disk plugins from local Hermes home**. closed without merge
  - maintainer direction: category `superseded_by_pr`; implication `superseded`; refs `eaecca4a71`, `#73926`, `#66911`, `#66152`

## Fix status

- Merged to main in PR #44326 (cited above). No release data is tracked. Verify downstream.
- Fix last verified (merged) `2026-07-29`.
- Subsystem: `apps/desktop`
