feat: detachable plugin windows as a bundled Windows plugin - #102
Draft
thomaspblock wants to merge 11 commits into
Draft
thomaspblock wants to merge 11 commits into
thomaspblock wants to merge 11 commits into
Conversation
Desktop windows act as browser-like tab containers: any page or launcher panel (Bestie, Agent Activity) can move to a new or existing window by right-click menu or by dragging, while Home and Settings stay in main. Rust owns the layout (persisted per profile), creates, restores and closes windows, hit-tests drops, and drives a native always-on-top drag ghost that stays visible beyond the source window and follows the app theme. The destination window is focused, highlights while hovered and selects the moved tab. Each window runs the full app on its assigned tabs; only main raises notifications, and detached windows follow the community selected in main. Signed-off-by: Thomas Petersen <thomasp@squareup.com>
…n-windows Signed-off-by: Thomas Petersen <thomasp@squareup.com> # Conflicts: # src/app/navigation.ts # src/app/shell/AppShell.tsx # src/app/shell/PanelLaunchers.tsx
…ding spot Dragging now feels continuous: past the threshold the tab blanks in its slot and the native pill appears exactly where it was, same size, icon and resolved styles read from the live DOM, keeping the grab offset. Glass launchers lift as an opaque icon disc and their images no longer start a native drag. A hovered window is told which tab is coming, so main rings its launcher row for a returning panel and the strip for pages. Signed-off-by: Thomas Petersen <thomasp@squareup.com>
A panel dropped on a detached window landed in its tab strip while the drop highlight pointed at the strip too. Launcher panels now live in the right-hand launcher row wherever they are and open as the companion card there; a detached window without pages shows its panel full-size and that view's close returns it to main. The strip no longer renders panel tabs. Signed-off-by: Thomas Petersen <thomasp@squareup.com>
…n-windows Signed-off-by: Thomas Petersen <thomasp@squareup.com>
The windowing runtime stays host-owned; the new bundled Windows plugin (buzz.windows) is its switch, so it appears in Settings -> Plugins like Terminal. A ctx.windows capability exposes the window layout to plugins and enable(): the plugin's whole body is ctx.effect(() => ctx.windows.enable()). Switching it off hides move menus and drag and gathers every tab back into main; a disabled plugin at launch discards the saved layout instead of restoring windows. App teardown never resets. Also tolerate a Tauri runtime without window metadata (browser fixtures) and move two shell classes onto design-system text roles and a solid surface. Signed-off-by: Thomas Petersen <thomasp@squareup.com>
thomaspblock
requested review from
a team,
comp615 and
wesbillman
as code owners
September 20, 2026 18:46
Contributor
Author
…n-windows Signed-off-by: Thomas Petersen <thomasp@squareup.com> # Conflicts: # crates/plugin-manager/src/lib.rs # src/app/shell/AppShell.tsx # src/bundled/index.ts
Since the reading fixture shrank to 20 tall messages (#83), the row above the anchored one can be taller than a single 300px wheel step, so the first wholly visible paragraph stayed the same message and "panel restoration yields to a new wheel reading position" failed on main in both engines. Keep making bounded, verified wheel progress until the visible reading row belongs to another message, reusing the shared anchor reader. Signed-off-by: Thomas Petersen <thomasp@squareup.com> (cherry picked from commit 664b27e)
…n-windows Adopt the shared shell controls for detachable tabs: PageTab now renders NavigationItem pills for pages and chrome IconButton discs for launchers, the drag ghost borrows the selected pill surface, and the window commands are generic over the Tauri runtime so they join the shared commands() handler used by the MockRuntime tests. Only main binds the Dock unread badge, like notifications. Signed-off-by: Thomas Petersen <thomasp@squareup.com> Conflicts: Cargo.lock src-tauri/Cargo.toml src-tauri/src/lib.rs src/app/App.tsx src/app/services.ts src/app/shell/AppShell.tsx src/app/shell/PanelLaunchers.tsx src/plugins/author.ts
…n-windows Keep the macOS title-bar double-click handlers on the header, actions row and launcher group of every window, and note in shell-design that the behaviour and the window capability cover detached tabs-* windows too. Signed-off-by: Thomas Petersen <thomasp@squareup.com> Conflicts: docs/shell-design.md src-tauri/src/lib.rs src/app/shell/AppShell.tsx
…n-windows The global search palette stays in the main window's launcher row, like the page finder it replaces; detached windows keep only their launchers. Signed-off-by: Thomas Petersen <thomasp@squareup.com> Conflicts: src/app/App.tsx src/app/shell/AppShell.tsx
wesbillman
marked this pull request as draft
September 28, 2026 21:12
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Summary
Desktop windows become browser-like tab containers. Any page (Messages, Projects, Agents, Workflows, external plugins) or launcher panel (Bestie, Agent Activity) can leave the main window into its own OS window, and windows can hold any combination of tabs. Home and Settings stay in main. The feature ships as the bundled Windows plugin (
buzz.windows), so it has a toggle in Settings → Plugins like Terminal.<profile>/windows.json) and restored on launch. Disabling or removing a plugin removes its tab wherever it lives; an emptied window shows an explanation with Close window.src-tauri/src/windows.rs); the newctx.windowscapability exposes the layout to plugins andenable(). The Windows plugin isctx.effect(() => ctx.windows.enable()). Switching it off hides menus/drag and gathers every tab back into main; a disabled plugin at launch discards the saved layout. App teardown never resets.Design and decisions:
docs/plans/2026-09-14-001-feat-detachable-plugin-windows-plan.md,docs/shell-design.md(Detached tab windows),docs/plugin-architecture.md(Desktop tab windows).Demo
Video — dragging tabs and Bestie between windows:
windowmagic.mp4
Settings → Plugins with the Windows plugin:
Reviewer notes
NavigationItempill and launchers the chromeIconButtondisc frommain;PageTabadds the move menu and pointer drag on top of them. Window commands are generic over the Tauri runtime so they sit in the sharedcommands()handler.src/app/services.ts(composeWindowsService, bind notifications only in main),src/plugins/author.ts(exportWindows,WindowLayout,WindowSnapshot),src/app/App.tsx.tauri.conf.jsonturns onmacOSPrivateApi(with the matching Cargo feature) for the transparent rounded drag pill. Apple rejects that API for App Store submission; bundling is off in this repo, and the fallback is an opaque pill.tabs-*windows get the same permissions asmainplus event listen/unlisten and window close. Thedrag-ghostwindow has no capability and no IPC.Test plan
Automated (all green on the head, macOS): Biome, tsc, design-foundation checks, frontend build, Vitest 1635/1635 (layout filtering, web fallback, drag coalescing, activation, drop-target, lifted-tab ghost, plugin enable/reset/teardown, live toggle in the app integration test), Clippy
-D warnings, Rust layout/persistence/reset tests, browser journeys 411/418 in Chromium and WebKit.tests/browser/emoji.spec.mjsfails on WebKit onmainas well — a local environment difference, not this branch.)terminal::tests::production_environment_probefails on machines whose login shell prints a banner; module unchanged.Manual, desktop build (
bin/just desktop):