Skip to content
Fran Gonzalez
← Back to blog
·Clanker·3 min read

Why I switched to zmx for terminal session persistence

zmx gives me the one thing I actually used from tmux (detachable sessions) and leaves window management to my OS, terminal, and editor.

Some matmuls wrote this slop, sorry. My goal with this content is to document some work I (a real human bean) do while poking the Clanker, and try to learn something along the way.

zmx is a terminal session manager by neurosnap. It keeps a shell alive after the terminal closes and allows later reattachment without providing windows, tabs, or splits. Its homepage describes window management as a responsibility of the OS window manager, terminal emulator, and editor.

Note

This post describes a shell setup tested in July 2026. Verify command names and behavior against the current zmx documentation before adopting it.

Why not just tmux

That model is described in erock’s “you might not need tmux”. A multiplexer sits between the terminal and the shell and re-translates escape codes. Depending on the configuration, colors can change when TERM is set incorrectly, scrollback can remain in the multiplexer’s buffer instead of the terminal, and terminal protocols such as kitty graphics can require passthrough configuration.

How zmx works

zmx provides the session-persistence part of tmux without providing window layout. A session is a shell attached to a PTY, owned by a daemon and reached over a per-session Unix socket. zmx attach <name> is an upsert: it creates the session if it is missing, otherwise reconnects to it and replays the terminal state and scrollback. zmx list shows active sessions, zmx detach disconnects without killing the session, zmx run sends a command without attaching, and zmx history dumps scrollback as plain text.

My setup

The setup has three small pieces.

Shell completions in .zshrc, right after compinit:

# ~/.zshrc
_have zmx && eval "$(zmx completions zsh)"

This is the upstream-recommended form. It also avoids a committed completion file that would need to be kept in sync with mise and atuin.

A session picker in .commonrc (shared by zsh and bash), guarded so it only exists when both tools are present. It pipes zmx list through fzf. Enter attaches to the selected session, while Ctrl-N passes a new session name to zmx attach:

# ~/.commonrc
if _have zmx && _have fzf; then
  zmx-select() {
    local selected
    selected=$(zmx list --short 2>/dev/null |
      fzf --prompt="zmx> " --expect=ctrl-n --header="Enter: attach | Ctrl-N: new")
    local key=${selected%%$'\n'*} name=${selected##*$'\n'}
    [[ -z "$name" ]] && return 130
    zmx attach "$name"
  }
fi

A prompt indicator shows which session a terminal belongs to. zmx exports ZMX_SESSION inside a session, so the prompt can include it in zsh’s prompt_precmd and bash’s __ps1, using the same guard:

# inside the prompt builder, after the base prompt is assembled
if _have zmx && [[ -n "$ZMX_SESSION" ]]; then
  PROMPT="[${ZMX_SESSION}] ${PROMPT}"
fi

The brackets and session name are also colored in the prompt.

What it gives up

This separates session persistence from window layout. zmx does not provide window layout. On a laptop, the window manager and terminal can provide tabs and splits natively, without the terminal translation layer used by tmux.

For SSH workflows, separate terminals can run ssh d.<name> with RemoteCommand zmx attach %k; SSH ControlMaster multiplexes them over a single TCP connection. Each remote session uses an OS window and the terminal’s scrollback.

The project documents two upgrade constraints: an IPC-breaking change terminates running sessions, and nested zmx-over-SSH cursor state is unsupported. These constraints should be checked before upgrades; zmx remains suitable for session persistence when they are acceptable.

References

  • neurosnap/zmx: the source repository and author of the tool.
  • zmx.sh: the tool’s homepage, philosophy, and docs.
  • you might not need tmux: erock’s argument that multiplexers add a complexity cascade and drag on terminal features; the motivation behind zmx.
  • fzf: the fuzzy finder used in the session picker.

This post was written with AI assistance.