tmuxdeck
A VS Code workspace extension for tmux 3.x on a Linux host, including Remote-SSH.
Shell startup files change only when you confirm Set Private Socket Directory,
and closing or detaching a terminal does not kill its tmux session.
Install and use
- Connect with VS Code Remote-SSH.
- Run Extensions: Install from VSIX... and choose the packaged tmuxdeck VSIX.
Ensure tmuxdeck is installed/enabled on the SSH host, not just locally.
- Open tmuxdeck in the Activity Bar.
- If necessary, run tmuxdeck: Locate tmux Executable. Shell aliases are not
executable paths; Detect from Shell Configuration can import literal
alias tmux=... and export TMUX_TMPDIR=... settings without executing them.
Install tmux Locally... (view ... menu or Command Palette) builds tmux 3.8 into
~/local without sudo, using scripts/install-tmux.sh in a visible terminal. On
success tmuxdeck uses the new binary. See docs/install-tmux.md for the manual
steps and shell setup.
- At startup tmuxdeck warns when
TMUX_TMPDIR is unset or points into a shared
temporary directory (/tmp, /var/tmp, /dev/shm), where cleanup can delete
tmux sockets and leave running sessions unreachable. It checks the extension
host's environment, then literal exports in ~/.zshrc or ~/.bashrc (for the
login shell), not .zshenv, .profile, or computed values.
Set Private Socket Directory (TMUX_TMPDIR)... asks for a non-shared directory
(default ~/tmux-sessions), creates it with mode 0700, and after confirmation
appends a marked # >>> tmuxdeck TMUX_TMPDIR (managed) >>> block to that file,
replacing an earlier tmuxdeck block. It also makes the directory the first
tmuxdeck.socketDirectories entry. Running servers and open terminals keep
their current location. Set tmuxdeck.checkSocketDirectory to false (or
choose Don't Show Again) to silence the warning.
The tree shows sessions > windows, and a window's panes only when it is split.
With several socket servers, or one in error, each server gets its own row above its
sessions. A session with a terminal in this VS Code window has a green icon and
"open here" in its description. Hover to attach; right-click for new, rename, kill, detach, open, or split
actions. Commands are also available from the Command Palette.
- Attach focuses a VS Code terminal already showing that session, window or pane,
or opens a panel terminal. A window/pane of a detached session is selected in it.
If the session is already attached, the window/pane opens in its own terminal
through a hidden grouped "viewer" session, so several windows of one session can
be open side by side without switching other clients. A viewer is removed when its
terminal closes or detaches; the session and its windows are unaffected.
- Directories are shown on every row, with
~ for your home and long paths
shortened from the left (hover for the full path). A pane shows its own current
directory; a window or session shows its active pane's, so it follows cd. A pane
that reports none, such as a dead one, falls back to the session's start directory.
- Open Directory in New Window / Current Window opens that directory as a VS Code
folder on the same host, to browse its files and worktree. It is a hover button
(new window), a right-click action, and a Command Palette command, and it refuses a
directory that no longer exists. The current window reloads (VS Code asks about
unsaved files) and restarts tmuxdeck. A newly opened folder may start in Restricted
Mode, which disables tmuxdeck there until you trust the folder.
- New Worktree... (view title bar, a server row's right-click menu, or the Command
Palette) creates a git worktree and attaches a new tmux session started in it.
Choose a main checkout directly inside
tmuxdeck.workDirectory, or Browse....
The branch name starts with tmuxdeck.branchPrefix. An existing local branch is
checked out (git refuses one checked out elsewhere), origin/<branch> is tracked,
and any other name becomes a new branch from a base you confirm, pre-filled with
origin/HEAD's target. tmuxdeck never fetches, so remote branches are as of your
last fetch. A new branch has no upstream; publish it with git push -u origin <branch>.
The folder defaults to <workDirectory>/<last branch segment>, or beside the source
repository, must not exist yet, and names the session (. and : become _).
git runs from the extension host's PATH. Git-ignored files, such as dependencies,
are not copied. If git fails after creating the folder (a failing hook, say), the
worktree remains and no session starts. Remove worktrees with Git: Delete
Worktree or git worktree remove.
- Detach This VS Code Client leaves external clients alone.
- Detach All Session Clients includes external clients and asks for confirmation.
- Kill terminates the selected tmux object and may terminate its processes.
It asks for confirmation. Killing a linked window affects all its sessions.
Killing a session also kills its viewer sessions, which would otherwise keep its
windows running.
- Split on a window splits its active pane.
- Rename pane changes its title; programs inside it may subsequently overwrite it.
- Clean Stale Sockets previews and confirms removal. It never kills sessions,
panes or servers. Only old, owned socket files in private, non-symlinked
tmux-<uid> directories are eligible, after a refused connection and a
second identity/liveness check. Permission errors and timeouts are not "stale".
Avoid restarting servers concurrently with cleanup: POSIX does not provide an
atomic "unlink only if still the same inactive socket" operation.
Remote host settings
These settings are machine-scoped; workspace settings cannot redirect execution:
{
"tmuxdeck.path": "/absolute/path/to/tmux",
"tmuxdeck.socketDirectories": ["~/tmux-sessions"],
"tmuxdeck.socketPaths": [],
"tmuxdeck.checkSocketDirectory": true,
"tmuxdeck.workDirectory": "~/work",
"tmuxdeck.branchPrefix": "dev/me/"
}
socketDirectories contains base directories, not the tmux-<uid> subdirectory.
The first configured base is the default for new servers; otherwise TMUX_TMPDIR
or /tmp is used. /tmp, /var/tmp, and the extension host's TMUX_TMPDIR are
always searched as well. Existing servers in different directories stay separate.
Use socketPaths for existing custom tmux -S sockets. Starting a new server is
restricted to an owned, private tmux-<uid> directory.
workDirectory (~ accepted) is where New Worktree lists source repositories
and creates worktrees, and where New Session starts. Leave it empty to create
each worktree beside its source repository and keep tmux's default directory for
new sessions. branchPrefix pre-fills new worktree branch names.
The executable is resolved from the setting, then ~/local/bin, ~/.local/bin,
~/bin, and absolute PATH entries. tmux is launched without an intervening shell,
with UTF-8 output and an explicit socket; TMUX is removed to avoid false nesting.
New servers use the host's normal tmux configuration and default shell.
If the host has no locale variables, LC_CTYPE=C.UTF-8 is supplied.
The tree polls every two seconds while visible and focused, and after actions, but
redraws only when something changed: a redraw briefly invalidates the rows, and a
click landing then would fall back to a target picker.
The status count is cached while the view is hidden. Errors appear in the tree or
notifications, with details in the tmuxdeck Output channel.
Development
Requires Node.js 22.18+ and npm for tooling; the extension targets VS Code 1.85+.
npm ci
npm run build
npm test
npm run test:vscode
npm run package
Tests use private temporary sockets, -f /dev/null and temporary git repositories,
never your default server or your repositories.
Set TMUXDECK_TEST_BINARY=/absolute/path/to/tmux if automatic discovery is unsuitable.
The VS Code tests download VS Code 1.85.2 and require a graphical display
(Xvfb is sufficient on headless Linux). F5 runs the extension development host.
The packaging-tool override selects a patched minimatch until vsce updates its dependency.
Scope and limitations
This is the M0-M1 implementation plus directories and worktrees: server/session/window/pane
browsing and management, terminal reuse, status count, stale-socket cleanup,
opening a session, window or pane directory in VS Code, and creating a git worktree
with its own session. No control-mode monitoring, clients sidebar, layouts, buffers,
hooks editor, pane preview, worktree removal, or resurrection yet.
Use tmux's normal keys inside attached terminals for those operations.
Control characters are replaced with ? in display labels and directories to keep
snapshots unambiguous, so a directory whose name contains one is shown with ? and
cannot be opened. New names reject control characters and semicolons; session names also
reject . and : because tmux silently rewrites them. Operations use tmux IDs
after checking the server generation and target existence.
Terminal reuse requires the VS Code terminal process ID to match a tmux client.
It is verified for direct tmux launches, including the tested tmux 3.3a AppImage.
Shell-wrapper terminals are not automatically recognized. Reload/SSH-reconnect
behavior also depends on VS Code terminal persistence and needs a manual Remote-SSH
smoke test. The tests recreate the terminal manager but do not simulate SSH loss.