Date: 2026-08-26 (updated 2026-08-28)
SOS now has a minimal Smithay compositor with a nested development backend and a direct DRM/GBM/libinput backend. Both keep Wayland beneath the generated presentation layer while SOS owns client identity, surface ordering, focus, input quiescing, and revision evidence. The direct backend and boot-owned logind/tty session pass in the reference Debian VM. The selectable GDM path has also passed physical Intel DRM, built-in keyboard, touchpad, and touchscreen diagnostics on a Framework Laptop 12 development-live boot. That physical run is not an installed-product or release-promotion verdict.
revision supervisor
| boot / prepare / present / confirm
v
permanent sos-experience-host PID
| authenticated bounded control protocol
| register / quiesce / arm / configure bounded shell surfaces
|
| Luau -> Experience API v4 graph -> retained GPUI
v
authenticated GPUI surfaces
| shell + shell overlay + independently hosted native applications
sos-compositor (Smithay 0.7.0)
| one shell + one overlay + bounded native/compatibility toplevels
| shared focus/input/activation policy
+-- nested winit submit -> outer development compositor
`-- libseat + udev + DRM/GBM + libinput -> KMS output
Luau still sees only the versioned Scene and provider capabilities. Shell-role
window_space and shell_overlay nodes describe bounded composition intent;
ordinary-role v4 graph roots open independently supervised GPUI/XDG surfaces.
Only the trusted hosts convert measured bounds into compositor geometry or
authenticate the corresponding surface. Luau
never receives a Wayland object, socket, file descriptor, surface identity,
PID, or arbitrary placement operation.
compositor-control-protocol is a separate bounded newline-JSON ABI between
the trusted permanent host and compositor.
The compositor creates a mode-0600 control socket in a caller-owned mode-0700
runtime directory. A client must present the launch token and a PID equal to
the socket's SO_PEERCRED PID before opening its GPUI Wayland connection. The
compositor records the Shell host PID as trusted shell authority. Each ordinary
v4 host separately registers its own peer-credential PID as
NativeApplication but receives no shell-control methods. Other Wayland client
PIDs are compatibility clients. The listener serves at most 16 registered or
registering control connections concurrently; every mutation still crosses
the single compositor event-loop channel. A long-lived shell registration
therefore cannot block an independently presented application from registering.
This is a development-session authenticator. A
production session must also isolate service users/credentials so another
same-UID process cannot inspect launch credentials.
The policy admits one fullscreen shell, one bounded overlay, and at most eight
application windows across SOS-native Wayland, ordinary Wayland, and the
explicitly enabled rootless XWayland path.
Application surfaces stay above the shell and within the active window-space
rectangle. They are not embedded into GPUI or exposed as generated nodes.
Floating mode uses bounded cascade placement and click-to-raise focus. A normal
xdg_toplevel.move from a compatibility client, or a trusted source-native
chrome gesture, moves the selected window and clamps it to the declared
window-space. Repeating a Floating configuration preserves those positions;
switching layout resets placement. Tiling recursively bisects the longest edge,
allocates each branch in proportion to its window count, and produces a
balanced quad for four windows instead of a fixed master and unbounded stack.
Focus changes only stacking order and never reassign managed geometry or
clipping rectangles. The initial
scrolling mode uses overlapping horizontal cards while
focus/scroll-position control remains a later protocol addition. Configure
requests are constrained to the declared region, and each application's
rendered surface tree and pointer hit test are clipped to its assigned
rectangle. Hit testing uses the same buffer render origin as drawing, the managed
window location minus the client's xdg_window_geometry inset. It refreshes a
stationary pointer target at an ungrabbed press boundary. This remains true
when an XDG client advertises a minimum size
larger than a tile. Popups are clipped with their owning application; layer
shell and arbitrary client placement remain outside this gate. A null XDG
buffer unmaps a role without destroying it; compositor application counts,
focus candidates, and layout are recomputed immediately. Attaching a later
buffer maps the same still-live role again. Destroy and unmap therefore cannot
double-decrement policy state, and an unrelated shell action cannot resurrect
an unmapped client.
Client maximize, unmaximize, and fullscreen requests are currently denied for application roles by recomputing the complete selected layout. This prevents a client title-bar double-click from applying the one-window size to one tile in place and overflowing its assigned rectangle. Distinct maximize and fullscreen semantics remain future shell policy.
Ordinary shell content cannot overlap an application surface. Stock therefore
reserves its top bar and command or agent rail outside window_space; opening
a rail reduces the application rectangle. The dedicated shell overlay is the
narrow exception: it stays above all applications, is clamped to the output,
and can be moved only through the compositor-owned XDG move path. Hover is
hit-tested by the compositor. An expanded overlay collapses to its stable
action rectangle for the duration of a move, so the action can reach every
output edge without stale expanded geometry constraining it. A stationary
trusted move gesture is reported as activation; a geometry-changing gesture
reports only its final bounded anchor. The host suppresses stale scene geometry
until that anchor commit returns, preventing a dragged overlay from flashing
back to its previous position. This lets Luau define the bubble and composer
without gaining surface handles or global placement authority.
Input quiescing begins before the provider/state authority changes. After the candidate VM is prepared, the supervisor asks the permanent host to quiesce the exact candidate revision and waits for the compositor acknowledgement. The compositor removes keyboard and pointer focus, sends releases for keys/buttons that the old scene saw pressed, drops subsequent backend events, and suppresses the eventual release of any device held across the boundary. The host clears its bounded pending-event and gesture queues. Only then may the coordinator promote provider/state authority.
At present, the host asks the Luau worker to commit the prepared VM. When the
worker confirms that commit, it performs this handoff on the GPUI event thread:
- Ask the already-quiesced compositor to arm the exact request/revision pair and wait for its current shell-commit sequence.
- Install the worker-confirmed retained scene and assets in the same host.
- Request the new GPUI frame.
- Let the compositor tag the first later root shell commit.
- Keep compositor input quiesced until that shell commit participates in a successful nested submit, or until the exact queued direct frame produces a DRM VBlank/page-flip event.
- Return the request ID, revision ID, shell-commit sequence, backend-submit sequence, and typed evidence to the host.
- Only then emit the supervisor's
presented;confirmstill proves the host loop responds beforecurrentadvances.
If authority promotion aborts before presentation, discard resumes the exact
revision-bound compositor fence before discarding the candidate VM. A control
disconnect clears the fence without restoring focus to the unauthenticated
stale shell. Successful presentation restores focus only to the still-live
surface that owned it before quiescing.
Arming at the actual retained-scene handoff matters. Arming in the earlier supervisor request handler would permit an animated frame from the old scene to commit while the Luau worker was still switching. Waiting for the worker's commit result also prevents a visible revision from being certified while its active VM is unavailable. If arming then fails, the host exits so the supervisor recovers the durable committed revision instead of continuing with divergent runtime and visible state.
The compositor also advertises wp_presentation. In nested mode it completes
client feedback and the SOS event after a successful winit-backend submit. That
is stronger than GPUI's next-frame callback but the outer compositor may still
discard or delay the buffer. In direct mode, queueing a DRM frame only records
the candidate; frame_submitted on the matching VBlank completes Wayland
feedback and emits drm_page_flip with the kernel sequence, timestamp, and
clock domain. Only that event releases input and lets the host tell the
supervisor presented.
If the permanent host dies, its control disconnect drops an armed fence and releases input. The supervisor starts the committed revision in a new PID; the compositor authenticates it, replaces any stale shell surface, and fences the recovery frame without restarting itself.
On a Linux development machine with Xvfb, Weston, and
weston-simple-shm installed:
./tools/linux-compositor/verify-nestedThe verifier builds the locked graph and creates only disposable state. It
runs Weston's X11 backend in Xvfb, runs sos-compositor through its Smithay
winit backend, boots the coordinated Linux session inside that compositor,
activates the test-only stateful fixture, kills the exact host PID, waits for supervisor
recovery, and maps weston-simple-shm as the compatibility client. It requires:
- unchanged PID across the normal Luau activation;
- exact authority/current-pointer agreement;
- no
gpui_next_framefallback; - three compositor submit fences: boot, activation, and recovered boot;
- native XTest -> Weston -> Smithay ->
wl_keyboarddelivery, exact persistedwaylandtext replacement, and Enter submission; - restricted input-method-v2 attach, pinyin preedit/candidates/selection/CJK commit, dead key composition, keyboard grab, popup, and cursor rectangle;
- Wayland clipboard copy/cut/paste ownership through the native editor;
- live Linux-provider note and video-frame mutation, system/resource model refresh, and worker rerender without another revision presentation;
- semantic snapshot, next/previous traversal, focus, activation, scrolling, selection, copy/cut/paste, status waits, and service recovery after host kill;
- at least one compositor-owned backend event suppressed while activation is quiesced;
- a new authenticated PID after forced host failure;
- shell/native-compatibility role classification, authenticated window-space configuration and bounded placement;
- an opt-in real
Xwaylandprocess and bounded rootlessxmessagewindow.
Expected leading output:
linux_nested_compositor_passed activation_pid=... restarted_pid=... revision_id=... evidence=nested_backend_submit
The composition-specific companion gate is:
./tools/linux-compositor/verify-composition-nestedIt installs the Agenda, Media, Dashboard, and Remix reference packages into a
disposable graph store, activates the resolved Dashboard graph through the
durable graph supervisor, and inspects the composed semantic tree. It requires
separate parent/child ownership, namespaced editable state, child-event
routing, appearance propagation without forcing the custom Media visual
system, the same host PID across graph activation, exact graph recovery after
host death, and three nested_backend_submit fences. Its raw logs and stores
can be retained with SOS_COMPOSITION_EVIDENCE_DIR.
The host creates the trusted shell-overlay GPUI window only when the active
Scene contains its corresponding content. It reconciles that window after the
current GPUI entity update finishes, so a revision can add or remove the
surface without a reentrant entity update or leaving a transparent input
surface behind. Set SOS_NESTED_OVERLAY_ONLY=1 on the broader nested verifier
for the focused open/close check. Independent application Experiences use
registry lifecycle and separate host processes.
The gate passes both on the ARM64 Ubuntu 24.04 development host and inside the
reference Debian 13.6 ARM64 KVM guest. The Debian run activated revision
552f06968bbc5c69de3db581454f60d4303289f304eaaf47a6e9dc3200297cdb in
unchanged PID 11310, then recovered the same committed revision in PID 11514.
Its compositor evidence was:
boot: commit_sequence=1 submit_sequence=928
activate: commit_sequence=9 submit_sequence=936
recovery: commit_sequence=14 submit_sequence=1009
The compatibility client mapped at (280, 140). Mesa software rendering is
acceptable for this functional gate and makes no GPU, latency, or physical
display claim.
Run this only inside the disposable reference VM:
./tools/linux-vm/verify-direct-sessionThe verifier refuses a non-virtualized or non-Debian-13 environment. It builds
the direct feature, records whether GDM was active, stops GDM, acquires seat0
through libseat's seatd backend, and restores GDM on every exit path. It
requires the compositor's dark recovery view to page flip before starting the
SOS shell. It then repeats the nested gate's activation, exact host kill and
recovery, authority agreement, and compatibility-client checks, while rejecting
both gpui_next_frame and nested_backend_submit evidence.
The ARM64 Debian 13.6/KVM run passed with revision
552f06968bbc5c69de3db581454f60d4303289f304eaaf47a6e9dc3200297cdb in
unchanged PID 59723 and recovered the committed revision in PID 59849. The
three shell fences were:
boot: commit_sequence=1 submit_sequence=3
activate: commit_sequence=14 submit_sequence=11
recovery: commit_sequence=20 submit_sequence=17
All were emitted from DRM VBlank callbacks with monotonic kernel timestamps.
The VirtIO driver reported output sequence 0; this remains exact driver
metadata, not a fabricated counter. The compositor presented its recovery view
both before boot and between the killed/restarted hosts, and the separate
compatibility client mapped at (280, 140).
The 2026-08-27 x86_64 Debian 13 v4 graph campaign passed at source revision
294fe67 on kernel 6.12.101+deb13-amd64 in 15.887747472 monotonic seconds.
It booted Stock graph b8d0745f…, activated candidate graph 27ddfcc9… in
unchanged host PID 16868, physically presented a fault-injected rejected Stock
candidate, physically restored 27ddfcc9… before completing discard, and
restarted that accepted graph in PID 17301. The exact DRM-frame graph sequence
was old, new, rejected old, restored new, restarted new. Input stayed quiesced
from each candidate boundary until authority finalization or the restored
frame; both held-input lifecycles contained one keyboard key, one pointer
button and two touch contacts. Registry and authority agreed, no singleton
pointer was created, and GDM and seatd were active after cleanup. The retained
evidence is indexed from docs/progress.md; it is VM, not physical-panel or
integrated-input evidence.
The direct backend remains intentionally one seat, but accepts multiple DRM
devices and simultaneous connected outputs. Its default mirror policy prefers
the internal eDP connector as the canonical logical canvas, falling back to
the connected output with the largest pixel area. It renders that full canvas
unchanged on the canonical output and fits it uniformly, without crop or
distortion, on every other output. On Framework 12 this gives the laptop its
native 1920x1200 canvas with no top/bottom bands; the 1920x1080 PiKVM capture
receives the complete 16:10 scene at 0.9 scale with 96-pixel side pillars.
"layout": "extend" retains the connector-sorted horizontal desktop when
independent output space is wanted. Both policies survive connector and
whole-device removal/addition.
SOS_OUTPUT_MODE, SOS_OUTPUT_SCALE, and SOS_OUTPUT_ROTATION set boot
configuration. A bounded JSON file selected by SOS_OUTPUT_CONFIG_FILE can
change those values and layout on a DRM udev event; the backend recreates
outputs without restarting the compositor.
That file can also associate an exact libinput device name with a connector in
input_outputs. Absolute mice, touchscreens, and tablets use the configured
connector's logical geometry regardless of connector discovery order. They
remain automatic on a single output, but fail closed when multiple outputs make
an unconfigured route ambiguous or when the configured connector is absent.
In mirror mode, absolute input on a fitted secondary output is transformed
through the inverse scale and offset into canonical coordinates; an internal
touchscreen remains identity-mapped to the panel.
Relative pointers stay inside the shared mirror canvas. In extended mode they
traverse the complete connected-output layout and clamp only to the nearest
valid output rectangle, including across gaps between outputs.
The direct VM gate changes Virtual-1 to 1024x768, 1.25 scale, and 180-degree
rotation, then hot-adds Virtual-2 and requires a nonempty first frame and page
flip on that second CRTC. The render graph composites either a live client
cursor surface with its hotspot or a deterministic compositor-owned fallback
above the shell.
The direct verifier creates kernel uinput devices named SOS Gate Keyboard,
SOS Gate Relative Pointer, and SOS Gate Multitouch. Direct libinput reports
their add/remove events and the compositor records keyboard, relative motion,
button, and two-slot touch classes. It holds one modifier, one button, and two
contacts through a successful activation and through an injected
before-promotion authority failure. Both paths require keys=1 buttons=1 touches=2 at quiesce and suppressed releases after presentation or abort.
Revision 250b1573… activated in PID 8641 and recovered after the exact host
kill in PID 8888 with DRM page-flip evidence.
Seat revocation may make a KMS commit return EACCES just before libseat
delivers PauseSession. The direct renderer treats only Smithay's explicit
inactive-device or permission-denied DRM errors as that transition: it stops
submitting, waits for the seat event, and resumes on ActivateSession. Other
render failures remain fatal. The boot verifier selects s2idle explicitly,
restores the prior /sys/power/mem_sleep selection on every exit, and proves
that the same compositor owner survives VT pause/activation, the kernel freezer
suspend test, and connector remove/reconnect. This avoids both a false failure
on machines whose default is deep and a real crash in the DRM-master
revocation race.
Activation quiescing includes touch. Existing contacts receive one
wl_touch.cancel, their physical motion/release is suppressed across either a
successful presentation or an aborted candidate, and contacts that begin and
end while quiesced never enter the client epoch. A fresh down may reuse a
released slot. Smithay keeps each slot focused on its down target, which is the
Wayland-level capture behavior. The pinned GPUI Wayland client binds
wl_touch and forwards down/move/up/cancel into the shared bounded Scene
raw-pointer router, including multi-touch,
surface capture, cancellation, gesture arbitration, and pointer-count updates.
The first direct run exposed a mutable-client borrow across the touch callback;
dispatching callbacks/frames after releasing that borrow fixed the crash.
Core wl_touch has no pressure field, so finger samples explicitly report
pressure unavailable. A separate pressure stylus is carried through
tablet-v2; the direct VM gate observes normalized nonzero Scene pressure.
The VM's software GBM/EGL stack lacks EGL_WL_bind_wayland_display; the cited
run therefore used the compositor's advertised wl_shm path. The direct
backend now also advertises explicit Linux dmabuf feedback from the formats
importable by every renderer with a connected output. It validates each client
dmabuf against those active renderers before completing buffer creation and
updates the feedback across connector/device changes. This is independent of
the optional EGL Wayland binding and leaves wl_shm as the safe fallback. The
cited VM result predates that protocol path and remains a software-rendering
result; none of it is a physical display, latency, touch, GPU-performance,
suspend/resume, or thermal claim.
The crate pins smithay = 0.7.0. Its state, input, and nested-winit setup were
reduced from the upstream MIT-licensed smallvil and anvil examples at tag
v0.7.0, commit a166cf4c94b5aedc332a65aa1dd753e8148829c3; the required notice is preserved
in crates/sos-compositor/SMITHAY-LICENSE.txt. See the
Smithay repository and
backend documentation.
Boot-to-SOS packaging now passes in the same VM: a systemd/PAM service owns the active logind tty1 session, waits for the recovery page flip before provider and host startup, receives its token through systemd credentials, and recovers both host and whole-session failures without seatd. The nested campaign additionally proves the restricted input-method-v2 client, non-Latin candidate/preedit/ commit, dead key, cursor rectangles, Wayland clipboard, Linux semantic service, live provider/media refresh, and focus/state recovery. The direct recovery layer is a readable compositor-owned panel with restart, rollback, safe-mode, and provider-disable controls. Multi-output, runtime mode/scale/rotation, rootless XWayland, tablet pressure, and executable bounded shaders now have VM or software-renderer evidence. The Framework development-live campaign has physical panel, Intel DRM, built-in keyboard, touchpad, and touchscreen evidence. Calibration accuracy, measured GPU/panel performance, full platform sleep/wake, latency, memory pressure, thermals, and an installed or immutable release gate remain open.