Documentation

SSH & remote hosts

A real SSH client inside the cockpit, and the option to run Muster's daemon on the far machine instead of tunnelling everything.

The client

  • Terminals with the same panes, scrollback and search as local ones, plus saved per-host command snippets.
  • A dual-pane file manager, local ↔ remote, with drag-and-drop transfers over rsync or SFTP and live progress.
  • An in-app editor for remote files.
  • Port forwarding — local, reverse and SOCKS, with live indicators. Tunnel a remote database port and point a saved connection at it.
  • Host monitor — the top 20 processes by %CPU (pid, %CPU, %MEM, command) and df filesystem rows. No load average, memory total or network figures; a failing ps and a failing df are reported separately.
  • Log tailing — follow a remote file as it grows.
  • Jump hosts, per-host keys, and password or key auth.

Transfers: which tool, and what you get

Muster prefers rsync and probes for it by running --info=progress2 together with --version, because the check has to distinguish a real rsync from one that merely answers --version:

Available toolProgressResume
rsync 3.1+ (typical Linux)Real percentageYes — --partial --append-verify continues an interrupted transfer
openrsync (stock macOS) or rsync 2.6.9Indeterminate — SFTP gives no incremental percentNo. The SFTP path restarts from zero
macOS ships openrsync as rsync, and it rejects --info=progress2. So on a stock Mac every transfer takes the SFTP path: the bar is indeterminate and asking to resume silently restarts. Install a real rsync (Homebrew) if you move large files over flaky links. The fallback itself is deliberate — the alternative was every transfer dying on "unrecognized option".

Other behaviour worth knowing before you rely on it

  • An agent already running is not upgraded. Every Muster version uploads its own agent binary to a version-scoped directory, but they all share one socket — so if an older agent is still up it keeps the socket, the new binary exits AlreadyRunning, and you stay on the old daemon. Muster records and logs the version that actually answered rather than the one it uploaded. Picking up a new agent means stopping the running one, which ends its remote sessions, so Muster will not do it to you automatically.
  • Password auth is macOS/Linux only. Feeding a saved password to ssh without putting it on a command line needs an SSH_ASKPASS helper, and Muster's is a POSIX shell script Windows cannot execute. On Windows use key authentication: the terminal, the port forward and every background command all refuse up front and name the remedy, rather than arming a helper that cannot run.
  • Unknown host keys are refused, not adopted. Everything that runs without you watching — agent bootstrap, background commands, SFTP, rsync, transfers, the monitor, tunnels and port forwards — uses StrictHostKeyChecking=yes and fails outright on a host whose key is not already in known_hosts. The interactive Terminal tab of a KEY-auth host uses ask: Muster shows you the fingerprint and you Accept or Reject, and that is the only place a key is ever written to known_hosts. One TOFU path remains — the interactive session of a password host, which stays on accept-new because ssh routes the host-key confirmation through the same channel as the password and an ask there would deadlock. A key that has CHANGED is refused everywhere; clearing it is a deliberate action in the app.
  • A profile's default SSH key applies to the remote-daemon path only. The terminal, file manager, transfers, monitor, tail viewer and port forwards use the host's own ssh_key_path, falling back to ssh's defaults when it is blank.
  • Directory transfers ask before overwriting — but only when there is something to lose. Dropping a folder onto a destination that is absent or empty just transfers; onto one that already holds files it raises the same four-way prompt a single file does, because a directory transfer MERGES and would otherwise replace same-named files with no way back. A destination holding only dotfiles counts as occupied. The four choices are Overwrite (replace the destination), Resume (continue the interrupted transfer — needs a real rsync 3.1+, since it is --partial --append-verify), Keep both (re-run to a fresh, non-colliding name) and Skip (abandon it, destination untouched).
  • Transfers run concurrently, not in a queue. Each drop starts its own worker immediately; "Queued" is the instant before its thread starts.
  • A green "Live" forward is a 450 ms timer, not a confirmed bind. Most bind failures exit inside that window and show as failures, but a slow one flips green first and only corrects when the process exits.

Remote daemon

A project can live on another machine, with Muster's daemon running there and the app attaching to it. Two transports:

  • Over SSH — the daemon is reached through a forwarded socket. Nothing extra to open.
  • Direct TLS — the daemon binds a port and the app connects to it.

The direct path is authenticated two ways at once: a shared token, and certificate-fingerprint pinning — the client refuses a certificate it has not pinned, so swapping the certificate does not silently work. Pairing is one copy-paste credential (MUSTER-PAIR-…) carrying the address, the token and the fingerprint together, so nobody is asked to eyeball a fingerprint by hand.

A pairing key is a bearer credential: anyone holding it can connect. Share it over a channel you trust, and rotate the token to revoke it.

One token rule applies: a daemon bound to a non-loopback address requires a token of at least 32 characters. A loopback bind requires only a non-empty one — it is not network-reachable, and the accept-loop throttle covers local guessing.

muster-daemon's generated tokens are 64 hex characters (256 bits), comfortably above that floor.

What runs on the remote daemon

Once a project points at a host, the daemon there does the work, not your machine:

  • Agents and terminals spawn on the remote, in the repo root.
  • Worktrees and git — worktree create/list/remove and post-create hooks (WtCreate/WtList/WtRemove/WtHook), plus the full WorktreeOps set over Req::WtGit: diff review with hunk and line staging, discard, commit, update-from-base with the conflict resolver, blame, history, the repo panel, and PR creation — create_pr pushes and runs gh pr create on the remote host, with the compare-URL fallback when gh isn't signed in there.
  • Automation actions — open-pr and run-command execute on the remote host through a scoped Req::Exec while the app is connected. Headless flows (the daemon running with no app attached) FAIL CLOSED for remote projects: they refuse rather than run local git against a remote path, so those flows need the app running.
  • Search and file tree — global search and the repo file tree run daemon-side (FsSearch/FsListDir/FsStat), honor .gitignore where the files live, and merge results with the host named on each. An unreachable host shows an honest warning row instead of silently dropping results.

Version skew: capability-probed, refused cleanly

Each remote feature set is advertised by the daemon as a capability at connect — worktrees, git-ops, exec, remote-fs — and the app probes the capability BEFORE issuing an op. A remote daemon older than the feature gets an actionable refusal, not a protocol error: "the remote agent on this host is too old … stop the remote agent (this ends its remote sessions) and reconnect so it picks up the current build." Stopping is never done for you automatically, because it ends the remote sessions that daemon owns.

What does not reach remote agents

Scoped MCP permissions with Ask approvals are local-only: a remote spawn gets the policy environment (MUSTER_MCP_POLICY and friends), but no MUSTER_CONTROL_SOCK and no MCP config injection — the MCP server's per-call policy re-resolution and audit trail open the app's SQLite database, which lives on your machine, so a remote agent has no muster MCP server entry at all. The narrowest capability set, never a wider one — and no live Ask prompts on remote tasks.

New here? Start the 7-day trial — every feature, card up front, $0 today, key on screen. Or buy outright: $39 once per device, no subscription.