IPC
Inspect and control Sweets through its control socket
Sweets exposes a versioned control socket for querying state, running actions,
and subscribing to changes. Use the built-in sweets msg client.
Quick start
sweets msg version
sweets msg outputs
sweets msg windows
sweets msg window 42
sweets msg workspace 2 DP-1
sweets msg status
sweets msg --json inputsPlain output is readable indented JSON. --json prints the compact envelope
with its version, request ID, and typed outcome. Errors go to stderr with a
non-zero exit status.
sweets msg --help lists the commands the installed binary accepts, and
sweets msg version reports the running compositor's capabilities.
Socket and trust
For WAYLAND_DISPLAY=wayland-2 the socket is:
$XDG_RUNTIME_DIR/sweets-wayland-2.sockSweets exports the absolute path as SWEETS_SOCKET to programs it launches.
The client uses that first, then falls back to deriving the path.
IPC is an owner-only administration interface, not a sandbox boundary. Any local process running as your user can read window metadata and run every action.
The socket is mode 0600, the runtime directory must be owned by you and
closed to everyone else, and peer credentials must match the compositor's UID.
If IPC cannot be established, Sweets still starts.
Queries
| Command | Returns |
|---|---|
version | Compositor and IPC versions, capabilities, limits |
outputs / output ID | Connectors, modes, geometry, power, scale, transform, VRR |
workspaces / workspace NUMBER [OUTPUT_ID] | Workspaces with output, active state, layout, master position |
special-workspace | Every special workspace: name, visibility, host output, and window IDs |
windows / window ID | Window identity, workspace, output, focus, state, icon |
window-rule ID | The resolved opening rule, the rules that matched or were excluded, and diagnostics for one window |
window-icon ID [SIZE [SCALE]] | One icon buffer's pixels, base64-encoded |
layers | Layer-shell identity, geometry, keyboard policy, opacity and blur |
inputs / input ID | libinput devices, capabilities, settings, switches |
frames / frame OUTPUT_ID | Per-output frame clock and presentation counters |
config | Path, generation, reload state, last error |
status | Lock, backend, rendering, explicit-sync health, and the active binding mode |
xwayland | XWayland lifecycle, display, and window counts |
binds [MODE] | Every binding in the active set, or in MODE |
batch SELECTOR ... | Several singular snapshots at one event boundary |
replay-events SEQUENCE FILTER ... | Retained events newer than a sequence |
Workspace state is ready for a bar or script:
{
"id": 2,
"output": "DP-1",
"active": true,
"layout": "grid",
"master_position": "left"
}Output and input IDs are exact and case-sensitive. Window IDs are stable while
the window is mapped. Unknown, removed, or stale targets return not_found.
In per_monitor workspace mode the same number appears once per monitor, so
name the output: sweets msg workspace 2 DP-1. An unqualified duplicate
returns ambiguous. Special workspaces are deliberately separate from the
numbered ones.
binds prints one line per binding. The trigger is spelled the way
sweets.bind accepts it, with MOD shown as the real modifier:
set: default (active)
SUPER+Return spawn foot
SUPER+SHIFT+slash show_bindings
SUPER+CTRL+x spawn foot -e htop System monitorRelease bindings show (release) after the trigger. With --json, each
binding also reports on (press or release), allow_when_locked,
repeating, and cooldown_ms. Name a mode to list it while another
set is active, or default for the default set.
Titles and application IDs can be sensitive. Treat window metadata carefully when forwarding IPC output somewhere else.
Window icons
Each window reports the icon its client set, or null:
{
"name": "org.gnome.Nautilus",
"buffers": [{ "size": 32, "scale": 1, "retained": true }]
}Resolve name through your XDG icon theme. buffers describes the pixel
images the client supplied — a window with "name": null and a non-empty
buffers has a pixel-only icon.
Fetch those pixels with window-icon:
sweets msg window-icon 42 | base64 -d > icon.rgba
sweets msg window-icon 42 64 1 | base64 -d > icon-64.rgbaWithout SIZE you get the largest buffer Sweets can deliver. The payload is
size × size × 4 bytes, row-major, R, G, B, premultiplied A. Plain output
prints the base64 alone so it pipes into base64 -d; --json adds the size,
scale, and format.
Sweets copies icon pixels when the client commits them. A buffer it cannot
keep — one wider than 128 pixels, past the 256 KiB per-window budget, or in a
format it does not convert — reports "retained": false, and asking for it
returns limit_exceeded or unavailable.
A size the window never declared returns not_found; one that exists at
several scales returns ambiguous until you name the scale.
X11 icons come from _NET_WM_ICON, which carries pixels only, so they always
report "name": null.
Icon, title, and application-ID changes raise the
window_metadata event, not window.
Layer surfaces
sweets msg layers is the layer-rule troubleshooting view. It lists live root
surfaces in stable-ID order with their namespace and current layer, the
requested against the resolved output, arranged geometry, keyboard
interactivity, and the resolved opacity and blur policy.
Blur demand describes compositor policy, not whether the renderer later succeeded. Independent popups are not roots and are omitted.
Batches
One batch fetches several unrelated snapshots together:
sweets msg batch --window 42 --output DP-1 --input event7 --workspace 2Selectors are --window, --output, --input, --frame, --workspace, and
--workspace-at NUMBER OUTPUT_ID. Results keep the requested order, echo the
selector, and carry their own success or error, so one stale target does not
discard the rest. Duplicates are preserved. Every --frame item shares one
time sample.
The result carries the global event sequence taken just before the items
were resolved. For a race-free refresh, subscribe first, then batch on a second
connection and install the result at that sequence. Buffered events up to it
are covered only for state the batch actually refreshed; retry if you already
applied a newer event.
A batch holds at most 32 items within a 32-unit budget: workspace and frame selectors cost 1, window and output 4, and input 16. Empty, oversized, and over-budget batches fail before any lookup.
Actions
sweets msg close
sweets msg force-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 workspace-previous
sweets msg move-to-workspace 4
sweets msg special-toggle [NAME]
sweets msg special-move [NAME]
sweets msg toggle-floating
sweets msg toggle-fullscreen
sweets msg toggle-windowed-fullscreen
sweets msg toggle-maximize
sweets msg minimize
sweets msg restore-minimizedDirections are left, right, up, and down.
force-close ends the focused window's application. It fails with
unavailable for an XWayland window; see
Force close.
workspace-previous returns the monitor you are on to the workspace it showed
before. It works whether or not workspace_back_and_forth is enabled, and does
nothing on a monitor you have not switched away from yet.
Targeting a window by ID
IDs from sweets msg windows work without focusing the window first:
sweets msg focus-window 42
sweets msg close-window 42
sweets msg force-close-window 42
sweets msg move-window-to-workspace 42 3
sweets msg move-window-to-output 42 right
sweets msg move-window-to-output-id 42 DP-2
sweets msg set-window-floating 42 on
sweets msg set-window-minimized 42 off
sweets msg set-window-maximized 42 on
sweets msg set-window-fullscreen 42 onfocus-window behaves like taskbar activation: it restores a minimized window
and reveals its workspace. The others do not change the selected workspace and
leave existing focus on the destination alone.
The set-window-* actions take on or off and are idempotent, which suits
declarative scripts. Un-minimizing does not focus — use focus-window when you
want both. move-window-to-output-id needs the exact id from
sweets msg outputs; moving a window to the output it is already on succeeds
and changes nothing.
Layout
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 previous
sweets msg resize horizontal grow
sweets msg resize vertical shrinkLayouts are tile, monocle, centered, grid, columns, deck,
dwindle, and scrolling. A cycle direction defaults to next and a reset scope to current.
These use the same paths as key bindings, so layout resize rules and an active
pointer resize still apply.
Administration
sweets msg reload
sweets msg reset-binding-mode
sweets msg output-power DP-1 off
sweets msg output-power DP-1 on
sweets msg quitreset-binding-mode returns to the global bindings from a
binding mode. It cannot select a mode, so
it is only ever a way out.
Everything else about outputs and input stays configuration-owned; IPC exposes no arbitrary mutation or command execution.
Every action returns changed and message. A valid no-op succeeds with
changed: false. While the session is locked, every action except quit is
rejected with locked.
Events
sweets msg subscribe focus window workspace
sweets msg --json subscribe all| Filter | Reports |
|---|---|
focus | Focus changes |
window | Windows opening, closing, and moving |
window_metadata | Title, application ID, X11 class or instance, and icon changes |
workspace | Selection, assignment, layout, and master position |
output | Monitor changes |
input | Input device changes |
config | Reload results |
lock | Session lock and unlock |
shutdown | The compositor stopping |
Events are small routing signals — queries stay authoritative, so use an event to decide what to re-query. An event fires only when the matching query would actually return something different.
Subscribe to window_metadata instead of polling if you display titles or
icons. Windows appearing and disappearing come through window.
Normal mode prints an acknowledgment then one compact event per line; JSON mode prints full envelopes. Sequence numbers increase globally and may skip values when you subscribe to only some filters.
Subscribers have bounded queues, and a client that falls behind is disconnected rather than allowed to grow compositor memory. Idle subscribers cause no repaints or polling.
Reconnecting
When a panel reconnects or sees a sequence gap, resume from the last sequence it applied:
sweets msg resume-events 37 workspace window
sweets msg --json resume-events 37 allOne acknowledgment subscribes you live at the returned sequence, with no
event lost in between. Status replayed carries the matching retained events
newer than your cursor — apply them in order, then process live frames from the
same socket. Status too_old carries no events but the socket is already
subscribed: keep it open, run an authoritative batch on a second connection,
install that at its sequence, and continue from there.
A malformed filter or a sequence ahead of the server returns an ordinary error and creates no subscriber.
replay-events is the one-shot equivalent for diagnostics and overlapping
handoffs:
sweets msg replay-events 37 workspace windowSweets retains at most 64 events and 128 KiB, and only while a subscriber is
active. An expired cursor returns too_old; refresh with ordinary queries
instead. When observation stops, Sweets reserves a sequence gap so unobserved
time can never look continuous.
Stability
The protocol is feature-frozen for panels and automation. Correctness fixes, hardening, and better diagnostics continue; a new request, action, or event category needs a deliberate version change.
Version 38 adds the on field to each binding in the binds reply.
Version 37 changed two input fields: enabled now reports the libinput
send-events mode (enabled, disabled or disabled_on_external_mouse) and
scroll_factor is now a { horizontal, vertical } object.
Version 36 added the binds query.
Version 30 added named special workspaces. special-workspace now returns a
list with a name per entry, a window's workspace reads
{"special":"NAME"} instead of "special", and special-toggle and
special-move take an optional name.
Version 29 added the status binding_mode field and the reset-binding-mode
action.
Version 28 added the window pinned field.
Version 27 added the workspace-previous action.
Version 26 added the window_metadata event and the window-icon query.
Version 25 added the window icon field. Version 24 renamed view to window
everywhere — the old spellings are not aliases.
Wire protocol
Each frame is one UTF-8 JSON value terminated by a newline. Every frame carries
the protocol version, and Sweets refuses any other with unsupported_version.
Run sweets msg version to read the version your compositor speaks.
{"version": 38,"id":7,"request":{"workspace":{"number":3,"output":"DP-2"}}}
{"version": 38,"id":8,"request":{"action":{"move_window_to_output_id":{"window":42,"output":"DP-2"}}}}
{"version": 38,"id":9,"request":{"batch":{"items":[{"type":"window","target":42},{"type":"frame","target":"DP-2"}]}}}
{"version": 38,"id":10,"request":{"resume_events":{"after":37,"filters":["workspace","window"]}}}Responses echo your request ID:
{"version": 38,"id":10,"outcome":{"status":"success","value":{"type":"resumed","data":{"after":37,"sequence":41,"filters":["workspace","window"],"status":"too_old","events":[]}}}}Error codes are invalid_frame, invalid_request, unsupported_version,
limit_exceeded, locked, not_found, ambiguous, too_old, unavailable,
and internal.
Unknown fields and variants, invalid JSON, trailing frames, wrong versions, and oversized collections are all rejected. The protocol deliberately excludes arbitrary command execution, force-kill, clipboard contents, raw input, and security tokens.
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 s |
| String field | 512 bytes |
| Batch items | 32 |
| Batch response cost | 32 units |
| Retained events | 64 |
| Retained event bytes | 128 KiB |
| Outputs | 32 |
| Modes per output | 64 |
| Workspaces | 576 |
| Windows | 256 |
| Layer-shell roots | 64 |
| Input devices | 64 |
Bindings in one binds reply | 256 |
Slow, malformed, or disconnected clients are removed without blocking 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, or server error |