Skip to content

Commands ​

Every command and option of the zeropty CLI. The same commands work over the socket and through the embedding APIs.

CLI at a glance ​

sh
zeropty new-session -d -s work -x 220 -y 80 -c ~/proj "$PWD/dist/claude-zeropty"   # starts the server if none is running
zeropty capture-pane -p -e -S -200 -t '=work:'    # screen + 200 lines of scrollback, with colors
zeropty wait-pane -t '=work:' -m '>' -q 1000 -T 60000   # until '>' appears and the session is quiet for 1s (60s max)
zeropty send-keys -t '=work:' -l 'hello' && zeropty send-keys -t '=work:' Enter
zeropty attach -t work                            # attach to watch as a human; detach with Ctrl-b d
zeropty attach -r -t work                         # read-only (detach with q or Ctrl-c)
zeropty kill-session -t '=work:'

Help and version. zeropty --help (or -h, help) prints the list of commands and options, and zeropty help <command> prints that command's usage, what it does and a link to the matching section of this document. Both write to standard output and exit with code 0. Abbreviations (help send) work too. The program answers on its own, so no server is needed and none is started. The zsh function and the bash builtin behave the same way. zeropty -V (or --version) prints the version of the CLI itself (for the version of the running server, use zeropty display -p '#{version}'). What counts as compatible is described in Versioning, and what changed is in Changelog. Each option is explained in the command reference below.

sh
zeropty --help     # list of commands (exit code 0)
zeropty help send-keys   # one command: usage, what it does, doc link (exit code 2 for an unknown command)
zeropty -V         # zeropty X.Y.Z (--version does the same)
zeropty            # usage: zeropty serve | <tmux command> ...  (standard error, exit code 2)

Command reference ​

Names in parentheses are the same aliases tmux uses. <value> after an option means the option takes a value.

Sessions ​

CommandOptionsWhat it does
new-session (new) [command]-d -s <name> -x <cols> -y <rows> -c <dir> -e <VAR=value> -A -P -F <format>Creates a session. Without a command it runs $SHELL (or /bin/sh if unset). The default size is 80×24, and without a name it uses the number of sessions created so far (0, 1, ...). -A succeeds and leaves the session alone if one with the same name exists. -P prints information about the new session (-F sets the format; the default is name:). -e can be repeated. -n -E -D -X are for windows and clients, so they are accepted and ignored
has-session (has)-t0 if the session exists, 1 if not (can't find session: name)
kill-session-t -aSends SIGHUP to the session's process group, then SIGKILLs any process still alive after 2 seconds. -a means every session except the -t session. -C is accepted and ignored
list-sessions (ls)-F <format>Lists sessions. The default output matches tmux: name: 1 windows (created ...)
rename-session (rename) <new name>-tRenames a session. An empty name, a name containing : or ., or a name already in use is an error
resize-window (resizew), resize-pane (resizep)-t -x <cols> -y <rows>Resizes the screen. The program receives SIGWINCH
pipe-pane (pipep) [command]-t -o -OKeeps feeding the session's output into the command's input (tmux's -O is the default). Calling it without a command closes the pipe. -o only closes it if one is already open. Output the command cannot accept yet is buffered up to 8MB, and anything beyond that is dropped. The pipe is closed when the session moves to another process
kill-serverSends SIGHUP to every session. A standalone server process also exits. An embedded engine ends only the sessions and keeps running

When the program exits, the session ends too (the same as tmux with remain-on-exit off).

The server keeps the environment of the process that started it (the first command that starts it: new-session, pull-sessions or zeropty serve), as tmux does: a session gets that environment with set-environment -g and -e applied, not the environment of the shell running new-session. restart-server starts the new server from the shell that runs it, so later sessions get that shell's environment, and values set with set-environment -g are dropped (set them again); running sessions keep theirs. Environment the program in a session receives: TERM=xterm-256color, COLUMNS/LINES, ZEROPTY_SESSION (the session name), ZEROPTY_COLS/ZEROPTY_ROWS, ZEROPTY_SIZE_FILE (the window size file the shim reads), and ZEROPTY_TTY_ID (which files are the session's terminal, for the shim). TMUX and TMUX_PANE are removed (even if the server was started inside tmux, the session is not inside tmux).

Sending keys ​

CommandOptionsWhat it does
send-keys (send) <key>...-t -l -H -N <count>Sends keys. For each argument, a key name sends that key's bytes, and anything else is sent as literal text. -l sends the text literally without interpreting key names. -H reads the arguments as hexadecimal bytes (-H 41 42 0a is AB plus a newline). -N repeats the whole thing that many times
paste-buffer (pasteb)-t -b <buffer> -d -p -r -s <separator>Sends the buffer's contents as keys. Newlines are sent as \r (unchanged with -r; -s sets the separator). -p wraps the text in bracketed paste if the program has enabled it. -d deletes the buffer after sending

Keys pass through the line discipline, just as with a PTY.

Reading the screen ​

CommandOptionsWhat it does
capture-pane (capturep)-t -p -e -J -N -S <line> -E <line> -b <buffer> -qReads the screen as text. Pending output is processed right before reading, so the screen is always current. -e includes color and font escapes, -J joins lines that were split by wrapping, and -N keeps trailing spaces. -S/-E use the same line numbers as tmux (0 is the first screen line, negative numbers are scrollback, - means to the end). Without -p, as in tmux, the screen goes into a buffer (-b, or buffer0 by default) and nothing is printed
display-message (display) [format]-t -p -F <format>Prints the format with format variables filled in. Example: display-message -p -t '=work:' '#{cursor_x},#{cursor_y}'

Waiting and searching ​

These are zeropty commands that tmux does not have. They tell you, without polling, when an agent has finished or which session is waiting for input.

CommandOptionsWhat it does
wait-pane-t -m <text> -q <ms> -T <ms>-m waits until the text appears on screen (immediately if it is already there), and -q waits until the session has printed nothing for that long. With both, it answers once both hold. After -T it exits with code 1 (wait-pane: timed out), and it also exits with 1 if the session ends while waiting (wait-pane: session ended)
grep-panes <text>-S <line>Searches every session's screen for the text and shows matches as session: line. -S also searches scrollback, like capture-pane -S (-S -100). Results are sorted by session name, and the exit code is 1 when nothing matches (like grep)
  • wait-pane checks only when output arrives at the server, and only the rows that output changed. Text is matched within a row (text split across a line wrap is not found).
  • The next command on the same connection is handled after wait-pane answers. client/zeropty.mjs opens a separate connection for each wait-pane, so other commands are not blocked.
  • If a session exits right after printing its last output, the engine may report the session's end before it checks that output, and wait-pane then ends with wait-pane: session ended (exit code 1). This is a known issue. Keep the session alive after the text you are waiting for appears, for example: sh -c 'make; echo build done; exec cat'
  • wait-pane is not available through the embedded engine's function call (there is no loop that could defer the answer). It works over the socket once you enable the server plugin. Rust hosts use Engine::wait_start and wait_check directly (examples/polled.rs).

Buffers ​

CommandOptionsWhat it does
load-buffer (loadb) <file>-b <buffer>Loads a file's contents into a buffer (buffer0 by default). Relative paths are resolved against the current directory of the side that sent the command
paste-bufferSee Sending keys
capture-pane -bWithout -p, puts the screen into a buffer

Viewing (attach) ​

CommandOptionsWhat it does
attach-session (attach, a)-t -rAttaches the current terminal to a session. Detach with Ctrl-b d. -r is read-only; detach with q or Ctrl-c. Without -t, it attaches to the only session if there is one, and asks for a number if there are several

While attached, the session follows your terminal's size, and it returns to its original size when you detach. Several terminals can attach to one session; the size follows the terminal that attached last.

Environment ​

CommandOptionsWhat it does
set-environment (setenv) <VAR> [value]-g -uSets an environment variable for sessions created afterwards. -u removes it. Without -g, even tmux applies the variable only to new windows, and since sessions never get new windows, it does nothing
show-environment (showenv)-gShows the variables set with -g. Removed variables are shown as -VAR

Server and moving sessions ​

CommandOptionsWhat it does
serve--bind <socket>Starts a standalone server yourself (normally new-session starts one for you)
pull-sessions [name...]-s <socket>Brings sessions from another server into this one (all of them if no names are given)
push-sessions [name...]-s <socket>Sends this server's sessions to another server
restart-serverA new server takes over every session and the socket. Use it for upgrades

Details: Moving sessions. The internal requests servers use with each other, export-sessions and import-sessions: socket protocol

Plugins ​

CommandOptionsWhat it does
list-pluginsOne line per attached plugin: name: state (api N) events=... commands=... access=... dropped=N. The state is running, stopped or failed (reason)
plugin-attachTurns the socket connection into a plugin. Only meaningful on the socket
plugin-run <library.dylib>Loads a C plugin library in a separate process and attaches it to the server. It exits when the server exits

Commands added by plugins are called from the CLI, the socket and the embedded engine just like built-in commands. If you set ZEROPTY_PLUGIN_DIR, zeropty serve starts the plugins in that directory and restarts them when they exit. If it is not set (the default), nothing is run. Pointing at a directory is consent to run the code in it as the same user as the server, so this is off by default (the same behavior as before this feature existed). How to attach plugins and the protocol: Plugin API

Diagnostics ​

CommandWhat it does
statsOne line of engine counters: sessions, heap_bytes (bytes requested from the allocator), screen_bytes, the number of live/frozen screens, the number of reads, and more
mstatsAllocator (mimalloc) statistics. Only on a standalone server (the command counts that process's allocator)
mem -t <session>Memory breakdown of one screen. For a frozen screen: frozen <bytes> B deep <true/false>

Released under the MIT or Apache-2.0 license.