#SSH
coterm ssh creates a workspace for a remote machine. Browser panes route through the remote network, files drag-and-drop via scp, coding agents send notifications to your local sidebar, and sessions reconnect on drops.
#Usage
coterm ssh user@remote
coterm ssh user@remote --name "dev server"
coterm ssh user@remote -p 2222
coterm ssh user@remote -i ~/.ssh/id_ed25519coterm ssh reads your ~/.ssh/config for host aliases, identity files, and proxy settings. All flags mirror their ssh equivalents.
#Flags
| Flag | Description |
|---|---|
--name | Set the workspace title |
-p, --port | SSH port (default 22) |
-i, --identity | Path to identity file |
-o, --ssh-option | Pass arbitrary SSH options (e.g. -o StrictHostKeyChecking=no) |
--no-focus | Create the workspace without switching to it |
#SSH deep links
Use Coterm SSH deep links when a website or tool wants to offer an Open in Coterm button. The link opens coterm, shows a confirmation prompt, then runs the equivalent coterm ssh command after the user confirms.
coterm://ssh?host=dev.example.com
coterm://ssh?host=dev.example.com&user=alice&port=2222&title=GPU%20box
coterm://ssh?host=workspace123.vm-ssh.freestyle.sh&user=workspace123%2Csession-token
coterm://ssh?host=dev.example.com&host-key-policy=accept-new&no-focus=trueUse the coterm.cc fallback URL for website buttons. It opens the native link and shows the download if Coterm is not installed.
https://coterm.cc/deeplink/ssh?host=workspace123.vm-ssh.freestyle.sh&user=workspace123%2Csession-token&title=FreestylePrompt and rules buttons use the same fallback shape. Commas, colons, and literal plus signs are preserved when they are URL encoded:
https://coterm.cc/deeplink/prompt?text=Review%20this%20branch
https://coterm.cc/deeplink/rules?name=freestyle&text=Prefer%20commas,%20colons:%20and%20small%20PRsUse the SVG icon for dashboard buttons, or the PNG logo when a raster image is required:
https://coterm.cc/coterm-icon.svg
https://coterm.cc/logo.pngBuild the fallback URL with URLSearchParams so titles, host aliases, and user names are encoded safely:
const params = new URLSearchParams({
host: "workspace123.vm-ssh.freestyle.sh",
user: "workspace123,session-token",
title: "Freestyle",
});
const href = "https://coterm.cc/deeplink/ssh?" + params.toString();| Parameter | Meaning |
|---|---|
host | Required SSH host or ~/.ssh/config alias. |
user | Optional SSH user. coterm combines it with host as user@host. |
port | Optional SSH port, 1 through 65535. |
title / name | Optional workspace title. Use only one of title or name. |
connect-timeout | Optional ConnectTimeout value in seconds, 1 through 600. |
server-alive-interval | Optional ServerAliveInterval value in seconds, 1 through 3600. |
server-alive-count-max | Optional ServerAliveCountMax value, 1 through 100. |
host-key-policy | Optional StrictHostKeyChecking policy: accept-new, ask, strict, or yes. |
no-focus | Optional boolean. true creates the workspace without switching to it. |
Use coterm:// for the stable app, coterm-nightly:// for Nightly, and coterm-dev:// for Debug or tagged dev builds.
External links cannot pass identity files, raw ssh options, commands, ProxyCommand, or forwarding rules. Put keys, ProxyJump, HostName, and advanced options in ~/.ssh/config instead. coterm displays the command preview and requires the user to trust the SSH target before connecting.
#Browser panes
Browser panes in a remote workspace route all HTTP and WebSocket traffic through the remote machine's network. Type localhost:3000 and you're looking at the dev server running on the remote box. No -L flags, no manual port forwarding. Each remote workspace gets an isolated cookie store so sessions are scoped per-connection.
#Drag and drop
Drag an image or file into a remote terminal and coterm uploads it via scp through the existing SSH connection. coterm detects the foreground SSH process by TTY and routes the upload through ControlMaster multiplexing.
#Notifications
Processes on the remote machine can run coterm commands that execute on your local instance. When a coding agent calls coterm notify on the remote box, the notification appears in your local sidebar. The blue ring lights up on the workspace tab. Cmd+Shift+U jumps to it. Notification spam from flaky connections is suppressed with a per-host cooldown.
#Coding agents over SSH
coterm claude-teams and coterm omo both work inside SSH sessions. The Go relay daemon on the remote host handles the same tmux-compat translation that the local Swift CLI does. Teammate agents spawn as native coterm splits on your local machine while computation runs on the remote box.
# Inside an SSH session:
coterm claude-teams
coterm omo#Reconnect
When the connection drops, coterm reconnects with exponential backoff (3s, 6s, 12s, up to 60s). The remote session persists and coterm reattaches on reconnect, resizing with smallest-screen-wins semantics. Default keepalive options (ServerAliveInterval=20, ServerAliveCountMax=2) are injected unless your config already sets them.
#Relay daemon
On first connect, coterm probes the remote host (uname -s, uname -m) and uploads a versioned cotermd-remote binary. The binary speaks JSON-RPC over stdio and handles three things:
| Feature | How |
|---|---|
| Browser traffic proxying | SOCKS5 and HTTP CONNECT over the daemon's stdio channel |
| CLI relay | Reverse TCP tunnel with HMAC-SHA256 auth so remote processes can call coterm commands locally |
| Session management | Persists sessions across reconnects, coordinates PTY resize across multiple attachments |
The daemon binary is stored at ~/.coterm/bin/cotermd-remote/<version>/<os>-<arch>/cotermd-remote on the remote host and verified against a SHA-256 manifest embedded in the app.