Skip to content

fix(tabs): keep a known agent's tab icon when the title only mentions another agent - #26615

Open
ryuki12 wants to merge 2 commits into
stablyai:mainfrom
ryuki12:fix/tab-icon-title-free-text-override
Open

ryuki12 wants to merge 2 commits into
stablyai:mainfrom
ryuki12:fix/tab-icon-title-free-text-override

Conversation

@ryuki12

@ryuki12 ryuki12 commented Oct 8, 2026

Copy link
Copy Markdown

ELI5

Claude Code names its terminal after the conversation. If the conversation is about Codex, the tab used to show the Codex icon even though Claude Code was running. Now the tab keeps the Claude icon, because a name that only shows up in the topic text is not a reliable sign of which agent is running.

What Changed

Before: in a Claude Code pane titled ◑ Tab title showing Codex instead of Claude Code, the tab bar showed the Codex icon whenever no live hook or foreground-process signal was present (between turns, before a hook reaches the renderer, remote panes).

After: the same pane keeps the Claude icon. A genuine identity title (for example Task - codex) still reclaims a reused pane.

Mechanism:

  • resolveTabAgentFromSignals only lets a title replace a known identity (finished hook or launch record) when collectAgentTitleEvidence reports anchored or vendor-marker. A name that appears only in free text no longer counts (src/renderer/src/lib/tab-agent-from-signals.ts). The check runs last in the condition, so it only costs anything when the other reuse conditions already hold.
  • The tab bar had its own older copy of resolveTabAgentFromSignals and resolveLaunchedAgentExitEvidence in use-tab-agent.ts. I deleted it, so the tab bar now calls the same tested function as the tests and open-tab-occupant-agent. That copy had drifted: it never received the OMP/Pi fix (fix(agents): keep OMP identity and forward ask/approval events #15713), the stale sleeping-session fix after /exit (fix(terminal): clear stale agent identity after shell exit #21714), or the Git Bash prompt-title handling (fix(sidebar): an agent's row stays while it runs, whatever its tab title #23948).
  • One existing expectation changes on purpose: use-tab-agent-pi-identity.test.ts expected a finished Claude pane whose title became ⠋ Codex to flip to codex. That title names Codex only in free text, so it now keeps claude (see Notes).

Why

The issue's principle is that the title is decoration: it may fill an empty slot or replace a stale signal only with strong evidence, and a name in task text never overrides anything. Removing the duplicate first means the fix lands in the function the tab bar really uses, instead of fixing only the tested copy.

PRs 2-4 of the plan (one title parser, one ranking, host-owned identity) are larger refactors with their own corpus and wire-compatibility checks. I kept them out so this one stays small and reviewable.

Linked Issue

Part of #26513 (PR 1 of the proposed plan)

Visual Proof

No screenshot captured. The tab icon is driven by resolveTabAgentFromSignals, and the new pure-function tests reproduce the bug (red, three cases return codex) and show the fix (green, claude). Before/after tab-bar screenshots can be attached here by the author if reviewers want them.

Testing

Run on Windows. bun was not installed, so I used pnpm test:node, which runs the same Vitest suites on Node.

New regression tests (src/renderer/src/lib/tab-agent-title-free-text-override.test.ts), before the fix:

Tests  3 failed | 6 passed (9)
  keeps claude from the completed hook   -> expected 'codex' to be 'claude'
  keeps claude from the launch intent    -> expected 'codex' to be 'claude'
  (a third, sibling-hook case, was dropped; see Notes)

After the fix: all 8 pass. Other checks:

pnpm test:node src/renderer/src/lib/            # see results below
pnpm test:node src/renderer/src/components/tab-bar   # 68 files, 586 tests passed
pnpm tc                                          # passed
pnpm run check:code-quality:changed              # 0 new findings
npx oxlint <changed files>                       # clean
npx oxfmt --check <changed files>                # clean

src/renderer/src/lib/ results are in the Notes section.

Full pnpm lint and pnpm build, every step covered except where noted:

pnpm lint    # all steps passed (oxlint, anti-slop, code-quality native + type-aware, reliability
             # gates, dead classes, max-lines / ts-nocheck ratchets, catalog + localization checks).
             # With mobile/ dependencies installed, anti-slop also reports 5 pre-existing
             # import(no-cycle) warnings in mobile/ files this PR does not touch.
pnpm build   # typecheck, relay, CLI, electron-vite (main/preload/renderer), web client and
             # mobile web bundle: passed; build:native not run here (needs Rust/cargo on Windows)

The full pnpm test did not finish in a reasonable time on this machine; the unrelated Windows failures it printed are in files this PR does not touch. CI will cover these.

  • I manually tested these changes locally
  • Automated tests added/updated, or explained why not below

AI Disclosure

Claude Code was used. Claude Opus 5.5 did the investigation, orchestration and review. Claude Sonnet 5.5 did the implementation and tests. Claude Haiku 5.5 did the initial issue triage and the follow-up test-expectation commit. I reviewed the changes.

Author

GitHub: @ryuki12
X (Twitter): https://x.com/nocode_teraji

Review

  • Scope: renderer only (src/renderer/src/lib); no shared/host/main changes.
  • Cross-platform: pure TypeScript, no path, shortcut or shell behavior touched. The Git Bash prompt-title handling now reaches the tab bar (Windows).
  • Remote / SSH / local: remote panes have no process signal, so they relied most on the title and gain the most from this fix. Local behavior for hook and process signals is unchanged.
  • Agent compatibility: the OMP/Pi, OpenCode and sleeping-session suites pass (one Pi-suite expectation updated on purpose, see Notes).
  • Performance: collectAgentTitleEvidence is called per resolve but short-circuited behind the other reuse conditions, so it only runs when a title names a different agent than the known owner.
  • UI: no markup or style change; only which icon is chosen.
  • Security: none; no new input handling or I/O.

Agent skill upstream boundary

  • Not applicable, or this change copies or mechanically translates no upstream skill-installer source, tests, fixtures, registry entries, path tables, comments, or documentation.

Notes

  • One existing expectation updated: use-tab-agent-pi-identity.test.ts (renamed to "keeps the completed identity over a free-text Codex title on mount") used to expect a finished Claude pane reused by a hookless Codex titled ⠋ Codex to switch to codex. collectAgentTitleEvidence('⠋ Codex') is free-text-only, so under the issue's principle it no longer replaces a known identity. Codex's foreground process (local) or its hook still switches the icon. Bare-name titles like this are the gap the issue assigns to PR 2.
  • Known gap left for PR 2: the strength check reads the evidence class, while the replacing agent still comes from the older parser. For Fix Codex bug - grok the evidence is anchored for grok but the older parser answers codex, so a reuse override would still pick codex. Unifying the parsers (PR 2) removes this mismatch.
  • Sibling-only case not fixed here: with only siblingHookAgent: 'claude' the focused slot is empty, so the title still fills it (codex). That is the empty-slot rule, which this PR does not change. I left it out of the tests instead of weakening the rule. It fits PR 2/3.
  • src/renderer/src/lib/ results: the only failure, before and after this change, is palette-match-performance (a timing budget that varies by machine). All 14 tab-agent test files (155 tests) pass. The decision-table test (tab-agent-identity-decision-table.test.ts) passes with its disagreement counts unchanged.
  • Not touched: getAgentLabel ordering, the ✳ / . / * handling, resolveCanonicalPaneAgentIdentity, uncoveredFallback, and host identity publishing (PR 2-4).

Checklist

  • This PR is small and focused
  • I explained what changed and why (ELI5, the user-facing before/after, the mechanism, and why over the alternatives)
  • Before/after screenshots or videos attached for UI changes, or N/A with reason
  • Self-reviewed for correctness, security, and performance
  • Cross-platform, SSH/remote, and path/shortcut impact considered (or N/A)
  • pnpm lint, pnpm typecheck, pnpm test, and pnpm build pass (or CI will cover; local preferred)

🤖 Generated with Claude Code

ryuki12 and others added 2 commits October 8, 2026 23:24
… agent

A tab title that names another agent only in task text (free-text evidence)
no longer replaces a known launch/completed-hook identity. Only anchored or
vendor-marker titles can reclaim a reused pane.

The tab bar now calls the tested resolveTabAgentFromSignals instead of a
drifted local copy, which also brings the OMP/Pi (stablyai#15713) and stale
sleeping-session (stablyai#21714) fixes to the tab icon.

Part of stablyai#26513

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UBp6T3vnmFFtQXXSyqTYhK
… identity

A "⠋ Codex" title names Codex only in free text, so it no longer reclaims a
completed claude identity. Update the pi-identity expectation to match, and
drop comments that repeated the regression test's own fixture names.

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Oct 8, 2026

Copy link
Copy Markdown
Contributor

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Repository UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: a9fc383d-17aa-4be2-a761-de71ac6fa26e
📥 Commits

Reviewing files that changed from the base of the PR and between 907cb6e and 7fefd18.

📒 Files selected for processing (4)
  • src/renderer/src/lib/tab-agent-from-signals.ts
  • src/renderer/src/lib/tab-agent-title-free-text-override.test.ts
  • src/renderer/src/lib/use-tab-agent-pi-identity.test.ts
  • src/renderer/src/lib/use-tab-agent.ts

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 9 remain after this review.


📝 Walkthrough

Walkthrough

The signal resolver now requires strong title evidence before a differing, incompatible title can reclaim a pane. The hook imports the resolver helpers from a shared module. Tests cover mention-only and anchored Codex titles, including how they affect existing Claude identities.

Priority: ⬇️ Low

Severity of issue fixed: Low

Merge Risk: ⚪ Minimal · up to 7fefd

The change is mergeable after normal checks; the identified mixed-title icon mismatch predates this PR.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main change: preserving a known agent's tab icon when another agent appears only in free-text title content.
Description check ✅ Passed The description is detailed and covers the user impact, mechanism, rationale, testing, compatibility, risks, and remaining limitations. It references the linked issue and documents that visual proof w…
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 4 functions across 4 files.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@AmethystLiang

Copy link
Copy Markdown
Contributor

Thanks for the PR. Will have @brennanb2025 review it to see if this is what he has in mind

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants