Skip to content
AGH RuntimeWorkspaces

Desktop State

Workspace-scoped OS shell state — the os_shell payload conventions, window snap fractions, and the derived-rendering rule agents rely on to arrange desktops.

Audience
Operators running durable agent work
Focus
Workspaces guidance shaped for scanability, day-two clarity, and operator context.

Desktop state is daemon-authoritative, workspace-scoped storage for the AGH OS shell: open windows, their geometry and z-order, and desktop-wide preferences. The daemon validates size, identifiers, and JSON-object shape only — payload schemas are client-owned and versioned with v, so the web shell and agents evolve them without daemon changes.

Every mutation lands through the same surface: agh desktop-state on the CLI, the /api/workspaces/{workspace_id}/desktop-state HTTP/UDS routes, and the WebSocket stream for live convergence. An agent that writes a win:* doc moves a window on every connected client.

Key conventions

KeyHolds
desktopDesktop-wide preferences: focused window, sessions rail, wallpaper, dock magnification, reduced motion.
win:<windowId>One window: app identity, location, rect, prevRect, z, minimized, maximized, snap.

Window ids are app:<appId> for single-instance apps and session:<sessionId> for session windows. Include v in every value object, and batch multi-key changes through one atomic apply call.

Window snap fractions

win:* docs carry snap: {fx, fy, fw, fh} | null — normalized fractions (0..1) of the desktop work area. Snap is how windows tile to halves and quarters, and it is agent-writable: any fraction rect within the rules below is valid, a strictly larger surface than the six pointer zones the web shell offers.

agh desktop-state set --workspace <id> --key 'win:app:tasks' \
  --value '{"v":1,"app":"tasks","instanceKey":null,"location":{"pathname":"/tasks","search":{}},"rect":{"x":10,"y":8,"w":640,"h":480},"prevRect":null,"z":1,"minimized":false,"maximized":false,"snap":{"fx":0.5,"fy":0,"fw":0.5,"fh":1}}' \
  -o json

Fraction rules:

  • Each origin (fx, fy) lies in 0..1; each span (fw, fh) covers at least 10% of the work area per axis; fx+fw ≤ 1 and fy+fh ≤ 1.
  • Clients salvage an invalid snap (out-of-range, negative or sub-minimum spans, overflow) to null without dropping the window.
  • snap and maximized are mutually exclusive. A doc claiming both keeps maximized.
  • snap always travels inside the whole doc — writing a doc with snap: null (or without the field) unsnaps the window. There are no partial updates to disagree with rect.

Derived rendering

Agents write fractions; clients derive pixels. While snap is set, each client renders the window as work area × fractions for its own viewport, clamped to the 280×180 window minimum. Resizing a browser viewport re-derives locally and never writes back, so a snapped half stays half on every screen and two clients with different viewport sizes converge on fractions, not pixels.

Derivation applies an 8px gutter: every derived edge that is not on the work-area boundary insets by half of it, so fraction-adjacent windows — one doc's fx + fw equal to the next doc's fx — render with a visible gap and grow a draggable linked seam between them in the shell. A user resizing a snapped window rewrites its fractions in place (the window stays snapped); dragging the window body away is what unsnaps it. None of this changes the payload contract — agents still just write fractions.

Two fields support readers that do not derive:

  • rect keeps the writing client's derived pixels at commit time — thumbnails and non-rendering consumers read it as the last concrete geometry.
  • prevRect keeps the pre-snap rect; restore returns it exactly.

On this page