Socket protocol
The JSON protocol on the server socket, including moving sessions between servers.
From other programs: the socket
Send one line of JSON to the server socket (~/.zeropty/mux.sock; change it with ZEROPTY_SOCK) and it answers with one line. One connection can carry many commands, and answers come back in order. The socket has 0600 permissions, so only the same user (and root) can connect.
→ {"argv":["capture-pane","-p","-t","=work:"],"cwd":"/"}
← {"code":0,"out":"...screen...","err":""}cwdis the base directory for relative paths (new-session -c,load-buffer).- If the request includes
"raw":true, the answer is not JSON but a line<code> <out byte count> <err byte count>followed by the raw out and err bytes. This is for clients that have a hard time parsing JSON (the zsh function). - An
attachconnection exchanges frames after the first answer:[kind u8][length u32 LE][bytes]. Server to client: 0 (output), 1 (session ended). Client to server: 0 (keys), 1 (size: cols and rows as u16 LE), 2 (detach). - A connection whose first request is
export-sessionsorimport-sessionsis used to hand sessions over (internal): socket protocol.
# From any language: for example, with nc
printf '{"argv":["list-sessions"],"cwd":"/"}\n' | nc -U ~/.zeropty/mux.sockMoving sessions
Moves sessions to another process. Running programs keep running (even the pid stays the same). The screen and scrollback are transferred as bytes, and the session's fds by fd passing (SCM_RIGHTS).
zeropty pull-sessions -s ~/.zeropty/other.sock [name...] # another server's sessions into this one (all if no names)
zeropty push-sessions -s ~/.zeropty/other.sock [name...] # this server's sessions to another server
zeropty restart-server # a new server takes over every session and the socket- The same commands work on an embedded engine. For example, a Node app can
pull-sessionsfrom the server when it starts andpush-sessionsthem back when it exits, so sessions survive app restarts. restart-serverstarts the new server from thezeroptybinary you just ran. That makes it the way to upgrade without losing sessions. Commands that arrive during the few ms of the switch go to the old server.- The sending side releases only the sessions the receiver confirmed it took. If anything fails midway, the sessions stay where they were. Sessions whose name already exists on the other side are not moved.
- Limitation: if an escape sequence was half received at the moment of the move, the rest of it is printed as text.
Socket protocol: export-sessions, import-sessions
These are internal requests that pull-sessions, push-sessions and restart-server use on the server socket. You will rarely send them yourself, and the session record format may change between versions (the first byte is the record version, and a record from another version is rejected with session record of another version). This section is kept as a human-readable reference. Implementation: src/engine/handover.rs.
- If the first request line of a connection is
{"argv":["export-sessions", name...],"cwd":""}or{"argv":["import-sessions"],"cwd":""}, the connection is used only to hand over sessions and is closed when done. Meanwhile the server does nothing else (usually a few ms). - Each side waits up to 10 seconds per step.
- Each session is sent as
[record length u32 LE][record]. The session's fds (whichever of input and output are open, 0~2 of them) are attached to the 4-byte length with SCM_RIGHTS. A length of 0 marks the end. A record may not exceed 256MB. - Every other line is a single line of JSON.
export-sessions (taker → server)
→ {"argv":["export-sessions","a","b"],"cwd":""} all sessions if no names
← [length][record] ... [0] each session with its fds
← ["b"] names the server does not have
→ {"taken":["a"],"failed":[]} sessions taken; the server releases only these
import-sessions (giver → server)
→ {"argv":["import-sessions"],"cwd":""}
← "ready"
→ [length][record] ... [0]
← {"taken":["a"],"failed":["duplicate session: b\n"]} the giver releases only the taken onesfailed holds the reason a session was not taken (a session with the same name already exists, a different record version, and so on). If the connection drops or the format is wrong at any step, the receiver releases the sessions it took, and the sessions stay on the original side.