sesh
Sesh is a CLI that helps you create and manage tmux sessions quickly and easily using zoxide
About sesh
This large README is shown as a plain-text preview. Read the full README at the source
<p align="center">
<img width="256" height="256" src="https://github.com/joshmedeski/sesh/blob/main/sesh-icon.png" />
</p>
<h1 align="center">Sesh, the smart tmux session manager</h1>
<p align="center">
<a href="https://github.com/joshmedeski/sesh/actions/workflows/test.yml">
<img alt="tests" src="https://github.com/joshmedeski/sesh/actions/workflows/test.yml/badge.svg" />
</a>
<a href="https://pkg.go.dev/github.com/joshmedeski/sesh/v2">
<img alt="Go Reference" src="https://pkg.go.dev/badge/github.com/joshmedeski/sesh/v2.svg" />
</a>
<a href="https://opensource.org/licenses/MIT">
<img src="https://img.shields.io/badge/License-MIT-yellow.svg" />
</a>
</p>
<div align="center">
[English](README.md) | [简体中文](README.zh-cn.md)
</div>
Sesh is a CLI that helps you create and manage tmux sessions quickly and easily using zoxide.
- **Smart session creation** - automatically names sessions based on git repo, git remote, or directory
- **Zoxide integration** - jump to your most-used projects instantly
- **Session configuration** - define startup commands, windows, and preview commands per project in `sesh.toml`
- **Wildcard configs** - apply settings to all projects matching a glob pattern
- **Built-in picker** - interactive session selector, or integrate with fzf, television, or gum
- **Clone and connect** - clone a git repo and start a session in one step
- **Mkdir and connect** - create a new directory (relative or absolute path) and start a session in one step
- **Last session switching** - seamlessly bounce between your two most recent sessions
- **Root session navigation** - jump to the root of a git worktree or repository
- **Nerd Font icons** - display session type icons in your picker
- **Shell completions** - tab completion for Bash, Zsh, Fish, and PowerShell
> [!NOTE]
> ⭐ If you find sesh useful, please star the repo — it helps the project grow and reach more developers!
> [!TIP]
> Want to see more features and help sesh mature? Consider [sponsoring the project](https://github.com/sponsors/joshmedeski) to support ongoing development.
## Table of Contents
<table>
<tr>
<td>
- [Videos](#videos)
- [How to install](#how-to-install)
- [Shell Completion](#shell-completion)
- [Extensions](#extensions)
- [Agent skill](#agent-skill)
- [How to use](#how-to-use)
- [Recommended tmux Settings](#recommended-tmux-settings)
</td>
<td>
- [Bonus](#bonus)
- [Configuration](#configuration)
- [Contributing](#contributing)
- [Background (the "t" script)](#background-the-t-script)
- [Contributors](#contributors)
- [Star History](#star-history)
</td>
</tr>
</table>
## Videos
<table>
<tr>
<td width="50%">
<a href="https://youtu.be/-yX3GjZfb5Y?si=iFG8qNro1hmZjJFY" target="_blank">
<img src="./smart-tmux-sessions-with-sesh.jpeg" alt="Smart tmux sessions with sesh">
<p><strong>Intro from Josh Medeski (sesh's creator)</strong></p>
</a>
</td>
<td width="50%">
<a href="https://www.youtube.com/watch?v=ejdzk_L6nIk" target="_blank">
<img src="./devops-toolbox-video-thumb.jpeg" alt="DevOps Toolbox - sesh">
<p><strong>Review from DevOps Toolbox</strong></p>
</a>
</td>
</tr>
</table>
## How to install
<details>
<summary>Homebrew</summary>
To install sesh, run the following [homebrew](https://brew.sh/) command:
```sh
brew install sesh
```
</details>
<details>
<summary>Arch Linux AUR</summary>
To install sesh, run the following [yay](https://aur.archlinux.org/packages/yay) command:
```sh
yay -S sesh-bin
```
</details>
<details>
<summary>Fedora (Copr)</summary>
Sesh is available from the [buckaroogeek/Tmux_sesh](https://copr.fedorainfracloud.org/coprs/buckaroogeek/Tmux_sesh/) Copr repository (Fedora and EPEL 10):
```sh
sudo dnf copr enable buckaroogeek/Tmux_sesh
sudo dnf install tmux-sesh
```
</details>
<details>
<summary>Go</summary>
Alternatively, you can install Sesh using Go's go install command:
```sh
go install github.com/joshmedeski/sesh/v2@latest
```
This will download and install the latest version of Sesh. Make sure that your Go environment is properly set up.
</details>
<details>
<summary>Conda</summary>
To install sesh, run **one** of the following commands, depending on your setup:
- Conda/(micro)mamba users
```sh
# Replace with mamba/micromamba if required
conda -c conda-forge install sesh
```
- Pixi users
```sh
pixi global install sesh
```
</details>
<details>
<summary>Nix</summary>
See the [nix package directory](https://search.nixos.org/packages?channel=unstable&show=sesh&from=0&size=50&sort=relevance&type=packages&query=sesh) for instructions on how to install sesh through the nix platform.
</details>
**Note:** Do you want this on another package manager? [Create an issue](https://github.com/joshmedeski/sesh/issues/new) and let me know!
## Shell Completion
Sesh supports shell completion (tab completion) for Bash, Zsh, Fish, and PowerShell. This helps you discover commands, flags, and arguments by pressing the Tab key.
<details>
<summary>Bash</summary>
```sh
# Generate completion script
sesh completion bash > sesh-completion.bash
# Install system-wide (recommended)
sudo cp sesh-completion.bash /etc/bash_completion.d/
# Or install user-only
mkdir -p ~/.local/share/bash-completion/completions
cp sesh-completion.bash ~/.local/share/bash-completion/completions/sesh
# Reload your shell
source ~/.bashrc
```
</details>
<details>
<summary>Zsh</summary>
```sh
# Generate completion script
sesh completion zsh > _sesh
# Install system-wide (recommended)
sudo mkdir -p /usr/local/share/zsh/site-functions
sudo cp _sesh /usr/local/share/zsh/site-functions/
# Or install user-only
mkdir -p ~/.zsh/completions
cp _sesh ~/.zsh/completions/
echo 'fpath=(~/.zsh/completions $fpath)' >> ~/.zshrc
echo 'autoload -U compinit && compinit' >> ~/.zshrc
# Reload your shell
source ~/.zshrc
```
</details>
<details>
<summary>Fish</summary>
```sh
# Generate and install completion
sesh completion fish > ~/.config/fish/completions/sesh.fish
# Reload fish configuration
source ~/.config/fish/config.fish
```
</details>
<details>
<summary>PowerShell</summary>
```powershell
# Generate completion script
sesh completion powershell > sesh.ps1
# Create PowerShell profile directory if it doesn't exist
mkdir -p (Split-Path $PROFILE)
# Add to PowerShell profile
Add-Content $PROFILE ". /path/to/sesh.ps1"
# Reload PowerShell
& $PROFILE
```
</details>
After setting up completion, you can press Tab while typing `sesh` to see available commands, flags, and arguments.
## Extensions
## Raycast Extension
The [sesh companion extension](https://www.raycast.com/joshmedeski/sesh) for [Raycast](https://www.raycast.com/) makes it easy to use sesh outside of the terminal.
Here are limitations to keep in mind:
- tmux has to be running before you can use the extension
- The extension caches results for a few seconds, so it may not always be up to date
<a title="Install sesh Raycast Extension" href="https://www.raycast.com/joshmedeski/sesh"><img src="https://www.raycast.com/joshmedeski/sesh/[email protected]?v=1.1" height="64" alt="" style="height: 64px;"></a>
## Ulauncher Extension
For Linux users using [Ulauncher](https://ulauncher.io/) there are two extensions to use sesh outside the terminal:
- [Sesh Session Manager](https://ext.ulauncher.io/-/github-jacostag-sesh-ulauncher)
- [SESHion Manager](https://ext.ulauncher.io/-/github-mrinfinidy-seshion-manager)
Here are limitations to keep in mind for Sesh Session Manager:
- tmux has to be running before you can use the extension
## Walker launcher usage (Linux)
Create an action directly on $XDG_CONFIG_HOME/config.toml
```
[[plugins]]
name = "sesh"
prefix = ";s "
src_once = "sesh list -d -c -t -T"
cmd = "sesh connect --switch %RESULT%"
keep_sort = false
recalculate_score = true
show_icon_when_single = true
switcher_only = true
```
### For the dmenu mode you can use:
#### Fish shell:
set ssession $(sesh l -t -T -d -H | walker -d -f -k -p "Sesh sessions"); sesh cn --switch $ssession
#### Bash/Zsh:
ssession=$(sesh l -t -T -d -H | walker -d -f -k -p "Sesh sessions"); sesh cn --switch $ssession
##### For dmenu launchers replace walker -dfk with dmenu or rofi)
## Agent skill
Sesh ships an [agent skill](https://agentskills.io) that teaches coding agents to start work through sesh instead of shelling out to `tmux new-session`, `tmux new-window`, and `tmux send-keys`. An agent that has it will pick a session or a window depending on whether the work belongs to something already open, resolve names and directories across tmux, zoxide, config, and tmuxinator, reuse what's already running instead of duplicating it, and leave you where you are when the work is a background step.
Install it with the [`skills`](https://github.com/vercel-labs/skills) CLI:
```sh
# globally, for every project
npx skills add joshmedeski/sesh -g
# or into the current project only
npx skills add joshmedeski/sesh
```
It works with Claude Code, Codex, Cursor, OpenCode, and [dozens of other agents](https://github.com/vercel-labs/skills#supported-agents) — `skills add` will ask which ones to install to, or take `-a claude-code` to pick.
The skill lives at [`skills/sesh/SKILL.md`](skills/sesh/SKILL.md) and is versioned with the CLI, so `npx skills update sesh` picks up changes. To install it by hand instead, copy or symlink that file to `~/.claude/skills/sesh/SKILL.md` (or your agent's equivalent skills directory).
### How to use
### tmux for sessions
[tmux](https://github.com/tmux/tmux) is a powerful terminal multiplexer that allows you to create and manage multiple terminal sessions. Sesh is designed to make managing tmux sessions easier.
### zoxide for directories
[zoxide](https://github.com/ajeetdsouza/zoxide) is a blazing fast alternative to `cd` that tracks your most used directories. Sesh uses zoxide to manage your projects. You'll have to set up zoxide first, but once you do, you can use it to quickly jump to your most used directories.
### Basic usage
Once tmux and zoxide are setup, `sesh list` will list all your tmux sessions and zoxide results, and `sesh connect {session}` will connect to a session (automatically creating it if it doesn't exist yet). It is best used by integrating it into your shell and tmux.
#### fzf
The easiest way to integrate sesh into your workflow is to use [fzf](https://github.com/junegunn/fzf). You can use it to select a session to connect to:
```sh
sesh connect $(sesh list | fzf)
```
#### tmux + fzf
In order to integrate with tmux, you can add a binding to your tmux config (`tmux.conf`). For example, the following will bind `ctrl-a T` to open a fzf prompt as a tmux popup (using `fzf-tmux`) and using different commands to list active sessions (`sesh list -t`), configured sessions (`sesh list -c`), zoxide directories (`sesh list -z`), and find directories (`fd...`).
```sh
bind-key "T" run-shell "sesh connect \"$(
sesh list --icons | fzf-tmux -p 80%,70% \
--no-sort --ansi --border-label ' sesh ' --prompt '⚡ ' \
--header ' ^a all ^t tmux ^g configs ^x zoxide ^d tmux kill ^f find' \
--bind 'tab:down,btab:up' \
--bind 'ctrl-a:change-prompt(⚡ )+reload(sesh list --icons)' \
--bind 'ctrl-t:change-prompt(🪟 )+reload(sesh list -t --icons)' \
--bind 'ctrl-g:change-prompt(⚙️ )+reload(sesh list -c --icons)' \
--bind 'ctrl-x:change-prompt(📁 )+reload(sesh list -z --icons)' \
--bind 'ctrl-f:change-prompt(🔎 )+reload(fd -H -d 2 -t d -E .Trash . ~)' \
--bind 'ctrl-d:execute(tmux kill-session -t {2..})+change-prompt(⚡ )+reload(sesh list --icons)' \
--preview-window 'right:55%' \
--preview 'sesh preview {}'
)\""
```
You can customize this however you want, see `man fzf` for more info on the different options.
To continuously refresh previews of active tmux sessions, add `--watch` to the preview command:
```sh
--preview 'sesh preview --watch {}'
```
Watch mode polls only active tmux sessions; directory and configured-session previews still render once. The default interval is 500 milliseconds and can be changed with `--interval 100ms`.
#### Custom list formatting
`--format` lets external pickers control how each `sesh list` row is rendered without changing the default output. The following placeholders are available:
| Placeholder | Value |
| --- | --- |
| `{name}` | The normal display name, including the source icon when `--icons` is set |
| `{session}` | The raw session name |
| `{source}` | Session source (`tmux`, `config`, `zoxide`, etc.) |
| `{path}` | Session path |
| `{active_window_name}` | The active tmux window name; empty for non-tmux sessions |
| `{active_window_name_prefix}` | The active window name followed by a space, or empty when there is none |
For example, used in combination with tmux plugin [tmux-nerd-font-window-name](https://github.com/joshmedeski/tmux-nerd-font-window-name)
```sh
sesh list --icons --format '{active_window_name_prefix}{name}'
```
```text
neovim-config
sesh
dotfiles
```
To use the active-window icon *instead of* the normal tmux source icon while keeping source icons for config/zoxide/etc., exclude only the tmux source icon:
```sh
sesh list --icons --icons-exclude tmux --format '{active_window_name_prefix}{name}'
```
Foreground colors can be scoped directly in the format using `{fg:COLOR}` and `{/fg}`. This keeps presentation in the format instead of tying a color to a particular placeholder:
```sh
sesh list --icons --icons-exclude tmux \
--format '{fg:yellow}{active_window_name_prefix}{/fg}{name}'
```
Colors can be applied to any part of the row, for example:
```sh
sesh list --format '{fg:gray}{source}{/fg} {fg:bright-cyan}{active_window_name}{/fg} {name}'
```
Supported colors are `black`, `red`, `green`, `yellow`, `blue`, `magenta`, `cyan`, `white`, and their `bright-*` variants. `gray`/`grey` are aliases for `bright-black`. `--no-color` removes format color tokens as well as built-in source-icon coloring.
The active window names are fetched live in one tmux call and only when the format uses an active-window-name placeholder. A tmux lookup failure simply leaves the active-window-name placeholders empty. `--format` cannot be combined with `--json`.
`sesh list --json` reports what connecting will actually use: each session's resolved `Icon` (the same one the picker shows), its `Alias`, `AliasAutoConnect`, and `Tmuxp`, the matching `Wildcard` pattern, and `StartupCommand`, `PreviewCommand`, `WindowNames`, and `WindowConfigs` with `[[wildcard]]` and `[default_session]` fallbacks applied. tmux sessions include their live `TmuxWindows` (`Name`, `Index`, `Path`, `Active`) whether or not `[tui] show_windows` is set. Sessions under a `[[worktree]]` root include `Worktree` (`Repo`, `Number`, `Title`, `State`), with `Title` and `State` read from the issue cache that `sesh worktree list` fills; it is `null` for every other session.
Arbitrary formatted rows are display output and are not parsed back by `sesh connect`. When using fzf, keep the raw session name in a hidden field and show only the formatted field:
```sh
selected="$(
sesh list --icons --format $'{session}\t{active_window_name_prefix}{name}' |
fzf --delimiter=$'\t' --with-nth=2
)"
sesh connect "${selected%%$'\t'*}"
```
#### tmux + [television](https://github.com/alexpasmantier/television)
If you prefer to use television instead of fzf, you can add a binding to your tmux config that opens the [sesh channel](https://alexpasmantier.github.io/television/community/channels-unix/#sesh) in a tmux popup.
```sh
bind-key "T" display-popup -E -w 80% -h 70% -d '#{pane_current_path}' -T 'Sesh' tv sesh
```
Use `Ctrl-s` to cycle through the sources, and `Ctrl-d` to kill the highlighted session.
### Window management
`sesh window` (alias `w`) lets you list, switch to, and create tmux windows within a session — similar to how `sesh list` and `sesh connect` work for sessions. It's a group of subcommands:
```sh
sesh window list # list the windows of a session
sesh window connect # select a window, creating it if it doesn't exist
```
#### List windows
```sh
sesh window list # the session you're attached to
sesh window list -t work # another session
sesh window list -j # as json
```
#### Switch to an existing window by name
```sh
sesh window connect editor
```
If a window named `editor` exists in the target session, sesh selects it. If it doesn't, sesh creates it.
#### Create a new window at a directory
```sh
sesh window connect ~/projects/my-app
```
A directory argument names the window after its basename (`my-app`) and roots it there. Running it again selects the window the first run created rather than opening a duplicate.
#### Run a command in the window
```sh
sesh window connect claude -t 'second brain' -c 'claude "summarize my notes"'
```
On a **created** window the command becomes the window's process, so the window closes when it exits. On an **existing** window it's typed into whatever is already running there. Pass `--new` when every invocation should get its own fresh window instead of reusing the name.
#### Target a specific session
Use `--target` / `-t` to manage windows in a session other than the one you're attached to:
```sh
sesh window list -t work
sesh window connect ~/projects/my-app -t work
```
The target is resolved the same way `sesh connect` resolves a session — across tmux, zoxide, config, and tmuxinator — and started if it isn't running yet, without moving you out of the session you're in. Use `-b` / `--background` to create the window without being taken to it, and `-s` / `--switch` when triggering sesh from outside the terminal.
> [!NOTE]
> `sesh window <name>` and `sesh window -s <session>` were replaced by `sesh window connect <name>` and `sesh window list -t <session>`. `--session` still works as a deprecated alias for `--target`, and `-s` now means `--switch` on `sesh window connect`, consistent with `sesh connect`.
#### fzf integration
You can combine the two subcommands with fzf to interactively switch windows:
```sh
sesh window connect "$(sesh window list | fzf)"
```
Or as a tmux keybind:
```sh
bind-key "W" run-shell "sesh window connect \"$(sesh window list | fzf-tmux -p 60%,50% --prompt '🪟 ')\""
```
### Create a directory and connect
`sesh mkdir` (alias `md`) combines `mkdir` and `sesh connect` into a single step: it creates the directory if it doesn't already exist, then connects to it as a session — no need to `cd` into it first or wait for zoxide to pick it up.
```sh
sesh mkdir my-new-project
```
`<path>` accepts both **relative** paths (resolved against your current working directory) and **absolute** paths, as well as `~` for your home directory:
```sh
sesh mkdir my-new-project # relative to the current directory
sesh mkdir ~/projects/my-app # relative to your home directory
sesh mkdir /Users/josh/dev/api # absolute path
```
## gum + tmux
If you prefer to use [charmbracelet's gum](https://github.com/charmbracelet/gum) then you can use the following command to connect to a session:
```sh
bind-key "K" display-popup -E -w 40% "sesh connect \"$(
sesh list -i | gum filter --limit 1 --no-sort --fuzzy --placeholder 'Pick a sesh' --height 50 --prompt='⚡'
)\""
```
**Note:** There are less features available with gum compared to fzf, but I found its matching algorithm is faster and it has a more modern feel.
> [!WARNING]
> As of [gum v0.15.0](https://github.com/charmbracelet/gum/releases/tag/v0.15.0) you have to add the `--no-strip-ansi` in order to display the icons correctly.
See my video, [Top 4 Fuzzy CLIs](https://www.youtube.com/watch?v=T0O2qrOhauY) for more inspiration for tooling that can be integrated with sesh.
#### sesh picker
Sesh has a built-in picker that can be used as a tmux popup:
```sh
bind-key "K" display-popup -h 90% -w 50% -E "sesh picker -i"
```Frequently Asked Questions
What is sesh?
sesh is a Utilities library for the Go programming language. Sesh is a CLI that helps you create and manage tmux sessions quickly and easily using zoxide
How many GitHub stars does sesh have?
sesh has 2,868 GitHub stars in the directory's latest synchronization.
How do I install sesh?
Install sesh with the Go module system using `go get joshmedeski/sesh`. Check the repository for the current installation instructions.
What category does sesh belong to?
sesh is listed under Utilities, specifically Utilities.