IPC
Inspect and control Sweets through its typed, owner-only IPC.
Sweets exposes a bounded, versioned control socket for querying state,
dispatching typed actions, and subscribing to state-change notifications. Use
the integrated sweets msg client; it exits before compositor initialization.
Quick start
sweets msg version
sweets msg outputs
sweets msg output DP-1
sweets msg workspaces
sweets msg workspace 2 DP-1
sweets msg windows
sweets msg window 42
sweets msg layers
sweets msg batch --window 42 --input event7 --frame DP-1 --workspace-at 2 DP-1
sweets msg replay-events 37 workspace window
sweets msg resume-events 37 workspace window
sweets msg input event7
sweets msg frame DP-1
sweets msg status
sweets msg --json inputsWithout --json, successful values are printed as readable indented JSON.
With --json, Sweets prints the compact response envelope, including its
version, request ID, and typed outcome. Server errors are printed to stderr and
return a non-zero exit status.
Run sweets msg --help for the command list accepted by the installed binary.
The version query also reports the running compositor's query, action, event,
and stream-mode capabilities.
Discovery and trust
For WAYLAND_DISPLAY=wayland-2, the compositor listens on:
$XDG_RUNTIME_DIR/sweets-wayland-2.sockSweets exports the absolute socket path as SWEETS_SOCKET to launched children
and the activation environment. The client uses that value first and otherwise
derives the standard path from XDG_RUNTIME_DIR and WAYLAND_DISPLAY.
IPC is an owner-only administration interface, not a sandbox boundary. A local process running as the compositor user can inspect window metadata and request every advertised action.
Before publishing IPC, Sweets verifies that the runtime directory is absolute,
real, owned by the compositor user, and inaccessible to group and other users.
The socket is mode 0600, and Linux peer credentials must match the
compositor's effective UID. An unsafe runtime directory or mismatched peer is
rejected. Startup continues if IPC cannot be established.
Queries
| Command | Result |
|---|---|
version | compositor and IPC versions, capabilities, frame, replay, and batch limits |
outputs | connector identity, modes, geometry, power, scale, transform, VRR, and gamma state |
output OUTPUT_ID | one output in the same snapshot shape |
workspaces | numbered workspace instances, output, active state, layout, and master position |
workspace NUMBER [OUTPUT_ID] | one enabled numbered workspace in the same snapshot shape |
batch SELECTOR ... | ordered window/output/workspace/input/frame snapshots, typed per-item outcomes, and an event sequence boundary |
replay-events SEQUENCE all|FILTER [FILTER ...] | bounded retained events newer than a global sequence, or typed too_old |
special-workspace | private-workspace visibility, host output, and window IDs |
windows | mapped window identity, workspace/output, focus, state, and urgency |
window WINDOW_ID | one mapped window in the same snapshot shape |
window-rule WINDOW_ID | immutable resolved opening rule and diagnostics for one mapped window |
layers | live layer-shell identity, output/geometry, keyboard policy, and resolved opacity/blur state including an optional alpha threshold |
inputs | typed libinput devices, capabilities, settings, and switches |
input INPUT_ID | one input device in the same snapshot shape |
frames | per-output frame clock and presentation counters |
frame OUTPUT_ID | one output frame clock in the same snapshot shape |
config | path, source, generation, reload state, and last error |
status | lock, backend, rendering, and explicit-sync health |
xwayland | XWayland lifecycle, retry health, display, and window counts |
Workspace state is directly suitable for bars and scripts:
{
"id": 2,
"output": "DP-1",
"active": true,
"layout": "grid",
"master_position": "left"
}In per_monitor workspace mode, the same number may appear once per output;
the output field distinguishes those independent instances. Use that exact,
case-sensitive ID with workspace NUMBER OUTPUT_ID. An unqualified duplicate
number returns ambiguous. Missing targets return not_found. The private
special workspace is intentionally separate from numbered workspaces.
Titles, application IDs, connector names, and other strings are bounded. Treat
window metadata as potentially sensitive when forwarding IPC output elsewhere.
Singular queries avoid collecting full output, workspace, window, input, or frame
lists. Input and output IDs are exact and case-sensitive, and window IDs are
stable for the mapped lifetime. Unknown, removed, disconnected, or stale
targets return not_found.
sweets msg layers is the layer-rule troubleshooting view. It lists live root
surfaces in stable-ID order and reports their exact namespace and current
background, bottom, top, or overlay layer. The snapshot distinguishes
the requested output from the currently resolved output, includes arranged
global geometry and keyboard interactivity, and exposes resolved appearance:
opacity, inherit/force/veto blur policy, effective blur mode, rule-mode
override, global blur enablement, retained client blur demand, and current
effect demand. Effect demand describes compositor policy, not whether a
renderer allocation later succeeded. Independent XDG popups are omitted.
Use one bounded batch when a panel needs several unrelated singular snapshots:
sweets msg batch --window 42 --output DP-1 --input event7 --frame DP-1 --workspace 2Selectors are fixed-arity flags: --window WINDOW_ID, --output OUTPUT_ID,
--input INPUT_ID, --frame OUTPUT_ID, --workspace NUMBER, and
--workspace-at NUMBER OUTPUT_ID. Results preserve the requested order, echo
the selector, and carry their own typed success or error. A stale window, removed
input, unknown output, or ambiguous unqualified workspace does not discard
successful siblings. Duplicates are preserved for deterministic correlation.
Every frame item in one batch uses one shared monotonic-time sample. The outer
result includes the global event sequence synchronized immediately before
the items are resolved.
For race-free refresh, establish a subscription first, then issue the batch on a second connection. Install the batch at its returned sequence. Buffered events through that value are covered only for state the batch fully refreshed; other events still require their normal query. Reject or retry a batch if you already applied a newer event. Changes after the batch receive larger sequences. Without an active subscriber, the value is only the current event position, not a continuously sampled mutation counter.
Use atomic resume when a panel reconnects or detects a sequence gap. Supply the last global sequence the panel applied:
sweets msg resume-events 37 workspace window
sweets msg --json resume-events 37 allOne successful acknowledgment establishes the live stream at its returned
sequence. Status replayed includes retained matching events newer than the
requested cursor; apply them in order, install the boundary, then process later
event frames from the same socket. Status too_old contains no replay events
but the socket is already subscribed at the returned boundary. Keep it open,
issue an authoritative batch on a second connection, install that snapshot at
its sequence, and then process buffered events above the covered boundary.
No event can be assigned between resume acknowledgment and live ownership.
Malformed filters and sequences ahead of the server return an ordinary error
without creating a subscriber. If the previous final subscriber disappeared,
Sweets reserves a sequence gap and resume returns too_old, preventing
unobserved time from appearing continuous.
The bounded one-shot query remains available for diagnostics and overlapping handoffs:
sweets msg replay-events 37 workspace window
sweets msg --json replay-events 37 allIts response echoes the requested sequence and unique filters, includes the
synchronized current sequence, and returns matching events in original
global order. Events are strictly newer than the requested sequence and no
newer than the response boundary.
Sweets retains at most 64 events and 128 KiB of encoded event data, and only
while at least one subscriber keeps observation active. If the cursor expired
or the last subscriber disappeared, replay returns typed too_old; refresh
authoritative state with singular or batch queries instead. Sweets reserves a
sequence gap when observation stops, so it never presents unobserved time as a
continuous event history.
A batch contains at most 32 items and has a 32-unit response budget. Workspace and frame selectors cost one unit, window and output selectors cost four, and input selectors cost 16. This permits up to 32 workspace/frame snapshots, eight window/output snapshots, or two maximum input snapshots, including mixtures, while keeping response work and memory bounded. Empty, over-count, and over-budget batches fail before target lookup.
Window and workspace actions
Directional actions accept left, right, up, or down:
sweets msg close
sweets msg focus left
sweets msg focus-output right
sweets msg move down
sweets msg move-to-output left
sweets msg switch-workspace 3
sweets msg move-to-workspace 4
sweets msg special-toggle
sweets msg special-move
sweets msg toggle-floating
sweets msg toggle-fullscreen
sweets msg toggle-maximize
sweets msg minimize
sweets msg restore-minimizedStable IDs from sweets msg windows can target a window without first focusing it:
sweets msg focus-window 42
sweets msg close-window 42
sweets msg move-window-to-workspace 42 3
sweets msg set-window-floating 42 on
sweets msg set-window-floating 42 off
sweets msg set-window-minimized 42 on
sweets msg set-window-maximized 42 on
sweets msg set-window-fullscreen 42 on
sweets msg move-window-to-output 42 right
sweets msg move-window-to-output-id 42 DP-2Targeted focus behaves like taskbar activation: it restores a minimized window
and reveals its numbered or special workspace. Targeted movement does not
switch the selected workspace and preserves an existing destination focus.
Floating assignment is idempotent, making it suitable for declarative scripts.
Unknown, unmapped, and stale IDs return not_found without changing state.
Minimize, maximize, and fullscreen also accept on or off and are
idempotent. Unminimizing does not activate a window; use focus-window when restore
and focus is intended. Output movement resolves direction from the target
window's current output and preserves the selected output and existing
destination focus.
Use move-window-to-output-id with the exact, case-sensitive id reported by
sweets msg outputs. Unknown or disconnected output IDs return not_found.
Moving a window to its current output is a successful no-op.
Layout actions
Layout names are tile, monocle, centered, grid, columns, deck, and
dwindle.
sweets msg layout grid
sweets msg cycle-layout
sweets msg cycle-layout previous
sweets msg reset-layout
sweets msg reset-layout all
sweets msg cycle-master-position
sweets msg cycle-master-position previous
sweets msg resize horizontal grow
sweets msg resize vertical shrinkOmitted cycle directions default to next; omitted reset scope defaults to
current. Layout operations call the same policy and held-presentation paths
as configured bindings. They do not bypass active pointer-resize ownership or
layout-specific resize rules.
Administration actions
sweets msg reload
sweets msg output-power DP-1 off
sweets msg output-power DP-1 on
sweets msg quitOutput power is applied through the backend owner. Other output and input settings remain configuration-owned; IPC does not expose arbitrary mutation or command execution.
Every action returns a typed result with changed and message. A valid no-op
is successful with changed: false. While the secure session lock is active,
all state-changing actions except clean quit are rejected with locked.
Events
Subscribe to one or more unique filters, or use all:
sweets msg subscribe focus window workspace
sweets msg --json subscribe all
sweets msg resume-events 37 workspace window
sweets msg --json resume-events 37 allAvailable filters are focus, window, workspace, output, input, config,
lock, and shutdown. Workspace events cover selection, assignment, layout,
and master-position changes. Queries remain authoritative: notifications are
small routing signals intended to trigger a follow-up query.
Normal mode prints a readable acknowledgment followed by one compact event per line. JSON mode prints complete acknowledgment and event envelopes. Sequence numbers increase globally and may contain gaps when a subscriber selects only some filters. The integrated client validates that resumed events match the requested filters, increase within the acknowledgment boundary, and precede every later live frame.
Subscribers have bounded output queues. A client that falls behind is evicted, so it cannot grow compositor memory or block the event loop. Idle subscribers do not cause repaint or polling loops.
Stability
Protocol v24 is the feature-frozen panel and automation surface. Version 24
uses window consistently across queries, IDs, snapshots, batch selectors,
targeted actions, special-workspace membership, event filters, and event
payloads. The removed view spellings are not aliases. Sweets will continue
to fix correctness issues, harden validation, and improve diagnostics.
New requests, actions, event categories, or authority boundaries require a
concrete consumer need and a deliberate protocol-version change rather than
speculative expansion.
Wire protocol v23
The shared sweets-ipc Rust crate owns the wire schema and has no Smithay or
live compositor-state dependency. Each frame is one UTF-8 JSON value terminated
by a newline.
{"version":23,"id":7,"request":{"workspace":{"number":3,"output":"DP-2"}}}{"version":23,"id":8,"request":{"action":{"move_window_to_output_id":{"window":42,"output":"DP-2"}}}}{"version":23,"id":9,"request":{"batch":{"items":[{"type":"window","target":42},{"type":"input","target":"event7"},{"type":"frame","target":"DP-2"},{"type":"workspace","target":{"number":3,"output":"DP-2"}}]}}}{"version":23,"id":10,"request":{"replay_events":{"after":37,"filters":["workspace","window"]}}}{"version":23,"id":11,"request":{"resume_events":{"after":37,"filters":["workspace","window"]}}}{"version":23,"id":11,"outcome":{"status":"success","value":{"type":"resumed","data":{"after":37,"sequence":41,"filters":["workspace","window"],"status":"too_old","events":[]}}}}Success and failure echo the caller-chosen request ID. Error codes are
invalid_frame, invalid_request, unsupported_version, limit_exceeded,
locked, not_found, ambiguous, too_old, unavailable, and internal.
The protocol rejects unknown fields and variants, invalid UTF-8 or JSON, trailing frames, wrong versions, invalid workspace numbers, and oversized collections. It deliberately excludes arbitrary command execution, force-kill, clipboard contents, raw input, security tokens, and configured command arguments.
Resource limits
| Resource | Limit |
|---|---|
| Concurrent clients | 32 |
| Request frame | 64 KiB |
| Response frame | 256 KiB |
| Event frame | 64 KiB |
| Subscriber queue | 64 KiB |
| Partial request lifetime | 10 seconds |
| String field | 512 bytes |
| Batch items | 32 |
| Batch response cost | 32 units |
| Retained replay events | 64 |
| Retained encoded event bytes | 128 KiB |
| Outputs | 32 |
| Modes per output | 64 |
| Workspaces | 576 |
| Windows | 256 |
| Layer-shell roots | 64 |
| Input devices | 64 |
The nonblocking calloop transport performs bounded work per wake. Slow, malformed, disconnected, or non-reading clients are removed without blocking or panicking the compositor.
Exit codes
| Code | Meaning |
|---|---|
0 | success, including a reported no-op |
2 | command usage error |
3 | socket discovery or connection error |
4 | transport, protocol, serialization, or typed server error |