Skip to content

Feature request: Open remote (SSH) worktrees in external IDEs (Zed / VS Code / Cursor / JetBrains) via each editor's own Remote-SSH mode #436

Description

@jeremybower

Summary

Remote SSH worktrees (shipped in #407) can be driven from the terminal, but the "Open in…" actions are disabled for them — a remote worktree can't be opened in any GUI editor. Every modern editor Supacode already lists now has a first-class Remote-SSH mode, and Supacode already holds every input needed to launch them against the remote host (real diffs + editing next to the remote agent, not just a terminal). This issue proposes wiring that subset up.

This completes the remote beta rather than adding new surface area: it reuses the local | remote worktree split, the RemoteHost metadata (already sourced from ~/.ssh/config), and the generic CLI-launcher seam from #417/#423.

Motivation

After #407 a remote worktree is a first-class sidebar row with terminal + git + agent orchestration over SSH — but the only way to see the code is the terminal. Meanwhile the major editors all natively open a folder on a remote host over SSH, so Supacode is one launch argument away from a full remote editing session beside the remote agent.

Current behavior

Open / Reveal is deliberately rejected for remote worktrees at the reducer chokepoint:

// supacode/Features/App/Reducer/AppFeature.swift  (openWorktreeEffect, ~L1263)
// Open / Reveal target local Finder / editors; a remote SSH path can't be
// reached, so reject it here regardless of the entry point ...
if worktree.host != nil {
  appLogger.info("Ignoring open of remote worktree ...")
  return .none
}

with matching gates in WorktreeDetailView (canOpenLocally = … host == nil) and the sidebar context menu (.disabled(worktree.host != nil)). This is correct today: for a remote worktree worktree.workingDirectory is a synthetic file:// URL over the remote path (Domain/RepositoryIdentity.swift, doc-commented "never hand it to FileManager"), so handing it to NSWorkspace/Process would open a nonexistent local path.

Proposed behavior

For editors that support Remote-SSH, branch instead of bail and launch the editor's CLI with a remote target:

  • Zedzed ssh://[<user>@]<host>[:<port>]/<remotePath> (also accepts scp-style zed ssh://host:~/project and the zed://ssh/… hotlink form). Zed shells out to ssh on PATH and inherits ~/.ssh/config, and auto-provisions its headless server on the remote (nothing to pre-install). Requires Zed ≥ v0.159. (Bonus: Zed dev containers — Stable since Jan 2026, v0.218 — build on this same remote architecture, so a remote + containerized agent workflow is a natural follow-on.)
  • VS Code family / Cursor / Windsurfcode --remote ssh-remote+<sshHost> <remotePath> (equivalently --folder-uri vscode-remote://ssh-remote+<sshHost><remotePath>).
  • JetBrains — Gateway link / gateway CLI form.
  • Editors / apps with no remote mode (Finder, git GUIs, Xcode) stay disabled for remote rows — no behavior change.

The inputs already exist on every remote worktree:

  • RemoteHost.authorityuser@host:port
  • WorktreeLocation.workingDirectoryPath → the absolute remote path

Where it plugs in

  1. AppFeature.swift openWorktreeEffect (~L1263) — the universal chokepoint. The host != nil guard branches to a remote launch for the supported editor subset instead of returning .none.
  2. Clients/Workspace/WorkspaceClient.swift (WorktreeOpener.perform, WorkspaceOpenResolver.resolve) — add an OpenTarget/OpenBehavior that emits the per-editor remote invocation, reusing the cliLauncher seam from Open each worktree in its own Zed window #417/Generalize worktree open targets #423 rather than NSWorkspace.open. (Zed is already wired to launch via its bundled CLI here, so it's the lowest-friction first editor.)
  3. UI gates (WorktreeDetailView canOpenLocally, SidebarItemsView .disabled(...)) — relax for the supported editors only.

Host-alias mapping (per-editor, smaller than it looks)

The one wrinkle is how each editor names the remote host:

  • Zed takes a raw ssh://[user@]host[:port]/path URI and resolves it through ~/.ssh/config itself — so RemoteHost.authority + the remote path map directly, no alias lookup needed. This makes Zed the clean first target.
  • VS Code / Cursor / Windsurf want ssh-remote+<hostAlias>, where <hostAlias> is a ~/.ssh/config Host entry rather than a raw user@host:port. Since RemoteHost is already sourced from ~/.ssh/config (per Remote repositories over SSH #373/Add remote SSH repositories and worktrees #407), the alias should be recoverable, but the exact mapping wants verification before committing to an arg format.

Scope / non-goals

Prior art in this repo

References

Contribution

I'd be happy to contribute a PR implementing this. I'd suggest starting with Zed as the first editor — it's already wired through the cliLauncher seam and its zed ssh://… form resolves ~/.ssh/config directly, so it sidesteps the host-alias mapping — then extending to the VS Code family and JetBrains once the remote-launch path is proven. Happy to align on scope/approach before opening the PR.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions