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
| Key | Holds |
|---|---|
desktop | Desktop-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 jsonFraction 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 ≤ 1andfy+fh ≤ 1. - Clients salvage an invalid
snap(out-of-range, negative or sub-minimum spans, overflow) tonullwithout dropping the window. snapandmaximizedare mutually exclusive. A doc claiming both keepsmaximized.snapalways travels inside the whole doc — writing a doc withsnap: null(or without the field) unsnaps the window. There are no partial updates to disagree withrect.
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:
rectkeeps the writing client's derived pixels at commit time — thumbnails and non-rendering consumers read it as the last concrete geometry.prevRectkeeps the pre-snap rect; restore returns it exactly.
Related reference
agh desktop-stateCLI — list, get, set, delete, watch.- Workspaces API — the desktop-state routes, apply batch, and stream contract.