gotomux

go to mux, (yet) another fuzzy tmux session picker with presets, shapes, zoxide.
Forget about tmux and just jump into work: live sessions, saved presets, with zoxide paths, and sticky shapes reapplied on new projects.
Install
Arch Linux:
paru -S gotomux
# optional, for instant cold start
systemctl --user enable --now gotomuxd
Go (any platform):
go install github.com/fm39hz/gotomux@latest
# binary: $(go env GOPATH)/bin/gotomux
# optional daemon:
go install github.com/fm39hz/gotomux/cmd/gotomuxd@latest
From source:
git clone https://github.com/fm39hz/gotomux.git && cd gotomux
make install # go install CLI
make install-all # CLI + daemon + systemd unit + enable
# or: make build && ./gotomux
# or: make pkg # Arch: dist/*.pkg.tar.zst
Requires: tmux, zoxide (optional)
Optional: Nerd Font (icons; or icons = "ascii" in the config file)
Usage
Usage: gotomux [flags]
Flags:
-h, --help Show this help
-v, --version Show version
-f, --freeze Freeze current or named session as a preset
-e, --edit Edit a named preset (or freeze-then-edit)
-r, --reset Restore current or named session to its baseline layout
The picker opens instantly. Type to filter, Enter to connect.
Daemon (gotomuxd)
Optional background service for faster cold start and automatic reranking supported telemetry.
systemctl --user enable --now gotomuxd
Gotomux auto-detects the daemon on startup. If absent, it will falls back to standalone mode (works identically, slightly slower cold start).
Keybind
Picker
| Key |
Action |
| type |
filter (diacritics folded) |
enter |
connect |
ctrl-n / ctrl-p |
next / prev |
ctrl-u / ctrl-w |
clear query / delete word |
ctrl-x |
kill active session |
ctrl-f |
freeze into preset + shape |
ctrl-t |
set sticky shape for new projects |
ctrl-e / ctrl-d |
edit / delete preset |
esc / ctrl-c |
cancel |
? |
toggle help |
Shell
This is the setup I use for myself, adapt into your own shell config if needed
Nushell
$env.config.keybindings ++= [{
name: launch_gotomux
modifier: control
keycode: char_b
mode: [emacs, vi_normal, vi_insert]
event: { send: executehostcommand, cmd: "gotomux" }
}]
Fish
function fish_user_key_bindings
for mode in insert default visual
bind -M $mode \cb 'gotomux; commandline -f repaint'
end
end
bind-key C-b display-popup -T " Go to mux " -w 80% -h 70% -x C -y C -E "gotomux"
bind-key C-e run-shell "gotomux -e"
bind-key -n C-f run-shell "tmux display-message \"$(gotomux -f)\""
Behaviour
| Item |
Enter |
| Active |
attach / switch |
| Preset |
load if missing, then attach |
| Create / Zoxide |
live? attach : same-name preset? load : unfreeze sticky shape into project root |
Shapes
A shape is cockpit essence (no paths, no pixel dumps).
Freeze saves a full instance, and a shape is derived from it (topology + tools only).
Sticky shapes are used for new projects via Create/Zoxide.
{
"id": "shape-2942bbbd21e65a14",
"label": "nvim+v2+yazi",
"windows": [
{ "fork": "1||nvim", "name": "editor", "panes": [{ "cmd": "nvim" }] },
{
"fork": "2|even-vertical|",
"name": "shell",
"split": "even-vertical",
"panes": [{}, {}]
},
{ "fork": "1||yazi", "name": "files", "panes": [{ "cmd": "yazi" }] }
]
}
The fork string is a window essence fingerprint (panes|split|tools).
Common patterns accumulate hit counts in the DB and can be composed into new shapes automatically.
Reset
gotomux -r restores a session to its recorded baseline layout — run it inside tmux for the current session, or pass a name (gotomux -r my-session).
- Baseline: the preset written when the session was created (bake) or frozen. Hand-built sessions get one on the first
-r, so a second run actually restores.
- Dead windows (the pane exited, tmux closed the window, renumbering shifted the rest) are recreated at their baseline index with their original command; surviving windows are moved back to their baseline position.
- Nothing is killed: windows you added beyond the baseline stay, processes intact.
No output and no changes when the session already matches the baseline.
Data
| Path |
Contents |
$XDG_CONFIG_HOME/gotomux/shapes/<label>--<id8>.json |
shape backup (auto-reconciled) |
$XDG_DATA_HOME/gotomux/state.db |
presets, shapes, usage, forks |
$XDG_DATA_HOME/gotomux/gotomuxd.sock |
daemon IPC (if running) |
$XDG_CONFIG_HOME/gotomux/config.toml |
settings (env vars override) |
Ranking
Sources is form into a space × time matrix ranking
|
Here |
Anywhere |
| Future |
Create |
Zoxide |
| Present |
— |
Active |
| Past |
— |
Preset |
Sort: tier > recency > cooccur > trans > kind > detail > busy > pathQ > idx.
Same formula everywhere, environment only changes inputs:
- Inside tmux (
ctxSession set): items matching the current session name or path are excluded; co-occurrence and directed switch (prev→next, learned by the daemon from real attach diffs) overlays active.
- Outside tmux: all items visible; co-occurrence/switch = 0.
"Just left" surfaces via recency.
Configuration
Settings live in $XDG_CONFIG_HOME/gotomux/config.toml, next to shapes/.
Precedence: defaults < config file.
# gotomux configuration
data_dir = "" # base for state.db + socket ($XDG_DATA_HOME/gotomux)
config_dir = "" # base for shapes/ + this file ($XDG_CONFIG_HOME/gotomux)
poll_interval = "10s" # daemon sync cadence
zoxide_cap = 40 # zoxide rows when the query is empty
max_show = 12 # visible picker rows
git_concurrency = 4 # git enrich workers
proc_cache_ttl = "2s" # pane process detection cache
prune_cutoff = "720h" # stale row prune age
icons = "auto" # auto | nerd | ascii
[daemon]
autostart = true # picker may start gotomuxd
prewarm = "auto" # auto (rotational disks) | on | off
Unknown keys are reported and ignored; a malformed entry degrades to its default instead of failing startup.
The daemon applies the file at start — systemctl --user restart gotomuxd after edits.
Roadmap
Local first.
WARNING!: gotomux is still in early development stages. Some unintended behavior might occur.
- Sources: create / tmux / preset / zoxide
- Freeze / load, sticky shapes, placement + fork learning
- Shape labels, config reconcile, product JSON (
split / tools)
-
go install / CI / local Arch package
- AUR release
- Polish everyday use until boring
- Remote tmux as one pool (
tmux@host; server: tmux + ssh only)
Dev
make help && make test
Acknowledgements
License
MIT