Small tmux popup toolkit with a TSV registry, generated bindings, shared shell helpers, dependency checks, and optional local overrides.
Prefix+Enterquick menu generated from registry rows- Direct bindings generated from the same rows
- Default registry:
popups.tsv - Local override registry:
~/.config/tmux-popups/popups.local.tsv - Dependency status in help and CLI output
- Doctor script for common tmux/TPM/config problems
- Bash-only implementation; no build step
- Generated config stored at
${XDG_CACHE_HOME:-$HOME/.cache}/tmux-popups/generated.conf
Add to ~/.tmux.conf or your sourced tmux config:
set -g @plugin 'PatrickFanella/tmux-popups'Reload tmux, then press TPM install key (prefix + I).
git clone https://github.com/PatrickFanella/tmux-popups.git ~/.config/tmux/plugins/tmux-popupsThen source the plugin entrypoint:
run-shell "$HOME/.config/tmux/plugins/tmux-popups/tmux-popups.tmux"Reload tmux:
tmux source-file ~/.tmux.confUseful when hacking on the plugin but still letting TPM manage load/update keys.
git clone https://github.com/PatrickFanella/tmux-popups.git ~/Projects/tools/tmux-popups
mkdir -p ~/.config/tmux/plugins
ln -sfn ~/Projects/tools/tmux-popups ~/.config/tmux/plugins/tmux-popupsKeep TPM registration in tmux config:
set -g @plugin 'PatrickFanella/tmux-popups'TPM will see tmux-popups; the symlink points it at your working tree.
The default registry includes the full popup set. Some rows need optional tools; dependency status is visible in Prefix+C-h and scripts/list-popups.sh --deps.
| Key | Popup |
|---|---|
Prefix+Enter |
Quick menu |
Prefix+C-h |
Popup help + dependency status |
Prefix+O |
quick chat via ocq |
Menu o |
opencode |
Prefix+T |
shell |
Menu N |
daily note |
Prefix+g |
lazygit |
Prefix+Y |
yazi |
Prefix+F |
ferrosonic |
Prefix+C-b |
tmux key list |
Prefix+Z |
dotfiles picker |
Prefix+R |
reload tmux config |
Session switching is intentionally left to tmux-sessionx. Example:
set -g @plugin 'omerxx/tmux-sessionx'
set -g @sessionx-bind 'j'
set -g @sessionx-prefix 'on'
set -g @sessionx-window-height '80%'
set -g @sessionx-window-width '60%'Then Prefix+j opens sessionx. If you prefer tmux's built-in picker, copy the sessions row from examples/popups.optional.tsv.
Set these before the plugin loads:
set -g @tmux-popups-menu-key 'Enter'
set -g @tmux-popups-reload-key 'R'
set -g @tmux-popups-config-file '~/.tmux.conf'
set -g @tmux-popups-default-width '80%'
set -g @tmux-popups-default-height '80%'
set -g @tmux-popups-local-registry '~/.config/tmux-popups/popups.local.tsv'
set -g @tmux-popups-enable-vscode 'on'
set -g @tmux-popups-vscode-command 'code .'
set -g @tmux-popups-yazi-mode 'window'@tmux-popups-config-file is the tmux config file reloaded by the reload binding (@tmux-popups-reload-key, default R) and the Quick Menu "reload tmux" entry. Defaults to ~/.tmux.conf. Set this if your config lives elsewhere, for example:
set -g @tmux-popups-config-file '~/.config/tmux/tmux.conf'Use - in a row's width or height to inherit the default width/height options.
Rows are tab-separated:
id direct_key menu_key title width height command| Column | Meaning |
|---|---|
id |
Unique popup id used by scripts/run-popup.sh |
direct_key |
Direct tmux binding after prefix, or - for none |
menu_key |
Key in quick menu, or - for none |
title |
Popup title |
width |
tmux popup width, e.g. 80%, or - for default |
height |
tmux popup height, e.g. 80%, or - for default |
command |
Plugin-relative script path, or - for an interactive shell |
Blank lines and lines beginning with # are ignored.
Default path:
~/.config/tmux-popups/popups.local.tsv
The plugin merges:
popups.tsv
+ popups.local.tsv
-> generated bindings
If a local row has the same id as a default row, the local row overrides it while keeping the original order. New local ids are appended.
Example local override: move chat to another key and use default popup size:
chat C-a a quick chat - - scripts/tools/chat.shExample local-only scratch shell:
scratch C-s s scratch shell 80% 80% -Reload tmux after edits:
tmux source-file ~/.tmux.confCreate scripts/tools/hello.sh:
#!/usr/bin/env bash
set -euo pipefail
printf 'Hello from tmux-popups.\n\nPress Enter to close... '
read -r _ || trueMake it executable:
chmod +x scripts/tools/hello.shAdd a row to popups.tsv or your local registry:
hello - h hello 75% 75% scripts/tools/hello.shReload tmux and open it with Prefix+Enter, then h.
Extra rows live in:
examples/popups.optional.tsv
Copy rows into your local registry or popups.tsv, install matching tools, then reload tmux.
Examples:
sessions C-j j sessions 80% 80% scripts/tools/sessions.sh
chat O g quick chat 80% 80% scripts/tools/chat.sh
yazi Y r yazi 80% 80% scripts/tools/yazi.shchat needs ocq.
scripts/list-popups.sh --pretty
scripts/list-popups.sh --deps
scripts/list-popups.sh --tsv
scripts/list-popups.sh --deps-tsvPrefix+C-h shows the same dependency status inside tmux.
Dependency groups can contain alternatives, e.g. glow|bat|less means one of those commands is enough.
Run:
scripts/doctor.shIt checks:
- tmux availability/version
- plugin root
- default/local registries
- TPM path and local plugin entry
- TPM registration in tmux config
- generated config creation
tmux source-file -nvalidation- per-popup dependency status
Warnings are informational. Failures exit nonzero.
scripts/generate-config.sh
tmux source-file -n ~/.cache/tmux-popups/generated.conf
tmux source-file ~/.tmux.confGitHub Actions runs:
bash -non plugin scripts- ShellCheck
- config generation smoke test
ocqfor quick OpenCode chatopencodetask/ Taskwarriornvim,vim,vi, or$EDITORtldr,man,lesskhal,calpython3ssh,fzfcliphist,wl-copy,wl-pastenewsboat,curljournalctl,tail,watchglow,batlazygit,yazi,ferrosonic
Some tool scripts respect environment variables:
| Variable | Script | Default |
|---|---|---|
NOTES_DIR |
notes popup |
~/Notes/daily |
PROJECTS_DIR |
projects popup |
~/Projects |
TMUX_POPUPS_YAZI_SAFE |
yazi launcher | on |
Yazi rows open in a normal tmux window by default. Yazi can report a terminal
response timeout inside display-popup, so window mode is the safer default.
Yazi still runs in safe mode by default. tmux popups do not reliably support
image-preview passthrough, so the launcher disables Yazi preview/preload plugins
via a generated cache config. Set TMUX_POPUPS_YAZI_SAFE=off before launch to
use your full Yazi config and accept the tmux risk.
To force popup mode:
set -g @tmux-popups-yazi-mode 'popup'Warning: popup mode may trigger Yazi terminal response timeouts; tmux-popups shows a warning before launching Yazi in popup mode.
popups.tsv + optional local registry
-> scripts/list-popups.sh --tsv
-> scripts/generate-config.sh
-> ~/.cache/tmux-popups/generated.conf
-> tmux source-file
scripts/run-popup.sh <id> reads the merged registry and executes the matching command inside display-popup.
popups.tsv: default popup registry~/.config/tmux-popups/popups.local.tsv: optional local overridesexamples/popups.optional.tsv: optional popup row examplestmux-popups.tmux: TPM/manual entrypointscripts/list-popups.sh: merged registry and dependency listingscripts/generate-config.sh: generates tmux bindingsscripts/run-popup.sh: dispatches popup ids to tool scriptsscripts/doctor.sh: diagnosticsscripts/popup-help.sh: help popupscripts/lib.sh: shared shell helpersscripts/tools/*.sh: popup tool implementations
MIT
