Skip to content

Advanced

Non-default tmux Server

By default every tmux call resolves ambiently: $TMUX when ccmux runs inside tmux, tmux’s default socket otherwise. That breaks when your agents live on a named server (tmux -L work) but the daemon was auto-started from a plain login shell, which lands it on the default socket. It scans a server with no panes on it, finds nothing, and the board sits empty.

Name the server explicitly, by config or environment:

Terminal window
ccmux config set tmuxSocket work # a label -> tmux -L work
ccmux config set tmuxSocket /tmp/my.sock # a path -> tmux -S /tmp/my.sock
ccmux daemon restart
export CCMUX_TMUX_SOCKET=work # same thing, per shell (wins over the config key)

There is also a convenience flag for an explicitly started daemon:

Terminal window
ccmux daemon start -b --label work
ccmux daemon start -b --socket /tmp/my.sock
ccmux daemon status # prints the socket the running daemon tracks

A leading / means a socket path, anything else a label. Environment and config are the primary interface because the daemon is usually auto-started for you (it inherits your environment, so both reach it); the flag only applies to a ccmux daemon start you run yourself.

After an upgrade you do not need to restart the daemon by hand: the next ccmux command notices the running daemon is on an older build and replaces it, as long as it has no running invocations or queued handoffs (a busy daemon is kept, with a one-line warning). A daemon started from a different checkout on the same version is left alone; switch with ccmux daemon restart. ccmux daemon status shows both builds.

Inside tmux, the client half of ccmux ignores the setting and uses the server you are attached to; the daemon always honors it, which is the point of the setting.

When the configured server cannot be reached, the picker, the sidebar, and ccmux show say so and name the socket (tmux server unreachable at /private/tmp/tmux-501/work) instead of reporting an empty session list.

Remote / SSH

ccmux tracks the sessions on the machine where it runs, so for a remote devbox, run everything there: install ccmux, tmux, and your agents on the remote host, run ccmux setup, and attach over SSH. Detection, hooks, the picker, and the sidebar all work at full fidelity because nothing crosses the SSH boundary; your terminal is just the window into it.

The one piece that doesn’t follow automatically is desktop notifications: the remote daemon has no desktop to deliver to. The osc notification backend covers this by writing a notification escape sequence into the session’s tmux pane, so it rides the terminal stream, SSH included, and renders as a banner in the emulator you’re sitting in front of. Opt-in only (never picked by auto) and informational only: no buttons, reply, sound, or retraction, and paneless background sessions are skipped. Kitty clients get OSC 99, everything else OSC 9 (title: body); supported by Ghostty, iTerm2, and WezTerm (OSC 9) and Kitty (OSC 99), silently ignored by Apple Terminal and Alacritty.

Terminal window
# on the remote host
ccmux config set notifications.enabled true
ccmux config set notifications.backend osc
tmux set -g allow-passthrough all # add to tmux.conf to persist
ccmux notify # test: a banner should appear locally

Use all rather than on: at on, tmux only forwards passthrough sequences from visible panes, and the agent that needs your attention is usually in a window you’re not looking at.

Nested tmux (a local tmux, SSH, then a remote tmux where ccmux runs) is detected automatically: the escape is wrapped twice so it survives both layers. Both tmux instances need allow-passthrough all (with on, the outer tmux drops the sequence whenever the SSH pane sits in a background local window), and ccmux can only verify the one it runs under, so set it on the local side too. A Kitty terminal behind an outer tmux receives the plain OSC 9 form, since Kitty can’t be detected through that outer tmux; the banner still appears, just without per-session grouping.