Files
cline/sdk/DOC.md
T
Bee 17529c8cb1 feat(core): add SSH remote environments (#14116)
* feat(core): add SSH remote environments

* fix(core): harden SSH lifecycle and helper package exports

* fix(core): use current SSH identity for pending cleanup

* docs(core): clarify SSH destination invariants during cleanup

* fix(core): recover SSH cleanup after remote Hub crashes

* test(core): make SSH regression coverage portable on Windows

* fix(core): leave account connectors untouched by SSH Hubs

* fix(core): restore missing SSH helpers for pending cleanup
2026-09-14 19:58:02 -07:00

3.3 KiB

SSH remote environments

RemoteEnvironmentService (exported by @cline/core and @cline/sdk) owns SSH profiles, connection testing, helper installation, authenticated loopback tunnels, remote commands, status changes, and cleanup. It runs in the client's Node host; browser clients expose this API through their host transport. No desktop code is required. OpenSSH config aliases, identity files, and ssh-agent authentication are supported. Connections use batch mode and require an already-trusted host key in OpenSSH known_hosts (or knownHostsPath). Before first use, verify the server fingerprint through a trusted channel and enroll it using your SSH client. Unknown or changed keys are rejected before inspection, upload, or execution.

import { ClineCore, RemoteEnvironmentService } from "@cline/core";

const environments = new RemoteEnvironmentService({
  helperBinaryDirectory: "/opt/my-client/remote-helpers",
  onStatusChange: (status) => console.log(status),
});
const profile = await environments.upsert({ name: "Build host", host: "builder" });
const connection = await environments.connect(profile.id);
const core = await ClineCore.create({
  clientName: "my-client",
  backendMode: "remote",
  remote: {
    endpoint: connection.endpoint,
    authToken: connection.authToken,
    workspaceRoot: connection.workspaceRoot,
  },
});
try {
  // The ordinary session, tools, approvals, and event APIs execute on this host.
  // Supply provider credentials in the session config, as for other remote hubs.
  console.log(await core.list());
} finally {
  await core.dispose();
  await environments.dispose();
}

The service also exposes list, upsert, delete, test, disconnect, run, getConnection, getActive, activateConnection, and getStatuses. onConnectionLost lets clients retire runtime bindings after a tunnel fails. Each service instance has a unique remote Hub discovery record, so another client connecting to the same host cannot stop its Hub. Connect/disconnect/profile mutations are serialized; concurrent connects reuse one tunnel. Dispose the ClineCore runtime before disconnecting its environment. Do not expose the connection's authentication token to a browser or logs.

Profiles default to ~/.cline/data/settings/remote-environments.json, written atomically with mode 0600. They contain identity-file paths, never private keys. Options include profilesPath, sshPath, knownHostsPath, process timeouts, helperBinaryPath, and helperBinaryDirectory. The corresponding helper/SSH configuration variables are CLINE_REMOTE_HELPER_BINARY, CLINE_REMOTE_HELPER_DIRECTORY, CLINE_SSH_PATH, and CLINE_SSH_KNOWN_HOSTS_FILE.

Clients package a matching self-contained helper using the @cline/core/remote/helper-entry executable entrypoint, compiled with Bun for the remote OS and architecture. Use remoteHelperBinaryFilename({ platform, arch }) for the filename (cline-remote-helper-<target-triple>). Linux and macOS on x64/arm64 are supported. Helpers must include the same SDK build as the client; missing helpers produce an explicit error, without installing a runtime from the network. The helper implements --remote-hub-ensure --cwd <path> --discovery-path <path> and the core detached-daemon sentinel. Agent tools and persistence run remotely; the host only manages SSH and forwards the authenticated hub connection.