Show agents in your status line
Put the agent counts in tmux’s own status line, and get the ambient state driver
in the same move. This is one line you add yourself; tma install-keys never
edits your status-right.
Add the driver
set -g status-right '#(tma status) %H:%M'
#(tma status) is not optional decoration. It is the ambient driver: it runs
every status-interval, refreshes each pane’s stamped state, and prints the
counts. Without it, ambient surfaces (window flags, per-window summaries) render
nothing, and with no daemon nothing keeps state fresh between your explicit
commands.
tma status prints state counts with glyphs and tmux color codes, which tmux
renders inline. One blocked and one working agent:
$ tma status
#[range=user|tma:blocked]#[fg=red]⚑1#[norange] #[range=user|tma:working]#[fg=yellow]●1#[norange]
The order is fixed (blocked working done idle unknown), zero-count classes are
omitted, and a server with no agents prints nothing at all, so tma adds nothing
to your status line until it has something to say. The #[range=…] markers are what make
each segment clickable; tmux draws nothing for them, and without the opt-in mouse
bindings nothing acts on them (Install the
keybindings). Glyphs and
colors come from [status] config; see
Configuration.
What a refresh costs
The driver is not a read-only renderer. Refreshing a pane’s stamped state means
tmux set-option, and tmux redraws every attached client in full on any option
write, even one whose value did not change. That is a whole-screen re-emission
rather than the single status row a plain status tick writes, so it is worth
knowing when it happens:
- An idle agent costs nothing. With nothing written to its window since its last stamp, the cycle reuses the stored verdict and issues no write at all.
- A working agent costs one redraw per cycle. Its screen keeps changing, so it is restamped every time. The stampede hint rides that same invocation instead of costing a second one.
- The status string itself is cheap. tmux skips the write when the expanded
status-rightis identical to what is already drawn, so a static string sends your terminal nothing no matter how shortstatus-intervalis. A%H:%Mclock costs one status-row write per minute, about 165 bytes.
A full redraw puts every wrapped line back through your terminal’s own wrap
logic, so a terminal that disagrees with tmux about a glyph’s width can visibly
re-wrap a pane during one. If you see that, upgrade tmux: 3.7 corrects the
redrawing of wide characters when they are overwritten and lets
codepoint-widths accept ranges. The upstream report for the agent-TUI side of
this is
anthropics/claude-code#91182.
Roll up the agents in each window
The driver also maintains a window-scoped @agent_summary option, so a
per-window rollup costs no extra process:
set -g window-status-format '#I:#W #{@agent_summary}'
Name windows after their agents
The rollup above renders beside the window name. The other option is to make it
be the window name, which is what you want when the window list is your only
view of the fleet (a narrow terminal, or a tab bar outside tmux reading
#{window_name}). This one needs the daemon, and it writes:
[daemon.window_names]
format = "{repo}:{state}"
A window with one blocked Claude in the tma checkout reads tma:blocked. The
tokens are {agent}, {state}, {detail}, {repo} and {branch}; the full
reference is in
Configuration. {state} is the
window’s highest-attention state, the same order the rollup prints in, so a
window holding a blocked agent and two working ones reads blocked.
Only windows with at least one agent pane are renamed, and only when the name
actually changes. A window whose rollup has not moved costs one read and no
write, which matters here for the reason above: a
rename-window is an option write and every one of those redraws every attached
client.
It gives the window back. On its first rename tma saves the window’s name in
@tma_window_name_orig and its automatic-rename setting in
@tma_window_autorename_orig (rename-window turns that off as a side effect,
so it has to be saved to be put back). Both are restored, and both options
dropped, when the last agent pane leaves the window or the daemon stops. Turning
the feature off and reloading (tma reload) restores them too.
It does not fight you. tma records what it last wrote in
@tma_window_name_last. Rename a window yourself and the current name no longer
matches that, so tma leaves that window alone until the next restore hands it
back.
The zero-write alternative is the window-status-format recipe above: it reads
the same rollup, costs no option write of its own, and needs no daemon. Reach for
window_names when something outside tmux’s status line has to see the state.
Scope it to one session
The counts tma status prints obey the selector
flags, so scoping the driver to the current
session is one flag:
set -g status-right '#(tma status --session #{session_name}) %H:%M'
The cheaper alternative, if all you want is counts per session, is the option the driver already maintains:
set -g status-right '#{@agent_session_summary} %H:%M'
It carries the same <state>:<count> grammar as the per-window @agent_summary,
in machine tokens rather than glyphs (see Pane options and JSON
contracts).
Two things to know before scoping the #() driver:
- tmux caches
#()jobs per expanded command string. Each distincttma status --session <name>is a separate long-lived job, so N attached sessions means Ntmaprocesses on everystatus-intervalinstead of one. That is fine for a handful of sessions and wasteful for dozens. - A filtered driver still refreshes everything. The selector narrows only what is printed; the cycle behind it stamps every agent pane on the server. So one scoped driver in one session keeps every other session fresh too.
The same holds for the other scopes: #(tma status --repo app) counts one repo’s
agents, and tma watch --repo app opens a dashboard for it.
Next
- Drive an external bar if your status bar is not tmux’s.
- Install the keybindings to make the segments clickable and put the picker on a key.
- Run the daemon for the two setups where a status-line driver alone is not enough.