Sweets
Configuration

Window Rules

Place and shape matching XDG and XWayland windows when they first map.

sweets.rule({ ... }) matches a window by exact app_id, title, and optional backend, then applies placement and behavior when it first maps. Rules are optional — an unmatched window opens on the current workspace.

sweets.rule({ app_id = "org.wezfurlong.wezterm", workspace = 2 })
sweets.rule({ title = "Picture-in-Picture", floating = true, focus = false })
sweets.rule({ backend = "xwayland", app_id = "steam", monitor = "DP-1" })
sweets.rule({ app_id = "org.gnome.Nautilus", floating = true, size = { 900, 700 } })
sweets.rule({ title = "Picture-in-Picture", floating = true, size = { 480, 270 }, position = "top-right" })

Options

KeyTypeDefaultDescription
app_idstringExact app_id (Wayland) or X11 class
titlestringExact window title
backendstringanyRestrict to xdg or xwayland
workspacenumcurrentWorkspace 110 to open on
monitorstringcurrentOutput name to open on
floatingboollayouttrue floats, false forces tiling
focusboolautofalse opens without taking focus
sizetablenaturalOpen size { width, height }. Floating only
positionstring | tablecenterAnchor name or { x, y }. Floating only
maximizedboolfalseOpen maximized
fullscreenboolfalseOpen fullscreen (cannot combine with maximized)

A rule must set at least one matcher (app_id, title, or backend). app_id, title, and monitor cannot be empty strings.

Matching

Matching is exact — not substring, not pattern. All present matchers must hold, so a rule with both app_id and title fires only when both match.

When several rules match one window they apply in config order, and later fields override earlier ones. This lets you layer a broad rule and a specific one.

Run sweetctl views to read each window's real app_id and title. Titles often contain dynamic text like Page — Firefox, so reserve exact title rules for stable ones such as Picture-in-Picture.

Placement and focus

When workspace or monitor sends a window somewhere not currently visible, Sweets follows it and switches to that workspace or output. If the target is already visible elsewhere, that output becomes active.

focus = false opens a window without keyboard focus. It cannot grant focus to a window that would not normally take it, so focus = true is the same as omitting the field.

If a rule names a disconnected monitor, Sweets falls back to the current output so the window stays reachable.

Size

size applies to floating windows only — the tiler owns tiled geometry. Pair it with floating = true. The window opens centered at the requested size, clamped to its output, and stays freely resizable.

Each value is pixels when greater than 1, or a fraction of the output when 1 or less. So { 900, 700 } is 900×700 pixels, while { 0.5, 0.5 } is half the monitor. Fractions scale across monitors of different resolutions.

Values must be finite, greater than 0, and at most 32767.

Position

position is floating-only and takes two forms.

An anchor name snaps the window to one of nine spots: center, top-left, top, top-right, left, right, bottom-left, bottom, bottom-right. Edge and corner anchors inset by the outer gap. center is the default.

{ x, y } coordinates set the top-left precisely. Each value is pixels when > 1 or a fraction when between 0 and 1, so { 100, 0.25 } is 100px from the left and a quarter down. The window is clamped to its output. Coordinates range from 0 to 32767.

Maximized and fullscreen

maximized = true covers the usable area. fullscreen = true covers the whole output with no border or gaps. Both work for tiled and floating windows.

Any size or position becomes the geometry the window restores to on exit. The two are mutually exclusive — setting both is rejected. A client that ignores the state keeps its own size.

Applying changes

Rules are evaluated once, when a window first maps. After editing rules, reload the config and reopen the window.

XWayland windows may set title and app_id slightly after appearing, which makes title-based rules unreliable for those clients.

On this page