“Send this to main” resolves to whichever session answers to that name first, and in a fleet that’s rarely the one you meant.
A name feels like it should be enough to pick out one thing. In a single project, with one agent running, “send this to main” has exactly one possible meaning. The moment there’s more than one project running more than one session — which happens quickly once agents are cheap enough to run in parallel — the same instruction stops having one answer, and nothing about the instruction itself changes to warn you.
The reason is structural, not accidental. Names get reused across repositories because they’re descriptive and short — “main,” “builder,” “reviewer” — and the same task identifier can exist in two different repos at once, produced independently by two different planning passes that had no reason to know about each other. I’ve had the same task number active in two unrelated projects on the same day, generated by two separate backlog tools that share nothing but a naming convention, and neither had any way of knowing the other existed. The same collision shows up one level down, in branch names and lane labels reused for the same reason — short and descriptive beats long and unique, right up until two short, descriptive things turn out to mean entirely different projects.
A tool that lists running agents by name, without also surfacing which repository or working directory each one belongs to, gives you a list that looks precise and isn’t. It tells you a name and whether it’s idle, and nothing about what it’s actually doing or where — which means the list answers a question nobody actually asked. Knowing that something called “main” exists and is idle tells you nothing about whether it’s the “main” relevant to the task in front of you.
The consequence isn’t a crash, which is what makes it worse than a bug that fails loudly. A message sent to the wrong session gets answered — confidently, fluently, from whatever context that session actually has, which has nothing to do with the question you meant to ask. The reply doesn’t look wrong. It looks like an answer, and if you don’t independently know it came from the wrong place, you’ll treat it as evidence about the thing you actually care about, and act on it.
I’ve stopped trusting a bare name as a target for anything that matters. I check the working path to establish which repository a session belongs to, then its current task and stable session identifier to establish which session it is. Two sessions can both be called “main”, and two processes can share a working directory while doing different things. The path supplies context; it is not a unique session address. A worktree-per-worker rule reduces accidental overlap, but it does not make a filesystem path an identity that the messaging tool can safely substitute for a session id.
This gets harder, not easier, as the fleet grows, because the instinct that “we have more agents now” should come with “so addressing needs to be looser” is backwards. More agents means more collisions, not fewer, and the fix isn’t a smarter name — it’s dropping the assumption that a name was ever a unique identifier and replacing it with something that actually is, before the first wrong-context reply gets mistaken for ground truth. A fleet that started at three agents and grew to thirty gets no warning at the crossover point — the tenth wrong-context reply looks exactly as confident as the first, which is what makes this particular failure so easy to carry for a long time without ever noticing it.
The lesson generalises past any one tool. Any system built for a fleet of agents needs an addressing scheme that survives the fleet growing, and “what a human would naturally call the thing” is a display label, not an address. Building on the display label instead of the real identity is a decision that looks fine at three agents and produces a quiet, confident wrong answer at thirty.