Keeps one remote shell alive while Termphin is disconnected, so a session survives losing the network, backgrounding the app or closing it. Termphin uploads this binary to the server over SSH and runs it there.
It is deliberately not a terminal multiplexer. No windows, panes, status bars, copy modes or mouse handling, and no terminal emulation of its own: it holds a PTY open and replays what the shell wrote.
The part worth reading before letting anything run on a machine you care about.
- No network listener. Every connection goes through a Unix socket at
~/.cache/termphin/sessions/<name>/control.sock, created with mode0600inside a directory created with mode0700. Nothing binds a port. On Windows the equivalent is a named pipe under%LOCALAPPDATA%\termphin\sessions, restricted to its owner via an ACL rather than a mode bit. - No privileges. Runs as your user. Nothing is installed system-wide, no setuid, no service unit, no cron entry.
- Everything lives under
~/.cache/termphin/sessions(%LOCALAPPDATA%\termphin\sessionson Windows). One directory per session holding the socket and acreated_atstamp. Killing a session removes its directory; nothing else on disk is touched. - It starts your
$SHELL(or/bin/sh) as a login shell on a PTY, and passes bytes between that PTY and the socket unchanged. On Windows that'spowershell.exeon a ConPTY pseudo console instead. - Scrollback is held in memory only, the last 2000 rows of the session's terminal state. It is never written to disk, except a periodic snapshot so a reboot can restore it.
- Two dependencies on Unix,
libcandvt100, over about 1400 lines of one file, small enough to read in an afternoon. Windows needswindows-sysfor ConPTY and named pipes and is a separate module.
Authorization is the filesystem (or, on Windows, the pipe's ACL). Anyone who can reach it is already running as your user, and could read the PTY anyway.
Windows has one gap against the Unix build: a live terminal resize during an
attach is polled every 100ms rather than delivered instantly - see the module
doc in src/windows.rs for why. The shell's working directory is tracked,
but by a different route: PowerShell's cd never touches the process's real
OS-level directory, so there is no /proc/<pid>/cwd equivalent to read from
outside. Instead the shell is started with a prompt function - chained onto
whatever the user's own profile defines, never replacing it - that reports
$PWD over an OSC marker. It rides in on -EncodedCommand so the shell
never echoes it. Persistence itself - a session surviving the
SSH connection that started it - relies on the new master process breaking
away from whatever job object owns the SSH session (Win32-OpenSSH's, usually).
If that job doesn't permit breakaway, the session just doesn't outlive the
connection, the same as a session that didn't shut down cleanly for any other
reason - there is no separate "unsupported" mode.
termphin-agent attach [--replay] <name>
termphin-agent list
termphin-agent rename <old-name> <new-name>
termphin-agent kill <name>
termphin-agent version --machine
Each session has a master process and a Unix socket below
~/.cache/termphin/sessions. The attach client forwards terminal resize events
to the child PTY. The master keeps the session's terminal state - 2000 rows of
scrollback, the screen, and the active DEC private terminal modes.
--replay reconstructs a fresh local terminal's scrollback and modes. The
buffer is sent as a series of frames, since it can exceed the 1 MiB protocol
frame limit. Modes that only affect input encoding are re-asserted after the
replayed bytes. The alternate screen is re-entered ahead of them, and only when
the sequence that switched to it has already been evicted, because entering it
again would clear what the replay just drew.
On attach the master also briefly changes the PTY height while the alternate screen is active. That buffer has no scrollback to reconstruct, so the resulting SIGWINCH is what makes a full-screen application repaint its current frame for the newly attached client.
The master serves at most 16 concurrent connections, gives a connection 30 seconds to identify itself before dropping it, and disconnects a client that falls more than 8 MiB behind rather than let it stall the session.
For the host:
cargo build --release
cargo testFor the binaries Termphin actually ships, which need docker:
./scripts/build.shThat writes stripped static x86_64 and aarch64 Linux binaries plus an
x86_64 Windows one to dist/, along with their SHA-256 manifest, using
cross-compilation images pinned by digest (musl for Linux, mingw-w64 for
Windows). The same source and the same script produce the same checksums on
any host, so you can verify that what Termphin uploads matches this
repository. The app checks those checksums before uploading, and again
against whatever is already on the server.
MIT. See LICENSE.