mirror of
https://github.com/l0ng-ai/tty7.git
synced 2026-09-21 16:02:20 +00:00
Agents animate in the terminal title while they work, and they do not agree on an alphabet: Claude Code cycles the quadrant circles and rests on an asterisk, others step through the braille frames, some write nothing at all. Rendered as they arrive, a column of tabs carries a mark in front of some rows and not others, in three vocabularies — while the row already says what the agent is doing, in one, with its status dot. So the mark comes off, for everyone, with no setting. A switch would not settle this: nobody opens settings to decide how a spinner is drawn, and a default-off toggle buys two render paths to maintain forever in order to answer a question that has one right answer per person and no way for the app to know which. **A known alphabet, not a shape.** The obvious rule — a leading character that is non-ASCII and above some code point, followed by a space — matches by shape, and `🔥 build`, or `📁 ~/repo` written by somebody's shell integration, fits it exactly and quietly loses its first character with no way to ask for it back and no clue as to what took it. Matching marks we have actually seen costs the same and cannot do that: the braille block, the four quadrant circles, and Claude Code's resting asterisk. When an agent invents a mark that is not on the list, the failure is today's behaviour — the mark stays — which is the safe direction to fail in, and adding it is a line in the table. Two things the rule insists on, both to keep it from reaching past what it is for. A mark only counts with whitespace behind it, so `✳fixing` is a word that starts with a character rather than a mark in front of one. And a title that is *only* a mark keeps it: taking it would leave an empty string, and an empty title is not a tab called nothing, it is a tab that falls back to its number — less than the mark was saying. It happens in `TabView::label`, which is where a title becomes a label, so the strip, the sidebar, the switcher and the rename box's prefill all agree without being told separately — and, because `label` reaches a given name before it reaches the title, a tab somebody deliberately called `✳ release` keeps what they called it. That ordering is the only thing standing between a user's name and a rename behind their back, so there is a test on it rather than a comment. Three existing tests carried `✳` in their fixtures and now expect it gone. The one in `switcher.rs` was asserting that a tab in another window is named the way a local one would be, which is still exactly what it asserts; the one in `tty7-cli` is the table getting this for free, since `tab_label` reads `label` and so `tty7 ls` says what the tab strip says without either being told about the other. The daemon's fixtures keep their marks on purpose: a title is stored as the terminal wrote it, and only what turns one into a label takes anything off. This leaves the row with nothing moving in it, which is a real loss and is answered separately: `AgentStatus::dot_rgb` returns three flat colours, and a `Working` dot that breathes says the same thing in the vocabulary the row already speaks.