Added
-
An agent's title is condensed into its keywords instead of shown with the tail cut off.
MAX_TITLE_LENtakes the END off a title, which is where the words saying WHICH task this is tend to sit: "Investigate why the nightly ETL job drops rows" reached a tab as "Investigate why the nightly".TITLE_CONDENSE=1drops a leading verb and the filler and joins what is left, so the same budget carries "nightly-ETL-job-drops-rows".It selects rather than generates. The words are the agent's own, in the order it wrote them, on the reasoning that it put the salient ones first.
TITLE_LEAD_VERBSandTITLE_FILLER_WORDSare the two lists, measured against the last title Claude Code generated in each of 65 titled sessions rather than written from imagination, andTITLE_WORD_SEPARATORandTITLE_CASEsay what the surviving words are joined and cased with. A condensed label is charged toMAX_TITLE_LENlike any other, the icon glyph and its space reserved out of it first.Off by default, so a config that does not name it renders exactly what
AGENT_TITLESrendered before. A title that condenses to nothing is left as the sentence, and so is one whose label would come out longer than the prose or wearing a leading "[12]", the shape a tab number has. -
The agent is shown alongside its task,
cc:auth-flowwhere a tab readauth-flow. Which agent is on a task was not recoverable from an agent tab: every agent herdr detects draws the same robot glyph, deliberately, and a title then replaced the one place the program name appeared. That costs a session running one agent nothing, and in a session running three it is what tells two tabs apart.TITLE_STYLE=name_and_taskasks for it andPROGRAM_ALIASESapplies, since asking for the name is asking for the name you chose for it. The name and its colon are charged toMAX_TITLE_LEN, so the task gives up the characters rather than the tab growing. The prefix is all or nothing: it goes in only where the budget seats the name, its colon andMIN_TASK_LENcharacters of task, and otherwise the name is what goes, because this asks for the task with the name added rather than the other way about. The glyph and its space are part of that budget where icons are on, and an alias carrying a space is never used as a prefix, truncation having cut such a name in half and left the tab reading a fragment of it.Off by default. A refused title is not prefixed either, "cc:cc" saying nothing twice.
Fixed
-
The workspace name follows the shell's directory (#20). A
cdemits no herdr event, so a workspace kept the name of the directory it was created in until something unrelated woke the plugin, while the tab beside it moved at the next prompt. The shell hook is the one thing that does fire on a cd, and it renamed only the tab.It now names the workspace from the same prompt, by the rules the reconcile uses: the directory is the shell's own
$PWD, the base is the repository that directory belongs to or the directory itself, and a workspace somebody named by hand is numbered and nothing else. A quiet prompt costs one state read and no herdr call, since the base we own is recorded and only a cd that leaves the project has anything to ask. A workspace the plugin has not adopted is left to the next event, adopting one meaning a round-trip on every prompt.Only the tab the workspace is on moves it, since herdr tracks a workspace's directory through its active pane and a prompt drawn in a background tab is about somewhere else. Panes with no shell hook installed are unchanged, and so is the five-second wait for herdr to persist a brand-new workspace.
-
One
PROGRAM_ALIASESentry now names an agent however it was installed (#19). Two agents answer to two names,cursor-agent, which herdr callscursor, andkiro-cli, which it callskiro, and which of the two reaches naming says only how the agent was installed. A native install arrives as its own executable, an npm-fronted one as the kind herdr detected behind the runtime. Keyed by exact name, one config labelled the two panes differently:cuwhere the alias matched,cursorwhere it did not.An alias is now looked up under both spellings, the exact name first, so a config naming each separately still gets each. The pair is read off the agent list that already carries both spellings rather than out of a second table somebody would have to keep in step with it.
-
Two herdr sessions no longer share one state store (#22). Every server numbers its tabs from
w1:t1, so the plugin running underherdr --session workand the one underherdr --session homewrote the same keys into the samestate.json, and each full pass pruned the other session's tabs as closed. A tab whose record is gone reads as renamed by hand on the next pass and opts out of naming until reset, which is how a machine running more than one session ended up with every tab frozen on whatever it was called when the other session last ran, and the lock they also shared dropped events on top of that.A named session now keeps its store under
sessions/<name>/inside the state directory, resolved the way the herdr CLI picks its server: from the session directory in the socket path herdr exports to plugin commands and pane environments alike, or fromHERDR_SESSIONwhen no socket path is set, so the herdr-invoked pass and the shell hooks resolve one file. The default session keeps the store where it always was.Upgrading costs nothing in the common case. A named session's store is created once from the owned records of the old shared one, so a tab the plugin was naming goes on being named. A record the shared store got wrong, which on a multi-session machine is most of them, ends where an empty store would put it: a tab whose label matches nothing the store owns is opted out, and the reset action or clearing the label hands it back as before. Nothing removes a session's store when the session is deleted, and the old shared file stays as the default session's; both are safe to delete by hand.