I had a handful of Claude Code agents running side by side, each in its own tmux pane — think of tmux as a way to split one terminal window into several live sub-windows, each running its own program. The agents talk to each other over a little messaging protocol, and every reply gets signed with the sender’s pane id so the acknowledgment routes back to the right place. Like putting a return address on an envelope.
Except the return addresses were wrong.
I only noticed during a manual audit. Agent B would answer a question, sign the reply as if it were Agent A, and the acknowledgment would sail off to A — who had no idea what it was about. Nothing crashed. No error. Messages just quietly landed at the wrong desk, and the conversation slowly drifted out of sync.
The line I trusted was this:
tmux display -p '#{pane_id}'
Reads innocent. “Print the current pane id.” I assumed “current” meant “the pane this command is running in.” It does not. Without a -t target flag, display reports whatever pane tmux considers globally active — the one that’s focused right now. So when I clicked into another pane, or an agent grabbed focus, every agent asking “who am I?” got the same answer: the focused pane’s id. They all signed as whoever happened to be in front.
That’s the trap. The query didn’t tell an agent about itself. It told the agent about tmux’s global mood, which any other actor could change out from under it.
The fix is almost stupidly small. Tmux hands each pane its own identity in an environment variable, $TMUX_PANE, baked in at launch and never touched by focus:
echo "$TMUX_PANE"
Or if you want to go through tmux, pin the query to your own pane explicitly:
tmux display-message -t "$TMUX_PANE" -p '#{pane_id}'
The -t says “answer for this pane,” not “answer for whoever’s on stage.”
Why the bare query drifts give me the detail
display-message runs in tmux’s client/server model. With no -t, the target defaults to the session’s active pane — resolved at command time from the server’s global focus state, not from the process’s own context. $TMUX_PANE is exported into each pane’s environment at creation and is immutable for that pane’s life, so it survives focus changes, select-pane, and other clients attaching.
Quick test — run in two panes at once, then focus one:
watch -n1 'echo focus=$(tmux display -p "#{pane_id}") self=$TMUX_PANE'self stays fixed per pane; focus flips to match whoever you clicked. If your routing keys off focus, that’s your bug.
The deeper lesson outlived the tmux detail for me. A “who am I” question should be answered against the artifact you actually inhabit — the pane, the process, the request — never inferred from ambient state that some other actor can move. If another agent’s click can change your answer, you’re not asking about yourself. You’re reading the room.
So when you route between processes, pin identity to the thing that can’t drift. Ask the pane you’re in.