[BUG] Terminal tab title never updates when a custom agent is pinned (--agent / settings.agent) — agentTitle suppresses topic-title generation

Status Open
Reported on v2.1.221
Maintainer reply None cached
Activity 0 comments · opened Aug 4, 2026

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

  1. Define any custom agent (or use a plugin-provided one).
  2. claude --agent my-agent, then send a normal free-text prompt.
  3. Watch the terminal tab title: it reads my-agent and never changes.
  4. 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 whose aiTitle is 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:

  1. generation is suppressed, so no topic title is ever produced, and
  2. 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-title transcript 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. Since aiTitle outranks agentTitle in 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 where agentTitle is fixed.
  • Model-generated naming works fine under a pinned agent — only the automatic path is blocked. In a --agent-pinned session, /rename with no argument immediately produces and persists a name (fix-session-title-generation-guard here) via rename_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 /rename does not set a session title at all: it renames the agent instance, writing agent-name records that feed standaloneAgentContext.name. That name outranks custom-title in the display, so a session can show the rename while its custom-title record holds something else entirely. Worth deciding whether that overload is intended — as it stands, pinned-agent sessions have no /rename path to a session title.
  • The headless path (claude -p) and the generate_session_title control 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 UserPromptSubmit hook returning hookSpecificOutput.sessionTitle (/rename renames 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.

View original on GitHub ↗