gotomux

command module
v0.4.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 25, 2026 License: MIT Imports: 22 Imported by: 0

README

gotomux

CI Release AUR Go

go to mux, (yet) another fuzzy tmux session picker with presets, shapes and zoxide.

Forget about tmux plumbing and just jump into work. One keystroke opens a fuzzy list of everything you could want to attach to:

  • Live sessions: ranked by real usage, not just mru
  • Saved presets: frozen snapshots of whole sessions (paths + commands)
  • Sticky shapes: the topology of your cockpit (windows / panes / tools), re-baked into new projects via Create / Zoxide
  • Zoxide paths: create a fresh session anywhere you've z'd before
  • Self-ranking: the daemon learns co-occurrence and directed transitions from real attach diffs, so the item you want surfaces first

One static binary. No accounts, no telemetry out, the only "telemetry" is live in a local SQLite file.

Why not a tmux script + fzf?

fzf-tmux one-liner gotomux
Session list ✓ + usage-ranked
Presets (frozen sessions) ✓ (gotomux -f)
Rebuild from shapes ✓ (sticky + learning)
Zoxide as source
Cold start ~5 ms (daemon: ~13 ms warm)

Quick start

# Arch
paru -S gotomux
systemctl --user enable --now gotomuxd   # optional, instant cold start

# any platform with Go
go install github.com/fm39hz/gotomux@latest
go install github.com/fm39hz/gotomux/cmd/gotomuxd@latest

Then bind it to a key (see Shell setup) and press it. Done.

Requires: tmux. Optional: zoxide, a Nerd Font (icons = "ascii" in the config otherwise).

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
# or: make run         # picker, ARGS="-f" / "-e name" / "-p"

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
  -p, --profile  Profile cold-start performance

The picker opens instantly. Type to filter, Enter to connect.

Daemon (gotomuxd)

Optional background service: pre-warms the data and does all ranking telemetry, so the picker does zero fs / tmux I/O on its hot path.

systemctl --user enable --now gotomuxd

gotomux auto-detects the daemon. If absent it falls back to standalone mode, behaviorally identical, slightly slower cold start.

Shell setup

This is the setup I use for myself, adapt it 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

[!TIP] Tmux popup: gotomux is a normal TUI, so it composes perfectly with display-popup.

bind-key C-b display-popup -T " Go to mux " -w 80% -h 70% -x C -y C -E "$HOME/go/bin/gotomux"
bind-key C-e display-popup  -T " Edit config " -w 80% -h 90% -x C -y C -E "$HOME/go/bin/gotomux -e"
bind-key C-r run-shell "tmux display-message \"$($HOME/go/bin/gotomux -r)\""
bind-key -n C-f run-shell "tmux display-message \"$($HOME/go/bin/gotomux -f)\""

Keybindings

Picker
Key Action
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

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. Shapes live as editable JSON next to your config: $XDG_CONFIG_HOME/gotomux/shapes/<label>--<id8>.json.

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.

Ranking

Sources form a space × time matrix:

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 (what you keep open alongside) and directed transition (what you usually switch into) overlays are active.
  • Outside tmux: all items visible, co-occurrence / transitions = 0.

The daemon learns transitions from real attach diffs (session_attached count deltas between polls, exactly one session lost a client and exactly one gained one), so it sees native tmux switches too, not just gotomux ones.

"Just left" surfaces via recency.

Configuration

Settings live in $XDG_CONFIG_HOME/gotomux/config.toml, next to shapes/. Precedence: defaults < config file. The file is the single inspectable source, there is deliberately no environment layer for settings.

# 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 reads the file at start, systemctl --user restart gotomuxd after edits.

Data
Path Contents
$XDG_CONFIG_HOME/gotomux/shapes/<label>--<id8>.json shape backup (auto-reconciled)
$XDG_DATA_HOME/gotomux/state.db presets, shapes, usage, pairs, transitions, forks
$XDG_DATA_HOME/gotomux/gotomux.sock daemon IPC (if running)
$XDG_CONFIG_HOME/gotomux/config.toml settings (defaults < file)

Development

make help    # every target
make test    # go test ./... (add -short for CI-style)
make fmt vet # gofmt + go vet
make pkg     # Arch package -> dist/*.pkg.tar.zst

Roadmap

Local first.

  • 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
  • Add remote tmux as stable source (tmux@host)

[!WARNING] gotomux is still in early development. Some unintended behavior might occur.

Built With

Acknowledgements

Gotomux started as a bash script gluing together several CLI tools before being rewritten into a standalone Go tool. Special thanks to the projects and tools that inspired and powered that original workflow:

  • sesh: Smart tmux session manager inspiration
  • fzf: Interactive fuzzy search & keybindings
  • tmuxp: Session freezing & layout persistence inspiration
  • zoxide: Smarter directory jumping as a session source
  • fd: Fast filesystem traversal for preset discovery
  • tmux: The terminal multiplexer itself

License

MIT

Documentation

The Go Gopher

There is no documentation for this package.

Directories

Path Synopsis
cmd
gotomuxd command
internal
gitinfo
Package gitinfo reads a repository's current branch label from disk.
Package gitinfo reads a repository's current branch label from disk.
tmuxtest
Package tmuxtest isolates tests from the developer's real tmux server.
Package tmuxtest isolates tests from the developer's real tmux server.
toolclass
Glyph codepoints: the single home for every Nerd Font signature the TUI draws.
Glyph codepoints: the single home for every Nerd Font signature the TUI draws.
zoxide
Package zoxide turns `zoxide query -l` output into the rows that both the picker and the daemon serve.
Package zoxide turns `zoxide query -l` output into the rows that both the picker and the daemon serve.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL