tmux-claude-status
livePer-window tmux tab badges for Claude Code sessions.
Demo
Five windows changing state: working, blocked on you, background shells running, ready to read.

The problem
I usually have four or five Claude Code sessions running at once, one per tmux window. A long refactor I am not waiting on, a quick question I want answered now, research I will get to in ten minutes.
The bottleneck stopped being Claude a while ago. It is me noticing which window finished. Nothing in the tab bar separates a session sitting on an answer it produced four minutes ago from one that is still thinking, or from one that has been quietly blocked on a permission prompt since I walked away.
What it does
One badge per tmux window, driven by Claude Code hooks.
- —
🔄running — prompt in flight, Claude is working - —
❓question — blocked on you: a permission prompt, a question, or an MCP dialog - —
📝plan — a plan is written and waiting for your approval - —
⚠️error — the turn died on an API error; nothing to read, it needs retrying - —
🌀loop — idle between iterations of a/loop, and will resume on its own - —
⏳shells — turn finished, but background shells or agents it started are still running - —
✅done — turn finished, nothing running, ready to read - —Only the checkmark ever clears. The rest describe live state, and looking at a window does not answer a question, approve a plan, or finish a build.
- —State is kept per pane and aggregated, so two Claude sessions split across one window do not overwrite each other.
How it is built
Two halves joined by a single tmux option, so either can be swapped. bin/claude-status is a POSIX shell state machine driven by Claude Code hooks; it sets @claude_status on the window owning the session and knows nothing about rendering. claude-status.tmux reads that option and publishes a format fragment.
Publishing a fragment rather than owning the status line is what makes it compose with any theme, and it is the only approach that works under frameworks like gpakosz that rebuild the status bar after sourcing your config.
The hooks ship as a Claude Code plugin, which removes the hardcoded absolute paths that made the original version unshareable.
- —Installs via TPM and the Claude Code plugin system
- —No dependencies beyond POSIX shell and tmux 3.1+
- —macOS and Linux
- —Test suite asserts on what a tab actually renders, active and inactive, against a clean tmux
The undocumented part
Most of what this depends on is not in the public docs. It was found by reading strings out of the Claude Code binary and running controlled experiments, then written up in the repo with the method for each claim so it can be re-checked after an upgrade.
That includes the full notification_type value set and why idle_prompt is deliberately excluded, that plugin hooks.json honours the matcher field, that settings.json hooks hot-reload into running sessions while plugin hooks do not, and why pgrep silently returns nothing inside a hook while ps works.
Two of the sharper findings came from real use: a background agent has no process for a process-tree walk to find, and tool failures and API errors fire their own events rather than the ones you would expect.