Skip to content

fix(web): show Linux icon in composer environment picker

MacroscopeApp / Macroscope - UI Consistency failed Aug 28, 2026 in 5m 34s

UI Consistency: 3 issues found

Three icon-system consistency issues were found in the changed web UI code.

  • apps/web/src/components/LinuxIcon.tsx — introduces a second glyph for a state the app already represents with lucide ContainerIcon + "Local sandbox" wording (LegacySidebar.tsx ~2322-2339). The Tux mark also asserts an OS from isDesktopLocalConnectionTarget, which only encodes "host-managed local backend" (local: connectionId prefix) and not the environment's platform, and it is a full-bleed solid-fill 24x24 brand path rendered at size-3/size-3.5 next to padded 1.5px-stroke lucide icons, so it reads heavier and optically larger. If a brand glyph is required it belongs in the shared components/Icons.tsx barrel typed as Icon.
  • apps/web/src/components/Sidebar.tsx — the thread row now shows the Linux glyph while SidebarThreadTooltip (line ~318, also used by SidebarSearchResultRow) still shows ServerIcon for the same environment label, so one environment renders two different icons within the same surface. The tooltip also colours icons via stroke-*, which a fill-only glyph would not honour.
  • apps/web/src/components/BranchToolbarEnvironmentSelector.tsx — the primary / desktop-local / cloud icon mapping is duplicated in the trigger and the SelectItem branch, with a third divergent variant in Sidebar.tsx; a single shared resolver would prevent drift.

Suggested smallest fix: pick one glyph for desktop-local environments (existing convention: ContainerIcon), resolve it in one shared helper, and use it from the selector trigger, the selector items, the sidebar row, and the thread tooltip.

Details

Note

Your check run agent prompt is: .macroscope/check-run-agents/ui-consistency.md
More information about how Check Run Agents work can be found in our Help Center.

Files examined: apps/web/src/components/LinuxIcon.tsx, apps/web/src/components/Sidebar.tsx, apps/web/src/components/BranchToolbarEnvironmentSelector.tsx, apps/web/src/components/BranchToolbar.logic.ts, apps/web/src/components/ChatView.tsx.

Context consulted beyond the diff: apps/web/src/connection/desktopLocal.ts (definition and doc comment of the local: prefix classification), apps/web/src/sidebarProjectGrouping.ts and apps/web/src/components/LegacySidebar.tsx (existing desktop-local indicator convention: ContainerIcon + "Local sandbox" tooltip wording), apps/web/src/components/Icons.tsx / JetBrainsIcons.tsx (brand-icon barrel convention and shared Icon type), and apps/web/src/components/Sidebar.tsx tooltip/search-row rendering.

Checks performed: verified the widened EnvironmentOption contract has only one producer (ChatView) so the added required isDesktopLocal field does not break other call sites; confirmed the environment icon selection is now duplicated across three sites; confirmed the sidebar hover card and search-result tooltip still render ServerIcon with stroke-* colouring for desktop-local environments. No CSS, Tailwind ownership, scroll/virtualization, or environment-routing regressions were found in this diff.


🔍 Agent activity — 16 tool calls

💭 I want to dig into this PR, particularly the addition of a Linux icon tied to isDesktopLocalConnectionTarget. I'm questioning whether "desktop local" actually implies Linux, since the branch name suggests this is about WSL specifically, and I want to check if similar icon logic exists elsewhere for consistency. Comparing LinuxIcon against the other icons used in BranchToolbarEnvironmentSelector like MonitorIcon and CloudIcon, checking stroke/size defaults and viewBox conventions to make sure it fits in cleanly. Let me pull up the actual files now.

1. browse_code — apps/web/src/connection/*.ts

2. browse_code — apps/web/src/components/BranchToolbarEnvironmentSelector.tsx

💭 I want to check desktopLocal.ts to understand what a desktop local connection target represents, and whether it's Linux-specific given the WSL reference in the branch name.

3. browse_code — apps/web/src/connection/desktopLocal.ts

💭 I'm questioning whether labeling "desktop local" with a Tux/Linux icon is semantically correct, since the icon seems derived from a connection-id prefix rather than actual OS info, which could misrepresent generic local backends like WSL. Let me check platform.ts for what desktop-local backends can actually be, look for any existing OS/platform utility that should be used for consistency, and grep for a duplicate Linux icon component already in the repo.

4. git_tools — Linux|linux|Tux|wsl|WSL

💭 I notice sidebarProjectGrouping.ts references a "desktopLocal env" concept tied to the WSL backend, which suggests there's already logic for identifying desktop-local environments in the sidebar that this PR might be duplicating. I want to check that file and Sidebar.tsx, plus LegacySidebar.tsx around line 398, to see how it's currently handled.

5. browse_code — apps/web/src/sidebarProjectGrouping.ts

6. browse_code — apps/web/src/components/Sidebar.tsx

💭 I'm checking whether the project header already uses a different icon (like ContainerIcon) for desktop-local groups, since introducing a new custom Linux icon for the thread row and environment selector could create inconsistency with the existing shared icon system for the same concept.

7. git_tools — allRemoteMembersAreDesktopLocal|isDesktopLocalEnvironment|ContainerIcon|BoxIcon

💭 I'm noticing an inconsistency: the existing convention uses lucide's ContainerIcon with "Local sandbox" wording, but this PR introduces a custom Tux LinuxIcon SVG for the same concept in both the new Sidebar thread row and environment selector—two different glyphs for the same environment class, plus a hand-rolled icon instead of the shared lucide set. I want to check whether Sidebar.tsx already handles the desktop-local case; grep shows it doesn't use allRemoteMembersAreDesktopLocal, though LegacySidebar already has desktopLocalEnvironmentIds, so the PR's duplicate addition in Sidebar.tsx seems necessary. I'm also weighing accessibility—whether lucide-react icons default to aria-hidden or need it set explicitly, since the Sidebar passes aria-hidden manually consistent with ServerIcon, but the environment selector doesn't seem to do the same for either icon. The bigger concern is that the Tux/Linux glyph is a solid, currentColor-filled path while every sibling icon is a thin-stroke lucide icon, creating a visual density mismatch—especially glaring at tiny sizes like size-3. This feels like a genuine consistency issue with the shared icon system, since introducing a hand-drawn solid brand glyph among stroke-based lucide icons breaks the established visual language. There's also a semantic problem: the icon asserts "Linux" but the underlying condition (isDesktopLocalConnectionTarget) really means "host-managed local backend," which today only happens to be WSL. It's derived from a connection-id prefix rather than actual OS/platform data, so a Linux icon could mislabel a non-Linux local backend—a real bug risk that existing code avoided by using a neutral container icon instead of an OS-specific one. The strongest concrete finding is inconsistency: the codebase already has a convention for this desktop-local state using ContainerIcon with "Local sandbox" wording, and the new hand-rolled Tux SVG diverges from that (also stands out as solid-fill among otherwise stroke-style icons). The fix should be to reuse the existing ContainerIcon rather than introducing a new brand-specific glyph. I'm also noticing the same primary/desktopLocal/cloud icon-mapping logic gets duplicated across three call sites -- the selector trigger, the selector items, and the sidebar row. Since these all need to stay in sync, it'd be worth extracting a shared environmentIcon(env) helper so the mapping can't drift between them.

8. git_tools — ServerIcon|buildSidebarProjectSnapshots|desktopLocalEnvironmentIds

💭 I notice the details tooltip built by SidebarThreadDetailsTooltip still uses ServerIcon even though the row itself now shows Tux for a desktop-local thread — that's an inconsistency worth flagging, though it might be considered out of scope for this PR. I should also check whether SidebarSearchResultRow, which takes environmentLabel too, renders ServerIcon for remote results while thread rows now show Tux, since that's another spot where the icon logic could diverge. Then I want to look at the ChatView change adding isDesktopLocal to the environment options, verifying environmentById is properly in scope there and that the mapping still works correctly for pull-request or multi-environment cases.

9. browse_code — apps/web/src/components/ChatView.tsx

10. git_tools — isRemote

💭 I'm also noticing the Tux glyph is a dense solid shape rendered at 14px alongside thin lucide stroke icons, making it visually heavier and out of place compared to the lighter ProviderInstanceIcon and ServerIcon nearby—likely because it lacks the padding lucide icons typically have within their viewBox. That confirms this is a real icon-metric inconsistency worth flagging alongside swapping in ContainerIcon, which matches the stroke weight and sizing convention already used elsewhere. I should also check whether there's an existing custom-icon convention in the repo, like an icons folder or components similar to ProviderInstanceIcon, before finalizing this recommendation.

11. browse_code — In apps/web/src, where do custom (non-lucide) SVG icon components live? Is there an icons directory or a convention (e.g. apps/web/src/components/icons/*.tsx or brand icon components)? List examples of custom inline SVG icon components and whether they set default width/height/aria-hidden or use size classes.

💭 I notice the existing convention keeps brand icons in the shared Icons.tsx barrel with a typed Icon interface, but this PR adds a standalone LinuxIcon.tsx that skips that shared type entirely—worth flagging as inconsistent with the established pattern, though I should check if JetBrainsIcons.tsx sets a precedent for separate files too. The more significant issues are: the existing "Local sandbox" indicator uses ContainerIcon in the LegacySidebar project header, so introducing a Tux glyph for the same concept creates two competing visual representations of the same environment across sidebars, plus a style mismatch since the brand glyph is solid full-bleed while lucide icons are stroke-based with padding at the same size. I'm also tracing whether the Linux glyph's derivation from isDesktopLocalConnectionTarget actually maps correctly to the semantics it's meant to represent. The flag really only signals a host-managed local backend, not "Linux" specifically — the actual OS is available elsewhere via server config/platform data, so tying the icon to this flag risks misrepresenting the OS if a non-Linux local backend ever registers. That aligns with the check's rule that user-facing labels should read from the environment's server config rather than an unrelated proxy signal, though I want to weigh whether this is too speculative given the doc comments are fairly generic. There's also duplicated icon-selection mapping logic across three separate locations, which creates drift risk under the "smallest durable contract" principle. I'm also noticing the sidebar details tooltip still shows a generic server icon for the same thread whose row now shows the Linux icon — a concrete inconsistency within the same component that's directly caused by this change, worth flagging briefly. I checked accessibility on the icon elements and they seem fine, with proper aria-hidden wrapping and labels elsewhere. Looking more closely at the selector logic, I notice the trigger and items use slightly different property access patterns for determining primary/desktop-local/cloud status, which could matter if the active environment reference differs.

12. git_tools — EnvironmentOption|isPrimary:

💭 ChatView seems to be the only producer of EnvironmentOption, with BranchToolbar just receiving it, but I want to double check there's no other component like a legacy sidebar also passing availableEnvironments.

13. git_tools — availableEnvironments=

14. git_tools — export type Icon|export function TraeIcon

💭 I'm pinning down the primary finding: the same "desktop-local environment" state is shown with inconsistent glyphs — the legacy sidebar uses a lucide container icon with "Local sandbox" text, while the new sidebar and branch-toolbar selector use a Tux glyph instead. That Tux mark is also a solid full-bleed brand icon, which reads heavier and larger than the neighboring 1.5px-stroke lucide icons at the same size. I'm also noting that isDesktopLocalConnectionTarget only signals a host-managed local backend based on the connection prefix, not an actual OS check, so treating it as evidence of Linux mislabels any non-WSL local backend — this should fold into the same comment. There's also duplicated icon-selection logic across three call sites that could use a shared helper, though I'll keep the inline comments focused: one on the new icon file addressing the glyph choice, sizing, and OS-assertion issues, and one on the Sidebar tying it back to consistency with the existing server icon convention. I'm double-checking where the tooltip and row rendering diverge — the shared tooltip component renders a server icon and is used by both the thread row's details tooltip and the search rows, while the row itself now renders the Tux glyph, so hovering a WSL thread shows two different icons for the same environment within the same surface. I'll settle on posting two comments: one on the new LinuxIcon.tsx file (folding in a brief note about the duplicated environment-to-icon mapping) and one on Sidebar.tsx at the added tooltip line, making sure both land on actual diff lines. For the LinuxIcon comment, I want to point out that the codebase already has an established pattern for representing a desktop-local environment—using a lucide container icon plus "Local sandbox" text—so introducing a second glyph for the same environment class is redundant. It also incorrectly infers an OS from a signal (the local connection-target check) that only indicates a host-managed local backend, not specifically WSL, meaning non-WSL local backends could render the wrong icon. For the second comment on Sidebar.tsx, I'm noting that this row now visually contradicts its own hover tooltip, since the details tooltip and search result tooltip still use a server icon for the same environment label — whichever icon is chosen needs to be applied consistently across both places. For the third comment, on BranchToolbarEnvironmentSelector.tsx, the primary/desktop-local/cloud icon mapping is duplicated across two spots in that file plus a third variant in Sidebar, so I'd suggest extracting it into a shared helper. Three comments feels okay to post separately since they're in different files, though I want to keep them terse — now I'm weighing whether failing the check is actually warranted here. The rubric says a clear consistency or regression risk warrants failure, and having a divergent glyph for the same state plus disagreement within the same surface qualifies as a consistency finding, so the default should be failure since findings exist. I'll go with that. Before finalizing, I want to double-check the tooltip's exact line reference in Sidebar.tsx — confirming it falls within the SidebarThreadTooltip component around lines 280-330.

15. browse_code — apps/web/src/components/Sidebar.tsx

💭 Also worth noting the tooltip icons are colored via stroke, so a fill-only glyph like a Tux icon would render invisible there — good supporting evidence for recommending a stroke-based lucide icon instead. Time to post the review.

16. modify_pr — UI consistency review found icon-system inconsistencies introduced by this change. Details inline.


Agent Credits: 231 credits

Token usage: 44 uncached input · 1,155,337 cache-read input · 177,539 cache-write input · 20,345 output
Agent Credits may also include non-token charges from external tools such as web research.