# The Tao of tmux Source: https://tmuxp.git-pull.com/about_tmux/ (about-tmux)= # The Tao of tmux :::{figure} /\_static/tao-tmux-screenshot.png :scale: 60% :align: center :loading: lazy ISC-licensed terminal multiplexer. ::: tmux is geared for developers and admins who interact regularly with CLI (text-only interfaces) In the world of computers, there are 2 realms: 1. The text realm 2. The graphical realm tmux resides in the text realm. This is about fixed-width fonts and that old fashioned black terminal. tmux is to the console what a desktop is to gui apps. It's a world inside the text dimension. Inside tmux you can: - multitask inside the terminal, run multiple applications. - have multiple command lines (pane) in the same window - have multiple windows (window) in the workspace (session) - switch between multiple workspaces, like virtual desktops ## Thinking tmux ### Text-based window manager | **tmux** | **"Desktop"-Speak** | **Plain English** | | ----------- | ------------------------------- | ------------------------------------- | | Multiplexer | Multi-tasking | Multiple applications simultaneously. | | Session | Desktop | Applications are visible here | | Window | Virtual Desktop or applications | A desktop that stores it own screen | | Pane | Application | Performs operations | ```{eval-rst} .. aafig:: :textual: +----------------------------------------------------------------+ | +--------+--------+ +-----------------+ +-----------------+ | | | pane | pane | | pane | | pane | | | | | | | | | | | | | | | | | | | | | +--------+--------+ | | +-----------------+ | | | pane | pane | | | | pane | | | | | | | | | | | | | | | | | | | | | +--------+--------+ +-----------------+ +-----------------+ | | | window | | window | | window | | | \--------+--------/ \-----------------/ \-----------------/ | +----------------------------------------------------------------+ | session | \----------------------------------------------------------------/ ``` - 1 {term}`Server`. - has 1 or more {term}`Session`. - has 1 or more {term}`Window`. - has 1 or more {term}`Pane`. :::{seealso} {ref}`glossary` has a dictionary of tmux words. ::: ### CLI Power Tool Multiple applications or terminals to run on the same screen by splitting up 1 terminal into multiple. One screen can be used to edit a file, and another may be used to `$ tail -F` a logfile. ```{eval-rst} .. aafig:: +--------+--------+ | $ bash | $ bash | | | | | | | | | | | | | | | | | | | +--------+--------+ ``` ```{eval-rst} .. aafig:: +--------+--------+ | $ bash | $ bash | | | | | | | +--------+--------+ | $ vim | $ bash | | | | | | | +--------+--------+ ``` tmux supports as many terminals as you want. ```{eval-rst} .. aafig:: :textual: +---------+---------+ | $ bash | $ bash | | | | | | | /-----------------\ +---------+---------+ --> |'switch-window 2'| | $ bash | $ bash | \-----------------/ | | | | | | | | +---------+---------+ | | '1:sys* 2:vim' | | +-------------------+ | /------------------------/ | v +---------+---------+ | $ vim | | | | | +-------------------+ | $ bash | $ bash | | | | | | | +-------------------+ | '1:sys 2:vim*' | +-------------------+ ``` You can switch between the windows you create. ### Resume everything later You can leave tmux and all applications running (detach), log out, make a sandwich, and re-(attach), all applications are still running! ```{eval-rst} .. aafig:: :textual: +--------+--------+ | $ bash | $ bash | | | | | | | /------------\ +--------+--------+ --> | detach | | $ vim | $ bash | | 'Ctrl-b b' | | | | \------------/ | | | | +--------+--------+ | /------------------/ | v +-----------------------+ | $ [screen detached] | | | | | | | | | | | | | +-----------------------+ v | v +-----------------------+ | $ [screen detached] | | $ tmux attach | | | /------------\ | | --> | attaching | | | \------------/ | | | | | | +-----------------------+ | | /---------------------------/ | v +--------+--------+ | $ bash | $ bash | | | | | | | +--------+--------+ | $ vim | $ bash | | | | | | | +--------+--------+ ``` ### Manage workflow - System administrators monitor logs and services. - Programmers like to have an editor open with a CLI nearby. Applications running on a remote server can be launched inside of a tmux session, detached, and reattached next time your ["train of thought"](http://en.wikipedia.org/wiki/Train_of_thought) and work. Multitasking. Preserving the thinking you have. ## Installing tmux tmux is packaged on most Linux and BSD systems. For the freshest results on how to get tmux installed on your system, "How to install tmux on \" will do, as directions change and are slightly different between distributions. tmuxp requires tmux **3.2 or newer**. The latest stable version is viewable on the [tmux homepage](https://github.com/tmux/tmux). **Mac OS X** users may install the latest stable version of tmux through [MacPorts](http://www.macports.org/), [fink](http://fink.thetis.ig42.org/) or [Homebrew](http://www.brew.sh) (aka brew). If **compiling from source**, the dependencies are [libevent](http://www.monkey.org/~provos/libevent/) and [ncurses](http://invisible-island.net/ncurses/). ## Using tmux ### Start a new session ```console $ tmux ``` That's all it takes to launch yourself into a tmux session. :::{admonition} Common pitfall :class: note Running `$ tmux list-sessions` or any other command for listing tmux entities (such as `$ tmux list-windows` or `$ tmux list-panes`). This can generate the error "failed to connect to server". This could be because: - tmux server has killed its last session, killing the server. - tmux server has encountered a crash. (tmux is highly stable, this will rarely happen) - tmux has not been launched yet at all. ::: (prefix-key)= ### The prefix key Tmux hot keys have to be pressed in a special way. **Read this carefully**, then try it yourself. First, you press the _prefix_ key. This is `C-b` by default. Release. Then pause. For less than a second. Then type what's next. `C-b o` means: Press `Ctrl` and `b` at the same time. Release, Then press `o`. **Remember, prefix + short cut!** `C` is `Ctrl` key. ### Session Name Sessions can be _named upon creation_. ```console $ tmux new-session [-s session-name] ``` Sessions can be _renamed after creation_. ```{eval-rst} =============== ========================================================= Command .. code-block:: bash $ tmux rename-session Short cut ``Prefix`` + ``$`` =============== ========================================================= ``` ### Window Name Windows can be _named upon creation_. ```console $ tmux new-window [-n window-name] ``` Windows can be _renamed after creation_. ```{eval-rst} =============== ========================================================== Command .. code-block:: bash $ tmux rename-window Short cut ``Prefix`` + ``,`` =============== ========================================================== ``` ### Creating new windows ```{eval-rst} =============== ========================================================= Command .. code-block:: bash $ tmux new-window [-n window-name] Short cut ``Prefix`` + ``c`` You may then rename window. =============== ========================================================= ``` ### Traverse windows By number ```console $ tmux select-window ``` Next ```console $ tmux next-window ``` Previous ```console $ tmux previous-window ``` Last-window ```console $ tmux last-window ``` | Short cut | Action | | --------- | ----------------------------------------------------------- | | `n` | Change to the next window. | | `p` | Change to the previous window. | | `w` | Choose the current window interactively. | | `0 to 9` | Select windows 0 to 9. | | `M-n` | Move to the next window with a bell or activity marker. | | `M-p` | Move to the previous window with a bell or activity marker. | ### Move windows Move window ```console $ tmux move-window [-t dst-window] ``` Swap the window ```console $ tmux swap-window [-t dst-window] ``` | Short cut | Action | | --------- | ----------------------------------------------- | | `.` | Prompt for an index to move the current window. | ### Move panes ```console $ tmux move-pane [-t dst-pane] ``` | Short cut | Action | | --------- | ------------------------------------------------ | | `C-o` | Rotate the panes in the current window forwards. | | `{` | Swap the current pane with the previous pane. | | `}` | Swap the current pane with the next pane. | ### Traverse panes Shortcut to move between panes. ```console $ tmux last-window ``` ```console $ tmux next-window ``` | Short cut | Action | | ------------- | --------------------------------------------------- | | `Up, Down` | Change to the pane above, below, to the left, or to | | `Left, Right` | the right of the current pane. | Recipe: tmux conf to `hjkl` commands, add this to your `~/.tmux.conf`: # hjkl pane traversal bind h select-pane -L bind j select-pane -D bind k select-pane -U bind l select-pane -R ### Kill window ```console $ tmux kill-window [-t target-window] ``` | Short cut | Action | | --------- | ------------------------ | | `&` | Kill the current window. | ### Kill pane ```console $ tmux kill-pane [-t target-pane] ``` | Short cut | Action | | --------- | ---------------------- | | `x` | Kill the current pane. | ### Splitting windows into panes ```console $ tmux split-window [-c start-directory] ``` Tmux windows can be split into multiple panes. | Short cut | Action | | --------- | ------------------------------------------------ | | `%` | Split the current pane into two, left and right. | | `"` | Split the current pane into two, top and bottom. | ## Configuring tmux Tmux can be configured via a `tmux(1)` configuration at `~/.tmux.conf`. Depending on your tmux version, there is different options available. ### Vi-style copy and paste ```console # Vi copypaste mode set-window-option -g mode-keys vi bind-key -t vi-copy 'v' begin-selection bind-key -t vi-copy 'y' copy-selection ``` ### Aggressive resizing for clients ```console setw -g aggressive-resize on ``` ### Reload config `` + `r`. ```console bind r source-file ~/.tmux.conf \; display-message "Config reloaded." ``` ### Status lines Tmux allows configuring a status line that displays system information, window list, and even pipe in the `stdout` of an application. You can use [tmux-mem-cpu-load][tmux-mem-cpu-load] to get stats (requires compilation) and [basic-cpu-and-memory.tmux][basic-cpu-and-memory.tmux]. You can pipe in a bash command to a tmux status line like: ```console $(shell-command) ``` So if `/usr/local/bin/tmux-mem-cpu-load` outputs stats to `stdout`, then `$(tmux-mem-cpu-load)` is going to output the first line to the status line. The interval is determined by the `status-interval`: set -g status-interval 1 [tmux-mem-cpu-load]: https://github.com/thewtex/tmux-mem-cpu-load [basic-cpu-and-memory.tmux]: https://github.com/zaiste/tmuxified/blob/master/scripts/basic-cpu-and-memory.tmux ### Examples - - works with tmux 1.5+. Supports screen's `ctrl-a` `Prefix key`. Support for system cpu, memory, uptime stats. - Add yours, edit this page on github. ## Reference ### Short cuts :::{tip} {ref}`prefix-key` is pressed before a short cut! ::: | Short cut | Action | | -------------------------------- | -------------------------------------------------------------------------------------------------------------------------- | | `C-b` | Send the prefix key (C-b) through to the application. | | `C-o` | Rotate the panes in the current window forwards. | | `C-z` | Suspend the tmux client. | | `!` | Break the current pane out of the window. | | `"` | Split the current pane into two, top and bottom. | | `#` | List all paste buffers. | | `$` | Rename the current session. | | `%` | Split the current pane into two, left and right. | | `&` | Kill the current window. | | `'` | Prompt for a window index to select. | | `,` | Rename the current window. | | `-` | Delete the most recently copied buffer of text. | | `.` | Prompt for an index to move the current window. | | `0 to 9` | Select windows 0 to 9. | | `:` | Enter the tmux command prompt. | | `;` | Move to the previously active pane. | | `=` | Choose which buffer to paste interactively from a list. | | `?` | List all key bindings. | | `D` | Choose a client to detach. | | `[` | Enter copy mode to copy text or view the history. | | `]` | Paste the most recently copied buffer of text. | | `c` | Create a new window. | | `d` | Detach the current client. | | `f` | Prompt to search for text in open windows. | | `i` | Display some information about the current window. | | `l` | Move to the previously selected window. | | `n` | Change to the next window. | | `o` | Select the next pane in the current window. | | `p` | Change to the previous window. | | `q` | Briefly display pane indexes. | | `r` | Force redraw of the attached client. | | `s` | Select a new session for the attached client interactively. | | `L` | Switch the attached client back to the last session. | | `t` | Show the time. | | `w` | Choose the current window interactively. | | `x` | Kill the current pane. | | `{` | Swap the current pane with the previous pane. | | `}` | Swap the current pane with the next pane. | | `~` | Show previous messages from tmux, if any. | | `Page Up` | Enter copy mode and scroll one page up. | | `Up, Down` | Change to the pane above, below, to the left, or to | | `Left, Right` | the right of the current pane. | | `M-1 to M-5` | Arrange panes in one of the five preset layouts: even-horizontal, even-vertical, main-horizontal, main-vertical, or tiled. | | `M-n` | Move to the next window with a bell or activity marker. | | `M-o` | Rotate the panes in the current window backwards. | | `M-p` | Move to the previous window with a bell or activity marker. | | `C-Up, C-Down` `C-Left, C-Right` | Resize the current pane in steps of one cell. | | `M-Up, M-Down` `M-Left, M-Right` | Resize the current pane in steps of five cells. | Source: tmux manpage[^id2]. To get the text documentation of a `.1` manual file: ```console $ nroff -mdoc tmux.1|less ``` For more information on how to export and differentiate tmux between versions, see https://github.com/tmux-python/tmux-manuals. [^id2]: [creative commons by-nc-nd 3.0 us]: http://creativecommons.org/licenses/by-nc-nd/3.0/us/ ### The Book :::::::{container} book-container ::::{container} leftside-book :::{figure} https://s3.amazonaws.com/titlepages.leanpub.com/the-tao-of-tmux/large :scale: 100% :width: 301 :height: 390 :align: left :target: https://leanpub.com/the-tao-of-tmux :alt: The Tao of tmux ::: :::: ::::{container} rightside-book _The Tao of tmux_ is available on [Leanpub][leanpub] and [Kindle][kindle] (Amazon). :::{figure} \_static/img/books/amazon-logo.png :scale: 19% :target: http://amzn.to/2gPfRhC :alt: Amazon Kindle ::: Read and browse the book for [free on the web][free on the web]. :::: [free on the web]: https://leanpub.com/the-tao-of-tmux/read [leanpub]: https://leanpub.com/the-tao-of-tmux [kindle]: http://amzn.to/2gPfRhC ::::::: ### License This page is licensed [Creative Commons BY-NC-ND 3.0 US][creative commons by-nc-nd 3.0 us]. --- # Completions Source: https://tmuxp.git-pull.com/cli/completion/ (completion)= (completions)= (cli-completions)= # Completions ## tmuxp 1.17+ (experimental) ```{note} See the [shtab library's documentation on shell completion](https://docs.iterative.ai/shtab/use/#cli-usage) for the most up to date way of connecting completion for tmuxp. ``` Provisional support for completions in tmuxp 1.17+ are powered by [shtab](https://docs.iterative.ai/shtab/). This must be **installed separately**, as it's **not currently bundled with tmuxp**. ```console $ pip install shtab --user ``` With a [uv](https://docs.astral.sh/uv/getting-started/features/#python-versions) project you can add it directly as a development dependency: ```console $ uv add --dev shtab ``` Or reach for [uvx](https://docs.astral.sh/uv/guides/tools/) when you want a pipx-style ephemeral install: ```console $ uvx shtab --help ``` :::{tab} bash ```console $ shtab --shell=bash -u tmuxp.cli.create_parser \ | sudo tee "$BASH_COMPLETION_COMPAT_DIR"/TMUXP ``` ::: :::{tab} zsh ```console $ shtab --shell=zsh -u tmuxp.cli.create_parser \ | sudo tee /usr/local/share/zsh/site-functions/_TMUXP ``` ::: :::{tab} tcsh ```console $ shtab --shell=tcsh -u tmuxp.cli.create_parser \ | sudo tee /etc/profile.d/TMUXP.completion.csh ``` ::: ## tmuxp 1.1 to 1.16 ```{note} See the [click library's documentation on shell completion](https://click.palletsprojects.com/en/8.0.x/shell-completion/) for the most up to date way of connecting completion for tmuxp. ``` tmuxp 1.1 to 1.16 use [click](https://click.palletsprojects.com)'s completion: :::{tab} Bash _~/.bashrc_: ```bash eval "$(_TMUXP_COMPLETE=bash_source tmuxp)" ``` ::: :::{tab} Zsh _~/.zshrc_: ```zsh eval "$(_TMUXP_COMPLETE=zsh_source tmuxp)" ``` ::: --- # tmuxp convert Source: https://tmuxp.git-pull.com/cli/convert/ (cli-convert)= # tmuxp convert Convert workspace configuration files between YAML and JSON formats. ## Command ```{eval-rst} .. argparse:: :module: tmuxp.cli :func: create_parser :prog: tmuxp :path: convert ``` ## Basic usage ````{tab} YAML -> JSON ```console $ tmuxp convert /path/to/file.yaml ``` ```` ````{tab} JSON -> YAML ```console $ tmuxp convert /path/to/file.json ``` ```` tmuxp automatically will prompt to convert `.yaml` to `.json` and `.json` to `.yaml`. --- # tmuxp debug-info Source: https://tmuxp.git-pull.com/cli/debug-info/ (cli-debug-info)= (tmuxp-debug-info)= # tmuxp debug-info Collect and display system information useful for debugging tmuxp issues and submitting bug reports. ## Command ```{eval-rst} .. argparse:: :module: tmuxp.cli :func: create_parser :prog: tmuxp :path: debug-info ``` ## Example output ```console $ tmuxp debug-info -------------------------- environment: system: Linux arch: x86_64 ... ``` --- # tmuxp edit Source: https://tmuxp.git-pull.com/cli/edit/ (edit-config)= (cli-edit)= # tmuxp edit Open a workspace configuration file in your default editor for quick modifications. ## Command ```{eval-rst} .. argparse:: :module: tmuxp.cli :func: create_parser :prog: tmuxp :path: edit ``` --- # Exit Codes Source: https://tmuxp.git-pull.com/cli/exit-codes/ (cli-exit-codes)= # Exit Codes tmuxp uses standard exit codes for scripting and automation. | Code | Meaning | |------|---------| | `0` | Success | | `1` | General error (config validation, tmux command failure) | | `2` | Usage error (invalid arguments, missing required options) | ## Usage in Scripts ```bash #!/bin/bash tmuxp load my-workspace.yaml if [ $? -ne 0 ]; then echo "Failed to load workspace" exit 1 fi ``` ```bash #!/bin/bash tmuxp load -d my-workspace.yaml || { echo "tmuxp failed with exit code $?" exit 1 } ``` --- # tmuxp freeze Source: https://tmuxp.git-pull.com/cli/freeze/ (cli-freeze)= (cli-freeze-reference)= # tmuxp freeze Export a running tmux session to a workspace configuration file. This allows you to save the current state of your tmux session for later restoration. ## Command ```{eval-rst} .. argparse:: :module: tmuxp.cli :func: create_parser :prog: tmuxp :path: freeze ``` ## Basic usage Freeze the current session: ```console $ tmuxp freeze ``` Freeze a specific session by name: ```console $ tmuxp freeze [session_name] ``` Overwrite an existing workspace file: ```console $ tmuxp freeze --force [session_name] ``` ## Output format Tmuxp will offer to save your session state to `.json` or `.yaml`. If no session is specified, it will default to the attached session. If the `--force` argument is passed, it will overwrite any existing workspace file with the same name. --- # tmuxp import Source: https://tmuxp.git-pull.com/cli/import/ (cli-import)= # tmuxp import Import and convert workspace configurations from other tmux session managers like teamocil and tmuxinator. (import-teamocil)= ## From teamocil Import teamocil configuration files and convert them to tmuxp format. ### Command ```{eval-rst} .. argparse:: :module: tmuxp.cli :func: create_parser :prog: tmuxp :path: import teamocil ``` ### Basic usage ````{tab} YAML ```console $ tmuxp import teamocil /path/to/file.yaml ``` ```` ````{tab} JSON ```console $ tmuxp import teamocil /path/to/file.json ``` ```` (import-tmuxinator)= ## From tmuxinator Import tmuxinator configuration files and convert them to tmuxp format. ### Command ```{eval-rst} .. argparse:: :module: tmuxp.cli :func: create_parser :prog: tmuxp :path: import tmuxinator ``` ### Basic usage ````{tab} YAML ```console $ tmuxp import tmuxinator /path/to/file.yaml ``` ```` ````{tab} JSON ```console $ tmuxp import tmuxinator /path/to/file.json ``` ```` --- # CLI Reference Source: https://tmuxp.git-pull.com/cli/ (cli)= (commands)= # CLI Reference ::::{grid} 1 1 2 2 :gutter: 2 2 3 3 :::{grid-item-card} tmuxp load :link: load :link-type: doc Load tmux sessions from workspace configs. ::: :::{grid-item-card} tmuxp shell :link: shell :link-type: doc Interactive Python shell with tmux context. ::: :::{grid-item-card} tmuxp freeze :link: freeze :link-type: doc Export running sessions to config files. ::: :::{grid-item-card} tmuxp convert :link: convert :link-type: doc Convert between YAML and JSON formats. ::: :::{grid-item-card} Exit Codes :link: exit-codes :link-type: doc Exit codes for scripting and automation. ::: :::{grid-item-card} Recipes :link: recipes :link-type: doc Copy-pasteable command invocations. ::: :::: ```{toctree} :caption: General commands :maxdepth: 1 load shell ls search ``` ```{toctree} :caption: Configuration :maxdepth: 1 edit import convert freeze ``` ```{toctree} :caption: Diagnostic :maxdepth: 1 debug-info ``` ```{toctree} :caption: Completion :maxdepth: 1 completion ``` ```{toctree} :caption: Reference :maxdepth: 1 exit-codes recipes ``` (cli-main)= (tmuxp-main)= ## Main command The `tmuxp` command is the entry point for all tmuxp operations. Use subcommands to load sessions, manage configurations, and interact with tmux. ### Command ```{eval-rst} .. argparse:: :module: tmuxp.cli :func: create_parser :prog: tmuxp :nosubcommands: subparser_name : @replace See :ref:`cli-ls` ``` --- # tmuxp load Source: https://tmuxp.git-pull.com/cli/load/ (cli-load)= (tmuxp-load)= (tmuxp-load-reference)= # tmuxp load Load tmux sessions from workspace configuration files. This is the primary command for starting sessions from YAML or JSON configurations. ## Command ```{eval-rst} .. argparse:: :module: tmuxp.cli :func: create_parser :prog: tmuxp :path: load ``` ## Basic usage You can load your tmuxp file and attach the tmux session via a few shorthands: 1. The directory with a `.tmuxp.{yaml,yml,json}` file in it 2. The name of the project file in your `$HOME/.tmuxp` folder 3. The direct path of the tmuxp file you want to load Path to folder with `.tmuxp.yaml`, `.tmuxp.yml`, `.tmuxp.json`: ````{tab} Project based Projects with a file named `.tmuxp.yaml` or `.tmuxp.json` can be loaded: ```console // current directory $ tmuxp load . ``` ```console $ tmuxp load ../ ``` ```console $ tmuxp load path/to/folder/ ``` ```console $ tmuxp load /path/to/folder/ ``` ```` ````{tab} User based Name of the config, assume `$HOME/.tmuxp/myconfig.yaml`: ```console $ tmuxp load myconfig ``` Direct path to json/yaml file: ```console $ tmuxp load ./myfile.yaml ``` ```console $ tmuxp load /abs/path/to/myfile.yaml ``` ```console $ tmuxp load ~/myfile.yaml ``` ```` ````{tab} Direct Absolute and relative directory paths are supported. ```console $ tmuxp load [filename] ``` ```` ## Inside sessions If you try to load a workspace file from within a tmux session, it will ask you if you want to load and attach to the new session, or just load detached. You can also load a workspace file and append the windows to the current active session. ``` Already inside TMUX, switch to session? yes/no Or (a)ppend windows in the current active session? [y/n/a]: ``` ## Options All of these options can be preselected to skip the prompt: - Attach / open the client after load: ```console $ tmuxp load -y config ``` - Detached / open in background: ```console $ tmuxp load -d config ``` - Append windows to existing session ```console $ tmuxp load -a config ``` ## Loading multiple sessions Multiple sessions can be loaded at once. The first ones will be created without being attached. The last one will be attached if there is no `-d` flag on the command line. ```console $ tmuxp load [filename1] [filename2] ... ``` ## Custom session name A session name can be provided at the terminal. If multiple sessions are created, the last session is named from the terminal. ```console $ tmuxp load -s [new_session_name] [filename1] ... ``` ## Logging The output of the `load` command can be logged to a file for debugging purposes. the log level can be controlled with the global `--log-level` option (defaults to INFO). ```console $ tmuxp load [filename] --log-file [log_filename] ``` ```console $ tmuxp --log-level [LEVEL] load [filename] --log-file [log_filename] ``` ## Progress display When loading a workspace, tmuxp shows an animated spinner with build progress. The spinner updates as windows and panes are created, giving real-time feedback during session builds. ### Presets Five built-in presets control the spinner format: | Preset | Format | |--------|--------| | `default` | `Loading workspace: {session} {bar} {progress} {window}` | | `minimal` | `Loading workspace: {session} [{window_progress}]` | | `window` | `Loading workspace: {session} {window_bar} {window_progress_rel}` | | `pane` | `Loading workspace: {session} {pane_bar} {session_pane_progress}` | | `verbose` | `Loading workspace: {session} [window {window_index} of {window_total} · pane {pane_index} of {pane_total}] {window}` | Select a preset with `--progress-format`: ```console $ tmuxp load --progress-format minimal myproject ``` Or via environment variable: ```console $ TMUXP_PROGRESS_FORMAT=verbose tmuxp load myproject ``` ### Custom format tokens Use a custom format string with any of the available tokens: | Token | Description | |-------|-------------| | `{session}` | Session name | | `{window}` | Current window name | | `{window_index}` | Current window number (1-based) | | `{window_total}` | Total number of windows | | `{window_progress}` | Window fraction (e.g. `1/3`) | | `{window_progress_rel}` | Completed windows fraction (e.g. `1/3`) | | `{windows_done}` | Number of completed windows | | `{windows_remaining}` | Number of remaining windows | | `{pane_index}` | Current pane number in the window | | `{pane_total}` | Total panes in the current window | | `{pane_progress}` | Pane fraction (e.g. `2/4`) | | `{progress}` | Combined progress (e.g. `1/3 win · 2/4 pane`) | | `{session_pane_progress}` | Panes completed across the session (e.g. `5/10`) | | `{overall_percent}` | Pane-based completion percentage (0–100) | | `{bar}` | Composite progress bar | | `{pane_bar}` | Pane-based progress bar | | `{window_bar}` | Window-based progress bar | | `{status_icon}` | Status icon (⏸ during before_script) | Example: ```console $ tmuxp load --progress-format "{session} {bar} {overall_percent}%" myproject ``` ### Panel lines The spinner shows script output in a panel below the spinner line. Control the panel height with `--progress-lines`: Hide the panel entirely (script output goes to stdout): ```console $ tmuxp load --progress-lines 0 myproject ``` Show unlimited lines (capped to terminal height): ```console $ tmuxp load --progress-lines -1 myproject ``` Set a custom height (default is 3): ```console $ tmuxp load --progress-lines 5 myproject ``` ### Disabling progress Disable the animated spinner entirely: ```console $ tmuxp load --no-progress myproject ``` Or via environment variable: ```console $ TMUXP_PROGRESS=0 tmuxp load myproject ``` When progress is disabled, logging flows normally to the terminal and no spinner is rendered. ### Before-script behavior During `before_script` execution, the progress bar shows a marching animation and a ⏸ status icon, indicating that tmuxp is waiting for the script to finish before continuing with pane creation. --- # tmuxp ls Source: https://tmuxp.git-pull.com/cli/ls/ (cli-ls)= (ls-config)= # tmuxp ls List available workspace configurations from your local project and global tmuxp directories. ## Command ```{eval-rst} .. argparse:: :module: tmuxp.cli :func: create_parser :prog: tmuxp :path: ls ``` --- # Recipes Source: https://tmuxp.git-pull.com/cli/recipes/ (cli-recipes)= # Recipes Copy-pasteable command invocations for common tasks. ## Load a workspace ```console $ tmuxp load my-workspace.yaml ``` ## Load in detached mode ```console $ tmuxp load -d my-workspace.yaml ``` ## Load from a project directory ```console $ tmuxp load . ``` ## Freeze a running session ```console $ tmuxp freeze my-session ``` ## Convert YAML to JSON ```console $ tmuxp convert my-workspace.yaml ``` ## Convert JSON to YAML ```console $ tmuxp convert my-workspace.json ``` ## List available workspaces ```console $ tmuxp ls ``` ## Search workspaces ```console $ tmuxp search my-project ``` ## Edit a workspace config ```console $ tmuxp edit my-workspace ``` ## Collect debug info ```console $ tmuxp debug-info ``` ## Shell with tmux context ```console $ tmuxp shell ``` Access libtmux objects directly: ```console $ tmuxp shell --best --command 'print(server.sessions)' ``` --- # tmuxp search Source: https://tmuxp.git-pull.com/cli/search/ (cli-search)= (search-config)= # tmuxp search Search for workspace configurations by name or content across your tmuxp directories. ## Command ```{eval-rst} .. argparse:: :module: tmuxp.cli :func: create_parser :prog: tmuxp :path: search ``` --- # tmuxp shell Source: https://tmuxp.git-pull.com/cli/shell/ (cli-shell)= (tmuxp-shell)= # tmuxp shell Launch an interactive Python shell with [libtmux] objects pre-loaded. Similar to Django's shell command, this provides quick access to your tmux server, sessions, windows, and panes for scripting and debugging. ## Command ```{eval-rst} .. argparse:: :module: tmuxp.cli :func: create_parser :prog: tmuxp :path: shell ``` ## Directly enter commands ```console $ tmuxp shell -c 'python code' ``` ```{image} ../_static/tmuxp-shell.gif :width: 878 :height: 109 :loading: lazy ``` ## Interactive usage Launch into a Python console with [libtmux] objects. Compare to django's shell. Automatically preloads current tmux {class}`server `, {class}`session `, {class}`window ` {class}`pane `. Pass additional arguments to select a specific one of your choice: ```console (Pdb) server (Pdb) server.sessions [Session($1 your_project)] (Pdb) session Session($1 your_project) (Pdb) session.name 'your_project' (Pdb) window Window(@3 1:your_window, Session($1 your_project)) (Pdb) window.name 'your_window' (Pdb) window.panes [Pane(%6 Window(@3 1:your_window, Session($1 your_project))) (Pdb) pane Pane(%6 Window(@3 1:your_window, Session($1 your_project))) ``` ## Debugger integration Supports [PEP 553][pep 553]'s `PYTHONBREAKPOINT` and compatible debuggers, for instance [ipdb][ipdb]: ```console $ pip install --user ipdb ``` Inside a [uv](https://docs.astral.sh/uv/getting-started/features/#python-versions)-managed project you can add `ipdb` as a development dependency: ```console $ uv add --dev ipdb ``` For a pipx-style ad hoc install, run it through [uvx](https://docs.astral.sh/uv/guides/tools/): ```console $ uvx --from ipdb ipdb3 --help ``` ```console $ env PYTHONBREAKPOINT=ipdb.set_trace tmuxp shell ``` ## Code execution You can also pass in python code directly, similar to `python -c`, do this via `tmuxp -c`: ```console $ tmuxp shell -c 'print(session.name); print(window.name)' my_server my_window ``` ```console $ tmuxp shell my_server -c 'print(session.name); print(window.name)' my_server my_window ``` ```console $ tmuxp shell my_server my_window -c 'print(session.name); print(window.name)' my_server my_window ``` ```console $ tmuxp shell my_server my_window -c 'print(window.name.upper())' MY_WINDOW ``` Assuming inside a tmux pane or one is attached on default server: ```console $ tmuxp shell -c 'print(pane.id); print(pane.window.name)' %2 my_window ``` [pep 553]: https://www.python.org/dev/peps/pep-0553/ [ipdb]: https://pypi.org/project/ipdb/ [libtmux]: https://libtmux.git-pull.com ## Shell detection `tmuxp shell` detects the richest shell available in your _site packages_, you can also pick your shell via args: - `--pdb`: Use plain old `breakpoint()` (python 3.7+) or `pdb.set_trace` - `--code`: Drop into `code.interact`, accepts `--use-pythonrc` - `--bpython`: Drop into bpython - `--ipython`: Drop into ipython - `--ptpython`: Drop into ptpython, accepts `--use-vi-mode` - `--ptipython`: Drop into ipython + ptpython, accepts `--use-vi-mode` --- # Environmental variables Source: https://tmuxp.git-pull.com/configuration/environmental-variables/ (environmental-variables)= # Environmental variables (TMUXP_CONFIGDIR)= ## `TMUXP_CONFIGDIR` Example: `TMUXP_CONFIGDIR=$HOME/.mytmuxpconfigdir tmuxp load cpython` (LIBTMUX_TMUX_FORMAT_SEPARATOR)= ## `LIBTMUX_TMUX_FORMAT_SEPARATOR` :::{seealso} [`LIBTMUX_TMUX_FORMAT_SEPARATOR`](https://libtmux.git-pull.com/api.html#tmux-format-separator) in libtmux API. ::: In rare circumstances the `tmux -F` separator under the hood may cause issues building sessions. For this case you can override it here. ```console $ env LIBTMUX_TMUX_FORMAT_SEPARATOR='__SEP__' tmuxp load [session] ``` (TMUXP_PROGRESS)= ## `TMUXP_PROGRESS` Master on/off switch for the animated progress spinner during `tmuxp load`. Defaults to `1` (enabled). Set to `0` to disable: ```console $ TMUXP_PROGRESS=0 tmuxp load myproject ``` Equivalent to the `--no-progress` CLI flag. (TMUXP_PROGRESS_FORMAT)= ## `TMUXP_PROGRESS_FORMAT` Set the spinner line format. Accepts a preset name (`default`, `minimal`, `window`, `pane`, `verbose`) or a custom format string with tokens like `{session}`, `{bar}`, `{progress}`: ```console $ TMUXP_PROGRESS_FORMAT=minimal tmuxp load myproject ``` Custom format example: ```console $ TMUXP_PROGRESS_FORMAT="{session} {bar} {overall_percent}%" tmuxp load myproject ``` Equivalent to the `--progress-format` CLI flag. (TMUXP_PROGRESS_LINES)= ## `TMUXP_PROGRESS_LINES` Number of script-output lines shown in the spinner panel. Defaults to `3`. Set to `0` to hide the panel entirely (script output goes to stdout): ```console $ TMUXP_PROGRESS_LINES=0 tmuxp load myproject ``` Set to `-1` for unlimited lines (capped to terminal height): ```console $ TMUXP_PROGRESS_LINES=-1 tmuxp load myproject ``` Equivalent to the `--progress-lines` CLI flag. --- # Examples Source: https://tmuxp.git-pull.com/configuration/examples/ (examples)= # Examples ## Short hand / inline style tmuxp has a short-hand syntax for those who wish to keep their workspace punctual. ::::{sidebar} short hand ```{eval-rst} .. aafig:: :textual: +-------------------+ | 'did you know' | | 'you can inline' | +-------------------+ | 'single commands' | | | +-------------------+ | 'for panes' | | | +-------------------+ ``` :::: ````{tab} YAML ```{literalinclude} ../../examples/shorthands.yaml :language: yaml ``` ```` ````{tab} JSON ```{literalinclude} ../../examples/shorthands.json :language: json ``` ```` ## Blank panes No need to repeat `pwd` or a dummy command. A `null`, `'blank'`, `'pane'` are valid. Note `''` counts as an empty carriage return. ````{tab} YAML ```{literalinclude} ../../examples/blank-panes.yaml :language: yaml ``` ```` ````{tab} JSON ```{literalinclude} ../../examples/blank-panes.json :language: json ``` ```` ## 2 panes ::::{sidebar} 2 pane ```{eval-rst} .. aafig:: +-----------------+ | $ pwd | | | | | +-----------------+ | $ pwd | | | | | +-----------------+ ``` :::: ````{tab} YAML ```{literalinclude} ../../examples/2-pane-vertical.yaml :language: yaml ``` ```` ````{tab} JSON ```{literalinclude} ../../examples/2-pane-vertical.json :language: json ``` ```` ## 3 panes ::::{sidebar} 3 panes ```{eval-rst} .. aafig:: +-----------------+ | $ pwd | | | | | +--------+--------+ | $ pwd | $ pwd | | | | | | | +--------+--------+ ``` :::: ````{tab} YAML ```{literalinclude} ../../examples/3-pane.yaml :language: yaml ``` ```` ````{tab} JSON ```{literalinclude} ../../examples/3-pane.json :language: json ``` ```` ## 4 panes ::::{sidebar} 4 panes ```{eval-rst} .. aafig:: +--------+--------+ | $ pwd | $ pwd | | | | | | | +--------+--------+ | $ pwd | $ pwd | | | | | | | +--------+--------+ ``` :::: ````{tab} YAML ```{literalinclude} ../../examples/4-pane.yaml :language: yaml ``` ```` ````{tab} JSON ```{literalinclude} ../../examples/4-pane.json :language: json ``` ```` ## Start Directory Equivalent to `tmux new-window -c `. ````{tab} YAML ```{literalinclude} ../../examples/start-directory.yaml :language: yaml ``` ```` ````{tab} JSON ```{literalinclude} ../../examples/start-directory.json :language: json ``` ```` ## Environment variable replacing tmuxp will replace environment variables wrapped in curly brackets for values of these settings: - `start_directory` - `before_script` - `session_name` - `window_name` - `shell_command_before` - `global_options` - `options` in session scope and window scope tmuxp replaces these variables before-hand with variables in the terminal `tmuxp` invokes in. In this case of this example, assuming the username "user": ```console $ MY_ENV_VAR=foo tmuxp load examples/env-variables.yaml ``` and your session name will be `session - user (foo)`. Shell variables in `shell_command` do not support this type of concatenation. `shell_command` and `shell_command_before` both support normal shell variables, since they are sent into panes automatically via `send-key` in `tmux(1)`. See `ls $PWD` in example. If you have a special case and would like to see behavior changed, please make a ticket on the [issue tracker][issue tracker]. [issue tracker]: https://github.com/tmux-python/tmuxp/issues ````{tab} YAML ```{literalinclude} ../../examples/env-variables.yaml :language: yaml ``` ```` ````{tab} JSON ```{literalinclude} ../../examples/env-variables.json :language: json ``` ```` ## Environment variables tmuxp will set session, window and pane environment variables. ```{note} Setting environment variables for windows and panes requires tmuxp 1.19 or newer. ``` ````{tab} YAML ```{literalinclude} ../../examples/session-environment.yaml :language: yaml ``` ```` ````{tab} JSON ```{literalinclude} ../../examples/session-environment.json :language: json ``` ```` ## Focusing tmuxp allows `focus: true` for assuring windows and panes are attached / selected upon loading. ````{tab} YAML ```{literalinclude} ../../examples/focus-window-and-panes.yaml :language: yaml ``` ```` ````{tab} JSON ```{literalinclude} ../../examples/focus-window-and-panes.json :language: json ``` ```` ## Terminal History tmuxp allows `suppress_history: false` to override the default command / suppression when building the workspace. This will add the `shell_command` to the shell history in the pane. The suppression of the `shell_command` commands from the shell's history occurs by prefixing the commands with a space when `suppress_history: true`. Accordingly, this functionality depends on the shell being appropriately configured: bash requires the shell variable `HISTCONTROL` to be set and include either of the values `ignorespace` or `ignoreboth` (to also ignore sequential duplicate commands), and zsh requires `setopt HIST_IGNORE_SPACE`. ````{tab} YAML ```{literalinclude} ../../examples/suppress-history.yaml :language: yaml ``` ```` ````{tab} JSON ```{literalinclude} ../../examples/suppress-history.json :language: json ``` ```` (enter)= ## Skip command execution See more at {ref}`enter`. :::{note} _Experimental setting_: behavior and api is subject to change until stable. ::: ```{versionadded} 1.10.0 `enter: false` option. Pane-level support. ``` Omit sending {kbd}`enter` to key commands. Equivalent to [`send_keys(enter=False)`](libtmux.Pane.send_keys). ````{tab} YAML ```{literalinclude} ../../examples/skip-send.yaml :language: yaml ``` ```` ````{tab} JSON ```{literalinclude} ../../examples/skip-send.json :language: json ``` ```` ````{tab} YAML (pane-level) ```{literalinclude} ../../examples/skip-send-pane-level.yaml :language: yaml ``` ```` ````{tab} JSON (pane-level) ```{literalinclude} ../../examples/skip-send-pane-level.json :language: json ``` ```` (sleep)= ## Pausing commands :::{note} _Experimental setting_: behavior and api is subject to change until stable. ::: ```{versionadded} 1.10.0 `sleep_before` and `sleep_after` options added. Pane and command-level support. ``` ```{warning} **Blocking.** This will delay loading as it runs synchronously for each pane as [`asyncio`](asyncio)) is not implemented yet. ``` Omit sending {kbd}`enter` to key commands. Equivalent to having a [`time.sleep`](time.sleep) before and after [`send_keys`](libtmux.Pane.send_keys). This is especially useful for expensive commands where the terminal needs some breathing room (virtualenv, poetry, pipenv, uv, sourcing a configuration, launching a tui app, etc). ````{tab} Virtualenv ```{literalinclude} ../../examples/sleep-virtualenv.yaml :language: yaml ``` ```` ````{tab} YAML ```{literalinclude} ../../examples/sleep.yaml :language: yaml ``` ```` ````{tab} JSON ```{literalinclude} ../../examples/sleep.json :language: json ``` ```` ````{tab} YAML (pane-level) ```{literalinclude} ../../examples/sleep-pane-level.yaml :language: yaml ``` ```` ````{tab} JSON (pane-level) ```{literalinclude} ../../examples/sleep-pane-level.json :language: json ``` ```` ## Window Index You can specify a window's index using the `window_index` property. Windows without `window_index` will use the lowest available window index. ````{tab} YAML ```{literalinclude} ../../examples/window-index.yaml :language: yaml ``` ```` ````{tab} JSON ```{literalinclude} ../../examples/window-index.json :language: json ``` ```` ## Shell per pane Every pane can have its own shell or application started. This allows for usage of the `remain-on-exit` setting to be used properly, but also to have different shells on different panes. ````{tab} YAML ```{literalinclude} ../../examples/pane-shell.yaml :language: yaml ``` ```` ````{tab} JSON ```{literalinclude} ../../examples/pane-shell.json :language: json ``` ```` ## Set tmux options Works with global (server-wide) options, session options and window options. Including `automatic-rename`, `default-shell`, `default-command`, etc. ````{tab} YAML ```{literalinclude} ../../examples/options.yaml :language: yaml ``` ```` ````{tab} JSON ```{literalinclude} ../../examples/options.json :language: json ``` ```` ## Set window options after pane creation Apply window options after panes have been created. Useful for `synchronize-panes` option after executing individual commands in each pane during creation. ````{tab} YAML ```{literalinclude} ../../examples/2-pane-synchronized.yaml :language: yaml ``` ```` ````{tab} JSON ```{literalinclude} ../../examples/2-pane-synchronized.json :language: json ``` ```` ## Main pane height ### Percentage :::{versionadded} 1.46.0 Before this, tmuxp layouts would not detect the terminal's size. ::: ````{tab} YAML ```{literalinclude} ../../examples/main-pane-height-percentage.yaml :language: yaml ``` ```` ````{tab} JSON ```{literalinclude} ../../examples/main-pane-height-percentage.json :language: json ``` ```` ### Rows ````{tab} YAML ```{literalinclude} ../../examples/main-pane-height.yaml :language: yaml ``` ```` ````{tab} JSON ```{literalinclude} ../../examples/main-pane-height.json :language: json ``` ```` ## Super-advanced dev environment :::{seealso} {ref}`tmuxp-developer-config` in the {ref}`developing` section. ::: ````{tab} YAML ```{literalinclude} ../../.tmuxp.yaml :language: yaml ``` ```` ````{tab} JSON ```{literalinclude} ../../.tmuxp.json :language: json ``` ```` ## Multi-line commands You can use YAML's multiline syntax to easily split multiple commands into the same shell command: https://stackoverflow.com/a/21699210 ````{tab} YAML ```yaml session_name: my project shell_command_before: - > [ -d `.venv/bin/activate` ] && source .venv/bin/activate && reset - sleep 1 windows: - window_name: first window layout: main-horizontal focus: true panes: - focus: True - blank - > uv run ./manage.py migrate && npm -C js run start - uv run ./manage.py runserver options: main-pane-height: 35 ``` ```` ## Bootstrap project before launch You can use `before_script` to run a script before the tmux session starts building. This can be used to start a script to create a virtualenv or download a virtualenv/rbenv/package.json's dependency files before tmuxp even begins building the session. It works by using the [Exit Status][exit status] code returned by a script. Your script can be any type, including bash, python, ruby, etc. A successful script will exit with a status of `0`. Important: the script file must be chmod executable `+x` or `755`. Run a python script (and check for it's return code), the script is _relative to the `.tmuxp.yaml`'s root_ (Windows and panes omitted in this example): ````{tab} YAML ```yaml session_name: my session before_script: ./bootstrap.py # ... the rest of your workspace ``` ```` ````{tab} JSON ```json { "session_name": "my session", "before_script": "./bootstrap.py" } ``` ```` Run a shell script + check for return code on an absolute path. (Windows and panes omitted in this example) ````{tab} YAML ```yaml session_name: another example before_script: /absolute/path/this.sh # abs path to shell script # ... the rest of your workspace ``` ```` ````{tab} JSON ```json { "session_name": "my session", "before_script": "/absolute/path/this.sh" } ``` ```` [exit status]: http://tldp.org/LDP/abs/html/exit-status.html ## Per-project tmuxp workspaces You can load your software project in tmux by placing a `.tmuxp.yaml` or `.tmuxp.json` in the project's workspace and loading it. tmuxp supports loading workspace via absolute filename with `tmuxp load` and via `$ tmuxp load .` if workspace is in the directory. ```console $ tmuxp load ~/workspaces/myproject.yaml ``` See examples of `tmuxp` in the wild. Have a project workspace to show off? Edit this page. - - - You can use `start_directory: ./` to make the directories relative to the workspace file / project root. ## Bonus: pipenv auto-bootstrapping :::{versionadded} 1.3.4 `before_script` CWD's into the root (session)-level `start_directory`. ::: If you use [pipenv] / [poetry] / [uv], you can use a script like this to ensure your packages are installed: ````{tab} YAML ```yaml # assuming your .tmuxp.yaml is in your project root directory session_name: my pipenv project start_directory: ./ before_script: pipenv install --dev --skip-lock # ensure dev deps install windows: - window_name: django project focus: true panes: - blank - pipenv run ./manage.py runserver ``` ```` You can also source yourself into the virtual environment using `shell_command_before`: ````{tab} YAML ```yaml # assuming your .tmuxp.yaml is in your project root directory session_name: my pipenv project start_directory: ./ before_script: pipenv install --dev --skip-lock # ensure dev deps install shell_command_before: - '[ -d `pipenv --venv` ] && source `pipenv --venv`/bin/activate && reset' windows: - window_name: django project focus: true panes: - blank - ./manage.py runserver ``` ```` [pipenv]: https://docs.pipenv.org/ [poetry]: https://python-poetry.org/ [uv]: https://github.com/astral-sh/uv ## Kung fu :::{note} tmuxp sessions can be scripted in python. The first way is to use the ORM in the {ref}`API`. The second is to pass a {py:obj}`dict` into {class}`~tmuxp.workspace.builder.WorkspaceBuilder` with a correct schema. See: {meth}`tmuxp.validation.validate_schema`. ::: Add yours? Submit a pull request to the [github][github] site! [github]: https://github.com/tmux-python/tmuxp --- # Workspace files Source: https://tmuxp.git-pull.com/configuration/ (config)= (configuration)= (workspace)= # Workspace files ::::{grid} 1 2 3 3 :gutter: 2 2 3 3 :::{grid-item-card} Top-level Options :link: top-level :link-type: doc Session and window configuration keys. ::: :::{grid-item-card} Environment Variables :link: environmental-variables :link-type: doc TMUXP_CONFIGDIR and other env vars. ::: :::{grid-item-card} Examples :link: examples :link-type: doc Sample workspace configurations. ::: :::: tmuxp loads your terminal workspace into tmux using workspace files. The workspace file can be JSON or YAML. It's declarative style resembles tmux's object hierarchy: session, window and panes. ## Launching your session Once you have `tmuxp` installed alongside tmux, you can load a workspace with: ```console $ tmuxp load ./path/to/file ``` tmuxp will offer to assist when: - _Session already exists_: tmuxp will prompt you to re-attach. It does this by checking if the workspace's `session_name` matches a session already running on the same server. - _When inside a tmux client_, `tmuxp` will let you create a new session and switch to it, or append the windows to your existing session. ## What's in a workspace file? 1. A session name 2. A list of _windows_ 3. A list of _panes_ for each window 4. A list of _commands_ for each pane ````{tab} Basics ```yaml session_name: My session windows: - window_name: Window 1 panes: - shell_command: - cmd: echo "pane 1" - shell_command: - cmd: echo "pane 2" ``` ```` ````{tab} Smallest possible ```{literalinclude} ../../examples/minimal.yaml :language: yaml ``` As of 1.11.x. ```` Breaking down the basic workspace into sections: 1. A session name ```yaml session_name: My session ``` 2. A list of _windows_ ```yaml windows: - window_name: Window 1 panes: ... # window settings - window_name: Window 2 panes: ... # window settings ``` 3. A list of _panes_ for each window ```yaml windows: panes: - # pane settings - # pane settings ``` 4. A list of _commands_ for each pane ```yaml windows: panes: - shell_command: - cmd: echo "pane 1 - cmd 1" # command options - cmd: echo "pane 1 - cmd 2" # command options ``` ## Where do I store workspace files? ### Direct You can create a workspace and load it from anywhere in your file system. ```console $ tmuxp load [workspace-file] ``` ````{tab} Relative ```console $ tmuxp load ./favorites.yaml ``` ```` ````{tab} Absolute ```console $ tmuxp load /opt/myapp/favorites.yaml ``` ```` ### User-based workspaces tmuxp uses the [XDG Base Directory] specification. Often on POSIX machines, you will store them in `~/.config/tmuxp`. Assume you store `apple.yaml` in `$XDG_CONFIG_HOME/tmuxp/apple.yaml`, you can then use: ```console $ tmuxp load apple ``` :::{seealso} This path can be overridden by {ref}`TMUXP_CONFIGDIR` ::: [xdg base directory]: https://specifications.freedesktop.org/basedir-spec/latest/ ### Project-specific You can store a workspace in your project's root directory as `.tmuxp.yaml` or `.tmuxp.json`, then: Assume `.tmuxp.yaml` inside `/opt/myapp` ```console $ tmuxp load [workspace-file] ``` ````{tab} In project root ```console $ tmuxp load ./ ``` ```` ````{tab} Absolute ```console $ tmuxp load /opt/myapp ``` ```` ## Reference and usage ::::{grid} 1 2 3 3 :gutter: 2 2 3 3 :::{grid-item-card} Top-level Options :link: top-level :link-type: doc Session and window configuration keys. ::: :::{grid-item-card} Environment Variables :link: environmental-variables :link-type: doc TMUXP_CONFIGDIR and other env vars. ::: :::{grid-item-card} Examples :link: examples :link-type: doc Sample workspace configurations. ::: :::: ```{toctree} :hidden: top-level environmental-variables examples ``` --- # Top-level configuration Source: https://tmuxp.git-pull.com/configuration/top-level/ (top-level)= (top-level-config)= # Top-level configuration ## `session_name` Used for: - tmux session name - checking for existing sessions Notes: - Session names may differ from workspace filename. e.g. _apple.yaml_: ```yaml session_name: banana windows: - panes: - ``` Load detached: ```console $ tmuxp load ./apple.yaml -d ``` Above: - tmuxp loads a file named _apple.yaml_ from the current directory. - tmuxp built a tmux session called _banana_. - `-d` means _detached_, loading in background. ```console $ tmux attach -t banana ``` Above: Use `tmux` directly to attach _banana_. --- # Glossary Source: https://tmuxp.git-pull.com/glossary/ (glossary)= # Glossary ```{glossary} tmuxp A tool to manage workspaces with tmux. A pythonic abstraction of tmux. tmux tmux(1) The tmux binary. Used internally to distinguish tmuxp is only a layer on top of tmux. ConfigReader configuration management class, for parsing YAML / JSON / etc. files to and from python data (dictionaries, in the future, potentially dataclasses) Server Tmux runs in the background of your system as a process. The server holds multiple {term}`Session`. By default, tmux automatically starts the server the first time ``$ tmux`` is ran. A server contains {term}`session`'s. tmux starts the server automatically if it's not running. Advanced cases: multiple can be run by specifying ``[-L socket-name]`` and ``[-S socket-path]``. Client Attaches to a tmux {term}`server`. When you use tmux through CLI, you are using tmux as a client. Session Inside a tmux {term}`server`. The session has 1 or more {term}`Window`. The bottom bar in tmux show a list of windows. Normally they can be navigated with ``Ctrl-a [0-9]``, ``Ctrl-a n`` and ``Ctrl-a p``. Sessions can have a ``session_name``. Uniquely identified by ``session_id``. Window Entity of a {term}`session`. Can have 1 or more {term}`pane`. Panes can be organized with a layouts. Windows can have names. Pane Linked to a {term}`Window`. a pseudoterminal. Target A target, cited in the manual as ``[-t target]`` can be a session, window or pane. ``` --- # Changelog Source: https://tmuxp.git-pull.com/history/ (changelog)= (history)= ```{include} ../CHANGES ``` --- # tmuxp Source: https://tmuxp.git-pull.com/ (index)= # tmuxp Session manager for tmux. Load, freeze, and convert tmux sessions through YAML/JSON configuration files. Powered by [libtmux](https://libtmux.git-pull.com/). ::::{grid} 1 2 3 3 :gutter: 2 2 3 3 :::{grid-item-card} Quickstart :link: quickstart :link-type: doc Install and run your first command. ::: :::{grid-item-card} CLI Reference :link: cli/index :link-type: doc Every command, flag, and option. ::: :::{grid-item-card} Configuration :link: configuration/index :link-type: doc Config format, examples, and environment variables. ::: :::: ::::{grid} 1 1 2 2 :gutter: 2 2 3 3 :::{grid-item-card} Topics :link: topics/index :link-type: doc Workflows, plugins, and troubleshooting. ::: :::{grid-item-card} Contributing :link: project/index :link-type: doc Internals, development setup, and release process. ::: :::: ## Install ```console $ pip install tmuxp ``` ```console $ uv tool install tmuxp ``` ```console $ brew install tmuxp ``` See [Quickstart](quickstart.md) for all installation methods and first steps. ## Load a workspace ```yaml session_name: my-project windows: - window_name: editor panes: - shell_command: - vim - shell_command: - git status ``` ```console $ tmuxp load my-project.yaml ``` ```{image} _static/tmuxp-demo.gif :width: 888 :height: 589 :loading: lazy ``` ```{toctree} :hidden: quickstart cli/index configuration/index topics/index internals/index project/index history ``` ```{toctree} :hidden: :caption: More about_tmux migration glossary MCP GitHub ``` --- # Colors - tmuxp._internal.colors Source: https://tmuxp.git-pull.com/internals/api/_internal/colors/ # Colors - `tmuxp._internal.colors` :::{warning} Be careful with these! Internal APIs are **not** covered by version policies. They can break or be removed between minor versions! If you need an internal API stabilized please [file an issue](https://github.com/tmux-python/tmuxp/issues). ::: ```{eval-rst} .. automodule:: tmuxp._internal.colors :members: :show-inheritance: :undoc-members: ``` --- # Config reader - tmuxp._internal.config_reader Source: https://tmuxp.git-pull.com/internals/api/_internal/config_reader/ # Config reader - `tmuxp._internal.config_reader` :::{warning} Be careful with these! Internal APIs are **not** covered by version policies. They can break or be removed between minor versions! If you need an internal API stabilized please [file an issue](https://github.com/tmux-python/tmuxp/issues). ::: ```{eval-rst} .. automodule:: tmuxp._internal.config_reader :members: :show-inheritance: :undoc-members: ``` --- # Internal Modules Source: https://tmuxp.git-pull.com/internals/api/_internal/ (api-internal)= # Internal Modules :::{warning} Be careful with these! Internal APIs are **not** covered by version policies. They can break or be removed between minor versions! If you need an internal API stabilized please [file an issue](https://github.com/tmux-python/tmuxp/issues). ::: ```{toctree} colors config_reader private_path types ``` --- # Private path - tmuxp._internal.private_path Source: https://tmuxp.git-pull.com/internals/api/_internal/private_path/ # Private path - `tmuxp._internal.private_path` :::{warning} Be careful with these! Internal APIs are **not** covered by version policies. They can break or be removed between minor versions! If you need an internal API stabilized please [file an issue](https://github.com/tmux-python/tmuxp/issues). ::: ```{eval-rst} .. automodule:: tmuxp._internal.private_path :members: :show-inheritance: :undoc-members: ``` --- # Typings - tmuxp._internal.types Source: https://tmuxp.git-pull.com/internals/api/_internal/types/ # Typings - `tmuxp._internal.types` ```{eval-rst} .. automodule:: tmuxp._internal.types :members: :show-inheritance: :undoc-members: ``` --- # tmuxp convert - tmuxp.cli.convert Source: https://tmuxp.git-pull.com/internals/api/cli/convert/ # tmuxp convert - `tmuxp.cli.convert` ```{eval-rst} .. automodule:: tmuxp.cli.convert :members: :show-inheritance: :undoc-members: ``` --- # tmuxp debug-info - tmuxp.cli.debug_info Source: https://tmuxp.git-pull.com/internals/api/cli/debug_info/ # tmuxp debug-info - `tmuxp.cli.debug_info` ```{eval-rst} .. automodule:: tmuxp.cli.debug_info :members: :show-inheritance: :undoc-members: ``` --- # tmuxp edit - tmuxp.cli.edit Source: https://tmuxp.git-pull.com/internals/api/cli/edit/ # tmuxp edit - `tmuxp.cli.edit` ```{eval-rst} .. automodule:: tmuxp.cli.edit :members: :show-inheritance: :undoc-members: ``` --- # tmuxp freeze - tmuxp.cli.freeze Source: https://tmuxp.git-pull.com/internals/api/cli/freeze/ # tmuxp freeze - `tmuxp.cli.freeze` ```{eval-rst} .. automodule:: tmuxp.cli.freeze :members: :show-inheritance: :undoc-members: ``` --- # tmuxp import - tmuxp.cli.import_config Source: https://tmuxp.git-pull.com/internals/api/cli/import_config/ # tmuxp import - `tmuxp.cli.import_config` ```{eval-rst} .. automodule:: tmuxp.cli.import_config :members: :show-inheritance: :undoc-members: ``` --- # CLI Source: https://tmuxp.git-pull.com/internals/api/cli/ (api_cli)= # CLI :::{warning} Be careful with these! Internal APIs are **not** covered by version policies. They can break or be removed between minor versions! If you need an internal API stabilized please [file an issue](https://github.com/tmux-python/tmuxp/issues). ::: ```{toctree} convert debug_info edit freeze import_config load ls progress search shell utils ``` ## `tmuxp.cli` ```{eval-rst} .. automodule:: tmuxp.cli :members: :show-inheritance: :undoc-members: ``` --- # tmuxp load - tmuxp.cli.load Source: https://tmuxp.git-pull.com/internals/api/cli/load/ # tmuxp load - `tmuxp.cli.load` ```{eval-rst} .. automodule:: tmuxp.cli.load :members: :show-inheritance: :undoc-members: ``` --- # tmuxp ls - tmuxp.cli.ls Source: https://tmuxp.git-pull.com/internals/api/cli/ls/ # tmuxp ls - `tmuxp.cli.ls` ```{eval-rst} .. automodule:: tmuxp.cli.ls :members: :show-inheritance: :undoc-members: ``` --- # tmuxp progress - tmuxp.cli._progress Source: https://tmuxp.git-pull.com/internals/api/cli/progress/ # tmuxp progress - `tmuxp.cli._progress` ```{eval-rst} .. automodule:: tmuxp.cli._progress :members: :show-inheritance: :undoc-members: ``` --- # tmuxp search - tmuxp.cli.search Source: https://tmuxp.git-pull.com/internals/api/cli/search/ # tmuxp search - `tmuxp.cli.search` ```{eval-rst} .. automodule:: tmuxp.cli.search :members: :show-inheritance: :undoc-members: ``` --- # tmuxp shell - tmuxp.cli.shell Source: https://tmuxp.git-pull.com/internals/api/cli/shell/ # tmuxp shell - `tmuxp.cli.shell` ```{eval-rst} .. automodule:: tmuxp.cli.shell :members: :show-inheritance: :undoc-members: ``` --- # CLI utilities - tmuxp.cli.utils Source: https://tmuxp.git-pull.com/internals/api/cli/utils/ # CLI utilities - `tmuxp.cli.utils` ```{eval-rst} .. automodule:: tmuxp.cli.utils :members: :show-inheritance: :undoc-members: ``` --- # Exceptions - tmuxp.exc Source: https://tmuxp.git-pull.com/internals/api/exc/ # Exceptions - `tmuxp.exc` ```{eval-rst} .. automodule:: tmuxp.exc :members: :show-inheritance: :undoc-members: ``` --- # API Reference Source: https://tmuxp.git-pull.com/internals/api/ (api)= # API Reference :::{seealso} See {ref}`libtmux's API ` and {ref}`Quickstart ` to see how you can control tmux via python API calls. ::: ```{toctree} _internal/index cli/index workspace/index exc log plugin shell util types ``` --- # Logging - tmuxp.log Source: https://tmuxp.git-pull.com/internals/api/log/ # Logging - `tmuxp.log` ```{eval-rst} .. automodule:: tmuxp.log :members: :show-inheritance: :undoc-members: ``` --- # Plugin - tmuxp.plugin Source: https://tmuxp.git-pull.com/internals/api/plugin/ # Plugin - `tmuxp.plugin` ```{eval-rst} .. automodule:: tmuxp.plugin :members: :show-inheritance: :undoc-members: ``` --- # Shell - tmuxp.shell Source: https://tmuxp.git-pull.com/internals/api/shell/ # Shell - `tmuxp.shell` ```{eval-rst} .. automodule:: tmuxp.shell :members: :show-inheritance: :undoc-members: ``` --- # Typings - tmuxp.types Source: https://tmuxp.git-pull.com/internals/api/types/ # Typings - `tmuxp.types` ```{eval-rst} .. automodule:: tmuxp.types :members: :show-inheritance: :undoc-members: ``` --- # Utilities - tmuxp.util Source: https://tmuxp.git-pull.com/internals/api/util/ # Utilities - `tmuxp.util` ```{eval-rst} .. automodule:: tmuxp.util :members: :show-inheritance: :undoc-members: ``` --- # Builder - tmuxp.workspace.builder Source: https://tmuxp.git-pull.com/internals/api/workspace/builder/ # Builder - `tmuxp.workspace.builder` ```{eval-rst} .. automodule:: tmuxp.workspace.builder :members: :show-inheritance: :undoc-members: ``` --- # Constants - tmuxp.workspace.constants Source: https://tmuxp.git-pull.com/internals/api/workspace/constants/ # Constants - `tmuxp.workspace.constants` ```{eval-rst} .. automodule:: tmuxp.workspace.constants :members: :show-inheritance: :undoc-members: ``` --- # Finders - tmuxp.workspace.finders Source: https://tmuxp.git-pull.com/internals/api/workspace/finders/ # Finders - `tmuxp.workspace.finders` ```{eval-rst} .. automodule:: tmuxp.workspace.finders :members: :show-inheritance: :undoc-members: ``` --- # Freezer - tmuxp.workspace.freezer Source: https://tmuxp.git-pull.com/internals/api/workspace/freezer/ # Freezer - `tmuxp.workspace.freezer` ```{eval-rst} .. automodule:: tmuxp.workspace.freezer :members: :show-inheritance: :undoc-members: ``` --- # Importers - tmuxp.workspace.importers Source: https://tmuxp.git-pull.com/internals/api/workspace/importers/ # Importers - `tmuxp.workspace.importers` ```{eval-rst} .. automodule:: tmuxp.workspace.importers :members: :show-inheritance: :undoc-members: ``` --- # Workspace Source: https://tmuxp.git-pull.com/internals/api/workspace/ (workspace)= # Workspace :::{warning} Be careful with these! Internal APIs are **not** covered by version policies. They can break or be removed between minor versions! If you need an internal API stabilized please [file an issue](https://github.com/tmux-python/tmuxp/issues). ::: ```{toctree} builder constants finders freezer importers loader validation ``` --- # Loader - tmuxp.workspace.loader Source: https://tmuxp.git-pull.com/internals/api/workspace/loader/ # Loader - `tmuxp.workspace.loader` ```{eval-rst} .. automodule:: tmuxp.workspace.loader :members: :show-inheritance: :undoc-members: ``` --- # Validation - tmuxp.workspace.validation Source: https://tmuxp.git-pull.com/internals/api/workspace/validation/ # Validation - `tmuxp.workspace.validation` ```{eval-rst} .. automodule:: tmuxp.workspace.validation :members: :show-inheritance: :undoc-members: ``` --- # Architecture Source: https://tmuxp.git-pull.com/internals/architecture/ # Architecture How the tmuxp CLI dispatches commands to the underlying library. ## Request Flow ``` tmuxp CLI (argparse) │ ├── tmuxp load ──→ workspace.loader ──→ workspace.builder ──→ libtmux ├── tmuxp freeze ──→ workspace.freezer ──→ libtmux ├── tmuxp convert ──→ _internal.config_reader ├── tmuxp shell ──→ libtmux (interactive) └── tmuxp ls/search ──→ workspace.finders ``` ## Key Components ### CLI Layer (`tmuxp.cli`) The CLI uses Python's `argparse` with a custom formatter ({mod}`tmuxp.cli._formatter`). Each subcommand lives in its own module under `tmuxp.cli`. The entry point is `tmuxp.cli.cli()`, registered as a console script in `pyproject.toml`. ### Workspace Layer (`tmuxp.workspace`) The workspace layer handles configuration lifecycle: 1. **Finding**: {mod}`tmuxp.workspace.finders` locates config files 2. **Loading**: {mod}`tmuxp.workspace.loader` reads and validates configs 3. **Building**: {mod}`tmuxp.workspace.builder` creates tmux sessions via libtmux 4. **Freezing**: {mod}`tmuxp.workspace.freezer` exports running sessions ### Library Layer (libtmux) tmuxp delegates all tmux operations to [libtmux](https://libtmux.git-pull.com/). The `WorkspaceBuilder` creates libtmux `Server`, `Session`, `Window`, and `Pane` objects to construct the requested workspace. --- # Internals Source: https://tmuxp.git-pull.com/internals/ (internals)= # Internals ```{warning} Everything in this section is **internal implementation detail**. There is no stability guarantee. Interfaces may change or be removed without notice between any release. If you are building an application with tmuxp, use the [CLI](../cli/index.md) or refer to the [libtmux API](https://libtmux.git-pull.com/api/). ``` ::::{grid} 1 1 2 2 :gutter: 2 2 3 3 :::{grid-item-card} Architecture :link: architecture :link-type: doc How the CLI dispatches to the workspace builder and libtmux. ::: :::{grid-item-card} Python API :link: api/index :link-type: doc Internal module reference for contributors and plugin authors. ::: :::: ```{toctree} :hidden: architecture api/index ``` --- # Migration notes Source: https://tmuxp.git-pull.com/migration/ (migration)= ```{currentmodule} libtmux ``` ```{include} ../MIGRATION ``` --- # Code Style Source: https://tmuxp.git-pull.com/project/code-style/ # Code Style ## Formatting tmuxp uses [ruff](https://github.com/astral-sh/ruff) for both linting and formatting. ```console $ uv run ruff format . ``` ```console $ uv run ruff check . --fix --show-fixes ``` ## Type Checking Strict [mypy](https://mypy-lang.org/) is enforced. ```console $ uv run mypy ``` ## Docstrings All public functions and methods use NumPy-style docstrings. ## Imports - Standard library: namespace imports (`import pathlib`, not `from pathlib import Path`) - Exception: `from dataclasses import dataclass, field` - Typing: `import typing as t`, access via `t.Optional`, `t.NamedTuple`, etc. - All files: `from __future__ import annotations` --- # Developing and Testing Source: https://tmuxp.git-pull.com/project/contributing/ (developing)= # Developing and Testing ```{eval-rst} .. todo:: link to sliderepl or ipython notebook slides ``` Our tests are inside `tests/`. Tests are implemented using [pytest]. `make test` will create a tmux server on a separate `socket_name` using `$ tmux -L test_case`. [pytest]: http://pytest.org/ (install-dev-env)= ## Install the latest code from git ### Get the source To begin developing, check out the code from github: ```console $ git clone git@github.com:tmux-python/tmuxp.git ``` ```console $ cd tmuxp ``` ### Bootstrap The easiest way to configure a dev environment is through [uv]. This automatically will manage virtualenv and python dependencies for tmuxp. For information on installing uv visit the [uv's documentation]. To begin developing, check out the code from github: ```console $ git clone git@github.com:tmux-python/tmuxp.git ``` ```console $ cd tmuxp ``` You can create a virtualenv, and install all of the locked packages as listed in uv.lock: ```console $ uv sync --all-extras --dev ``` If you ever need to update packages during your development session, the following command can be used to update all packages as per uv settings: ```console $ uv sync --all-extras --dev --upgrade ``` Then before any python command in tty / terminal session, run with: ```console $ uv run [command] ``` That is it! You are now ready to code! [uv]: https://github.com/astral-sh/uv [uv's documentation]: https://docs.astral.sh/uv ### Advanced: Manual virtualenv Now create a virtualenv, if you don't know how to, you can create a virtualenv with: ```console $ virtualenv .venv ``` Then activate it to your current tty / terminal session with: ```console $ source .venv/bin/activate ``` Good! Now let's run this: ```console $ pip install -e . ``` This has `pip`, a python package manager install the python package in the current directory. `-e` means `--editable`, which means you can adjust the code and the installed software will reflect the changes. When you manage dependencies with [uv](https://docs.astral.sh/uv/getting-started/features/#python-versions), add the checkout as an editable development dependency instead: ```console $ uv add --dev --editable . ``` Prefer a one-off, pipx-style execution while you hack? Call tmuxp via [uvx](https://docs.astral.sh/uv/guides/tools/): ```console $ uvx tmuxp ``` ```console $ tmuxp ``` ## Test Runner [pytest] is used for tests. As you've seen above, the `tmuxp` command will now be available to you, since you are in the virtual environment, your `PATH` environment was updated to include a special version of `python` inside your `.venv` folder with its own packages. ### Rerun on file change via [pytest-watcher] (works out of the box): ```console $ make start ``` via [`entr(1)`] (requires installation): ```console $ make watch_test ``` [pytest-watcher]: https://github.com/olzhasar/pytest-watcher ### Manual (just the command, please) ```console $ uv run py.test ``` or: ```console $ make test ``` ### pytest options `PYTEST_ADDOPTS` can be set in the commands below. For more information read [docs.pytest.com] for the latest documentation. [docs.pytest.com]: https://docs.pytest.org/ Verbose: ```console $ env PYTEST_ADDOPTS="-verbose" make start ``` Pick a file: ```console $ env PYTEST_ADDOPTS="tests/workspace/test_builder.py" uv run make start ``` Drop into `test_automatic_rename_option()` in `tests/workspace/test_builder.py`: ```console $ env PYTEST_ADDOPTS="-s -x -vv tests/workspace/test_builder.py" \ uv run make start ``` Drop into `test_automatic_rename_option()` in `tests/workspace/test_builder.py` and stop on first error: ```console $ env PYTEST_ADDOPTS="-s -x -vv tests/workspace/test_builder.py::test_automatic_rename_option" \ uv run make start ``` Drop into `pdb` on first error: ```console $ env PYTEST_ADDOPTS="-x -s --pdb" make start ``` If you have [ipython] installed: ```console $ env PYTEST_ADDOPTS="--pdbcls=IPython.terminal.debugger:TerminalPdb" make start ``` [ipython]: https://ipython.org/ ```console $ make test ``` You probably didn't see anything but tests scroll by. If you found a problem or are trying to write a test, you can file an [issue on github]. (test-specific-tests)= ### Manual invocation Test only a file: ```console $ py.test tests/test_config.py ``` will test the `tests/test_config.py` tests. ```console $ py.test tests/test_config.py::test_export_json ``` tests `test_export_json` inside of `tests/test_config.py`. Multiple can be separated by spaces: ```console $ py.test tests/test_{window,pane}.py tests/test_config.py::test_export_json ``` (test-builder-visually)= ### Visual testing You can watch tmux testsuite build sessions visually by keeping a client open in a separate terminal. Create two terminals: - Terminal 1: `$ tmux -L test_case` - Terminal 2: `$ cd` into the tmuxp project and into the `virtualenv` if you are using one, see details on installing the dev version of tmuxp above. Then: ```console $ py.test tests/workspace/test_builder.py ``` Terminal 1 should have flickered and built the session before your eyes. tmuxp hides this building from normal users. ### Run tests on save (old method) You can re-run tests automatically on file edit. :::{note} This requires [`entr(1)`]. ::: Install [entr]. Packages are available on most Linux and BSD variants, including Debian, Ubuntu, FreeBSD, OS X. To run all tests upon editing any `.py` file: ```console $ make watch_test ``` You can also re-run a specific test file or any other [py.test usage argument]: ```console $ make watch_test test=tests/test_config.py ``` ```console $ make watch_test test='-x tests/test_config.py tests/test_util.py' ``` ### Testing options `RETRY_TIMEOUT_SECONDS` can be toggled if certain workspace builder tests are being stubborn. e.g. `RETRY_TIMEOUT_SECONDS=10 py.test` ```{literalinclude} ../.github/workflows/tests.yml :language: yaml ``` ## Documentation ### Rebuild on save Rebuild the documentation when an `.md` file is edited: ```console $ cd doc ``` ```console $ make watch ``` ```console $ make SPHINXBUILD='uv run sphinx-build' watch ``` (tmuxp-developer-config)= ## tmuxp developer config ```{image} _static/tmuxp-dev-screenshot.png :width: 1030 :height: 605 :align: center :loading: lazy ``` After you {ref}`install-dev-env`, when inside the tmuxp checkout: ```console $ tmuxp load . ``` this will load the `.tmuxp.yaml` in the root of the project. ```{literalinclude} ../.tmuxp.yaml :language: yaml ``` ## Formatting ### ruff The project uses [ruff] to handle formatting, sorting imports and linting. ````{tab} Command uv: ```console $ uv run ruff ``` If you setup manually: ```console $ ruff check . ``` ```` ````{tab} make ```console $ make ruff ``` ```` ````{tab} Watch ```console $ make watch_ruff ``` requires [`entr(1)`]. ```` ````{tab} Fix files uv: ```console $ uv run ruff check . --fix ``` If you setup manually: ```console $ ruff check . --fix ``` ```` #### ruff format [ruff format] is used for formatting. ````{tab} Command uv: ```console $ uv run ruff format . ``` If you setup manually: ```console $ ruff format . ``` ```` ````{tab} make ```console $ make ruff_format ``` ```` ### mypy [mypy] is used for static type checking. ````{tab} Command uv: ```console $ uv run mypy . ``` If you setup manually: ```console $ mypy . ``` ```` ````{tab} make ```console $ make mypy ``` ```` ````{tab} Watch ```console $ make watch_mypy ``` requires [`entr(1)`]. ```` (gh-actions)= ## Continuous integration ### Github Actions tmuxp uses [github actions] for continuous integration / automatic unit testing. To view the tmux and python versions tested see the [.github/workflows/tests.yml]. Builds are done on `master` and pull requests and can be viewed on the [gh build site]. [py.test usage argument]: https://pytest.org/latest/usage.html [entr]: http://entrproject.org/ [`entr(1)`]: http://entrproject.org/ [ruff]: https://ruff.rs [ruff format]: https://docs.astral.sh/ruff/formatter/ [mypy]: http://mypy-lang.org/ [github actions]: https://github.com/features/actions [gh build site]: https://github.com/tmux-python/tmuxp/actions?query=workflow%3Atests [.github/workflows/tests.yml]: https://github.com/tmux-python/tmuxp/blob/master/.github/workflows/tests.yml [issue on github]: https://github.com/tmux-python/tmuxp/issues --- # Project Source: https://tmuxp.git-pull.com/project/ (project)= # Project Information for contributors and maintainers. ::::{grid} 1 1 2 2 :gutter: 2 2 3 3 :::{grid-item-card} Contributing :link: contributing :link-type: doc Development setup, running tests, submitting PRs. ::: :::{grid-item-card} Code Style :link: code-style :link-type: doc Ruff, mypy, NumPy docstrings, import conventions. ::: :::{grid-item-card} Releasing :link: releasing :link-type: doc Release checklist and version policy. ::: :::: ```{toctree} :hidden: contributing code-style releasing ``` --- # Releasing Source: https://tmuxp.git-pull.com/project/releasing/ # Releasing ## Release Process Releases are triggered by git tags and published to PyPI via OIDC trusted publishing. 1. Update `CHANGES` with the release notes 2. Bump version in `src/tmuxp/__about__.py` 3. Commit: ```console $ git commit -m "tmuxp " ``` 4. Tag: ```console $ git tag v ``` 5. Push: ```console $ git push && git push --tags ``` 6. CI builds and publishes to PyPI automatically via trusted publishing ## Changelog Format The `CHANGES` file uses this format: ```text tmuxp () ------------------------ ### What's new - Description of feature (#issue) ### Bug fixes - Description of fix (#issue) ### Breaking changes - Description of break, migration path (#issue) ``` --- # Quickstart Source: https://tmuxp.git-pull.com/quickstart/ (quickstart)= # Quickstart ## Installation Ensure you have at least tmux **>= 3.2** and python **>= 3.9**. ```console $ pip install --user tmuxp ``` If you're managing dependencies with [uv]_ inside a project environment, add tmuxp directly to your lockfile: ```console $ uv add tmuxp ``` To run tmuxp without installing it globally—similar to what you'd do with `pipx`—invoke it via [uvx]_: ```console $ uvx tmuxp ``` You can upgrade to the latest release with: ```console $ pip install --user --upgrade tmuxp ``` Within a uv-managed project you can upgrade by refreshing the lockfile and syncing the environment: ```console $ uv lock --upgrade-package tmuxp $ uv sync ``` Then install {ref}`completion`. If you are a Homebrew user you can install it with: ```console $ brew install tmuxp ``` (developmental-releases)= ### Developmental releases New versions of tmuxp are published to PyPI as alpha, beta, or release candidates. In their versions you will see notification like `a1`, `b1`, and `rc1`, respectively. `1.10.0b4` would mean the 4th beta release of `1.10.0` before general availability. - [pip]\: ```console $ pip install --user --upgrade --pre tmuxp ``` - [uv]_: ```console $ uv add tmuxp --prerelease allow ``` - [uvx]_: ```console $ uvx --from 'tmuxp' --prerelease allow tmuxp ``` - [pipx]\: ```console $ pipx install --suffix=@next 'tmuxp' --pip-args '\--pre' --force ``` Then use `tmuxp@next load [session]`. via trunk (can break easily): - [pip]\: ```console $ pip install --user -e git+https://github.com/tmux-python/tmuxp.git#egg=tmuxp ``` - [uv]_: ```console $ uv add "tmuxp @ git+https://github.com/tmux-python/tmuxp.git@master" ``` - [uvx]_: ```console $ uvx --from "tmuxp @ git+https://github.com/tmux-python/tmuxp.git@master" tmuxp ``` - [pipx]\: ```console $ pipx install --suffix=@master 'tmuxp @ git+https://github.com/tmux-python/tmuxp.git@master' --force ``` [pip]: https://pip.pypa.io/en/stable/ [pipx]: https://pypa.github.io/pipx/docs/ [uv]: https://docs.astral.sh/uv/getting-started/features/#python-versions [uvx]: https://docs.astral.sh/uv/guides/tools/ ## Commands :::{seealso} {ref}`examples`, {ref}`commands`, {ref}`completion`. ::: tmuxp launches workspaces / sessions from JSON and YAML files. Workspace files can be stored in `$HOME/.tmuxp` or in project directories as `.tmuxp.py`, `.tmuxp.json` or `.tmuxp.yaml`. Every workspace file is required to have: 1. `session_name` 2. list of `windows` 3. list of `panes` for every window in `windows` Create a file, `~/.tmuxp/example.yaml`: ```{literalinclude} ../examples/2-pane-vertical.yaml :language: yaml ``` ```console $ tmuxp load example.yaml ``` This creates your tmuxp session. Load multiple tmux sessions at once: ```console $ tmuxp load example.yaml anothersession.yaml ``` tmuxp will offer to `switch-client` for you if you're already in a session. You can also load a workspace and append the windows to the current active session. You can also have a custom tmuxp config directory by setting the `TMUXP_CONFIGDIR` in your environment variables. ```console $ TMUXP_CONFIGDIR=$HOME/.tmuxpmoo tmuxp load cpython ``` Or in your `~/.bashrc` / `~/.zshrc` you can set: ```console export TMUXP_CONFIGDIR=$HOME/.yourconfigdir/tmuxp ``` You can also [Import][import] configs [teamocil] and [tmuxinator]. ## Pythonics :::{seealso} {ref}`libtmux python API documentation ` and {ref}`developing`. ::: ORM - [Object Relational Mapper][object relational mapper] AL - [Abstraction Layer][abstraction layer] ### python abstraction layer | {ref}`tmuxp python api ` | {term}`tmux(1)` equivalent | | ------------------------------------- | -------------------------- | | {meth}`libtmux.Server.new_session` | `$ tmux new-session` | | {meth}`libtmux.Server.sessions` | `$ tmux list-sessions` | | {meth}`libtmux.Session.windows` | `$ tmux list-windows` | | {meth}`libtmux.Session.new_window` | `$ tmux new-window` | | {meth}`libtmux.Window.panes` | `$ tmux list-panes` | | {meth}`libtmux.Window.split` | `$ tmux split-window` | | {meth}`libtmux.Pane.send_keys` | `$ tmux send-keys` | [import]: http://tmuxp.git-pull.com/commands/#import [tmuxinator]: https://github.com/aziz/tmuxinator [teamocil]: https://github.com/remiprev/teamocil [abstraction layer]: http://en.wikipedia.org/wiki/Abstraction_layer [object relational mapper]: http://en.wikipedia.org/wiki/Object-relational_mapping --- # Topics Source: https://tmuxp.git-pull.com/topics/ (topics)= # Topics Conceptual guides and workflow documentation. ::::{grid} 1 1 2 2 :gutter: 2 2 3 3 :::{grid-item-card} Workflows :link: workflows :link-type: doc CI integration, scripting, and automation patterns. ::: :::{grid-item-card} Plugins :link: plugins :link-type: doc Plugin system for custom behavior. ::: :::{grid-item-card} Library vs CLI :link: library-vs-cli :link-type: doc When to use tmuxp CLI vs libtmux directly. ::: :::{grid-item-card} Troubleshooting :link: troubleshooting :link-type: doc Common shell, PATH, and tmux issues. ::: :::: ## Compared to tmuxinator / teamocil tmuxp, [tmuxinator](https://github.com/aziz/tmuxinator), and [teamocil](https://github.com/remiprev/teamocil) all load tmux sessions from config files. Key differences: tmuxp is Python (not Ruby), builds sessions through [libtmux](https://libtmux.git-pull.com/)'s ORM layer instead of raw shell commands, supports JSON and YAML, and can [freeze](../cli/freeze.md) running sessions back to config. ```{toctree} :hidden: workflows plugins library-vs-cli troubleshooting ``` --- # Library vs CLI Source: https://tmuxp.git-pull.com/topics/library-vs-cli/ # Library vs CLI tmuxp is a CLI tool. [libtmux](https://libtmux.git-pull.com/) is the Python library it's built on. Both control tmux, but they serve different needs. ## When to Use the CLI Use `tmuxp` when: - You want **declarative workspace configs** — define your layout in YAML, load it with one command - You're setting up **daily development environments** — same windows, same panes, every time - You need **CI/CD tmux sessions** — `tmuxp load -d` in a script - You prefer **configuration over code** — no Python needed ```console $ tmuxp load my-workspace.yaml ``` ## When to Use libtmux Use [libtmux](https://libtmux.git-pull.com/) directly when: - You need **dynamic logic** — conditionals, loops, branching based on state - You want to **read pane output** — capture what's on screen and react to it - You're **testing** tmux interactions — libtmux provides pytest fixtures - You need **multi-server orchestration** — manage multiple tmux servers programmatically - The CLI's config format **can't express** what you need ```python import libtmux server = libtmux.Server() session = server.new_session("my-project") window = session.new_window("editor") pane = window.split() pane.send_keys("vim .") ``` ## Concept Mapping How tmuxp config keys map to libtmux API calls: | tmuxp YAML | libtmux equivalent | |------------|-------------------| | `session_name: foo` | `server.new_session(session_name="foo")` | | `windows:` | `session.new_window(...)` | | `panes:` | `window.split(...)` | | `shell_command:` | `pane.send_keys(...)` | | `layout: main-vertical` | `window.select_layout("main-vertical")` | | `start_directory: ~/project` | `session.new_window(start_directory="~/project")` | | `before_script:` | Run via `subprocess` before building | ## What the CLI Can't Express tmuxp configs are static declarations. They can't: - **Branch on conditions** — "only create this pane if a file exists" - **Read pane output** — "wait until the server is ready, then open the browser" - **React to state** — "if this session already has 3 windows, add a 4th" - **Orchestrate across servers** — "connect to both local and remote tmux" - **Build layouts dynamically** — "create N panes based on a list of services" For these, use libtmux directly. See the [libtmux quickstart](https://libtmux.git-pull.com/quickstart.html). --- # Plugins Source: https://tmuxp.git-pull.com/topics/plugins/ (plugins)= # Plugins The plugin system allows users to customize and extend different aspects of tmuxp without the need to change tmuxp itself. ## Using a Plugin To use a plugin, install it in your local python environment and add it to your tmuxp workspace file. ### Example Workspace files ````{tab} YAML ```{literalinclude} ../../examples/plugin-system.yaml :language: yaml ``` ```` ````{tab} JSON ```{literalinclude} ../../examples/plugin-system.json :language: json ``` ```` ## Developing a Plugin tmuxp expects all plugins to be a class within a python submodule named `plugin` that is within a python module that is installed in the local python environment. A plugin interface is provided by tmuxp to inherit. [uv] is the chosen python package manager for tmuxp. It is highly suggested to use it when developing plugins; however, `pip` will work just as well. Only one of the configuration files is needed for the packaging tool that the package developer decides to use. ```console python_module ├── tmuxp_plugin_my_plugin_module │   ├── __init__.py │   └── plugin.py └── pyproject.toml # Python project configuration file ``` When publishing plugins to pypi, tmuxp advocates for standardized naming: `tmuxp-plugin-{your-plugin-name}` to allow for easier searching. To create a module configuration file with uv, run `uv virtualenv` in the module directory. The resulting file looks something like this: ```toml [project] name = "tmuxp-plugin-my-tmuxp-plugin" version = "0.0.2" description = "An example tmuxp plugin." authors = ["Author Name .com>"] requires-python = ">=3.8,<4.0" dependencies = [ "tmuxp^=1.7.0" ] [build-system] requires = ["hatchling"] build-backend = "hatchling.build" ``` The `plugin.py` file could contain something like the following: ```python from tmuxp.plugin import TmuxpPlugin import datetime class MyTmuxpPlugin(TmuxpPlugin): def __init__(self): """ Initialize my custom plugin. """ # Optional version dependency configuration. See Plugin API docs # for all supported config parameters config = { 'tmuxp_min_version' = '1.6.2' } TmuxpPlugin.__init__( self, plugin_name='tmuxp-plugin-my-tmuxp-plugin', **config ) def before_workspace_builder(self, session): session.rename_session('my-new-session-name') def reattach(self, session): now = datetime.datetime.now().strftime('%Y-%m-%d') session.rename_session('session_{}'.format(now)) ``` Once this plugin is installed in the local python environment, it can be used in a configuration file like the following: ```yaml session_name: plugin example plugins: - my_plugin_module.plugin.MyTmuxpPlugin # ... the rest of your config ``` ## Plugin API ```{eval-rst} .. automethod:: tmuxp.plugin.TmuxpPlugin.__init__ ``` ```{eval-rst} .. automethod:: tmuxp.plugin.TmuxpPlugin.before_workspace_builder ``` ```{eval-rst} .. automethod:: tmuxp.plugin.TmuxpPlugin.on_window_create ``` ```{eval-rst} .. automethod:: tmuxp.plugin.TmuxpPlugin.after_window_finished ``` ```{eval-rst} .. automethod:: tmuxp.plugin.TmuxpPlugin.before_script ``` ```{eval-rst} .. automethod:: tmuxp.plugin.TmuxpPlugin.reattach ``` [uv]: https://github.com/astral-sh/uv --- # Troubleshooting Source: https://tmuxp.git-pull.com/topics/troubleshooting/ # Troubleshooting ## tmuxp command not found Ensure tmuxp is installed and on your `PATH`: ```console $ which tmuxp ``` If installed with `pip install --user`, ensure `~/.local/bin` is in your `PATH`. ## tmux server not found tmuxp requires a running tmux server or will start one automatically. Ensure tmux is installed: ```console $ tmux -V ``` Minimum required version: tmux 3.2a. ## Configuration errors Use `tmuxp debug-info` to collect system information for bug reports: ```console $ tmuxp debug-info ``` ## Session already exists If a session with the same name already exists, tmuxp will prompt you. Use `tmuxp load -d` to load in detached mode alongside existing sessions. ## Shell completion not working See [Shell Completion](../cli/completion.md) for setup instructions for bash, zsh, and fish. --- # Workflows Source: https://tmuxp.git-pull.com/topics/workflows/ # Workflows ## CI Integration tmuxp can set up tmux sessions in CI pipelines for integration testing: ```console $ tmuxp load -d my-workspace.yaml ``` The `-d` flag loads the session in detached mode, useful for headless environments. ## Scripting tmuxp's exit codes enable scripting and error handling. See [Exit Codes](../cli/exit-codes.md) for the complete list. ## Automating Development Environments Use tmuxp to codify your development environment: 1. Set up your ideal tmux layout manually 2. Freeze it: `tmuxp freeze my-session` 3. Edit the generated YAML to add commands 4. Load it on any machine: `tmuxp load my-workspace.yaml` ## User-Level Configuration Workspace configs can be stored in: - `~/.tmuxp/` (legacy) - `~/.config/tmuxp/` (XDG default) - Project-local `.tmuxp.yaml` or `.tmuxp/` directory ---