Expand description
Durable SSH terminals (P4 of SPEC_REMOTE_TERMINALS_AND_DURABLE_SESSIONS_2026_10_02.md, §7).
A pane on an SSH connection with term:durable set is not a local PTY. It
runs ssh -T host -- agentmux-remote attach --session ID --offset N ...
and speaks the helper’s frames (agentmux_remote::frame) over that
channel: the shell itself lives in the helper’s daemon on the host, so a
dropped link, a sleeping laptop or an AgentMux restart only drops this
ssh, and the pane reattaches and gets exactly what it missed.
- Output lands in the pane’s
termfile through the same append as a PTY’s (shell::handle_append_block_file), and the next remote offset is kept beside it in that file’s metadata (remote:offset), written right after each append, so a reattach asks for exactly what is missing. - The session id is the block’s
remote:session_id, made on first start. - The status stays
runningwhile reconnecting; only the session’s own end (Exited) makes itdone, which is what offers “press to restart”. - Reconnect never gives up while the pane is open (§7.4): backoff 1, 2, 5,
10, then every 30 s. A ping every 15 s, and an
sshsilent for 35 s is killed and replaced rather than left to its own timeout (§7.5). - Closing the pane ends the session; quitting AgentMux detaches it (it keeps running on the host for the next start to reattach); a forced restart or a connection change detaches too.
sshhas no terminal here, so its prompts (a password, a passphrase, a new host key) go to the user through the askpass bridge (remote::askpass). A login it still cannot make stops the pane with the reason rather than asking again every 30 s.
Structs§
- Done 🔒
- How a pane’s run ended, when the pane should show it done.
- Durable
SshController - Inner 🔒
- Run 🔒
- One durable pane’s connection loop.
Enums§
- Accept
- What part of an
Outputframe the pane has not seen yet, given the next offset it expects. - Ended 🔒
- How one
sshended. - Leave 🔒
- How the pane leaves its session.
Constants§
- EXIT_
COMMAND_ 🔒NOT_ FOUND sshexits 127 when the remote shell cannot find the command: no helper.- EXIT_
GRACE 🔒 - How long an
sshwhose output ended has to exit before it is killed. - EXIT_
SSH_ 🔒FAILED ssh’s own failures (it could not connect or log in) exit 255.- FILE_
META_ REMOTE_ OFFSET termfile meta: the next offset of the remote session’s output.- FIRST_
REACH_ 🔒TRIES - Tries a pane durable only by default makes at a host it has never reached, and the helper never ran on, before it becomes a plain SSH terminal.
- META_
KEY_ DURABLE - Block meta: turns a pane on an SSH connection into a durable one.
- META_
KEY_ SESSION_ ID - Block meta: the helper session this pane attaches to.
- PING_
EVERY 🔒 - STALLED_
AFTER 🔒
Statics§
- APP_
EXITING 🔒 - Set when AgentMux is quitting: panes then detach (their sessions live on for the next start) instead of ending their sessions as a pane close does.
Functions§
- accept
- Decide what to do with output at
offset, when the pane expectsexpected. - append_
checked 🔒 - Append to the pane’s
termfile, then tell the frontend where the bytes landed (the sameblockfileappend event a PTY’s output produces). Unlike the PTY path’shandle_append_block_file, which logs and swallows a store error, this says whether the bytes were stored, so the remote offset never moves past output that was lost. - attach_
command - The command
sshruns on the host. - backoff
- How long to wait before reconnect attempt
attempt(0-based): 1, 2, 5, 10, then 30 s for ever. Never a last attempt: a cap is how a recoverable pane becomes a dead one. - helper_
path - Where the helper is installed on the host: a versioned path, so two
AgentMux versions can use one host (spec §6.2).
~is the remote home. - login_
refused - ssh could not log in, and trying again would only fail (or ask) again: refused credentials, or a host key it will not accept.
- note_
app_ exiting - AgentMux is quitting (
sagas::agent_teardown::app_exit). - show_
done 🔒 - Show the pane
donewithdone.code; a session that is over is forgotten, so the next start makes a new one. - term_
size 🔒 - The pane’s size from its runtime options, as
(cols, rows); 80 x 24 when it has none yet (the frontend resizes right after it attaches). - valid_
session_ id - A session id as the helper accepts it: letters, digits,
-and_, up to 64 (agentmux-remote’sdaemon::valid_session_id). - windows_
answer 🔒 - The host’s answer to
cmd /c echo %OS%: Windows, not Windows, orNonewhen ssh itself failed (exit 255, or no exit code) and the host never answered. - windows_
shell_ refused - The host’s shell is Windows’ (
cmdor PowerShell), which can’t run the helper: it answered the attach command that it doesn’t know it.
Type Aliases§
- Fallback
- Restarts a pane through
resync_controller, which then picks the plain shell controller becausewantshas turned false. Built byresync_controlleritself, which holds everything a restart needs. False when it did not restart: the pane would still be durable (so a restart would only come back here), or the block is gone.