pertmux ([ru]-pert multiplexer) is a unified SWE dashboard that links GitLab/GitHub MRs to local branches/worktrees, tmux sessions, and coding agent instances. It provides a real-time view of merge request status, pipeline health, worktree management, and session progress — all from a single TUI.
Features
- Multi-forge support — GitLab and GitHub MR/PR tracking with pipeline dots, comments, and unread indicators
- Worktree management — list, create, remove, and merge worktrees via worktrunk
- Multi-project support — fuzzy finder (
fkey) with overview panel showing MR counts - Smart tmux integration — focus panes across sessions, auto-detect existing windows
- Coding agent monitoring — track Claude/opencode instances across tmux panes
- MR Overview — press
mto see all your open MRs across all configured forges, with quick navigation to configured projects or browser-open for unconfigured ones - Activity feed — live log of agent state changes and MR events; press
Ato open the feed popup, navigate withj/k, and pressEnterto jump directly to the relevant tmux pane or MR - Daemon/client architecture — background daemon keeps data fresh, TUI client connects instantly via Unix socket
Architecture
┌─────────────────────────────────────────────────────────┐
│ pertmux serve │
│ (daemon) │
│ │
│ ┌─────────┐ ┌──────────┐ ┌──────────┐ ┌─────────┐ │
│ │ tmux │ │ Forge │ │ worktrunk│ │ agent │ │
│ │ poll │ │ API │ │ CLI │ │ status │ │
│ │ (2s) │ │ (60s) │ │ (30s) │ │ (2s) │ │
│ └────┬────┘ └────┬─────┘ └────┬─────┘ └────┬────┘ │
│ └─────────┬──┴─────────────┴──────────────┘ │
│ ▼ │
│ DashboardSnapshot │
│ │ │
│ Unix socket │ /tmp/pertmux-{USER}.sock │
└─────────────────┼───────────────────────────────────────┘
│ broadcast (multi-client)
┌─────────┼─────────┐
▼ ▼ ▼
┌─────────┐ ┌─────────┐ ┌─────────┐
│ connect │ │ connect │ │ connect │
│ (TUI) │ │ (TUI) │ │ (TUI) │
└─────────�� └─────────┘ └─────────┘
Setup
Prerequisites
- tmux 3.2+ (for popup support)
- worktrunk (optional) — enables the worktree management panel. Install with
cargo install worktrunkand ensurewtis on your PATH.
Install
Or build from source:
git clone https://github.com/rupert648/pertmux.git cd pertmux cargo install --path .
tmux Integration
Add to your ~/.tmux.conf for a popup overlay (recommended):
# pertmux dashboard popup (prefix+a toggles open/close) bind-key a display-popup -h 80% -w 80% -E "pertmux connect"
prefix+aopens the TUI client, connecting to the running daemonprefix+aagain closes the popup; next open reconnects instantlyq/Escquits the client (daemon keeps running)
Commands
pertmux serve # start daemon (backgrounds automatically) pertmux connect # open TUI client (connects to running daemon) pertmux stop # stop the daemon pertmux status # show socket path, daemon state pertmux --version # show version pertmux -c config.toml serve # start daemon with specific config pertmux serve --foreground # run in foreground (for debugging)
The daemon must be started before connecting. It forks to the background automatically, logging to /tmp/pertmux-daemon.log and listening on /tmp/pertmux-{USER}.sock.
Configuration
pertmux works out of the box with zero configuration for basic agent monitoring. For GitLab/GitHub MR tracking and multi-project support, create a TOML config file.
pertmux -c ./path/to/config.toml serve
If no -c flag is provided, pertmux looks for ~/.config/pertmux.toml. If that file doesn't exist, defaults are used.
Multi-project config (recommended)
[gitlab] host = "gitlab.example.com" token = "glpat-your-token-here" [github] token = "ghp_your-token-here" [[project]] name = "My App" source = "gitlab" project = "team/my-app" local_path = "/home/user/repos/my-app" username = "youruser" [[project]] name = "OSS Project" source = "github" project = "org/oss-project" local_path = "/home/user/repos/oss-project" username = "youruser"
Single-project config (backwards compatible)
[gitlab] host = "gitlab.example.com" token = "glpat-your-token-here" project = "team/my-app" local_path = "/home/user/repos/my-app" username = "youruser"
Agent-only config (no forge)
pertmux supports two coding agents: opencode and Claude Code. Enable one or both in your config.
opencode must be started with --port 0 so pertmux can query its local HTTP server for session status:
refresh_interval = 2 [agent.opencode] # db_path = "~/.local/share/opencode/opencode.db"
Claude Code requires no special flags — pertmux reads its JSONL transcript files automatically:
refresh_interval = 2 [agent.claude_code]
Config reference
| Key | Type | Default | Description |
|---|---|---|---|
refresh_interval |
integer | 2 |
How often (in seconds) to poll tmux panes |
default_agent_command |
string | — | Command to run in a split pane when focusing a worktree (e.g. "opencode") |
default_worktree_with_prompt |
string | — | Command template for creating a worktree with an injected prompt. Use {{msg}} as the placeholder (e.g. "opencode run {{msg}}"). Enables the w keybinding. |
[gitlab]
| Key | Type | Default | Description |
|---|---|---|---|
host |
string | gitlab.com |
GitLab instance hostname |
token |
string | — | Personal access token (or set PERTMUX_GITLAB_TOKEN env var) |
[github]
| Key | Type | Default | Description |
|---|---|---|---|
host |
string | github.com |
GitHub hostname (use custom host for GitHub Enterprise) |
token |
string | — | Personal access token (or set PERTMUX_GITHUB_TOKEN env var). Needs repo scope for private repos. |
[[project]]
| Key | Type | Required | Description |
|---|---|---|---|
name |
string | yes | Display name (shown in overview) |
source |
string | yes | "gitlab" or "github" |
project |
string | yes | Full project path (e.g. team/app or org/repo) |
local_path |
string | yes | Absolute path to local repo (validated at startup) |
username |
string | no | Your username (for filtering MRs/PRs to your own) |
[agent.opencode]
Including this section enables the opencode agent. Omit or comment it out to disable.
| Key | Type | Default | Description |
|---|---|---|---|
db_path |
string | ~/.local/share/opencode/opencode.db |
Path to the opencode SQLite database |
[agent.claude_code]
Including this section enables the Claude Code agent. Omit or comment it out to disable. Claude Code requires no special startup flags — pertmux reads its JSONL transcript files from ~/.claude/ automatically.
| Key | Type | Default | Description |
|---|---|---|---|
| (none currently) | — | — | No configuration options needed |
[[agent_action]]
Define custom agent actions sent to coding agent instances. When present, replaces the built-in defaults. Omit to use the two default actions (rebase, pipeline fix).
| Key | Type | Required | Default | Description |
|---|---|---|---|---|
name |
string | yes | — | Display name in the actions popup |
prompt |
string | yes | — | Prompt template (supports {target_branch}, {source_branch}, {mr_url}, {mr_iid}, {project_name}) |
requires_mr |
boolean | no | false |
If true, action is skipped when no MR is linked |
[keybindings]
Remap action keys. Navigation keys (j/k/↑/↓/Tab/Enter/Esc/q) are not configurable. Each action must have a unique key — duplicates are rejected at startup.
| Key | Type | Default | Description |
|---|---|---|---|
refresh |
string | "r" |
Refresh all data |
mr_overview |
string | "m" |
Open MR Overview popup showing all open MRs across forges |
activity_feed |
string | "A" |
Open Activity Feed popup — navigate and jump to recent events |
open_browser |
string | "o" |
Open selected MR in browser |
copy_branch |
string | "b" |
Copy selected branch name to clipboard |
filter_projects |
string | "f" |
Fuzzy filter to switch project |
create_worktree |
string | "c" |
Create new worktree |
delete_worktree |
string | "d" |
Delete selected worktree |
merge_worktree |
string | "M" |
Merge selected worktree into default branch |
open_worktree_with_prompt |
string | "w" |
Create worktree and inject a prompt into the agent (requires default_worktree_with_prompt) |
Keybindings
Navigation
| Key | Action |
|---|---|
j/k or ↑/↓ |
Navigate list |
Tab |
Toggle between MR list and worktree panel |
Enter |
Focus selected pane/worktree in tmux |
Actions (configurable)
Action keys can be remapped via the [keybindings] section in your config file. Defaults shown below.
| Key | Context | Action |
|---|---|---|
r |
Global | Refresh all data |
m |
Global | Open MR Overview — all your open MRs across forges |
A |
Global | Open Activity Feed popup — navigate recent events and jump to the relevant pane or MR |
o |
MR selected | Open MR in browser |
b |
Any | Copy selected branch name |
f |
Global | Fuzzy filter to switch project |
c |
Worktree panel | Create new worktree |
w |
Worktree panel | Create worktree and inject a prompt (requires default_worktree_with_prompt config) |
d |
Worktree panel | Delete selected worktree |
M |
Worktree panel | Merge selected worktree into default branch |
q/Esc |
Global | Quit client (daemon keeps running) |
prefix+a |
tmux | Toggle dashboard popup |
Pipeline Visualization
The pipeline job status dots in the MR detail panel are inspired by glim. Each CI/CD job is rendered as a colored dot for a compact at-a-glance view of pipeline health, grouped by stage.
