Skip to content

cmux Workspaces

Scripts in home/bin/ that keep cmux workspaces and tmux sessions in sync. They are uv inline-script executables — the dependency headers mean they run straight from $PATH with no virtualenv to manage.

Script Description
cmux-dump-save Save the open workspaces to a dump file
cmux-dump-restore Recreate workspaces from a dump file
cmux-dump-edit Open the dump file in $EDITOR
cmux-tmux-sync Give unattached tmux sessions a workspace, once; --host/--all to cover the other Macs
cmux-tmux-watch Same as sync, but polling continuously
cmux-doctor Check the tools, socket, config, and hosts these scripts depend on
_cmux.py Shared helpers; imported by the above, not run directly

They keep their files in ~/.config/cmux-tmux/ ($XDG_CONFIG_HOME is honored). That is deliberately not ~/.config/cmux/, which belongs to the cmux app itself. Files from the old locations, ~/.config/cmux/session-dump.* and ~/.config/tmux/hosts.toml, are moved into place automatically the first time any of these scripts runs on a Mac.

The two halves work in opposite directions. cmux-dump-save / cmux-dump-restore treat a hand-editable file as the source of truth and rebuild workspaces from it. cmux-tmux-sync / cmux-tmux-watch treat the running tmux server as the source of truth, so work left behind in a detached session gets a window back instead of quietly aging out.

Dump and Restore

cmux-dump-save          # save open workspaces to ~/.config/cmux-tmux/session-dump.toml
cmux-dump-edit          # edit that file to add host / tmux / session fields
cmux-dump-restore       # recreate any workspace that is not already open

The dump defaults to ~/.config/cmux-tmux/session-dump.toml. All three take an optional path argument to use another file; a .json extension writes or reads JSON. cmux-dump-restore and cmux-dump-edit detect the format from the extension and fall back to session-dump.json when no TOML file exists. None of them has other options.

cmux cannot report whether a workspace is running mosh or tmux, so host, tmux, and session are hand-added. Re-dumping preserves them by matching on title, and keeps annotated entries whose workspaces have since been closed, so closing a workspace does not lose its config. Writes are atomic, so an interrupted dump cannot corrupt those hand-edited fields.

Field Description
title Workspace title; also the default tmux session name
cwd Working directory
color Custom workspace color
pinned Whether the workspace is pinned
description Workspace description
host Host to mosh to; treated as local if it matches this machine
tmux Attach a tmux session in the workspace
session Explicit tmux session name, overriding the title-derived one
[[workspaces]]
title = "thumb.im"
cwd = "/Users/jefftriplett/Projects/thumb.im/thumb.im-git"
host = "mac-mini-pro-2023"
tmux = true

The last three fields combine to decide where a workspace runs:

Fields Result
host + tmux = true mosh to the host and attach a tmux session there, started in cwd
host only plain mosh to the host
tmux = true only attach a local tmux session, started in cwd
neither plain local workspace

Restoring is safe to rerun: workspaces whose title already exists are skipped, and tmux sessions use new-session -A, so a restore resumes an existing session rather than duplicating it. Remote workspaces get a [mosh] label on the cmux title; it is display-only and never reaches the remote tmux session name.

Sync and Watch

cmux-tmux-sync --dry-run              # show which local sessions would get a workspace
cmux-tmux-sync                        # create the missing workspaces
cmux-tmux-sync --host mac-studio-2023 # sync that Mac as mosh workspaces
cmux-tmux-sync --all                  # every machine in the registry
cmux-tmux-watch                        # keep syncing local sessions as they appear
cmux-tmux-sync option Description
--host, -H Sync sessions from this host; repeatable
--all Sync every host in the machine list
--dry-run, -n Show what would be created
--include-attached Also sync local sessions that have a client; remote is unaffected
--timeout, -t ssh connect timeout in seconds (default 5)
cmux-tmux-watch option Description
--interval, -i Seconds between polls (default 5)
--once Run a single sync and exit
--max-failures Exit 1 after this many consecutive errors (default 5)

cmux-tmux-sync gives a local session a workspace when nothing is attached to it and no open workspace already maps to it. Attached sessions are left alone so opening the new workspace does not add a second client to a session you are already using; --include-attached overrides that, which is useful when a session is only attached from outside cmux.

Syncing Across Macs

--host (repeatable) and --all extend the same idea to the other Macs, using the same ssh path as tmux-remote-ls. The machine list behind --all is the one every cmux-* and tmux-remote-* script shares: $TMUX_REMOTE_HOSTS (space separated) when set, otherwise the [machines] table of ~/Projects/projects.toml, otherwise the older ~/.config/cmux-tmux/hosts.toml. A remote session becomes a workspace that moshes to the host and attaches there, exactly like a host + tmux = true entry in the dump file.

The unattached test does not carry over. A session on the mini reads as attached because a workspace on the mini holds it, which says nothing about whether this machine can see it — so a remote session gets a workspace when none here already points at it, regardless of who else has it open. Remote workspaces are titled host:session, so the same session name on two Macs stays distinct. A host that cannot be reached prints an error and the remaining hosts still run.

Because most remote sessions are attached on their own machine, opening a synced workspace adds a second client to a live session. With window-size latest (the tmux default, and what these Macs run) the window resizes to whichever client was most recently active, so the other Mac's view changes size while you work in it. That is the tradeoff for seeing every session from one place.

cmux-tmux-watch polls on an interval (--interval, default 5s) and covers both attached and detached sessions — its only requirement is that no workspace already covers the session. It is local-only; use cmux-tmux-sync --all for the other Macs. Use --once for a single pass. When a poll fails, say because cmux is not running, it prints the error, backs off, and gives up with exit 1 after --max-failures consecutive errors, so a dead cmux does not leave it spinning at the poll rate.

Workspaces are matched to sessions by the same slug cmux-dump-restore feeds to tmux new-session, so a workspace titled thumb.im counts as covering the thumb-im session and is not created twice. Sessions are attached by name rather than by directory, which matters when two projects share a parent directory.

Doctor

cmux-doctor is the preflight for everything on this page and on the tmux one. It exits non-zero when a required check fails, so a script can run it first.

cmux-doctor                 # full run, probes every Mac over ssh
cmux-doctor --skip-hosts    # offline: tools, socket, and config only
cmux-doctor --timeout 10    # slower network
Section What it checks
Tools tmux, cmux, mosh, ssh, and the status-bar helpers are on $PATH, with versions. A missing required tool fails; an optional one warns
Socket The cmux control socket exists and answers. Honors $CMUX_SOCKET_PATH, then the app's last-socket-path, then the default under ~/.local/state/cmux/. A closed socket prints the cmux.json setting that opens it
Config ~/.config/cmux-tmux/ and the session dump exist
Hosts The machine list parses, this Mac recognizes itself in it, and each remote host answers over ssh, with its tmux session count
Remote tmux rpc Whether cmux's remote.tmux.sessions rpc reports a working directory yet. It does not today, which is why the rpc path prints (unknown) in tmux-remote-ls
Summary Counts of ok, warn, and fail
Option Description
--skip-hosts Do not probe remote hosts over ssh
--timeout Per-host ssh connect timeout in seconds (default 5)