Window Management
Persistent virtual desktops, semantic window placement, revision-safe layouts, connected clients, and recovery.
CompozyOS stores one authoritative window topology per workspace. Persistent virtual desktops own tiled groups and floating windows; clients project that same normalized topology into their own viewport. The daemon, not the browser, validates membership, layout trees, weights, history, and revisions.
Topology and presentation
Every window belongs to exactly one desktop. A tiled group is a tree of leaves, weighted splits, and stacks; floating windows retain normalized geometry. This lets two browsers with different viewport sizes render one shared arrangement without persisting pixels.
Active desktop and focused window are client-local. Commands that change presentation — desktop
switch and window focus — require an explicit connected client_id, so one operator cannot silently
redirect another operator's screen. Each client view has an independent,
monotonic presentation revision: these commands do not advance topology revision, change layout
history, or emit extension hooks.
Revision-safe operations
Read the current topology before changing it:
compozy layout get --workspace <workspace-id> -o jsonEvery durable CLI mutation requires --revision. A successful command advances the workspace
revision once and atomically records the normalized snapshot and event. Layout/topology commands add
one history entry; route navigation does not enter or clear layout history. Preview, validation,
rejection, and no-op paths write nothing.
compozy desktop create --workspace <workspace-id> --revision <revision> --name Build
compozy window open --workspace <workspace-id> --revision <revision> --app tasks \
--pathname /tasks --search-json '{}'
compozy window navigate --workspace <workspace-id> --revision <revision> --id <window-id> \
--pathname /tasks/<task-id> --search-json '{"tab":"runs"}'
compozy window move --workspace <workspace-id> --revision <revision> --id <window-id> \
--desktop <desktop-id> --target <window-id> --placement right
compozy window move --workspace <workspace-id> --revision <revision> --id <window-id> \
--desktop <desktop-id> --groupOn window_manager_revision_conflict, read the topology again and recompute the semantic action.
Do not replay stale geometry blindly.
Window placement is structural (tiled, stacked, or floating). Its separate durable route
contains an internal absolute pathname and canonical JSON-object search state, so detail/filter state
resumes after reload or daemon restart and converges in peer clients. Add --client to
compozy window navigate only when the same operation should also activate and focus that explicit client.
Tiling behavior
New windows float by default and may be opened tiled beside the focused window. Structural drops
use before, after, left, right, top, bottom, or center; dropping onto an occupied target
reflows the tree instead of overlapping it. Shared-boundary resize updates all descendants on each
side. When a viewport cannot satisfy minimum window sizes, that client projects the affected split
as a stack without corrupting the stored topology. Group relocation moves the source window's tiled
group and is exclusive with --target, --placement, and --rect.
Repeated side snapping cycles through one-half, two-thirds, and one-third by default. Top-center
targets zoom the window: the unit holding it (the window or its whole tab frame) becomes the only
full-size island of a desktop. When nothing else is showing on the window's desktop it zooms right
there; when another window is visible, it moves to a new desktop placed right after the current one so
no window gets covered. That desktop works like any other, so you can still add tabs and tiles to it.
Unzooming brings the unit back to where it came from and removes the desktop the zoom created once it
is empty; closing the zoomed window does the same. Grouping a window into the zoomed frame keeps the
zoom; tiling another window to a screen edge gives the zoomed window the remaining space and ends the
zoom, and arranging, moving, swapping, resizing, or floating ends it in place. A minimized window that
was zoomed comes back zoomed. Bottom-center is reserved for the Dock unless remapped. Both behavior and
thresholds are validated under [window_manager] in config.toml.
To restore an internal maximized window, click its Restore window control (the zoom button changes its icon and label while maximized). This returns the saved size and placement. You can also drag any border or corner to resize it directly: resizing ends zoom and saves the new tiled size on its current desktop. The same internal window controls serve Web and Electron; they are separate from native browser or operating-system fullscreen.
Persistent desktops
compozy desktop list --workspace <workspace-id> -o json
compozy desktop clients register --workspace <workspace-id> --client <stable-client-id>
compozy desktop switch --workspace <workspace-id> --revision <revision> \
--client <stable-client-id> --id <desktop-id>
compozy desktop delete --workspace <workspace-id> --revision <revision> --id <desktop-id> \
--destination <desktop-id>Deleting the final desktop is rejected. A non-empty desktop requires a distinct destination so the window transfer and deletion happen in one transaction. The Web shell exposes the same desktops as a minimal horizontal dot pager at the lower left, aligned with the Dock, and opens full management on demand.
Declarative layouts and recovery
Settings → Layouts accepts zero for the gap between tiles and for each outer inset independently. A failed Save keeps your draft and offers retry or discard. The save result distinguishes applied settings from saved settings that still need an action, and displays application warnings. If a save reaches disk but application fails, retry applies the pending layout; discard keeps the configuration already saved on disk.
PATCH /api/settings/window-manager retains the section fields and adds an apply receipt with
applied, next_action, warnings, and partial_failures. A successful HTTP response does not by
itself mean the configuration became active. Send preserve_shortcuts: true with a behavior-only
config to preserve the current shortcut and global-hotkey maps atomically. Explicit top-level
shortcuts or global_shortcuts still replace those maps; omitting the flag retains full-config
replacement behavior. Settings uses preservation so an open spacing draft cannot overwrite a
separately edited shortcut.
Semantic commands are the normal control surface. A validated layout document is the raw recovery escape hatch:
compozy layout export --workspace <workspace-id> -o json > layout.json
compozy layout validate --workspace <workspace-id> --file layout.json -o json
compozy layout apply --workspace <workspace-id> --revision <revision> --file layout.json -o jsonExport omits history. Validate never writes. Apply validates the complete document, binds it to the
requested workspace, preserves current routes for surviving window IDs, and replaces the topology
atomically. Extensions can contribute declarative window_layout resources; discover them through
compozy__resources_list, then arrange by
resource_id. The Settings layout editor lists and saves profiles through
/api/workspaces/{workspace_id}/window-manager/layout-profiles. That projection contains global
profiles plus profiles scoped to the selected workspace, and rejects cross-workspace writes.
Resources cannot execute code or receive pointer events.
A tiled return anchor in an exported document carries return_anchor.source_group, the daemon's
validated deep capture of its source group. Restoring a minimized window reinstalls the exact group and
node identities, order, weights, and placement while the source residue is unchanged. If the source
changed in the meantime, CompozyOS preserves those edits and falls back to the structural anchor, then
the client's focused window on the same desktop, then a floating placement. A zoomed window's
return_anchor is the slot unzoom takes it back to. Preserve source_group and return_anchor.zoomed
during raw document round trips instead of constructing or editing this recovery state.
Agent and transport access
The lazy compozy__window_manager toolset exposes 26 desktop, window, and layout tools with structured
revisions, diagnostics, capability gates, and risk classifications. Resolve compozy__tool_info before
calling a tool. CLI fallbacks are grouped under compozy desktop,
compozy window, and compozy layout.
HTTP and UDS expose identical routes below
/api/workspaces/{workspace_id}/window-manager; see the
Workspaces API for request and response schemas. The WebSocket
stream accepts an optional registered client_id. A bound stream fences that client's view in its
initial snapshot and then sends only strictly newer presentation frames for that ID alongside
workspace-revision topology events; an unbound stream receives topology only. After slow-consumer
eviction, reconnect and replace local state from the next fence. After a daemon restart, register the
same stable client ID again before reconnecting.
Use compozy layout watch --workspace <workspace-id> --client <stable-client-id> -o jsonl for the bound
CLI stream. Omit --client when only topology revisions are needed.
Committed operations emit exactly window_manager.layout.applied,
window_manager.desktop.created, window_manager.desktop.deleted, and
window_manager.window.moved as async hooks. Pointer previews, navigation, focus changes, and
desktop switching do not emit extension hooks.