Skip to content

Add remote SSH sessions (Phase 2): index, search & resume past sessions - #77

Closed
HAN-oQo wants to merge 2 commits into
doctly:mainfrom
HAN-oQo:feat/remote-ssh-phase2
Closed

Add remote SSH sessions (Phase 2): index, search & resume past sessions#77
HAN-oQo wants to merge 2 commits into
doctly:mainfrom
HAN-oQo:feat/remote-ssh-phase2

Conversation

@HAN-oQo

@HAN-oQo HAN-oQo commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Summary

Phase 2 of remote SSH support. Phase 1 (#76) let you launch Claude/shell on remote hosts, but remote sessions appeared in the sidebar only while live. This PR indexes a connected host's past sessions so they persist across restarts, are searchable, and resume in a terminal — reaching local parity. No transcript is copied to your local disk; everything is read on demand over the existing SSH connection.

⚠️ Stacks on #76. This branch builds on the Phase 1 branch, so until #76 merges this PR's diff includes #76's changes. Please merge #76 first; the Phase-2-only work is the final commit.

Screenshots use redacted demo hosts (gpu-server, build-box, *.example.com); no real infrastructure is shown.

Past remote sessions now persist in the sidebar — grouped by remote directory, each with the SSH badge, the Claude logo, and a ⟳ refresh control (local projects, e.g. dev/webapp, have neither):

Remote sessions grouped in the sidebar

Full-text search covers remote transcripts too — here memory matches two remote sessions by their synced content, not just titles:

Searching remote sessions

What's new

  • Auto-discovery — connect a host and every past session on it appears, grouped by its remote directory (ssh://<host>/<dir>). No per-directory registration needed.
  • Search — remote sessions are indexed into the existing FTS table (tagged with a new source column) and show up in search alongside local ones.
  • Persistence — indexed remote sessions survive app restarts (served from the local cache DB); a background sweep re-syncs reachable hosts on launch.
  • Click-to-resume — clicking a remote session resumes it in a terminal (cd <dir> && claude --resume "<id>" on the host), same UX as local. Fork supported. Remote Control reconnects automatically on resume when the session had it.
  • View messages — reads the remote transcript live over SSH (no local copy); prompts to connect when offline.
  • Refresh (⟳) on remote project headers; status-bar feedback for sync results.

How it works

  • Transport: metadata-over-SSH sync over the Phase 1 ControlMaster socket (remote-index.js). Lists ~/.claude/projects/*.jsonl, derives a project per session from its cwd, fetches only new/changed transcripts via a length-framed stream, parses them in memory with the shared parseSessionContent (extracted from read-session-file.js, identical to local behavior), and upserts into the cache + FTS with source = <host>. Vanished sessions are pruned.
  • DB: additive migration adds a source column to session_cache and search_map (NULL = local — no cache wipe). All folder-scoped queries are source-isolated so local and remote rows never collide.
  • No local mirror: transcripts are never written to disk; "View messages" and resume read the remote host directly (source of truth).

Testing

  • 56 unit tests (npm test, run under Electron's node to match the app's better-sqlite3 ABI): JSONL parsing, the SSH listing/framing/diff/cwd parsers, the source migration + source-isolation, sync orchestration (SSH runners injected), and sidebar grouping.
  • The v3→v4 migration was verified against a copy of a real DB (34 sessions preserved, source backfilled to local).
  • Manual: connect → past sessions appear + searchable → restart shows them from cache → click resumes on the host → View messages streams live.

Roadmap

Remote SSH support ships in phases, ordered by effort‑to‑value — each is independently useful and lands as its own PR. This PR is Phase 2.

  • Phase 1 — Remote sessions & host management (Add remote SSH sessions (Phase 1): remote projects, Connect, Browse, host management #76): launch Claude/shell on remote hosts; remote hosts + directories as first‑class projects; interactive Connect; remote directory Browse; host config (import, manual add, identity/options, write‑to‑~/.ssh/config).
  • Phase 2 — Indexing, search & resume (this PR): index a connected host's past sessions (metadata over the existing SSH connection — no transcript copied to disk) so they persist in the sidebar, are searchable, and resume/fork in a terminal on the host. Adds a source column to the cache/search tables.
  • Phase 3 — IDE emulation over SSH: reverse‑forward the IDE MCP socket (ssh -R) so remote proposed diffs / file opens land in Switchboard's side panel (behind a setting).

Why this order: Phase 1 delivers the core "run Claude Code on my server" value with the least new machinery (reuses the node‑pty + shell‑profile path, mirroring how WSL is modeled); Phase 2 unlocks history, search, and resume; Phase 3 adds richer IDE workflows. Nothing later blocks shipping this one.

(Remote Control — claude --remote-control for live cross-device mirroring — is orthogonal to local-vs-remote and is tracked separately, not part of this roadmap.)

🤖 Generated with Claude Code

HAN-oQo and others added 2 commits July 13, 2026 18:33
Run Claude Code and shells on remote hosts over SSH. Remote hosts and directories
are first-class projects alongside local ones — no local-only assumption anymore.

- shell-profiles + remote-hosts: SSH shell profiles (mirrors the existing WSL
  wrapped-command pattern), ~/.ssh/config parsing, remote command assembly
  (single-quoted to survive ssh's argv re-parse), ControlMaster multiplexing.
- main.js: open-terminal remote branch (skips local-path checks, local cwd=$HOME,
  no MCP/shim), plus IPC for remote projects, interactive connect, remote dir
  browse, host save/test, and write-to-~/.ssh/config.
- session-cache: persisted remote projects injected into the sidebar; live remote
  sessions group under them (remote Claude reads as a Claude session).
- renderer: Add Project (Local | Remote SSH) with "+ Add new host", inline Connect
  with structured password / host-key popups (no raw terminal), remote directory
  browser, host management in Settings, SSH badges.
- 30 unit tests (node --test).

Auth stays with the user: passwords/passphrases/passkeys/host-key confirmations are
entered by the user; nothing is stored. Remote session indexing/search (Phase 2),
fork/resume on the remote (Phase 3), and IDE-over-SSH (Phase 4) are deferred — see
the PR description.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Builds on Phase 1 (doctly#76). Remote sessions previously appeared in the sidebar only
while live; this indexes a connected host's PAST sessions so they persist, are
searchable, and resume in a terminal — with no transcript copied to local disk.

- read-session-file: extract pure parseSessionContent(content, meta), shared by
  local and remote indexing (identical summary/title/search behavior).
- remote-index (new): metadata-over-SSH sync over the live ControlMaster socket.
  Lists a host's ~/.claude/projects/*.jsonl, auto-discovers a remote project per
  session from its cwd (ssh://<label>/<dir>), fetches only new/changed transcripts
  (length-framed stream), parses in memory, upserts cache + FTS tagged source=host,
  prunes vanished sessions. Pure helpers are unit-tested.
- db: add `source` column to session_cache + search_map (NULL = local; additive
  migration, no cache wipe). Source-scoped queries isolate local vs remote rows.
  DB path overridable via env for tests.
- main: sync-remote-host IPC + runRemoteSync; triggers on connect, manual refresh,
  remote-session exit, and a background sweep at startup (status surfaced to the
  status bar). read-session-jsonl streams remote transcripts live over SSH
  (View messages) with a needsConnect fallback. remove-project drops a remote
  project's indexed rows.
- Click-to-resume parity: a remote session resumes in a terminal via
  `cd <dir> && claude --resume "<id>"` on the host (fork supported); the resume
  dir is derived from the ssh:// projectPath. Remote Control reconnects
  automatically on resume when the session had it.
- sidebar/app: past remote sessions show the SSH badge + Claude logo; a refresh
  (⟳) control on remote project headers.
- test: run under Electron's node (matches the app's better-sqlite3 ABI).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@HAN-oQo

HAN-oQo commented Jul 14, 2026

Copy link
Copy Markdown
Contributor Author

Superseded by #78, which combines remote-SSH Phase 1–3 into a single PR for easier review.

@HAN-oQo HAN-oQo closed this Jul 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant