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 - —
⏳**shells** — turn finished, but background shells 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 or finish a build.
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 hooks are snapshotted at session start and nothing reloads them, and why pgrep silently returns nothing inside a hook while ps works.