Examples

Short hand / inline style

tmuxp has a short-hand syntax to for those who wish to keep their workspace punctual.

session_name: shorthands
windows:
  - window_name: long form
    panes:
      - shell_command:
          - echo 'did you know'
          - echo 'you can inline'
      - shell_command: echo 'single commands'
      - echo 'for panes'
{
  "windows": [
    {
      "panes": [
        {
          "shell_command": [
            "echo 'did you know'", 
            "echo 'you can inline'"
          ]
        }, 
        {
          "shell_command": "echo 'single commands'"
        }, 
        "echo 'for panes'"
      ], 
      "window_name": "long form"
    }
  ], 
  "session_name": "shorthands"
}

Blank panes

No need to repeat pwd or a dummy command. A null, 'blank', 'pane' are valid.

Note '' counts as an empty carriage return.

session_name: Blank pane test
windows:
  # Emptiness will simply open a blank pane, if no shell_command_before.
  # All these are equivalent
  - window_name: Blank pane test
    panes:
      -
      - pane
      - blank
  - window_name: More blank panes
    panes:
      - null
      - shell_command:
      - shell_command:
          -
  # an empty string will be treated as a carriage return
  - window_name: Empty string (return)
    panes:
      - ""
      - shell_command: ""
      - shell_command:
          - ""
  # a pane can have other options but still be blank
  - window_name: Blank with options
    panes:
      - focus: true
      - start_directory: /tmp
{
  "windows": [
    {
      "panes": [
        null, 
        "pane", 
        "blank"
      ], 
      "window_name": "Blank pane test"
    }, 
    {
      "panes": [
        null, 
        {
          "shell_command": null
        }, 
        {
          "shell_command": [
            null
          ]
        }
      ], 
      "window_name": "More blank panes"
    }, 
    {
      "panes": [
        "", 
        {
          "shell_command": ""
        }, 
        {
          "shell_command": [
            ""
          ]
        }
      ], 
      "window_name": "Empty string (return)"
    },
    {
      "panes": [
        {
          "focus": true
        },
        {
          "start_directory": "/tmp"
        }
      ],
      "window_name": "Blank with options"
    }
  ], 
  "session_name": "Blank pane test"
}

2 panes

session_name: 2-pane-vertical
windows:
  - window_name: my test window
    panes:
      - echo hello
      - echo hello
{
  "windows": [
    {
      "panes": [
        "echo hello",
        "echo hello"
      ], 
      "window_name": "my test window"
    }
  ], 
  "session_name": "2-pane-vertical"
}

3 panes

session_name: 3-panes
windows:
  - window_name: dev window
    layout: main-vertical
    shell_command_before:
      - cd ~/
    panes:
      - shell_command:
          - cd /var/log
          - ls -al | grep \.log
      - echo hello
      - echo hello
{
  "windows": [
    {
      "panes": [
        {
          "shell_command": [
            "cd /var/log", 
            "ls -al | grep \\.log"
          ]
        },
        "echo hello",
        "echo hello"
      ], 
      "shell_command_before": [
        "cd ~/"
      ], 
      "layout": "main-vertical", 
      "window_name": "dev window"
    }
  ], 
  "session_name": "3-panes"
}

4 panes

session_name: 4-pane-split
windows:
  - window_name: dev window
    layout: tiled
    shell_command_before:
      - cd ~/
    panes:
      - shell_command:
          - cd /var/log
          - ls -al | grep \.log
      - echo hello
      - echo hello
      - echo hello
{
  "windows": [
    {
      "panes": [
        {
          "shell_command": [
            "cd /var/log", 
            "ls -al | grep \\.log"
          ]
        }, 
        "echo hello",
        "echo hello",
        "echo hello"
      ], 
      "shell_command_before": [
        "cd ~/"
      ], 
      "layout": "tiled", 
      "window_name": "dev window"
    }
  ], 
  "session_name": "4-pane-split"
}

Start Directory

Equivalent to tmux new-window -c <start-directory>.

session_name: start directory
start_directory: /var/
windows:
  - window_name: should be /var/
    panes:
      - shell_command:
          - echo "\033c
          - it trickles down from session-level"
      - echo hello
  - window_name: should be /var/log
    start_directory: log
    panes:
      - shell_command:
          - echo '\033c
          - window start_directory concatenates to session start_directory
          - if it is not absolute'
      - echo hello
  - window_name: should be ~
    start_directory: "~"
    panes:
      - shell_command:
          - 'echo \\033c ~ has precedence. note: remember to quote ~ in YAML'
      - echo hello
  - window_name: should be /bin
    start_directory: /bin
    panes:
      - echo '\033c absolute paths also have precedence.'
      - echo hello
  - window_name: should be workspace file's dir

    start_directory: ./
    panes:
      - shell_command:
          - echo '\033c
          - ./ is relative to workspace file location
          - ../ will be parent of workspace file
          - ./test will be \"test\" dir inside dir of workspace file'
      - shell_command:
          - echo '\033c
          - This way you can load up workspaces from projects and maintain
          - relative paths.'
{
  "windows": [
    {
      "panes": [
        {
          "shell_command": [
            "echo \"\\033c", 
            "it trickles down from session-level\""
          ]
        }, 
        "echo hello"
      ], 
      "window_name": "should be /var/"
    }, 
    {
      "panes": [
        {
          "shell_command": [
            "echo '\\033c", 
            "window start_directory concatenates to session start_directory", 
            "if it is not absolute'"
          ]
        }, 
        "echo hello"
      ], 
      "start_directory": "log", 
      "window_name": "should be /var/log"
    }, 
    {
      "panes": [
        {
          "shell_command": [
            "echo \\\\033c ~ has precedence. note: remember to quote ~ in YAML"
          ]
        }, 
        "echo hello"
      ], 
      "start_directory": "~", 
      "window_name": "should be ~"
    }, 
    {
      "panes": [
        "echo '\\033c absolute paths also have precedence.'", 
        "echo hello"
      ], 
      "start_directory": "/bin", 
      "window_name": "should be /bin"
    }, 
    {
      "panes": [
        {
          "shell_command": [
            "echo '\\033c", 
            "./ is relative to workspace file location", 
            "../ will be parent of workspace file", 
            "./test will be \\\"test\\\" dir inside dir of workspace file'"
          ]
        }, 
        {
          "shell_command": [
            "echo '\\033c", 
            "This way you can load up workspaces from projects and maintain", 
            "relative paths.'"
          ]
        }
      ], 
      "start_directory": "./", 
      "window_name": "should be config's dir"
    }
  ], 
  "session_name": "start directory", 
  "start_directory": "/var/"
}

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”:

$ 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.

start_directory: "${PWD}/test"
shell_command_before: "echo ${PWD}"
before_script: "${MY_ENV_VAR}/test3.sh"
session_name: session - ${USER} (${MY_ENV_VAR})
windows:
  - window_name: editor
    panes:
      - shell_command:
          - tail -F /var/log/syslog
    start_directory: /var/log
  - window_name: logging for ${USER}
    options:
      automatic-rename: true
    panes:
      - shell_command:
          - htop
          - ls $PWD
{
  "before_script": "${MY_ENV_VAR}/test3.sh", 
  "windows": [
    {
      "panes": [
        {
          "shell_command": [
            "tail -F /var/log/syslog"
          ]
        }
      ], 
      "start_directory": "/var/log", 
      "window_name": "editor"
    }, 
    {
      "panes": [
        {
          "shell_command": [
            "htop", 
            "ls $PWD"
          ]
        }
      ], 
      "window_name": "logging for ${USER}", 
      "options": {
        "automatic-rename": true
      }
    }
  ], 
  "shell_command_before": "echo ${PWD}", 
  "start_directory": "${PWD}/test", 
  "session_name": "session - ${USER} (${MY_ENV_VAR})"
}

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 and tmux 3.0 or newer.

session_name: Environment variables test
environment:
  EDITOR: /usr/bin/vim
  DJANGO_SETTINGS_MODULE: my_app.settings.local
  SERVER_PORT: "8009"
windows:
  - window_name: Django project
    panes:
      - ./manage.py runserver 0.0.0.0:${SERVER_PORT}
  - window_name: Another Django project
    environment:
      DJANGO_SETTINGS_MODULE: my_app.settings.local
      SERVER_PORT: "8010"
    panes:
      - ./manage.py runserver 0.0.0.0:${SERVER_PORT}
      - environment:
          DJANGO_SETTINGS_MODULE: my_app.settings.local-testing
          SERVER_PORT: "8011"
        shell_command: ./manage.py runserver 0.0.0.0:${SERVER_PORT}
{
  "environment": {
    "EDITOR": "/usr/bin/vim",
    "DJANGO_SETTINGS_MODULE": "my_app.settings.local",
    "SERVER_PORT": "8009"
  },
  "windows": [
    {
      "panes": [
        "./manage.py runserver 0.0.0.0:${SERVER_PORT}"
      ],
      "window_name": "Django project"
    },
    {
      "environment": {
        "DJANGO_SETTINGS_MODULE": "my_app.settings.local",
        "SERVER_PORT": "8010"
      },
      "panes": [
        "./manage.py runserver 0.0.0.0:${SERVER_PORT}",
        {
          "environment": {
            "DJANGO_SETTINGS_MODULE": "my_app.settings.local-testing",
            "SERVER_PORT": "8011"
          },
          "shell_command": "./manage.py runserver 0.0.0.0:${SERVER_PORT}"
        }
      ],
      "window_name": "Another Django project"
    }
  ],
  "session_name": "Environment variables test"
}

Focusing

tmuxp allows focus: true for assuring windows and panes are attached / selected upon loading.

session_name: focus
windows:
  - window_name: attached window
    focus: true
    panes:
      - shell_command:
          - echo hello
          - echo 'this pane should be selected on load'
        focus: true
      - shell_command:
          - cd /var/log
          - echo hello
  - window_name: second window
    shell_command_before: cd /var/log
    panes:
      - pane
      - shell_command:
          - echo 'this pane should be focused, when window switched to first time'
        focus: true
      - pane
{
  "windows": [
    {
      "panes": [
        {
          "shell_command": [
            "echo hello",
            "echo 'this pane should be selected on load'"
          ], 
          "focus": true
        }, 
        {
          "shell_command": [
            "cd /var/log", 
            "echo hello"
          ]
        }
      ], 
      "window_name": "attached window on load", 
      "focus": true
    }, 
    {
      "panes": [
        "pane", 
        {
          "shell_command": [
            "echo 'this pane should be focused, when window switched to first time'"
          ], 
          "focus": true
        }, 
        "pane"
      ], 
      "shell_command_before": "cd /var/www", 
      "window_name": "second window"
    }
  ], 
  "session_name": "focus window and pane when loading sessions"
}

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.

session_name: suppress
suppress_history: false
windows:
  - window_name: appended
    focus: true
    suppress_history: false
    panes:
      - echo "window in the history!"

  - window_name: suppressed
    suppress_history: true
    panes:
      - echo "window not in the history!"

  - window_name: default
    panes:
      - echo "session in the history!"

  - window_name: mixed
    suppress_history: false
    panes:
      - shell_command:
          - echo "command in the history!"
        suppress_history: false
      - shell_command:
          - echo "command not in the history!"
        suppress_history: true
      - shell_command:
          - echo "window in the history!"
{
  "windows": [
    {
      "panes": [
        "echo 'window in the history!'"
      ],
      "focus": true,
      "suppress_history": false,
      "window_name": "appended"
    },
    {
      "panes": [
        "echo 'window not in the history!'"
      ],
      "suppress_history": true,
      "window_name": "suppressed"
    },
    {
      "panes": [
        "echo 'session in the history!'"
      ],
      "window_name": "default"
    },
    {
      "panes": [
        {
          "shell_command": "echo 'command in the history!'",
	  "suppress_history": false
        },
	{
	  "shell_command": "echo 'command not in the history!'",
	  "suppress_history": true
	},
	{
	  "shell_command": "echo 'window not in the history!'"
	}
      ],
      "suppress_history": true,
      "window_name": "mixed"
    }
  ],
  "suppress_history": false,
  "session_name": "suppress"
}

Skip command execution

See more at Skip command execution.

Note

Experimental setting: behavior and api is subject to change until stable.

Added in version 1.10.0: enter: false option. Pane-level support.

Omit sending enter to key commands. Equivalent to send_keys(enter=False).

session_name: Skip command execution (command-level)
windows:
  - panes:
      - shell_command:
          # You can see this
          - echo "___$((11 + 1))___"
          # This is skipped
          - cmd: echo "___$((1 + 3))___"
            enter: false
{
  "session_name": "Skip command execution (command-level)",
  "windows": [
    {
      "panes": [
        {
          "shell_command": [
            "echo \"___$((11 + 1))___\"",
            {
              "cmd": "echo \"___$((1 + 3))___\"",
              "enter": false
            }
          ]
        }
      ]
    }
  ]
}
session_name: Skip command execution (pane-level)
windows:
  - panes:
      - shell_command: echo "___$((1 + 3))___"
        enter: false
      - shell_command:
          - echo "___$((1 + 3))___"\;
          - echo "___$((1 + 3))___"
        enter: false
{
  "session_name": "Skip command execution (pane-level)",
  "windows": [
    {
      "panes": [
        {
          "shell_command": "echo \"___$((1 + 3))___\"",
          "enter": false
        },
        {
          "shell_command": [
            "echo \"___$((1 + 3))___\"\\;",
            "echo \"___$((1 + 3))___\""
          ],
          "enter": false
        }
      ]
    }
  ]
}

Pausing commands

Note

Experimental setting: behavior and api is subject to change until stable.

Added in version 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) is not implemented yet.

Omit sending enter to key commands. Equivalent to having a time.sleep before and after 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).

session_name: virtualenv
shell_command_before:
  # - cmd: source $(poetry env info --path)/bin/activate
  # - cmd: source `pipenv --venv`/bin/activate
  - cmd: source .venv/bin/activate
    sleep_before: 1
    sleep_after: 1
windows:
  - panes:
      - shell_command:
          - ./manage.py runserver
session_name: Pause / skip command execution (command-level)
windows:
  - panes:
      - shell_command:
          # Executes immediately
          - echo "___$((11 + 1))___"
          # Delays before sending 2 seconds
          - cmd: echo "___$((1 + 3))___"
            sleep_before: 2
          # Executes immediately
          - cmd: echo "___$((1 + 3))___"
          # Pauses 2 seconds after
          - cmd: echo "Stuff rendering here!"
            sleep_after: 2
          # Executes after earlier commands (after 2 sec)
          - cmd: echo "2 seconds later"
{
  "session_name": "Pause / skip command execution (command-level)",
  "windows": [
    {
      "panes": [
        {
          "shell_command": [
            "echo \"___$((11 + 1))___\"",
            {
              "cmd": "echo \"___$((1 + 3))___\"",
              "sleep_before": 2
            },
            {
              "cmd": "echo \"___$((1 + 3))___\""
            },
            {
              "cmd": "echo \"Stuff rendering here!\"",
              "sleep_after": 2
            },
            {
              "cmd": "echo \"2 seconds later\""
            }
          ]
        }
      ]
    }
  ]
}
session_name: Pause / skip command execution (pane-level)
windows:
  - panes:
      - # Wait 2 seconds before sending all commands in this pane
        sleep_before: 2
        shell_command:
          - echo "___$((11 + 1))___"
          - cmd: echo "___$((1 + 3))___"
          - cmd: echo "___$((1 + 3))___"
          - cmd: echo "Stuff rendering here!"
          - cmd: echo "2 seconds later"
{
  "session_name": "Pause / skip command execution (pane-level)",
  "windows": [
    {
      "panes": [
        {
          "sleep_before": 2,
          "shell_command": [
            "echo \"___$((11 + 1))___\"",
            {
              "cmd": "echo \"___$((1 + 3))___\""
            },
            {
              "cmd": "echo \"___$((1 + 3))___\""
            },
            {
              "cmd": "echo \"Stuff rendering here!\""
            },
            {
              "cmd": "echo \"2 seconds later\""
            }
          ]
        }
      ]
    }
  ]
}

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.

session_name: Window index example
windows:
  - window_name: zero
    panes:
      - echo "this window's index will be zero"
  - window_name: five
    panes:
      - echo "this window's index will be five"
    window_index: 5
  - window_name: one
    panes:
      - echo "this window's index will be one"
{
  "windows": [
    {
      "panes": [
        "echo \"this window's index will be zero\""
      ],
      "window_name": "zero"
    },
    {
      "panes": [
        "echo \"this window's index will be five\""
      ],
      "window_index": 5,
      "window_name": "five"
    },
    {
      "panes": [
        "echo \"this window's index will be one\""
      ],
      "window_name": "one"
    }
  ],
  "session_name": "Window index example"
}

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.

session_name: Pane shell example
windows:
  - window_name: first
    window_shell: /usr/bin/python2
    layout: even-vertical
    suppress_history: false
    options:
      remain-on-exit: true
    panes:
      - shell: /usr/bin/python3
        shell_command:
          - print('This is python 3')
      - shell: /usr/bin/vim -u none
        shell_command:
          - iAll panes have the `remain-on-exit` setting on.
          - When you exit out of the shell or application, the panes will remain.
          - Use tmux command `:kill-pane` to remove the pane.
          - Use tmux command `:respawn-pane` to restart the shell in the pane.
          - Use <Escape> and then `:q!` to get out of this vim window. :-)
      - shell_command:
          - print('Hello World 2')
      - shell: /usr/bin/top
{
  "session_name": "Pane shell example",
  "windows": [
    {
      "window_name": "first",
      "window_shell": "/usr/bin/python2",
      "layout": "even-vertical",
      "suppress_history": false,
      "options": {
        "remain-on-exit": true
      },
      "panes": [
        {
          "shell": "/usr/bin/python3",
          "shell_command": [
            "print('This is python 3')"
          ]
        },
        {
          "shell": "/usr/bin/vim -u none",
          "shell_command": [
            "iAll panes have the `remain-on-exit` setting on.",
            "When you exit out of the shell or application, the panes will remain.",
            "Use tmux command `:kill-pane` to remove the pane.",
            "Use tmux command `:respawn-pane` to restart the shell in the pane.",
            "Use <Escape> and then `:q!` to get out of this vim window. :-)"
          ]
        },
        {
          "shell_command": [
            "print('Hello World 2')"
          ]
        },
        {
          "shell": "/usr/bin/top"
        }
      ]
    }
  ]
}

Set tmux options

Works with global (server-wide) options, session options and window options.

Including automatic-rename, default-shell, default-command, etc.

session_name: test window options
start_directory: "~"
global_options:
  default-shell: /bin/sh
  default-command: /bin/sh
options:
  main-pane-height: ${MAIN_PANE_HEIGHT} # works with env variables
windows:
  - layout: main-horizontal
    options:
      automatic-rename: on
    panes:
      - shell_command:
          - man echo
        start_directory: "~"
      - shell_command:
          - echo "hey"
      - shell_command:
          - echo "moo"
{
  "windows": [
    {
      "panes": [
        {
          "shell_command": [
            "man echo"
          ], 
          "start_directory": "~"
        }, 
        {
          "shell_command": [
            "echo \"hey\""
          ]
        }, 
        {
          "shell_command": [
            "echo \"moo\""
          ]
        }
      ], 
      "layout": "main-horizontal", 
      "options": {
        "automatic-rename": true
      }
    }
  ], 
  "session_name": "test window options", 
  "start_directory": "~", 
  "global_options": {
    "default-shell": "/bin/sh", 
    "default-command": "/bin/sh"
  }, 
  "options": {
    "main-pane-height": "${MAIN_PANE_HEIGHT}"
  }
}

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.

session_name: 2-pane-synchronized
windows:
  - window_name: Two synchronized panes
    panes:
      - ssh server1
      - ssh server2
    options_after:
      synchronize-panes: on
{
  "session_name": "2-pane-synchronized",
  "windows": [
    {
      "window_name": "Two synchronized panes",
      "panes": [
        "ssh server1",
        "ssh server2"
      ],
      "options_after": {
        "synchronize-panes": true
      }
    }
  ]
}

Main pane height

Percentage

Added in version 1.46.0: Before this, tmuxp layouts would not detect the terminal’s size.

session_name: main-pane-height
start_directory: "~"
windows:
  - layout: main-horizontal
    options:
      main-pane-height: 67%
    panes:
      - shell_command:
          - top
        start_directory: "~"
      - shell_command:
          - echo "hey"
      - shell_command:
          - echo "moo"
    window_name: my window name
{
  "windows": [
    {
      "panes": [
        {
          "shell_command": [
            "top"
          ], 
          "start_directory": "~"
        }, 
        {
          "shell_command": [
            "echo \"hey\""
          ]
        }, 
        {
          "shell_command": [
            "echo \"moo\""
          ]
        }
      ], 
      "layout": "main-horizontal", 
      "options": {
        "main-pane-height": "67%"
      }, 
      "window_name": "editor"
    }
  ], 
  "session_name": "main pane height", 
  "start_directory": "~"
}

Rows

session_name: main-pane-height
start_directory: "~"
windows:
  - layout: main-horizontal
    options:
      main-pane-height: 30
    panes:
      - shell_command:
          - top
        start_directory: "~"
      - shell_command:
          - echo "hey"
      - shell_command:
          - echo "moo"
    window_name: my window name
{
  "windows": [
    {
      "panes": [
        {
          "shell_command": [
            "top"
          ], 
          "start_directory": "~"
        }, 
        {
          "shell_command": [
            "echo \"hey\""
          ]
        }, 
        {
          "shell_command": [
            "echo \"moo\""
          ]
        }
      ], 
      "layout": "main-horizontal", 
      "options": {
        "main-pane-height": 30
      }, 
      "window_name": "editor"
    }
  ], 
  "session_name": "main pane height", 
  "start_directory": "~"
}

Super-advanced dev environment

session_name: tmuxp
start_directory: ./ # load session relative to config location (project root).
shell_command_before:
- uv virtualenv --quiet > /dev/null 2>&1 && clear
windows:
- window_name: tmuxp
  focus: True
  layout: main-horizontal
  options:
    main-pane-height: 67%
  panes:
  - focus: true
  - pane 
  - make watch_mypy
  - make watch_test
- window_name: docs
  layout: main-horizontal
  options:
    main-pane-height: 67%
  start_directory: docs/
  panes:
  - focus: true
  - pane
  - pane
  - make start
{
  "session_name": "tmuxp",
  "start_directory": "./",
  "shell_command_before": [
    "uv virtualenv --quiet > /dev/null 2>&1 && clear"
  ],
  "windows": [
    {
      "window_name": "tmuxp",
      "focus": true,
      "layout": "main-horizontal",
      "options": {
        "main-pane-height": "67%"
      },
      "panes": [
        {
          "focus": true
        },
        "pane",
        "make watch_mypy",
        "make watch_test"
      ]
    },
    {
      "window_name": "docs",
      "layout": "main-horizontal",
      "options": {
        "main-pane-height": "67%"
      },
      "start_directory": "docs/",
      "panes": [
        {
          "focus": true
        },
        "pane",
        "pane",
        "make start"
      ]
    }
  ]
}

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

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 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):

session_name: my session
before_script: ./bootstrap.py
# ... the rest of your workspace
{
    "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)

session_name: another example
before_script: /absolute/path/this.sh # abs path to shell script
# ... the rest of your workspace
{
    "session_name": "my session",
    "before_script": "/absolute/path/this.sh"
}

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.

$ 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

Added in version 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:

# 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:

# 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

Kung fu

Note

tmuxp sessions can be scripted in python. The first way is to use the ORM in the API Reference. The second is to pass a dict into WorkspaceBuilder with a correct schema. See: tmuxp.validation.validate_schema().

Add yours? Submit a pull request to the github site!