Adopts glisse (Liquid Glass for the web) in the desktop renderer, scoped to the places where glass actually reads as glass.
cb0778c: refined Liquid Glass surfaces, accessibility and UI polish.396b9e4: aligned the macOS toolbar capsules, vibrancy glass and composer buttons.2f0d0b4: enforced unused-dependency checks with Knip in CI, and dropped unused deps.
[@univerjs](/univerjs) sheet presets, mobile clsx/ws and harness bun-types.b42e409: refined interaction recovery and accessibility, with new tests.eb71315 refreshes the three reduced-motion chat baselines, which the vibrancy change shifted.522c5a0 fixes a double …/…/ in compacted search paths, with a regression test.Command palette as Spotlight. It is anchored in the upper third, so it grows downward as results change instead of re-centering and jumping. It also gets a large search field, an accent-filled selected row, and a faint scrim instead of a heavy grey one.
| Light | Dark |
|---|---|
![]() | ![]() |
Notification banners. Toasts become macOS-style banners: rounded and lifted, with severity in a red icon tile and a neutral bold title.
| Light | Dark |
|---|---|
![]() | ![]() |
Sheets. Dialogs drop the heavy dark outline for a hairline edge and a deep, soft shadow.
| Light |
|---|
![]() |
Sidebar symbols take the accent, like Finder and Mail. The context panel's section labels also drop the wide-tracked uppercase.
| Light | Dark |
|---|---|
![]() | ![]() |
Pass 4 images live in commit 6fdd3e0 and leave the tree in the next commit.
These go beyond glass. Each image shows the PR's earlier head on the left and pass 3 on the right.
Settings sidebar: System Settings–style icon tiles. White glyphs on Apple system colors. Group labels lose the shouty uppercase.
| Light | Dark |
|---|---|
![]() | ![]() |
Working glow. While the agent runs, a slow conic light circles the composer rim, in the spirit of Apple Intelligence. The colors are spun from the accent hue. It sits outside the opaque surface, so text contrast is untouched.
| Light | Dark |
|---|---|
![]() | ![]() |
macOS menus and capsule buttons. Menus get rounder proportions, a soft ambient shadow, and an accent-filled highlight row. Push buttons become capsules as in macOS 26, and every rounded rectangle draws as a continuous superellipse.
| Menu |
|---|
![]() |
Also in pass 3
Pass 3 images live in commit bf653b7 and leave the tree in the next commit.
Real Electron renders from the quality-gate harness (Linux, 1240×820): main on the left, this PR on the right.
Zoomed details
| Light | Dark |
|---|---|
![]() | ![]() |
Chat: toolbar capsules on both sides, the glass "3 new updates" pill over the scrolled feed, and the glass send button.

New-chat landing: glass starter capsules and the sidebar capsule.

Settings → Experiments: Liquid Glass switches on the app accent, and the glass Back capsule.

Settings → Tool Access: segmented control and glass search capsule.

The images live in commit a94b61d and are removed from the tree again in 5cbffd9, so nothing extra lands on main.
Foundation
glisse out of the root harness dependencies and into apps/desktop, pinned to 0.4.3.components/ui wrappers, so feature code never imports glisse directly:
GlassGroup and GlassButton.SearchField: defaults to w-full, like the shadcn Input it replaces.SegmentedControl: assigns tab ids and aria-controls for its tab panel.Switch: the shared switch is now glisse-backed and keeps the shadcn contract: checked/defaultChecked/onCheckedChange, size, and the data-slot/data-state hooks.styles/glass.css maps glisse onto the app's tokens at desktop density and handles Reduce Transparency, Increase Contrast and forced colors. Colour tokens live in tokens/base.css, where token-compliance wants colour formulas.agent_docs/desktop-ui.md documents the glass layer as an explicit exception to "no custom component libraries", plus the gotchas below. It also covers the pass 3 and pass 4 conventions:
Surfaces
Switch.role="tabpanel".Deliberately not done
Menu also lacks a portal, collision handling and typeahead.Gotchas encoded in the wrappers and CSS
glass.css; the search field uses revert-layer to hand width back to utilities.scale/translate, so positioned glass buttons use a wrapper for centring.bun run typecheck:desktop, bun run knip and bunx biome check . pass.HTMLAnchorElement, which glisse's segmented control needs.mcr.microsoft.com/playwright:v1.62.0-noble). That container reproduces CI's renders, and the full gate passes there with 76 passed, 0 failed and 4 skipped. docs/assets/desktop-product.png is synced.d681a9e: all 13 checks pass on Bun 1.4.4.main 82c4f3b)tmpScratchRoots canonicalized blocked roots and then filtered the result against the original spellings. A project root reached through a symlink came back as writable scratch in no-project-write (read-only) policies. Both spellings are now blocked. This fixes Tests, Linux native sandbox x64/arm64 and macOS ARM64 smoke.ContextSidebar.tsx and ActivityGroupCard.tsx. The SidebarSearchOverlay query re-trigger is intentional, so it now has a documented biome-ignore, following the repo convention.d681a9e): daily canary builds 675ee5b97 and 9365e0c1a break the unit suite on main.
Link fails a default-export interop check, and journal and window-mode tests fail too.main runs 41688828221 and 41785796391 show it..bun-version is now 1.4.4, the CI contract test requires an exact release, and agent_docs/repo-contracts.md documents the pin..bun-version too, so they now build on 1.4.4 as well.main. They were regenerated in CI's exact Playwright image and verified pixel-identical to CI's own failure renders.🤖 Generated with Claude Code
claude.ai/code/session_01Xh9rMb5z6HnGxac2co5X3R
[!NOTE] Medium Risk Very broad desktop UI and styling changes (new glisse dependency, composer/top-bar/settings surfaces) with scattered interaction tweaks; no auth or server logic, but high visual/regression surface for Electron quality gates and a11y modes.
Overview This PR re-skins the desktop renderer around glisse Liquid Glass, with new
@/components/uiwrappers (GlassGroup,GlassButton,SearchField,SegmentedControl, glisse-backedSwitch) and a largestyles/glass.css+ token bridge so overrides beat glisse’s unlayered CSS and accessibility modes (Reduce Transparency, Increase Contrast, forced colors) stay sane.Where glass lands: top-bar toolbar capsules, jump-to-latest, composer send/stop (composer body stays opaque with rim +
data-agent-workingconic glow), new-chat starter chips, settings Back, and glass search fields across settings. Tool Access and Subagents drop Radix tab chrome forSegmentedControlwith explicit tab/panel ARIA.Non-glass Apple craft: capsule push buttons, superellipse corners, macOS menu/select highlighting, Spotlight-style command palette placement/scrim, sheet shadows, notification banners with icon tiles, accent sidebar nav icons, overlay scrollbars, and System Settings–style colored nav tiles (
settingsPagestints).Tooling / deps:
.bun-versionpins 1.4.4 (not canary); CI runsknip --include dependencies,devDependencies; seven unused[@univerjs](/univerjs)sheet presets are removed fromapps/desktop.Smaller behavior fixes: readiness errors parsed for display (
formatReadinessError), file explorer “Open” always usesopenFile, new-chat composer no longer locks on attachment ingest (status text instead), activity timeline keyboard scroll ownership, adaptive rail width when not overlay, and thread-details toggle aria labels.Reviewed by Cursor Bugbot for commit 3d735878bc626929cddb982f9621105982576c32. Bugbot is set up for automated code reviews on this repo. Configure here.
This comment shows the latest Codex review activity on this pull request.
| Review | Status | Commit | Review trigger |
|---|---|---|---|
| 📝 Code Review | ✅ Completed 2026-11-05T05:02:08.724335Z | 3d73587 | New commits |
| 🔒 Security Review | ✅ Completed 2026-11-05T05:06:12.996257Z | 3d73587 | New commits |
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.
CI status: the red checks so far are already red on main at 82c4f3b (run 40392834293), so this PR didn't cause them:
resolveSandboxPolicy > temp scratch exclusion canonicalizes symlinked project roots fails identically on main. No fix exists yet; it's outside this PR's scope.main fails bun run check on format drift in ContextSidebar.tsx / ActivityGroupCard.tsx and a useExhaustiveDependencies error in SidebarSearchOverlay.tsx. This PR's own files are Biome-clean.main.main already fails 18 screenshot assertions in CI (stale snapshots). This PR intentionally changes the composer buttons, jump pill, toolbar and switches, so those shipping-chat-*, Canvas and first-paint snapshots need regenerating in the CI Playwright image (bun run desktop:quality:update) either way. Clipping, keyboard, contrast and Axe checks pass with this branch.I'll recheck each job as it finishes and fix anything that turns out to be this PR's.
Generated by Claude Code
chatgpt-codex-connector[bot] · · 1 file comment
Here are some automated review suggestions for this pull request.
Reviewed commit: 9f7dff3473
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
cursor[bot] · · 1 file comment
Stale Bugbot comment from a previous run.
Electron UI quality gates update. On baadf3b, 22 tests failed, and all 22 failures were screenshot mismatches. The clipping, keyboard, contrast and Axe checks passed in CI's image, per the error-context.md files in the failure artifact.
baadf3b (artifact electron-quality-failure-1), after diffing each against the old baseline. The changes are the toolbar capsule, the glass send button and the composer rim. The wider sizes also pick up main's sidebar Search change, which the old baselines predate. docs/assets/desktop-product.png is synced so desktop:quality:screenshot:check stays green. d485ae2 refreshed them again for the top-left sidebar capsule.main. Canvas is the popout window, and first-paint is the bootstrap screen. Each Canvas test also takes four screenshots, and the artifact only holds the first failure, so I've left these for a baseline refresh on main.Current head d485ae2: 70 passed, 6 failed. All 16 shipping-chat screenshots pass, and the 6 failures are exactly the Canvas and first-paint screenshots above.
Generated by Claude Code
Windows smoke (arm64) failed on 6dc32fe in test/providers/codex-app-server-resolver.test.ts. The failing case is forced Codex companion repair > serializes real process activation for same home without sharing temporary files, where a worker missed its 2s phase deadline. This PR doesn't cause it:
main.6dc32fe itself only changes PNG baselines.I'll re-run the failed jobs once when the rest of the workflow finishes; GitHub refuses a re-run while the run is still in progress. If it fails again, it's a real timing flake in that test and needs its own fix outside this PR.
Generated by Claude Code
chatgpt-codex-connector[bot] · · 1 file comment
Here are some automated review suggestions for this pull request.
Reviewed commit: 5cbffd9337
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Windows smoke (arm64) failed again on d485ae2, on the same test as on 6dc32fe: forced Codex companion repair > serializes real process activation for aliased home without sharing temporary files in test/providers/codex-app-server-resolver.test.ts. The second worker reported ready after 46ms but didn't report contended within the 2s activation budget:
Codex worker second (pid 1592) waiting for contended: phase deadline exceeded; elapsed=2048ms; exitCode=null
This isn't this PR's:
d485ae2 only changes PNG baselines.This is the second failure after the one re-run, though, so I'm treating it as a real timing flake rather than retrying. The activation phase shares one 2s budget across about eight cross-process round trips (copy, contend, release, activate, exit, then the same for the second worker). That's tight for a cold Windows arm64 runner.
Suggested fix, kept out of this PR so it doesn't widen the diff: give the shared phase budgets headroom in test/providers/codex-app-server-resolver.test.ts. The budgets stay shared per phase, which keeps the test's intent of no fresh timeout per message.
// Shared per-phase budget; generous enough for cold Windows ARM runners.
const PHASE_BUDGET_MS = 10_000;
// ...
const startupDeadline = performance.now() + PHASE_BUDGET_MS;
// ...
const activationDeadline = performance.now() + PHASE_BUDGET_MS;
The test-level timeout would need to cover two full phases as well. I haven't changed this test here.
Generated by Claude Code
cursor[bot] · · 1 file comment
Stale Bugbot comment from a previous run.
Windows smoke (arm64) failed on 57daaaf with two timeouts:
task artifact versions > restores planning when deferred settlement still needs fresh review evidence hit the 5s test timeout.task workspace subscription routing > ordinary chat createTask tool subscribes the source socket for takeover notifications failed with Timed out waiting for turn/start response.I'm treating this as runner timing, not a regression:
27460f7, and the only changes since then are CSS and screenshot baselines.57daaaf is green, including Windows smoke (x64), Tests and the Electron quality gate.I'm re-running the failed job once. If it fails again, these task-workspace timeouts need their own fix outside this PR.
Generated by Claude Code
cursor[bot] · · 1 file comment
Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 396b9e4340645ae8dda149fa758be9a0d0c294e6. Configure here.
Tests failed on 2f0d0b4 and again on b42e409 with the same 8 failures:
HubLinkRow through Expo Link (mobile), all with TypeError: (0, useLinkToPathProps_1.default) is not a function inside Expo Router's Link.app window-mode notification routing > settings replaces the chat shell across the full window.server JSON-RPC flows > thread/resume replays a journal cursor once before reattaching the live thread sink.Confirmed: these failures come from the Bun canary, not this PR. Manual CI runs on main (82c4f3b) fail the same way:
| Run | Canary |
|---|---|
| 41688828221 | 1.4.4-canary.1+675ee5b97 |
| 41785796391 | 1.4.4-canary.1+9365e0c1a (latest as of Nov 4, 06:4x UTC) |
Both fail the 6 HubLinkRow tests, the journal-cursor test and the window-mode routing test. They also fail the sandbox symlink test, which this PR fixes.
Other evidence:
eb71315) used 1.4.4-canary.1+da867c60b.b42e409, including when run exactly as the full runner does (--max-concurrency=1, JUnit reporter, UI bootstrap).No fix exists yet. agent_docs/repo-contracts.md says .bun-version deliberately tracks the rolling canary channel, so I haven't pinned it here. There are two options: wait for a canary that fixes the regression, or temporarily pin .bun-version to 1.4.4 and update the contract. The second is the maintainer's call. Every other check on b42e409 is green.
Generated by Claude Code
Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.
A user or team admin can review and increase usage limits in the Cursor dashboard.
(requestId: 71cb5d98-c7b3-436b-ae65-7415b22bd77c)
Sign in to comment.
Medium Severity
Replacing Input with SearchField drops the built-in w-full. glass.css then reverts glisse’s fill width so only an explicit width utility can size the capsule. The connectors field passes only max-w-md in a flex row, so it shrinks to content instead of growing up to that cap. Archived chats passes no width at all.
Reviewed by Cursor Bugbot for commit 5852cfd2543491a9d274392fccd7e92b264dd4ef. Configure here.
Medium Severity
The settings icon is now wrapped in a span, so the forced-colors rule for [aria-current="page"] > span also hits the tile. That rule sets HighlightText and forced-color-adjust: none, overriding the tile's color: inherit outline. HighlightText is for a Highlight surface, so the current-page glyph and border can disappear against Canvas/ButtonFace.
Reviewed by Cursor Bugbot for commit 27460f77eebd9a4ffda5fba8c02c737a26a5bef9. Configure here.
Low Severity
compactDisplayPath always concatenates a prefix of ~/ or …/ with another …/ before the last two segments. Home paths become the intended ~/…/dir/file, but every other long path renders as …/…/dir/file.
Reviewed by Cursor Bugbot for commit 396b9e4340645ae8dda149fa758be9a0d0c294e6. Configure here.
Update README.md
#125 mobile-fixes ← main
Updated 5 months ago
Preserve the tab-panel accessibility linkage
For screen-reader users in Tool Access settings, replacing the Radix tab triggers with this independent segmented control breaks the active panel's accessible name and tab association. The retained TabsContent still generates aria-labelledby using a Radix trigger ID, but SegmentedControl passes only labels and values to glisse, so no element has that ID. Preserve Radix trigger composition or explicitly wire matching IDs and ARIA relationships between the replacement tabs and panels.
Useful? React with 👍 / 👎.
Confirmed and fixed in c8ba795 (pushing now). SegmentedControl assigns each glisse tab a stable id plus aria-controls, and Tool Access drops the Radix Tabs/TabsContent shell for an explicit role="tabpanel" whose aria-labelledby points at the selected segment. A regression assertion in tool-access-page.test.tsx checks the linkage before and after a tab switch, and it fails without the fix.
Generated by Claude Code
Valid for the connectors field. In its flex row, width: auto sized the capsule to its content rather than growing to max-w-md. Archived Chats was unaffected, since it sits in block flow and already filled its container. Fixed in baadf3b: the SearchField wrapper now defaults to w-full like the shadcn Input it replaces, and tailwind-merge lets callers' explicit widths (w-56, flex-1) override it.
Generated by Claude Code
Make the Tool Access segments fit compact settings layouts
When the Apps feature flag is enabled, the five fixed-width segments require at least 560px, but compact Settings layouts can provide only 480px: at a 720px window width, resolveAdaptiveLayout retains the inline navigation and reserves a 520px primary area, and SettingsShell adds 40px of horizontal padding. The parent’s flex-wrap wraps the entire segmented control, not its individual tabs, so the rightmost section overflows and forces horizontal scrolling. The previous TabsList allowed individual triggers to wrap. Make the segment sizing responsive or otherwise preserve access to every section without horizontal overflow.
Useful? React with 👍 / 👎.
Valid. Five fixed 112px segments need 566px, and the compact Settings column can be 480px. The fix, now pushed:
SegmentedControl observes its container and shrinks every segment evenly to fit, between a 64px floor and the preferred width. With 5 tabs at 480px, each segment is about 94px.max-width: 100%.Checked in the live build: a container forced down to 320px gives four 78px segments, all labels visible and no overflow.
Generated by Claude Code
This doesn't reproduce: the current row's surface is Highlight, not Canvas/ButtonFace.
theme-bridge.css sets --surface-settings-nav-active: Highlight and --text-settings-nav-active-icon: HighlightText.Highlight.HighlightText from that > span rule is the intended pairing. Its glyph and currentColor border match the label on the same Highlight row.The gate's forced-colors baseline shows exactly this: settings-navigation-models-forced-colors-linux.png in this push has a white outlined glyph on the Highlight row. That baseline was regenerated in CI's Playwright image, and the forced-colors Axe and contrast checks pass. Leaving it as is.
Generated by Claude Code
Confirmed and fixed in 522c5a0. Long paths outside the home folder rendered as …/…/dir/file because the non-home prefix was itself an ellipsis. The function now keeps ~/ for home paths and otherwise uses a single …/. sidebar-search-path.test.ts covers home, non-home and Windows-separator paths.
Generated by Claude Code
feat(desktop): Liquid Glass controls with glisse
#382 main ← claude/glisse-apple-design-ui-gt9vr9
Updated last week