---
title: SSH Remote (run sessions on another machine)
---
# SSH Remote (run sessions on another machine)

## What it is

SSH Remote lets any individual Omniscio session run its Claude CLI on a **different** machine — your GPU box, a Linux dev server, a cloud VM — while you drive it from the Omniscio UI on your desktop. Under the hood Omniscio opens an SSH connection to the remote host, pipes a bash bootstrap script over stdin, launches the CLI remotely, and streams the NDJSON output back to your local UI as if the process were running here. Useful when the code you need Claude to edit lives on a remote box, when a session needs GPU access your laptop doesn't have, or when you want session work isolated to a cheap cloud VM. Per-session (not per-project), so you can freely mix local and remote sessions in the same project.

## Where to find it

**Settings → SSH Remotes** — add a host, choose a key strategy, and optionally set it as the default. A session then picks a remote from the **Run** chip.

## How it behaves

### How to use it

1. **Add a remote host.** Settings → **SSH Remotes** → **Add remote**. Fill in a nickname, host, port (default 22), username, and pick a key strategy — **Generate new Ed25519 key** (Omniscio creates one for this host, stored in `{userData}/keys/`) or **Use existing** (point at a private key file you already manage).
2. **Install the public key on the server.** Omniscio shows you the public key — paste it into `~/.ssh/authorized_keys` on the remote host (or use your existing method). Click **Test connection** — Omniscio does a quick handshake and reports success/failure with the exact error if it fails.
3. **Trust the host key.** First connection adds the server's SSH host-key to an app-managed `ssh_known_hosts` file (isolated from your regular `~/.ssh/known_hosts` so Omniscio can't pollute your system config). Subsequent connections TOFU-verify against this file — mismatches will fail closed, which is what you want if someone's MITM'ing you.
4. **Launch a session on the remote.** Start a new session, then on the new-session screen use the **Run** chip in the pill row (beside Model / Thinking / MCP). It lists **Local** plus every SSH remote you configured (the remotes Omniscio creates for its own cloud sessions are internal and never listed). Pick one and send your first message — the session is created on that host, and the status dot, output stream, and input all behave like a local session. The pick is staged, so nothing connects until you send. Each **project** gets its own folder on the remote: a new session runs in `<Remote Working Dir>/<project-slug>`, created automatically on first use, so two projects on the same remote never share a directory. That folder is decided once, when a session first runs, and stays put — renaming the project or editing the remote never moves a running session's work, and a session that already ran keeps the directory it has been using. (Cloud VMs and Windows remotes keep a single working directory instead.)
5. **Switch defaults.** If most of your work happens on one remote, make it the default via Settings → SSH Remotes → **Set as default**. The Run chip then pre-selects it on every new session, with **Local** one click away.

**Which engines can run remotely.** Only the native **Claude** engine. Every other engine
(Codex, Gemini, Cursor, the DeepSeek/Kimi/GLM family, the GPT/xAI proxies, and the rest)
runs on your own computer regardless of this setting — their credentials are a local
overlay that is never forwarded to the remote host. The Run chip greys those remotes out
and says so, rather than letting a session silently run in the wrong place.

**Phone and web.** Choosing a remote is desktop-only. The SSH commands are deliberately
refused over the mobile bridge because they expose private-key paths, so on a phone the
Run chip shows Local only.

### How it works

The 9 IPC channels are declared in [/src/shared/ipc-channels/remote.ts](/src/shared/ipc-channels/remote.ts): `SSH_LIST_REMOTES`, `SSH_SAVE_REMOTE`, `SSH_DELETE_REMOTE`, `SSH_GET_DEFAULT`, `SSH_SET_DEFAULT`, `SSH_TEST_CONNECTION`, `SSH_GET_CONFIG_HOSTS`, `SSH_QUICK_CONNECT_BOOTSTRAP`, `SSH_QUICK_CONNECT_PROGRESS`. Handlers live in [/src/main/ipc/ssh-handlers.ts](/src/main/ipc/ssh-handlers.ts). CRUD + validation + connection-testing is in [/src/main/services/ssh/ssh-remote-manager.ts](/src/main/services/ssh/ssh-remote-manager.ts). Ed25519 keys are generated by spawning `ssh-keygen` via [/src/main/services/ssh/ssh-key-manager.ts](/src/main/services/ssh/ssh-key-manager.ts) and stored at file mode `0o600` in `{userData}/keys/`. Spawn construction — which is where the security invariants bite — is [/src/main/services/ssh/ssh-command-builder.ts](/src/main/services/ssh/ssh-command-builder.ts): **never** uses `shell: true`, always runs `shellEscape()` on any user-supplied value (remote working directory, environment variables, arguments), pipes a bash bootstrap script to stdin so we don't have to argv-encode multi-line scripts. Per-session resolution — which remote to use for a given sessionId — happens in [/src/main/services/ssh/ssh-remote-resolver.ts](/src/main/services/ssh/ssh-remote-resolver.ts). The settings UI is [/src/renderer/src/features/settings/sections/ssh-remotes/SshRemotesSettings.tsx](/src/renderer/src/features/settings/sections/ssh-remotes/SshRemotesSettings.tsx). TOFU host-key verification uses an app-private `ssh_known_hosts` file in `{userData}/` — isolated from `~/.ssh/known_hosts` so Omniscio can neither read your personal hosts nor mutate them. Ed25519 private keys are **not** additionally encrypted by Omniscio — on-disk protection is OS file permissions only (0600). Full security context: [security.md](/.claude/memory/security.md).

## Related

- [cli-control.md](cli-control.md) — CLI Control is the _inverse_ pattern: other tools controlling a local Omniscio
- [session-stuck-in-needs-you.md](session-stuck-in-needs-you.md) — remote sessions hit the same pending-action surfaces
