An open API service indexing awesome lists of open source software.

https://github.com/binaryphile/tmux-claude

A TPM-installable tmux plugin: session manager + coordinator for multiple Claude Code panes (single host, multi-tmux-session, optional cross-host via era inbox streams)
https://github.com/binaryphile/tmux-claude

Last synced: 14 days ago
JSON representation

A TPM-installable tmux plugin: session manager + coordinator for multiple Claude Code panes (single host, multi-tmux-session, optional cross-host via era inbox streams)

Awesome Lists containing this project

README

          

# tmux-claude

A tmux plugin that turns tmux into a session manager and coordinator for
multiple Claude Code panes.

## Why

tmux is great at managing panes. Claude Code is great at being in a pane.
But the seams aren't quite right:

- A claude pane crashes, you reboot, you restart tmux — your sessions are
gone. tmux-resurrect can bring back the *pane* but not the *Claude
session attached to it*.
- You have 6 claude panes running across 3 projects. Which one is waiting
for you? Which is mid-flow? You alt-tab through them all to find out.
- You want claude-A in pane 0 to send a status ping to claude-B in pane
3, both working on the same epic. There's no in-tmux primitive for
that.

tmux-claude is the in-tmux glue for these jobs. It does:

- **Session restore with the right `--resume `** for each pane,
derived from `~/.claude/projects//.jsonl`.
- **Status indicators** — pane border / status-bar color reflects whether
Claude is idle, working, or waiting for operator input.
- **Labeled spawn** — `tmux-claude spawn [label]` creates a new
claude pane in a project with an optional role label (auto-generated A..Z
if omitted; collision-rejected against currently-active labels).
- **Cross-pane messaging** (when `era`/`evtctl` are installed) — one
claude can send another a message via the inbox-stream pattern.

## Status

**UC1 (View Pane Topology) + UC3 (Spawn Labeled Pane) + UC4 (Identify
Waiting Pane) + UC5 (Switch Focus to Next Waiting Pane) shipped.** See
`docs/use-cases.md` for behavioral contracts and `docs/design.md` for
mechanisms. Remaining UCs (restore, messaging, snapshot, label rename/
remove, ambient state indicators) are queued; see `CLAUDE.md` for scope
tiers.

## Usage

```bash
# from anywhere inside a tmux session with tmux-claude on PATH:
tmux-claude topology # render the topology
tmux-claude next-waiting # jump focus to the next pane in `waiting` state
tmux-claude spawn [label] # create a new claude pane in , with optional label
```

Topology output (state and AGE driven by UC4's projection over Claude Code hook events):

```
PANE PROJECT SESSION LABEL STATE AGE
%3 sofdevsim-2026 04828084-ca16-4400-af2d-86392a1efeab — working 12s
%4 tmux-claude b9c81921-26ac-448b-8be3-2204cb4d15bc — waiting 3m
%5 era 1beae198-5024-47bb-9065-c4aa5c6c7898 — n/a
```

State vocabulary: `working` (claude mid-turn), `waiting` (turn ended /
permission needed → operator action expected), `` (no recent
state event observed for this session_id, or state knowledge is stale).

`—` (em-dash) in the LABEL column means no label is bound to that
session_id; running `tmux-claude spawn [label]` is the way
to bind one.

### Spawning labeled panes (UC3)

```bash
tmux-claude spawn ~/projects/era era-A # explicit label
tmux-claude spawn ~/projects/jeeves # auto-label (first unused letter A..Z)
```

The spawn flow: validate the project directory, check `claude` is on
PATH, allocate the label (collision-rejected; auto-generated if not
supplied), `tmux new-window` in the project, poll for the new claude
session's `.jsonl` (up to `TMUX_CLAUDE_SPAWN_TIMEOUT`), publish a
`label-assigned` event that UC1's topology view consumes. Any
post-spawn failure (timeout, ambiguous attribution under concurrent
.jsonl creation, era publish error) kills the newly-spawned window so
no partially-labeled pane is left behind (UC3 Minimum Guarantee).

### Configuration knobs

| Env var | Default | Meaning |
|---|---|---|
| `TMUX_CLAUDE_STALE_SECONDS` | `3600` | After this many seconds without a state-changing hook event, the state collapses to ``. Set to `0` to disable (states persist indefinitely). |
| `TMUX_CLAUDE_SPAWN_TIMEOUT` | `10` | Seconds the spawn command polls for the new claude session's `.jsonl` before timing out. Non-integer or negative treated as default; `0` disables (immediate timeout — useful for debugging). |

## Keybinding

When loaded via TPM (or `tmux run-shell ~/path/to/tmux-claude.tmux`), the
plugin binds:

| Key | Action |
|---|---|
| `prefix + ?` | Show topology in a `display-popup` (tmux ≥ 3.0; falls back to `display-message` on older tmux) |
| `prefix + N` | Jump focus to the next claude pane in `waiting` state. Round-robins through waiting panes in numeric pane-id order (`%2` before `%10`), starting after the currently-focused pane with wrap-around. `display-message` reports edge cases (no waiting panes; only the current pane is waiting; target pane vanished). |

## Install

Via [TPM](https://github.com/tmux-plugins/tpm):

```tmux
set -g @plugin 'binaryphile/tmux-claude'
```

Then `prefix + I` to install. TPM clones the plugin into
`~/.tmux/plugins/tmux-claude/` and runs `tmux-claude.tmux` via
`tmux run-shell`.

Manual install:

```bash
git clone https://github.com/binaryphile/tmux-claude ~/.tmux/plugins/tmux-claude
echo 'run-shell ~/.tmux/plugins/tmux-claude/tmux-claude.tmux' >> ~/.tmux.conf
tmux source-file ~/.tmux.conf
```

(The `.tmux` file is a bash script — TPM and tmux's `run-shell` execute
it; `source-file` would attempt to parse it as a tmux config and fail.)

## License

TBD.