Remote sessions
--remote runs your sessions on another machine over SSH while the rozi window stays on your own computer. The shells and programs in the panes run on the remote host; the theme, keybindings, overlays, and clipboard stay local. This page covers connecting, managing hosts, SSH setup, installing rozi on the host, and what happens when a connection drops.
Inside a remote pane, rozi context and rozi --here target that pane's session on the remote host. --here cannot borrow your local UI's authority across SSH. Layout mutations require the controller to detach, and input locks must be unlocked, unless the command is submitted through the controlling UI's socket on the UI host. When direct session control requires that authority, --here returns unsupported. See caller context.
Connect
rozi --remote workbox
rozi --remote workbox dev
rozi --remote ssh://user@host:2222
rozi --remote workbox sessions attach dev
rozi --remote workbox sessions new review
rozi sessions new scratch --detach --remote workbox
rozi sessions list --remote workbox
rozi sessions restart dev --remote workbox
rozi sessions upgrade dev --remote workbox
rozi sessions kill dev --remote workboxSession commands behave as they do locally: a named target attaches to its running session or launches the profile of the same name. See Sessions. The rozi worktrees commands also accept --remote; see Worktrees on a remote host.
A bare rozi --remote workbox names no session, so [session] startup decides what happens, applied on workbox. Under the default, picker, rozi connects, lists the host's sessions, and creates nothing. See Choose startup behavior for the other values.
rozi supports Linux, macOS, and Windows as both client and remote host. The local machine needs ssh on PATH; installing rozi automatically onto a Windows host also needs scp. rozi downloads and verifies release files itself, so installing does not need curl, tar, or unzip.
For a host you use regularly, add it in Remote hosts instead of typing it each time. Use [remote.hosts.*] for a host that needs more settings, such as an identity file, extra ssh arguments, or a fixed binary path.
Manage remote hosts
Open Sessions (Ctrl+A, then s) and press Ctrl+R to open Remote hosts. It lists configured hosts, hosts you added, recently used hosts, hosts remembered for reconnecting, and hosts with a live attachment. Opening or returning to this list does not contact any machine.
Enter opens Sessions with that host’s tab selected.
| Key | Remote hosts |
|---|---|
Enter | Open the selected host’s Sessions tab, connecting first if needed |
Ctrl+N | Add a host |
Ctrl+E | Edit the selected host |
Ctrl+R | Reconnect a connected host and refresh its sessions |
Ctrl+K twice | Forget the selected host |
Esc | Cancel a connection in progress, otherwise return to the previous picker |
The Sessions picker provides session creation, switching, restart, kill, and disconnect actions. Esc closes Sessions; Ctrl+R opens host management.
Connect and open a host
Press Enter on a host to open Sessions on its tab. A disconnected host connects first; a connected host opens immediately. Connection failures leave the host list open with the error on its row so you can retry or edit the host. Opening a host does not attach a session or start a shell; choose or create a session in Sessions.
While a host is connecting, its row shows a spinner and Connecting…, and Esc cancels the attempt. One host connects at a time.
rozi --remote <host> also opens Sessions on the host’s tab as soon as it connects. Ctrl+R reconnects and refreshes the host while staying on Remote hosts.
Add a host
Press Ctrl+N. The form has the same three fields as the host editor:
› Host adam@10.0.0.5
Username adam
Port 22Typing a login in the host field, as in adam@10.0.0.5 or ssh://adam@workbox:2222, fills in Username and makes it read-only. Delete the user@ part to edit Username again. Leave Username empty to use the login from ~/.ssh/config.
Tab and Shift+Tab move between fields, Enter saves, and Esc cancels.
rozi saves the host before it tries to connect, and keeps it whether or not the connection succeeds. rozi never stores passwords; OpenSSH asks for one when needed.
Added hosts are saved to saved-hosts in the state directory, which only you can read. If saving fails, the host is still usable until rozi exits, and a warning explains why.
When a connection fails
The row stays in the list, marked ! in the error colour with a short reason, and a toast shows the same message:
! workbox SSH login rejectedThe error stays on the row until the host connects or you retry, edit, or forget it. Enter retries, Ctrl+E edits the host, and Ctrl+K twice forgets it. See Troubleshooting for what each message means.
Edit or forget a host
Ctrl+E opens the host editor with the saved host, username, and port. Saving updates the entry in place and returns to the list without connecting. For aliases, keys, SSH agents, ProxyJump, and other advanced options, use ~/.ssh/config.
Ctrl+K twice forgets a host you added or one rozi remembers from a past connection. Forgetting also removes the host's cached session list. Some hosts cannot be forgotten here:
- A configured host stays as long as it is in the configuration.
- A host known only through a live attachment disappears when that attachment ends.
- A host with a live or connecting attachment must be disconnected first.
Work on a host without a session
Opening a host scopes the launcher to that machine. Opening it never creates or attaches a session, and [session] startup does not run again. A client can stay scoped to a host while holding no session there:
╭─REMOTE · workbox──────────────────────────╮
│ Enter / Ctrl+A Enter shell on workbox │
│ Ctrl+A s pick a session │
│ Ctrl+A q / Ctrl+A d leave │
╰───────────────────────────────────────────╯This is a normal state, not an error, and it does not mean an SSH connection is open. Enter starts a temporary shell on workbox. You land here after rozi --remote workbox under startup = "picker" once you dismiss the picker, and when you close Sessions on the workbox tab with nothing attached.
Closing Sessions keeps the scope. To leave the host, press Ctrl+X on its Sessions tab; it is available whenever this client is tied to that host, including by scope alone.
Sessions opened from this state starts on the host's tab, so its Ctrl+N and Ctrl+T create sessions on that host; switch to Local for this machine. See Scope and The sessionless launcher.
Set up SSH authentication
rozi uses your OpenSSH configuration, keys, agent, known_hosts, jump hosts, and other SSH policy. It does not manage credentials.
By default, rozi asks for host-key approval, passwords, and key passphrases when needed. For regular use, load a key into your SSH agent or set an identity file:
[remote.hosts.workbox]
host = "workbox.example.com"
user = "dev"
identity_file = "~/.ssh/id_ed25519"Set [remote] batch_mode = true to refuse SSH prompts. Unattended command-line runs always use batch mode, so their authentication must complete without a prompt.
Test authentication directly when setup fails:
ssh workboxPrompts inside the UI
A running rozi client shows SSH prompts in a dialog by default:
- A password or key passphrase is masked and never shown.
- A host-key question shows OpenSSH's wording as is and has a text field, because OpenSSH accepts the fingerprint itself as an answer as well as
yesandno. What you type is not masked. The full fingerprint is repeated on its own line below the question so you can compare it without a line break in the middle. - Any other yes-or-no question from SSH offers
YesandNo.←and→move between them, andEnteror a click chooses one. - A rejected password is reported on the prompt when SSH asks again.
Esccancels the connection attempt.- A prompt left unanswered for five minutes fails its connection and closes.
The dialog needs OpenSSH 8.4 or newer on your machine, and it replaces a desktop SSH_ASKPASS program for rozi's own connections. With an older OpenSSH, rozi cannot show prompts, so load a key into your agent, or connect once with ssh <HOST> to accept its host key.
Interactive command-line runs keep SSH's ordinary terminal prompt: rozi sessions list --remote, rozi sessions new --detach --remote, rozi sessions kill --remote, and the install prompt shown before launch.
Configure aliases and defaults
--remote accepts an SSH config alias, a bare hostname, or an ssh://[user@]host[:port] URL.
[remote]
default_host = "workbox"
install = "prompt"
[remote.hosts.workbox]
host = "workbox.example.com"
user = "dev"
port = 2222
identity_file = "~/.ssh/id_ed25519"
ssh_args = ["-J", "bastion"]
[remote.hosts.staging]
host = "staging.example.com"With default_host set, rozi --remote with no host uses that target. The default host's entry also supplies user, port, identity_file, ssh_args, and binary_path to other aliases that do not set them. A value set on the alias wins, and a non-empty ssh_args list on the alias replaces the inherited list.
For an ssh:// URL, the user and port in the URL win. Other settings come from a host entry with the same hostname, then from the default host's entry.
Use binary_path when rozi is already installed at a fixed path on the host:
[remote.hosts.workbox]
binary_path = "/opt/rozi/bin/rozi"Shared SSH connections
Opening a host runs several SSH commands in a row. On Linux and macOS, they share one connection, so you authenticate once per host: a password host asks for the password a single time, and later commands skip the handshake.
rozi manages this connection itself, so its own ControlMaster and ControlPath settings take the place of yours for rozi's commands. The connection is shared by every rozi window on your machine, and closes about a minute after the last command using it finishes.
Windows clients do not share SSH connections and authenticate for each command.
Choose an install policy
Before connecting, rozi checks the host for a compatible rozi binary, whether you open the host inside rozi or start with rozi --remote <host>. When rozi needs to install one, a dialog shows the host, the install location as the host resolves it (your home directory shown as ~), and the version, with Install and Cancel; Esc also cancels. While rozi copies itself onto the host, the host's row shows a spinner and Installing…. The connection continues after installation.
[remote] install | TUI connection or interactive terminal | Non-interactive run |
|---|---|---|
prompt | Ask before installing. This is the default. | Fail without changing the host. |
always | Install when needed without asking. | Fail without changing the host. |
never | Fail when no compatible binary is found. | Fail without changing the host. |
Background discovery and monitoring never install anything; installation happens only when you connect to a host or session. Set install = "never" or pin binary_path if installing on the host is not acceptable.
Where rozi looks for an existing binary
On POSIX hosts, rozi checks PATH and common install locations: ~/.local/bin, ~/.cargo/bin, ~/bin, ~/.nix-profile/bin, /opt/homebrew/bin, /usr/local/bin, and /usr/bin. On Windows hosts, it checks PATH, %USERPROFILE%\.local\bin, and %USERPROFILE%\.cargo\bin. After these, it checks its own managed install directory. Listing, attaching, monitoring, and killing sessions all use the path found, so the host's non-interactive SSH PATH does not need these directories. Use binary_path for an installation anywhere else.
Where rozi installs
When the host has more than one compatible rozi, a new session uses the one matching the client's exact version, then the newest release. Automatic installation never replaces a rozi you installed yourself. It installs a copy matching the client's exact version, so several client versions can coexist:
| Host | Install path |
|---|---|
POSIX, XDG_DATA_HOME set to an absolute path | $XDG_DATA_HOME/rozi/remote/<version>/rozi |
| POSIX, otherwise | $HOME/.local/share/rozi/remote/<version>/rozi |
| Windows | %LOCALAPPDATA%\rozi\remote\<version>\rozi.exe |
Windows, LOCALAPPDATA unavailable | %USERPROFILE%\.local\share\rozi\remote\<version>\rozi.exe |
When the client and host run the same platform, rozi can copy its own executable. Otherwise, it downloads the signed release manifest and the matching archive for the client's version and the host's platform. The manifest is verified against a signing key built into rozi and checked for expiry, and it is used to verify the archive and binary. A release server or ROZI_RELEASE_BASE_URL mirror is only a download location; it cannot sign releases.
rozi checks that the new binary runs before it moves it into place. A failed install leaves any existing one untouched.
For development or CI:
ROZI_REMOTE_BINARYuploads a specific local binary. It overrides[remote] install, includinginstall = "never", and uploads without asking.ROZI_RELEASE_BASE_URLpoints to an HTTPS directory containing the version'srozi-release.json,rozi-release.signatures.json, and release archives.
Version compatibility
Your rozi and the rozi on the host do not have to be the same release. Releases that share a session protocol generation work with each other in both directions: an updated client attaches to a session the host started on an older release, and a host updated first still serves an older client. A feature the other end does not have yet is shown but disabled, with the release it needs, and everything else keeps working. Updating the client alone never restarts remote sessions.
A release that starts a new generation says so in its release notes, and its update notice tells you which running sessions it affects. A session on an older generation keeps running on the old release but refuses an attach from the new one. Restart it on the host's current rozi with rozi sessions upgrade <NAME> --remote <HOST>, which reopens it from its snapshot.
To move a session from an older release to the host's current one at any time, run rozi sessions upgrade <NAME> --remote <HOST>. The programs running in its panes end; its layout and terminal history come back as resurrection restores them.
Understand the client and server boundary
| Local client | Remote server |
|---|---|
| Theme, keybindings, overlays, and sidebar UI | Terminals and pane processes |
| Copy, search, and hint interfaces | Shared layout authority |
| Local control socket | Session discovery and resurrection |
| Hooks and desktop notifications | Pane working directories |
| Local clipboard access | Agent definitions and agent detection |
| File-tree rendering | Remote directory and Git data |
The remote host chooses the shell. Your local [shell] settings and shell integration files are not sent to it. A remote shell that emits OSC 7 still reports its current directory; without it, directory tracking may stay at the pane's starting directory.
While attached remotely, the Files and Git sidebar tabs read the remote filesystem. Git change markers need git on the remote host's PATH. File search covers only directories already expanded in the tree.
Hooks run locally and receive ROZI_REMOTE_HOST. The control socket also stays local.
Extension commands, services, and sidebar tabs run on your client by default, and a command that runs there starts in rozi's own directory rather than the remote pane's. An extension can place a contribution on the session's host instead: rozi then runs it on the remote machine, over a separate SSH connection, from a copy of the extension's files, and relays its requests back to your client. rozi extensions status shows what runs where. rozi sessions list --remote, rozi sessions restart --remote, rozi sessions upgrade --remote, rozi sessions kill --remote, and rozi worktrees --remote each run as a separate SSH command. Quote ~ in their paths so your local shell does not expand it.
A new remote pane has SSH_CONNECTION set to your current connection. On a Linux host with a systemd user session, it also gets the desktop variables, such as DISPLAY and WAYLAND_DISPLAY, of the desktop running on that host, so a window it opens appears on the host's screen rather than yours. With no running desktop, it has none.
Clipboard reads and writes happen on the machine running the rozi window, so OSC 52 from a remote pane can update your local clipboard when enabled. Paste images or copied files with Ctrl+V or the paste command to upload them and insert remote paths. A program that accesses a clipboard API directly still uses the remote host's clipboard. See Select, copy, and paste for file limits, retention, and the distinction from running plain ssh in a pane.
Reconnection and switching
Switching to another local or remote session keeps the current one connected in the background. Returning to it reuses its live screens.
If an SSH connection drops — including a connection that silently stopped working after sleep, a lost network, or missed heartbeats from the session — rozi shows a reconnecting overlay and retries in place for up to two minutes. It reuses the rozi binary it already found on the host.
Escstops waiting and opens Sessions.- These automatic retries never prompt. If the host now needs a password, passphrase, or host-key approval, they fail until the session goes Offline; a retry you start with
Entercan then show the SSH dialog. - A reconnect you start, with
Enteron an offline session or by switching back to a session that lost its connection, shows any SSH prompt over the overlay.Esccancels that prompt, and the reconnecting overlay returns. - If the remote session no longer exists, the overlay shows Session lost. rozi never starts a replacement on its own: press
Enterto recreate the session from the panes still on screen, orEscto open Sessions without recreating it. - If the host is still unreachable after two minutes, the session stays on screen as Offline.
Enterretries andEscopens Sessions.
Dismissing Sessions with Esc while the current session is offline shows the launcher. The offline session remains available in Sessions with its retained panes.
Named remote sessions keep running when the SSH connection drops. Temporary ones close after 45 seconds with no client attached; see Recover a temporary session.
Connected-host monitoring
Connecting a host also opens a separate channel that watches the host's sessions. It stays open when you close the Sessions sidebar or switch to another machine. Opening a picker does not start a connection. rozi never automatically contacts a host you haven't connected.
By default, hosts you deliberately connected reconnect when rozi starts. Their tabs and last-seen sessions appear immediately while the connections happen in the background. rozi displays no SSH prompts and installs nothing during automatic reconnects. Configuring a host or launching with --remote alone does not add it to future launches. Adding and successfully connecting a host, opening it from Remote hosts, or connecting it from the Sessions sidebar does. A failed attempt is remembered only after that host connects successfully.
Disconnect a host with Ctrl+X in Sessions or its sidebar close button to stop reconnecting it on future launches. Other windows keep their own connections until you disconnect them. Set reconnect_on_launch = false to leave remembered hosts disconnected at startup.
The channel keeps the host's session list current. It does not attach to sessions, receive terminal output, or take layout control. If the host becomes unreachable, rozi keeps trying in the background, and its last session list stays visible with rows marked Last seen. Ctrl+K twice on a Last seen row forgets it without contacting the host; if the host still reports the session later, it is listed again.
Background reconnects never prompt. SSH login and host-key failures wait for you to reconnect. If a host needs a password or host-key approval, select it in Remote hosts and reconnect with Enter, or Ctrl+R if it still shows connected; unless [remote] batch_mode = true, the SSH dialog then handles the prompt.
If the host's rozi is too old to be monitored, the host shows an error until you update rozi there and reconnect. Updating rozi on the host does not restart its running sessions.
Agents on a machine you are not in
Monitoring also reports what the agents in each session are doing. Session rows then read:
WORKBOX ● Connected
dev 2 panes · Codex working
backend 4 panes · 2 blockedEach row shows the most urgent state in the session — blocked, then working, then done — and names the agent when only one is in that state. Idle agents are not shown. A session you are attached to shows no summary, because the Agents tab already shows its live state.
When an agent becomes blocked or finishes, you get the same desktop notification and sound as in an attached session, under the same [notifications] and [sounds] settings, and Do not disturb silences them the same way. The first update after connecting only sets a baseline, so connecting to a host whose agent has been waiting since yesterday does not notify.
Summaries contain the session, pane, and agent, its state and the reason it gave, the task a listed session names or else its terminal title, how many runs the agent has finished, and when its state last changed. Terminal contents, scrollback, working directories, and layout need an attached session.
The Agents view (Ctrl+A, then a) lists these alongside local agents, most urgent first, placed in the project and branch the host's project summaries report. The sidebar's Agents tab lists them under the checkouts they work in. Enter on a remote row attaches to that session and focuses the agent's pane in one step.
Projects on a machine you are not in
When both ends support the project-summaries feature, monitoring also reports which checkouts each session works in: each checkout's root, the repository it belongs to, its branch, and which panes and published agents work there. The sidebar's Projects tab arranges every host's sessions by these. Working directories below a checkout's root still need an attached session.
Port forwarding
When you open an http or https link to localhost, 127.0.0.1, 0.0.0.0, or :: from a remote session pane on your client, rozi opens an SSH local port forward (127.0.0.1) to that host's loopback port, keeps the same port number when free or picks an available local port otherwise, and opens the rewritten local URL. Link handlers placed on the session host keep the original URL without forwarding.
Forwards belong to your client for that SSH host rather than to one session, so switching sessions keeps them running and later opens to the same host and port reuse the existing tunnel. Quitting rozi, disconnecting from the host (Ctrl+X), or forgetting the host closes its forwards.
Run Ports… from the command palette (shown while attached to a remote session or while any forward exists) to inspect forwards, add a forward (Remote host, Remote port, and optional Local port), retry a failed forward, open a ready HTTP(S) forward in your browser, or close forwards; see Ports. You can also manage forwards from scripts or another terminal with rozi ports list, rozi ports forward <PORT>, and rozi ports close <PORT>, or configure automatic link forwarding and port selection under [remote.ports].
Disconnect from a host
Ctrl+W disconnects one session attachment. Ctrl+X disconnects this client from the whole host:
- Monitoring and its reconnect attempts stop, including on future launches.
- Every attachment to that host closes, both current and background.
- Every port forward to that host closes.
- Named sessions on the host keep running, whichever client started them.
- A temporary session this client created there and never used is closed, since nothing could reattach to it by name.
- A launcher scoped to that host is no longer scoped to it.
Disconnecting never kills a session, even a named session this client created. Only Ctrl+K kills a session. To reconnect, use the session picker or the Sessions sidebar.
Disconnecting does not close the shared SSH connection, which another rozi client may be using. It closes on its own about a minute after the last command using it finishes.
Troubleshooting
| Message | Check |
|---|---|
ssh not installed here | Install OpenSSH on the client and check PATH. |
Unknown host name | Check DNS, SSH config, and the host alias. |
Host not responding | Check power, network, VPN, routing, and firewalls. |
SSH port closed | Check sshd, the configured port, and port forwarding. |
Host unreachable | Check the network, VPN, and routing to the host. |
SSH login rejected | Check the user, key, agent, and server authorization. |
Host key not trusted | Connect with ssh and inspect known_hosts. |
Host key changed | The host's identity does not match the recorded key, and OpenSSH refuses to connect. Verify the new key out of band before removing the old entry. |
No rozi on host | Allow installation or set binary_path. |
Install cancelled | You declined the install prompt. Connect again and choose Install, or set binary_path. |
Rozi update needed | The host's rozi does not speak this client's session protocol. Install the matching version on the host. |
| Incompatible version | The session runs on an older protocol generation. Run rozi sessions upgrade <NAME> --remote <HOST>. |
Connection failed | Any other SSH failure. Run rozi --remote <host> from a shell to see the error. |
| Git markers missing | Install git on the remote host and check its PATH. |
When a sidebar message is not enough, run rozi --remote <host> from a shell to see the underlying SSH error.
See also Troubleshooting.
Security
- SSH provides authentication and encryption. rozi opens no network port for sessions.
- On the remote host, sessions are reachable only by the same user, through private local connections.
- rozi does not forward your local environment into remote panes, so local display connections and configured credentials are not copied to the host.
ssh_argsandbinary_pathare trusted configuration. Keepbinary_patha single token without shell-special characters.- When enabled, OSC 52 lets a remote pane write to your local clipboard. Set
[clipboard] enable_osc52 = falseif remote programs should not have that access. - A writable remote client has the same authority over a session as a local one; see Shared sessions.
- An extension process placed on a remote host acts on your client only through rozi, which checks each request against the host and session it was placed for and never lets it start a process on your client; see Run on the session host.