---
purpose: Document the managed tmux workflow, bindings, and integrations.
applies_to: Configuring or troubleshooting this repository's tmux module.
entrypoint: modules/shell/tmux/default.nix and config/tmux/config.
verification: Run hey check and exercise the documented binding.
update_when: Tmux behavior, bindings, integrations, or recovery steps change.
---

# Tmux Module

Terminal multiplexer with custom XDG path support, plugin management, and Catppuccin theme.

## Installation

Enable in host config:

```nix
modules.shell.tmux.enable = true;
```

## What This Module Provides

- **Custom wrapper script:** XDG path support + env var fallbacks for Ghostty
- **Plugin integration:** copycat, prefix-highlight, yank, opencode-status, opencode-integrated
- **Opensessions integration (optional):** declarative sidebar bootstrap + keybinding handoff
- **Jmux integration (optional):** popup launcher + Ghostty startup handoff
- **Theme configuration:** Catppuccin with auto-hide status bar
- **Shell integration:** tmuxifier initialization, aliases

## Files

| Source           | Destination                | Purpose                                                                                   |
| ---------------- | -------------------------- | ----------------------------------------------------------------------------------------- |
| `config/tmux/*`  | `~/.config/tmux/`          | Config, theme, scripts                                                                    |
| (auto-generated) | `~/.tmux.conf`             | Compatibility shim for tools that hardcode it (e.g. jmux); only when `jmux.enable = true` |
| (auto-generated) | `~/.config/tmux/extraInit` | Plugin loading, window-name config                                                        |

## Configuration Options

```nix
modules.shell.tmux = {
  enable = true;
  rcFiles = [
    "${configDir}/tmux/theme.conf"
    "${configDir}/tmux/cmux-concept.conf"
  ];
  opensessions.enable = true;
  jmux.enable = false;                            # set true to use jmux integration
};
```

Default behavior includes the cmux-inspired snippet (`cmux-concept.conf`).
Theme config loads BEFORE plugins (required for prefix-highlight placeholder replacement).

### Opensessions (optional)

Enable the declarative integration with:

```nix
modules.shell.tmux.opensessions.enable = true;
```

When enabled, the module syncs an upstream opensessions checkout into `~/.local/share/opensessions/current`, bootstraps dependencies with bun, and loads the sidebar from `extraInit`.

opensessions now includes a native Pi watcher upstream, so this module only links local supplemental watchers (currently `hunk.js`).

The module also seeds a writable `~/.config/opensessions/config.json` (if missing) with Emdash-like defaults:

- left-side sidebar (`"sidebarPosition": "left"`)
- Catppuccin theme (`"theme": "catppuccin-mocha"`)
- pane/window detail rows enabled (`"showWindowDetails": true`)

opensessions keeps its native `prefix o` command table (`s` to focus, `t` to toggle, `1-9` to jump). For discoverability, tmux-which-key also exposes an `opensessions` submenu on `prefix Space o`.

### Jmux (optional)

Enable optional jmux integration with:

```nix
modules.shell.tmux.jmux.enable = true;
```

When enabled, the module:

- writes `~/.config/tmux/open-jmux.sh` with a Ghostty-safe PATH
- writes `~/.config/tmux/jmux.conf` and appends it after the base tmux config
- writes a compatibility `~/.tmux.conf` shim so jmux can read your XDG tmux config
- writes `~/.config/jmux/config.json` when `modules.shell.tmux.jmux.configFile` is set
- makes Ghostty launch jmux on startup instead of the plain `tmux new-session -A -s home`
- can point `modules.shell.tmux.jmux.package` at `pkgs.my.jmux` so jmux uses the same `C-c` prefix as the rest of this tmux setup
- with `pkgs.my.jmux`, `prefix n` stays tmux `next-window`, while jmux's new session/worktree prompt moves to `prefix M`
- the base tmux config explicitly leaves direct `prefix M` unbound so jmux can consume it cleanly; pane swap-to-master remains on `prefix Space p m`

## Dev Layouts (tml)

The `sesh` module provides tmux dev layouts via shell functions:

```
┌──────────────────┬─────────┐
│                  │         │
│    AI tool       │ lazygit │
│    (70%)         │  (30%)  │
│                  │         │
├──────────────────┴─────────┤
│         shell (15%)        │
└────────────────────────────┘
```

| Command     | Layout                     |
| ----------- | -------------------------- |
| `tml <cmd>` | Any tool + lazygit + shell |
| `nic`       | pi + lazygit + shell       |
| `nicx`      | opencode + lazygit + shell |

Enable with `modules.shell.sesh.enable = true;`.

## Plugins

| Plugin                  | Description                                                       |
| ----------------------- | ----------------------------------------------------------------- |
| **copycat**             | Enhanced search (regex, files, URLs, git hashes)                  |
| **prefix-highlight**    | Visual prefix key indicator in status bar                         |
| **yank**                | System clipboard integration                                      |
| **opencode-status**     | AI agent activity: ○ idle, ● busy, ◉ waiting, ✗ error, ✔ finished |
| **opencode-integrated** | Smart naming + OpenCode status                                    |
| **opensessions**        | Sidebar + command-table session switcher                          |

## tmux-opencode-integrated Behavior

Custom icon mappings for common programs:

| Icon | Programs            |
| ---- | ------------------- |
| `OC` | opencode            |
| `CC` | claude              |
| `V`  | vim, nvim, vi       |
| `G`  | git                 |
| `JJ` | jjui                |
| `λ`  | zsh, bash, sh, fish |

Settings:

- Uses `~` for home directory abbreviation
- Max window name length: 24 chars
- Shows directory for: nvim, vim, git, jjui, opencode, claude
- Auto-detects node-based AI agents (opencode, claude)

## Keybindings

Prefix is **`C-c`** (Ctrl+c), not `C-b`.

### Windows & Sessions

| Key     | Action                                         |
| ------- | ---------------------------------------------- |
| `c`     | New window                                     |
| `A`     | New Pi window here                             |
| `X`     | Kill window                                    |
| `x`     | Kill pane                                      |
| `q`     | Kill session                                   |
| `Q`     | Kill server                                    |
| `n/C-n` | Next window                                    |
| `p/C-p` | Previous window                                |
| `S`     | Choose session (when opensessions is disabled) |
| `W / .` | Choose window                                  |
| `/`     | Choose session                                 |
| `t`     | Session picker (sesh + fzf)                    |

### Project & Worktree (tmux-which-key)

Open tmux-which-key with `prefix Space`, then:

| Key path | Action                                     |
| -------- | ------------------------------------------ |
| `P p`    | Attach/create current project session      |
| `P w`    | Create sibling worktree via `tw`           |
| `P h`    | Open Agent + Hunk sessions                 |
| `P x`    | Remove sibling worktree via `twd`          |
| `I`      | Open the fast live Pi sessions picker      |
| `A`      | Start a new Pi window in current pane path |

#### Agent + Hunk session recovery

`prefix Z` and `prefix Space P h` open the same picker:

| Runtime  | New session command | Native resume ownership                     |
| -------- | ------------------- | ------------------------------------------- |
| OMP      | `omp`               | OMP JSONL via `omp --cwd … --resume …`      |
| Pi       | `pi`                | Pi JSONL via `pi --session …`               |
| Hermes   | `hermes`            | Hermes database via `hermes --resume …`     |
| OpenCode | `opencode`          | OpenCode service via `opencode --session …` |

The picker lists new sessions, resumable native session history, and live Active windows across repository worktrees. Conversation transcripts remain owned by each runtime; Hunk persists only the latest reloadable review source for each worktree.

Choosing Active focuses the matching window, preserves its live agent pane, and recreates a missing or dead Hunk pane from that worktree's saved review source. Choosing history after the whole window was lost resumes the selected runtime conversation and reopens Hunk on the same saved source. If the installed Hunk lacks resume support, recovery falls back to a normal worktree diff.

### Panes

| Key         | Action                                            |
| ----------- | ------------------------------------------------- |
| `v`         | Split horizontal                                  |
| `s / V`     | Split vertical (`V` when opensessions is enabled) |
| `h/j/k/l`   | Navigate panes                                    |
| `H/J/K/L`   | Swap panes                                        |
| `Space p m` | Swap to master                                    |
| `o`         | Zoom pane                                         |
| `< / >`     | Resize left/right (10)                            |
| `+ / -`     | Resize down/up (5)                                |
| `=`         | Break pane to new window                          |
| `_`         | Join pane                                         |
| `C-w`       | Last pane                                         |

### Splits & Tools

| Key   | Action                                                                |
| ----- | --------------------------------------------------------------------- |
| `u`   | Split vertical + jjui                                                 |
| `U`   | Split horizontal + jjui                                               |
| `C`   | Prompt: run command in new split                                      |
| `Z`   | Open Agent + Hunk sessions                                            |
| `g`   | Git TUI popup                                                         |
| `G`   | Critique (diff review) popup                                          |
| `R`   | Critique (staged diff) popup                                          |
| `]`   | Hunk (diff review) in persistent right pane                           |
| `}`   | Hunk (staged diff) in persistent right pane                           |
| `{`   | Hunk (committed-on-branch) in persistent right pane                   |
| `g h` | Hunk (diff review) in right pane (tmux-which-key Git submenu)         |
| `g H` | Hunk (staged diff) in right pane (tmux-which-key Git submenu)         |
| `g c` | Hunk (committed-on-branch) in right pane (tmux-which-key Git submenu) |
| `O`   | Opensessions config popup                                             |
| `f`   | File picker popup                                                     |
| `F`   | File picker (git root) popup                                          |
| `D`   | Directory picker popup                                                |
| `z`   | Zoxide picker popup                                                   |
| `d`   | Zoxide dir-only picker popup                                          |

### Opensessions Sidebar (when enabled)

| Key     | Action                                 |
| ------- | -------------------------------------- |
| `s`     | Toggle sidebar                         |
| `S`     | Focus sidebar                          |
| `o`     | Enter opensessions command table       |
| `o 1-9` | Jump directly to visible session slots |

### Copy Mode & Misc

| Key         | Action                      |
| ----------- | --------------------------- |
| `Enter`     | Enter copy mode             |
| `b`         | List paste buffers          |
| `B`         | Choose paste buffer         |
| `P`         | Paste from system clipboard |
| `i`         | Beads capture popup         |
| `m`         | Task note capture popup     |
| `Space n n` | Daily note popup            |
| `e`         | Beads explore (cwd) popup   |
| `E`         | Beads explore (home) popup  |
| `r`         | Reload config               |

### Vim-aware Navigation (no prefix)

| Key   | Action                                     |
| ----- | ------------------------------------------ |
| `C-h` | Left (passed to vim if in vim)             |
| `C-j` | Down (passed to vim/pi if in vim or agent) |
| `C-k` | Up (passed to vim if in vim)               |
| `C-l` | Right (passed to vim if in vim)            |
| `C-\` | Last pane (passed to vim if in vim)        |

## Aliases

| Alias  | Command            | Description                                                      |
| ------ | ------------------ | ---------------------------------------------------------------- |
| `tp`   | `tmproj`           | Attach/create project session                                    |
| `piw`  | (function)         | Create a `.pi/worktrees` checkout, `cd`, then run Pi             |
| `pir`  | (function)         | Review `origin/main` by default, or check out a PR and review it |
| `ta`   | `tmux attach`      | Attach to session                                                |
| `tl`   | `tmux ls`          | List sessions                                                    |
| `tmx`  | (function)         | Bootstrap/switch project session (`code/test/logs/ops`)          |
| `tf`   | `tmux find-window` | Find window (inside tmux)                                        |
| `mine` | `tmux detach -a`   | Detach other clients                                             |
| `tn`   | (function)         | Create new session                                               |
| `tt`   | (function)         | Send command to next window                                      |
| `tdup` | (function)         | Start grouped session                                            |

`piw -- "prompt"` is the shortcut for an auto-named worktree plus an initial Pi prompt.

`pir` with no PR number reviews the current checkout against `origin/main`.

## Theme Features

- **Catppuccin** color scheme
- **Auto-hide status bar:** Status bar hides when only one window exists
- **Prefix highlight:** Visual feedback when prefix key is pressed

## Troubleshooting

### Environment variables not set (Ghostty)

Ghostty launches with `--noprofile --norc`, bypassing shell initialization. The wrapper script provides fallback defaults for `TMUX_HOME`, `DOTFILES`, and `DOTFILES_BIN`.

### tmuxifier not in PATH

Restart shell after `hey rebuild` to pick up `$TMUXIFIER/bin` in PATH.

### Plugins not loading

Check that `extraInit` exists and is sourced:

```bash
cat ~/.config/tmux/extraInit
```

Theme must load before prefix-highlight plugin. Verify `rcFiles` order in module config.
