I had three Claude Code sessions running in the same project folder, and two of them were wearing each other’s names.
Claude Code is the terminal agent I use to do actual engineering work — it runs in a pane, chews through a task, and I keep several going at once. To tell them apart in my statusline (the little strip of text at the bottom of the terminal), I’d been giving each one a human-readable name like “auth-refactor” or “flaky-test-hunt.” That’s the whole story: I just wanted labels so I could glance down and know which session was which.
The way I did it was dumb in a way I didn’t see until it bit me. Each session has a UUID — a long random ID — and its transcript gets written to a file under that UUID. So to attach a name, I first had to find the session’s UUID, and the trick I used was ls -lt on the transcript directory: list files newest-first and grab the top one. The session that just wrote something is probably the one asking for a name, right?
Right, until two sessions in the same directory both write within the same breath. Then ls -lt hands you whichever transcript touched disk most recently, which may not be the session that called you. So “auth-refactor” would ask for its name and get tagged with the transcript from “flaky-test-hunt.” I confirmed two of these mismatches by hand before I believed it. It was a race — two things reaching for the same shared thing, and the loser gets corrupted.
The real problem wasn’t the naming. It was that I was inferring identity from a shared, racy filesystem. The project directory is shared by design; that’s the whole point of running several agents on one codebase. Any scheme that says “the current session is whatever file is newest here” is guessing, and guessing loses under load.
So I stopped guessing. tmux — the terminal multiplexer that owns the panes — already knows exactly which pane it’s in, because $TMUX_PANE is set inside each one. Every pane is its own isolated box. Instead of writing a file and hoping to find it again, I hang the name directly on the pane as a user-option, and the statusline reads it back from that same pane.
No UUID to discover. No directory to scan. No file I/O in the hot path at all. The pane is a stable handle that’s already unique per session, so there’s nothing to race over.
tmux pane user-options for per-session state give me the detail
Instead of ~/.claude/session-names/<uuid> plus an ls -lt guess, set an option scoped to the current pane and read it in the statusline:
# inside the session, when the name is chosen:
tmux set-option -p -t "$TMUX_PANE" @sess "auth-refactor"# in tmux.conf statusline:
set -g status-right "#{@sess}"-p scopes the option to the pane; @sess is a custom user-option (the @ prefix is required). $TMUX_PANE is set by tmux in every pane, so each session writes only to its own box. #{@sess} interpolates that pane’s value — no shared directory, no newest-file heuristic, no race.
The transferable bit: when you need per-session metadata for terminal agents, attach it to the thing that’s already stably isolated — the pane — instead of reconstructing identity from a shared surface everyone else is writing to. If you’re keying state by an ID you have to discover, that discovery step is where the race lives. Delete the step.