writing / spaces 8 public repos
← writing ↑ part of Interfaces
platformssolutions

Spaces — a desktop platform that freezes and thaws whole workspaces

One surface, many contexts

One machine has to serve many unrelated work contexts.

And switching between them means manually reopening apps, re-tiling windows, and paying for idle ones in GPU and RAM. The class is one surface, many contexts: reshaping a machine to a use without forking the logic per platform.

What it is

A desktop platform that organizes a machine into compartments — Spaces — each with its own apps, window layout, and local-model context. A keystroke summons a takeover surface; selecting a Space switches to it with its apps launched and snapped into a panel grid. Background Spaces freeze — their processes suspended, GPU and RAM reclaimed — and thaw on return with state intact. It runs on GNOME and Hyprland from a shared core, currently on an X1 Pro handheld and a fleet dev box.

1
Rust core — the data model and zone math
2
native front-ends: GNOME + Hyprland
~1,800
lines in warden, the freeze/thaw daemon
v0
GNOME surface, shipped and dogfooded
What's honest about the scope. Shipped and dogfooding on the X1 Pro: the shared core and zone math, the Hyprland adapter seam, warden freeze/thaw, the GNOME surface v0, local open-weight serving. The per-Space sandbox — the boundary that would keep a local model scoped to one Space — is design intent, not built: a Space groups and switches, it does not wall its contents off. The workspace allocator, multi-monitor placement, daemon hardening, and fleet install are in build.

Where it generalizes

This is the endpoint / workspace layer: one machine reshaped into switchable work contexts with their resources reclaimed — endpoint standardization that scales across a fleet. Shipped and dogfooded on an X1 Pro, GNOME surface v0: menu → launch → snap → freeze → thaw.

The unit of organization

A Space is data. The windows are a projection.

A Space is a named work context — a set of apps, a window layout, and a local-model assignment, held together as one switchable unit. The desktop holds several; one is foreground at a time, the rest are dormant. Switching between them is a single selection, not a manual reopening of windows and a re-tiling of the screen.

Summon

A takeover surface on a keystroke

A keystroke brings up a full-screen, per-Space configurable menu of the available Spaces and their actions. On GNOME the summon rides the existing Activities press — no Super-key rebind, no new global shortcut, no custom compositor.

Pick

Selecting a Space resolves it

Its apps launch if they are not already running, and the live OS windows snap into the zones its layout defines — each Space's apps place onto its own workspace.

Place

Real windows, really tiled

The panel grid is a real tiling layout over real OS windows: the windows snapped into a Space's zones are the same windows the window manager owns, repositioned — not reparented copies or embedded views.

Leave

Back to the surface

Leaving a Space, or summoning another, returns to the surface. The surface is a GNOME shell extension layered over the stock session, so the rest of the desktop keeps working as it did.

Defined in data, not code

The state that defines a Space lives in a .space manifest — which apps it launches, how they place into the layout grid, and what local-model context it carries. That description is the durable artifact; the running windows are a projection of it. Because the definition is data, a Space can be authored, edited, and re-summoned without the apps being open at edit time.

This is an organizational model, not an enforcement one. A Space groups and switches; it does not wall its contents off from the rest of the machine. The boundary between Spaces is a layout and lifecycle boundary, not a security one — see the Status tab.

The shared core and the adapter seam

One layout engine, two window managers, one seam between them.

The platform-independent work — the Space data model and the zone and layout math that decides where a window goes — is one Rust crate with no UI dependency. It computes placement; it does not know how a window is moved. Two platforms sit on top of that one core, driven by the same math.

Core

Shared core, native front-ends

The Space data model and the zone/layout math live in one Rust core with no UI dependency. Each platform gets a native front-end over that core: a GNOME shell extension and a Hyprland layer-shell renderer.

Seam

The `WindowManagerAdapter` trait

The gap between “where a window should go” and “make the window go there” is a trait each platform implements — the seam that lets a single layout engine target two different window managers without the core knowing which one it is talking to.

Hyprland

Driven directly

Hyprland accepts placement commands directly, so its adapter drives the compositor without an intermediary.

GNOME

Through a companion

GNOME exposes no external window-control API, so its adapter routes through a companion that translates the core's placement contract into Mutter's move_resize_frame calls — the move/resize primitive GNOME's window manager does expose.

The pieces

Shared core
one Rust crate Space data model + zone/layout math; no UI dependency
Front-ends
GNOME shell extension · Hyprland layer-shell renderer native per platform, same core math
Placement seam
WindowManagerAdapter trait Hyprland driven directly; GNOME via a companion → Mutter `move_resize_frame`
Manifest
.space — a shared schema the front-end reads the layout, warden owns the launch, the console authors it
Local models
llama.cpp on Vulkan · vLLM handheld iGPU · fleet dev box — served on the machine, not over a network

Local models

Each Space can carry a local open-weight model as part of its context. The serving backend follows the hardware: on the X1 Pro handheld the model runs on the integrated GPU through llama.cpp on Vulkan; on the fleet dev box it runs through vLLM. The model assignment is part of a Space's definition, so summoning a Space brings up its model context alongside its apps and layout.

The freeze-and-thaw daemon

A Space you've left doesn't need CPU, GPU, or RAM.

warden is the Rust daemon that takes them back. When a Space goes to the background its processes are paused, not terminated, and the resources it held are reclaimed; on return it resumes with state intact.

Freeze

The cgroup-v2 freezer

warden suspends a background Space's processes through the cgroup-v2 freezer — the kernel mechanism that stops a control group's tasks without killing them — and reclaims the GPU and RAM the Space held.

Thaw

State intact on return

On return, warden thaws the group and the Space resumes with its state intact, because the processes were paused, not terminated.

Built

Small, tested against the real thing

Roughly 1,800 lines of Rust. It speaks D-Bus for IPC, is managed by systemd, and its tests run against real systemd slices rather than mocks.

The line

Lifecycle, not isolation

The freezer suspends a group's scheduling; it does not put the group in its own namespace, restrict what it can see, or sandbox its data. warden reclaims resources from an idle Space; it does not contain a running one. That distinction is deliberate — it is the line between what is shipped and what is still design intent.

Where it stands

Freeze is shipped. Enforcement is not.

What runs today, what is in build, and where implementation stops and design intent begins — stated plainly.

shipped · dogfooding

Running today on the X1 Pro

The GNOME surface v0 loop — menu → launch → snap → freeze → thaw — on GNOME 49.6/Wayland, over the shared core.

shared core + zone mathWM-adapter seam (Hyprland)warden freeze/thawGNOME surface v0local open-weight servingCabin design system
in build

Toward daily use and the fleet

A Space as a dedicated GNOME workspace (the allocator); multi-monitor placement; daemon hardening for daily use; lightweight authoring and a one-command fleet install.

in progress
not built

The per-Space sandbox

The per-Space data boundary / ACL is not implemented. Spaces are organizational, not enforced — warden freezes a Space, it does not isolate one. The boundary is the design intent for keeping a local model scoped to one Space.

design intent

Licensing

Substrate
Apache-2.0 OR MIT warden, the WM adapters, the GNOME companion — usable independently
Product
AGPL-3.0 + commercial dual the host / control plane

Open-core, two tiers. Third-party packages run as separate processes over IPC and do not link the host crate, so they fall outside the AGPL derivative-works boundary; a commercial license covers embedding the host without AGPL obligations.