[BUG] Terminal tab title never updates when a custom agent is pinned (--agent / settings.agent) — agentTitle suppresses topic-title generation
Summary
Any session launched with --agent <name> (or settings.agent) shows the raw agent type as its terminal tab title for the life of the session. Haiku topic-title generation never runs, so every concurrent tab reads the same constant string — exactly the case where telling tabs apart matters most.
Stock claude gets dynamic topic titles. claude --agent anything never does.
Steps to reproduce
- Define any custom agent (or use a plugin-provided one).
claude --agent my-agent, then send a normal free-text prompt.- Watch the terminal tab title: it reads
my-agentand never changes. grep '"type":"ai-title"' ~/.claude/projects/<project>/<session>.jsonl— no generated topic is ever persisted. Depending on the version you either get no record at all, or records whoseaiTitleis the agent type verbatim (see Notes).
Same session without --agent gets a topic title within the first turn.
Cause
screens/REPL.tsx:
const agentTitle = mainThreadAgentDefinition?.agentType;
const terminalTitle = sessionTitle ?? aiTitle ?? agentTitle ?? haikuTitle ?? 'Claude Code';
and the one-shot generation guard:
if (!titleDisabled && !sessionTitle && !aiTitle && !agentTitle && !haikuTitleAttemptedRef.current) {
… generateSessionTitle(firstUserMessageText) …
}
agentTitle appears in both places. Because it is truthy whenever an agent is pinned:
- generation is suppressed, so no topic title is ever produced, and
- the display falls through to
agentType, an internal namespaced identifier (my-plugin:reviewer) rather than a topic or even a display name.
agentTitle also can't be cleared in-session: the resume path re-sets it from the same pinned definition, and haikuTitleAttemptedRef latches after the first attempt.
Suggested fix
Drop agentTitle from the generation guard, keeping it as the pre-generation display fallback only:
if (!titleDisabled && !sessionTitle && !aiTitle && !haikuTitleAttemptedRef.current) { … }
The tab then shows the agent type until the title arrives, and the topic afterwards. Precedence is unchanged for everyone else.
Secondary: consider using the agent's description / display name for that fallback rung rather than the raw namespaced agentType.
Notes
- Reproduced on 2.1.221. The same guard is present in 2.1.88, so this is long-standing rather than a recent regression.
- On 2.1.205 / 2.1.206 the pinned agent type is additionally written into
ai-titletranscript records — one session here holds 22 of them, every one{"type":"ai-title","aiTitle":"woz:code"}, which is the plugin's agent type, not a generated topic. SinceaiTitleoutranksagentTitlein both the precedence chain and the generation guard, those records make the constant title survive resume even for a session that later runs a build whereagentTitleis fixed. - Model-generated naming works fine under a pinned agent — only the automatic path is blocked. In a
--agent-pinned session,/renamewith no argument immediately produces and persists a name (fix-session-title-generation-guardhere) viarename_generate_name, a separate kebab-case generator with no agent guard. Same session, same pinned agent, model naming on demand — a one-command contrast repro. - Note that under a pinned agent
/renamedoes not set a session title at all: it renames the agent instance, writingagent-namerecords that feedstandaloneAgentContext.name. That name outrankscustom-titlein the display, so a session can show the rename while itscustom-titlerecord holds something else entirely. Worth deciding whether that overload is intended — as it stands, pinned-agent sessions have no/renamepath to a session title. - The headless path (
claude -p) and thegenerate_session_titlecontrol request have no agent guard and do generate titles — only the interactive REPL is affected, which suggests the guard wasn't deliberate. - The only real workaround is a
UserPromptSubmithook returninghookSpecificOutput.sessionTitle(/renamerenames the agent, per above). It requires a plugin to supply the string, doesn't restore built-in topic generation, and has to defer past the first assistant turn — the hook runs before the turn, and a custom title suppresses the generator, so titling on the first prompt would preempt generation in every unpinned session too. - Distinct from #74717 (first message is a slash command), #70329 (title latches onto an interrupted first message) and #76092 (no way to disable/customize the title) — none of those involve the pinned-agent guard.