vmux
Appsvmux Daemon

vmuxd Reference

Server invocation, flags, signals, and the daemonization model.

Synopsis

vmuxd [--config PATH] [--socket PATH] [--shell PATH] [--cwd PATH] [--daemonize]

vmuxd is the persistent server. It opens a AF_UNIX SOCK_STREAM listener on --socket, owns the PTYs of every pane in every session, and pushes frames and state to attached clients over the same socket.

You can run zero, one, or two vmuxd processes per UID:

  • Zero: typical case. The first vmux invocation auto-launches one in daemonized mode.
  • One: managed by launchd or started manually for a non-default socket.
  • Two or more: only by giving each a different --socket. They are otherwise unaware of each other.

Flags

FlagArgumentDefaultEffect
--configPATHfirst match in search listLoad a specific config file. Bypasses the default search.
--socketPATH/tmp/vmux-<uid>.sockOverride the listen path. Wins over both shared and server config sections.
--shellPATH$SHELL then /bin/zshShell to spawn for new shell-role panes.
--cwdPATHunset (inherits)Working directory for newly spawned shells.
--daemonizeforegroundRe-exec the same binary in the background, redirect stdio to /dev/null, then exit. The replacement process keeps the resolved socket/shell/cwd.

Any unknown flag is rejected with a non-zero exit and vmuxd: bindFailed(EINVAL) on stderr.

The flag layer is one of three resolution layers, in this order of precedence (last writer wins):

  1. The config file's shared.socketPath.
  2. The config file's server.* block.
  3. The flags passed on the command line.

Default socket path

/tmp/vmux-<uid>.sock, where <uid> is the numeric user ID returned by getuid(2). This isolates daemons by user without configuration.

You can confirm it on a running system with:

echo "/tmp/vmux-$(id -u).sock"

Override it with --socket, the VMUX_CONFIG-pointed config file, or by setting shared.socketPath or server.socketPath in ~/.config/vmux/config.json.

Foreground vs daemonized

Foreground is the default and is the right mode for development:

vmuxd --shell /bin/zsh

Output goes to your terminal. Ctrl+C shuts the server down cleanly.

Daemonized mode forks a fresh vmuxd process, redirects stdout/stderr to /dev/null, and the parent returns. The auto-start path used by vmux always uses this mode:

vmuxd --daemonize --socket /tmp/vmux-$(id -u).sock

There is no PID file. Use pgrep -u $(id -u) vmuxd (or lsof -U on the socket) to find a running daemon. To stop a daemonized server cleanly:

pkill -INT vmuxd     # or -TERM

Signal handling

vmuxd installs handlers via DispatchSourceSignal. The originals are masked with SIG_IGN first so a stray SIGINT does not interrupt the event loop in the middle of a write.

SignalBehavior
SIGINTGraceful stop. Cancels the accept source, closes the listening socket, unlinks the socket file, terminates every pane's PTY, drops every connected client, then exit(0).
SIGTERMSame as SIGINT.
SIGHUPNot currently caught — has the default action (terminates the daemon). Run inside nohup if you need to disown an interactive session that started one.
SIGKILLThe kernel terminates the process immediately. The socket file is left on disk; the next daemon start unlinks it before binding.

There is no reload-config signal. To pick up a config change, stop and restart the daemon.

Where it logs

vmuxd does not currently log to a file. In foreground mode it prints framed [vmuxd] … traces to stderr — useful for debugging client attach, pane lifecycle, and PTY resize.

vmuxd --shell /bin/zsh 2>/tmp/vmuxd.log

In --daemonize mode the spawned child has its stdout and stderr redirected to /dev/null — there is no log unless you run under launchd and direct stdio to a file via the plist (see Installation).

Restart workflow

The daemon owns all live PTY processes. Stopping it kills them. The right pattern depends on what you want to keep:

  • Quick restart, accept losing in-flight panes. pkill -INT vmuxd; vmuxd --daemonize — or just run vmux ls and let auto-start do it.
  • Migrate work first. Detach with Ctrl+D, copy any unsaved files inside the panes, then restart. The state file is in-memory only.
  • Two daemons side by side. Useful when testing a new build. Start the new daemon on a non-default socket and point a single client at it:
# old daemon stays on /tmp/vmux-501.sock
vmuxd --daemonize --socket /tmp/vmux-test.sock
vmux --socket /tmp/vmux-test.sock attach

Lifecycle of a session

A session is created lazily on first attach to a name that does not exist. The default session name is default. So:

vmux attach              # creates "default", attaches
vmux attach -s work      # creates "work", attaches
vmux attach -s work      # reuses "work"

Sessions with no attached clients keep running. They only end when:

  • Every pane in the session has exited.
  • The daemon shuts down (SIGINT, SIGTERM, or SIGKILL).

There is no kill-session command — see the deviation list in vmux-cli-sessions. To end a session, exit every pane in it (exit in the last shell, or vmux pane close <uuid> --force).

Multi-socket setups

Two daemons on different sockets are fully independent: separate sessions, separate panes, separate clients. The flag layer makes this easy:

# Project-A daemon
VMUX_CONFIG=~/.config/vmux/project-a.json vmuxd --daemonize

# Project-B daemon
VMUX_CONFIG=~/.config/vmux/project-b.json vmuxd --daemonize

Each client respects the same config-resolution path, so VMUX_CONFIG=...project-a.json vmux attach connects to the right one without --socket.

See also