A fuzzy switcher for tmux sessions and project directories.
gmux scans the project roots you configure, one level deep, and merges those
directories with your live tmux sessions into a single fzf picker. Pick one and
you land in it — attaching to the session if it exists, creating it in the right
directory if it doesn't.
🟢 api-server ← attached (you are here)
🔵 web-client ← session running in the background
🔵 scratch ← session with no matching directory
🌑 infra ← project directory, no session yet
🌑 my.proj ← dots become underscores in the session name
It is a single POSIX shell script with no runtime dependencies beyond tmux and
fzf. No daemon, no cache, no state.
git clone https://github.com/Vilos92/gmux.git ~/.gmuxThen put bin on your PATH in your shell rc:
export PATH="$HOME/.gmux/bin:$PATH"That's the whole install — there is no install script, and nothing is written
outside the checkout unless you choose to put your config in ~/.config.
Requirements: tmux and fzf. fd is used
for directory scanning when present and find is used when it isn't; installing
fd is a speed optimization, not a requirement.
gmux needs to know where your projects live. Copy the template:
cp ~/.gmux/config.example ~/.gmux/configand list one root per line:
# Each root is scanned one level deep.
~/src
~/work
/Volumes/external/projects
Every directory found under a root becomes an entry in the picker. Roots that don't exist are skipped silently, so it's fine to list paths that only exist on some of your machines.
| Location | When to use it |
|---|---|
$GMUX_ROOTS env var |
One-off override: GMUX_ROOTS=~/scratch gmux |
~/.config/gmux/config |
Preferred — survives re-cloning gmux |
~/.config/gmux/config.d/* |
Drop-ins, merged with the file above |
<checkout>/config |
Fallback — git-ignored, lives beside the code |
Higher rows win, except config and config.d/* which are additive: use
drop-ins when several independent sources each need to contribute a root
without any one of them owning the whole file. $GMUX_ROOTS is
newline-separated and accepts exactly the same entries as a file.
Prefer a file over the environment variable. tmux run-shell bindings and
desktop widgets invoke gmux from a bare sh -c that sources no shell rc, so
anything exported by your .zshrc — or defined as a shell function — is simply
not there. Config files are read at invocation time and work in every context.
If you manage dotfiles across machines, note that a config living inside the
checkout breaks if you ever install gmux into a read-only prefix, so
~/.config/gmux/config is the more portable choice.
- One absolute path or
~/-relative path per line - Blank lines are ignored
- A line beginning with
#is a comment — paths containing#still work - Surrounding whitespace is trimmed
- The file is not executed as a shell script, so
$VARIABLESdo not expand. This is deliberate: a config format that runs arbitrary code makes "paste this snippet into your config" a security problem. Use$GMUX_ROOTSif you need paths computed at runtime.
Run gmux with nothing configured and it will tell you where it looked, then
fall back to showing your live tmux sessions.
gmux # open the picker
gmux <name> # attach directly to a known project or existing session
gmux <name> <dir> # attach to <name>, creating it in <dir> if it is newThe direct form doesn't invoke fzf, so it stays usable in scripts, keybindings,
and status-bar widgets.
Most people alias it:
alias g=gmuxtmux rewrites . to _ when creating a session, so gmux canonicalizes names
the same way: a directory named my.proj becomes session my_proj while the
picker still displays my.proj. Passing either form to gmux <name> works.
The repo also ships attach-tmux-session, the create-or-attach primitive gmux
is built on. It is useful on its own:
attach-tmux-session <session-name> [directory] [command...]It does the right thing whether or not you are already inside tmux — attaching from outside, switching the client from inside — and is idempotent.
sh test/equivalence.shA self-contained golden-spec harness. It fabricates project directories and stub
tmux/fzf/attach-tmux-session binaries, runs the real script, and asserts the
exact picker contents and attach calls. It covers hidden and dotted and spaced
directory names, status markers, config precedence, ~ expansion, the
unconfigured fallback, and the missing-fzf path. No tmux server is touched.
MIT