PR dock chips; tooltips only where nothing else names the control
Leo's agent-chat bugs (cosmic-gray): the opened-PR row above the composer was a full-width bar with its X clipped and a needless tooltip, and tooltips sat on text that already shows.
Captures
Real cmux DEV builds, the same seeded agent chat with a pull request (a gh pr create in the mock fixture), cropped to the chat column; the host's computer name is painted out. Before is base a5341bc5 with this PR's mock fixture only (so its dock shows the same pull request); after is this PR's head 3dc7d0c3. The merged head 0d5c6813 only adds base merges after that, none touching these files. The pointer is the debug page hover (debug.agent_pane hover), so the page gets real pointer events and its tooltips, but no CSS :hover tint, and the arrow in the clip is drawn in.
Dark

Light

Hover across the chip, its ×, and a code block's Copy (dark, base left, this PR right): base shows a tooltip on all three; this PR only on Copy, which is icon only.

Full quality:
What changed
- PR dock: each pull request is now a chip as wide as its content: icon, #N, repo, and the title cut off at 360 px. The dismiss X sits inside the chip, and the chip has no tooltip. Clicking it still opens the PR.
- Tooltip audit: a row, chip, link, path or thought whose text is already on screen no longer gets a tooltip, even when the text is cut off. Tooltips remain on:
- icon-only controls;
- shortcuts;
- text that appears nowhere else (each marked
tooltip-allow: <reason>):- why a control is disabled: Passwords export, the diff options needing host support, Push with nothing to push;
- a failure or warning detail: settings row error, cloud transfer error, the chat header warning, Markdown read-only or save failed, an image too large to show;
- who reacted, emoji names, icon+count badges (keybinding conflicts, the settings filter, channel members), an image attachment's name;
- policy enforcement detail (handoff review, session coverage, permission coverage);
- New Tab kind shortcuts.
- Hover delay: dropped from this PR. Base #20528 (hover intent, app-wide) already makes tooltips wait, then stay warm, so the merge takes base's
ui/titleTooltips.tsandui/Tooltip. The Swift.themedHelpaudit found nothing to remove (every use is on an icon-only or label-hidden control). - Lint:
webviews/test/tooltip-rules.test.tsreads the JSX and fails ontitle/data-tooltip/ui/Tooltiparound an element whose text shows. It skips the dev-onlygallery/andoptchat-inspector/.
Verification
- Red, at b46b555f3430c:
bun test test/tooltip-rules.test.ts→ 105 findings. - Green, at the head: same command → 1 pass.
bun run checkpasses. jsdom suites run file by file all pass, exceptdiff-label-bundleanddiff-worker-bundle, which need built bundles (environment only, not run here).- The PR dock browser test now checks the chip's size, that the X sits inside it, and that it has no tooltip. Browser lanes run only in CI (no Chromium on big-red).
Removed tooltips
~85 tooltips across 48 files
BranchBasePicker.tsx:control(row.worktreeDir);button.base-picker-button(full untruncated comparison)DiffToolbar.tsx:span.source-pill-additions(label("additions"));span.source-pill-deletions(label("deletions"))agent-session/acpmux/AddProjectPanel.tsx:span(path)agent-session/acpmux/Composer.tsx:control(t(steerKind === "steer" ? "composer.steerTooltip" : "compose);div.acpmux-attachment(attachment.name);control(attachment.name)agent-session/acpmux/ComposerContext.tsx:span.acpmux-menu-text(folder.id);span.acpmux-location-picker(selected)agent-session/acpmux/ComposerPickers.tsx:control(t(PICKER_LABELS.planHint))agent-session/acpmux/FileSearch.tsx:control(match.path)agent-session/acpmux/FloatingChat.tsx:span.acpmux-floating-title(floating.title); folded bar: title + last line dropped, now just Expand ⌘Jagent-session/acpmux/Inspector.tsx:dd(snapshot.sessionId)agent-session/acpmux/ProjectChooser.tsx:control(current ?${t("project.label")}: ${current}: undefined);control(project?.cwd);span.acpmux-project-host(project.host)agent-session/acpmux/SessionSidebar.tsx: control;control(placeLabel ?${title}\n${placeLabel}: title)agent-session/acpmux/TrustAsk.tsx:span.acpmux-trust-ask-text(ask.cwd);span.acpmux-trust-ask-text(ask.state === "failed" ? undefined : ask.cwd)agent-session/acpmux/changes/FileHeader.tsx:control(file.path);span.acpmux-fh-badge(t("turn.outside.title"))agent-session/acpmux/chips/LinkChips.tsx:control(outside ?${path}\n${t("chip.outsideProject")}: path);a.cv-link(href)agent-session/acpmux/chips/ReplyImage.tsx:control(outside ?${path}\n${t("chip.outsideProject")}: path);span.cv-image-placeholder(src)agent-session/acpmux/chips/ReplyMedia.tsx:span(path);span(url);span.cv-media(title)agent-session/acpmux/conversation/ArtifactPanel.tsx:span.acpmux-artifact-title(title === language ? title :${title} (${language}));control(t("artifact.versionCount", { index: index + 1, total: list.l)agent-session/acpmux/conversation/EditDiff.tsx:span.cv-edit-diff__name(file.path} data-path={file.path)agent-session/acpmux/conversation/EditedFilesCard.tsx:span.acpmux-edited-path(path} data-path={path);span.acpmux-edited-path(file.path} data-path={file.path);control(t("edited.undoHostLabel"))agent-session/acpmux/conversation/Markdown.tsx:span.cv-link(lm[2]);span.cv-link(src);a.cv-link(src)agent-session/acpmux/conversation/PreviewCard.tsx:a.acpmux-turn-preview-address(site?.title ?${site.title}\n${url}: url)agent-session/acpmux/conversation/RenderCard.tsx:span.acpmux-render-card-title(title)agent-session/acpmux/header/PullRequestChip.tsx:control(label);a(check.name);span(check.name}>{check.name}</span)agent-session/acpmux/header/WorktreePill.tsx:control(title)agent-session/acpmux/newtab/AllChatsList.tsx:control(project.cwd ?? label);control(row.cwd ?${title}\n${row.cwd}: title)agent-session/acpmux/prototype/RowBranch.tsx:span.proto-row-branch(branch)agent-session/acpmux/prototype/RowPullRequest.tsx:span.proto-row-pr(pullRequest.title)agent-session/acpmux/prototype/WorkspaceShell.tsx:span.proto-profile(Browser profile: ${profile.name});control(Open as a tab in ${workspaceLead(target).title})agent-session/acpmux/question/QuestionCard.tsx:control(each.header ?? each.prompt)agent-session/acpmux/replay/ReplayScreen.tsx:control(t("replay.speed"));control(t("replay.continueHint"))agent-session/acpmux/shell/ShellRow.tsx:code.acpmux-shell-block-command(run.command)agent-session/acpmux/summary/PullRequestDock.tsx:a.acpmux-pr-dock__bar(title || undefined);span.acpmux-pr-dock__repo(pr.repo)agent-session/acpmux/summary/SummaryPopover.tsx:control(file.path);control(source.url);control(file.path);control(${pr.repo}#${pr.number}${pr.state === "open" ? "" :· ${t);span.acpmux-summary-text(task.command);span.acpmux-summary-text(wakeup.text)agent-session/acpmux/toolCards/ToolCards.tsx:span.acpmux-trust-ask-text(card.text);control(action.hint)diff-viewer/FileHeader.tsx:span.file-header-path(previousPath == null ? path :${previousPath} → ${path});span.file-header-additions(label("additions"));span.file-header-deletions(label("deletions"));control(reason === "generated" ? label("generatedFile") : label("lar)diff-viewer/Toolbar.tsx:control(option.message);selectrepo picker (selected option's message);option(option.message)pages/cloud/AccountPanel.tsx:control(signOutUnavailable ? t(L.unavailable) : undefined)pages/editor/EditorPage.tsx:span.ed-file(path)pages/files/FilesPage.tsx:header.files-header(root.folder)pages/markdown/MarkdownPage.tsx:span.md-file(path)pages/settings/components/ActionRow.tsx:div.row-help(help)pages/settings/components/HarnessesCard.tsx:div.row-help(row.update.command)pages/settings/components/HostCards.tsx:span.row-help(host.terminal.ghostty_config);span.row-help(host.terminal.shell_integration ?? undefined)pages/settings/components/HostSections.tsx:div.row-help(row.subtitle)pages/settings/components/ThemeStudio.tsx:div.row-help(text(appRow.summary))pages/settings/editors/ChatRootsEditor.tsx:span.folder-path(folder.path)pages/settings/editors/FolderListEditor.tsx:span.folder-path(folder)ui/ContextMenu.tsx:span.ui-menu-label(item.label)ui/variant-pick/VariantPick.tsx:ui/Tooltiparound the Pick button
String keys whose only use was a removed tooltip (chip.outsideProject, replay.continueHint, composer.steerTooltip/interruptTooltip, picker.planHint, edited.undoHostLabel, turn.outside.title, artifact.versionCount, sidebar.folderOnHost, diffViewer.branchPickerComparing) are left in the catalogs. A string cleanup can drop them.
Changelog
- Changed: The pull request bar above the agent composer is a compact chip with its dismiss button inside. Tooltips show only on icon buttons and shortcuts.
🤖 Generated with Claude Code
Need help on this PR? Tag @codesmith-bot with what you need.
Summary by cubic
Makes the opened-PR row above the agent composer a compact chip as wide as its content, with its dismiss button inside and no tooltip. Across the pages, tooltips now appear only where nothing else names the control; about 85 tooltips are gone across 48 files.
Tooltip rules
webviews/test/tooltip-rules.test.tsscans the JSX and fails on any element whose own text shows but still carries atitle/data-tooltip/ui/Tooltip;tooltip-allow: <reason>comments mark the exemptions kept.- Tooltips stay on icon-only controls, shortcuts, disabled-state reasons, and failure, policy, participation, or action-scope detail. Channel image attachments keep their name tooltip, since the name is visible only when the image fails to load.
- Browser tests cover the chip's size, the dismiss X inside it, no tooltip, and the dock taking its own space so the transcript ends above it. The worked-chat mock now opens a pull request so captures show the dock.
- Tooltip timing comes from base's hover intent; this PR's own delay logic was dropped. The fold button's tooltip is kept under
tooltip-allowbecause it names what a click does; the Steer tooltip stays because it adds the shortcut.
Changelog
- Changed: The pull request bar above the agent composer is a compact chip with its dismiss button inside. Tooltips show only on icon buttons and shortcuts.
Showcase


