Basic Configuration
Create, validate, and reload your Sweets Lua configuration
Put only the values you want to change in ~/.config/sweets/sweets.lua:
sweets.general({
mod_key = "SUPER",
})
sweets.gaps({
inner = 12,
outer = 12,
smart = true,
})
sweets.bind("MOD+D", "spawn", { "fuzzel" })Do not edit the installed sweets.lua. Package upgrades and source installs
replace it.
Load order
| Order | File |
|---|---|
| 1 | PREFIX/share/sweets/sweets.lua — installed defaults |
| 2 | ~/.config/sweets/sweets.lua — yours, optional |
PREFIX follows the binary. /usr/bin/sweets reads
/usr/share/sweets/sweets.lua, /usr/local/bin/sweets reads
/usr/local/share/sweets/sweets.lua. XDG_CONFIG_HOME is honored when set.
With neither file present, Sweets starts with built-in defaults and a small set of emergency bindings.
How the layers combine
Your file does not replace the installed one wholesale. Each API merges differently:
| Declaration | Merge |
|---|---|
| Singleton sections | Your fields override; omitted fields stay unchanged |
| Layout styles | Overlays fields for the same layout only |
| Key bindings | Replaces the same key; sweets.unbind removes it |
| Environment entries | Replaces the same variable name |
| Monitor and workspace rules | Replaces the rule for the same connector or number |
| Window and layer rules | Installed rules run first, yours append |
| Input selectors | Global block overlays; selector rules append |
| Startup commands | Both layers run, installed first |
| Animations | Your fields overlay the installed timing |
A singleton such as sweets.general, sweets.layout, or sweets.gaps may be
declared once per layer. Declaring one twice in the same layer, includes
counted, is an error.
Validate
sweets --check-config # installed and personal together
sweets --check-config ./test.lua # one file on its ownA successful check prints the resolved path, then every evaluated source in order: installed defaults, their includes, your override, and its includes. If no file exists, it reports built-in defaults. An explicit path lists only that file and its includes. Syntax errors, unknown fields, wrong types, duplicate declarations, and unsafe include paths exit nonzero, list sources attempted so far, and name the failing source. Neither form opens a Wayland socket.
Reload
Sweets watches the installed file, your file, and every
included file, and reloads on save.
To reload manually, press MOD+Shift+R or run:
sweets msg reloadA reload is all or nothing. A rejected candidate leaves the last valid configuration active and shows the error on every monitor until you fix it.
Inspect the active path, generation, and latest error:
sweets msg configIndividual pages note when a valid reload affects only future actions or future windows.
X11 applications
XWayland is disabled by default. To run X11 applications, add this to your personal configuration and restart Sweets:
sweets.xwayland({ enabled = true })X11 menus and tooltips keep their application-requested positions when reopened, including on mixed-scale monitors.
The sweets table
The global sweets table is the only API available to your configuration.
| Call | Configures |
|---|---|
sweets.general | Modifier, background, workspace mode, cross-monitor policy |
sweets.xwayland | Private rootless XWayland startup |
sweets.layout | Layout defaults, master position, insertion, cycling |
sweets.layout_style | Per-layout appearance overrides |
sweets.gaps, sweets.border, sweets.window, sweets.special | Gaps, borders, corners, special-workspace appearance |
sweets.notify | Configuration-error bar appearance |
sweets.keyboard, sweets.cursor | XKB, repeat, Num Lock, cursor theme |
sweets.pointer | Automatic pointer-follow behavior |
sweets.input | Global and per-device libinput settings |
sweets.gesture, sweets.gestures | Touchpad swipe actions and recognition policy |
sweets.bind_switch | Lid and tablet-mode bindings |
sweets.monitor | Mode, scale, transform, position, adaptive sync |
sweets.workspace | Workspace-to-monitor pins |
sweets.window_rule | Opening behavior and appearance for matching windows |
sweets.layer_rule | Appearance for matching layer-shell surfaces |
sweets.blur | Global backdrop-blur policy |
sweets.shadow | Global drop-shadow policy |
sweets.animations | Window and workspace transitions |
sweets.curve | Names a curve for reuse |
sweets.env | Environment for programs Sweets launches |
sweets.exec_once | Programs started once per session |
sweets.bind, sweets.unbind | Key bindings and sequences |
sweets.include | Additional Lua files |
Unknown names and fields are rejected.
Strict globals
Reading an undeclared global rejects the configuration. This catches typos that Lua would otherwise turn into a silently absent field:
local enabled = true
sweets.pointer({ follow_focus = enabled }) -- valid
sweets.input({ natural_scroll = falsed }) -- error: unknown global `falsed`Declare variables before reading them. An explicit nil still omits the entry
as usual.
Sandbox
Lua functions, loops, tables, and the string, table, math, and utf8
libraries are available. Filesystem, process, and native-module access is not:
io, os, package, require, debug, dofile, loadfile, load,
pcall, xpcall, collectgarbage, and print are all removed.
Use sweets.include instead of
require, and sweets.exec_once or a spawn
binding to start programs. Commands are argument arrays and are never passed to
a shell.
Each load is bounded:
| Limit | Value |
|---|---|
| Instructions | 5 million |
| Evaluation time | 250 ms |
| Memory | 16 MiB |
| Call depth | 128 |
| Sources / include depth | 32 / 16 |
| Per file / all files | 256 KiB / 512 KiB |
Exceeding a limit rejects the configuration like any other error. Numbers must
be finite; math.huge and 0/0 are rejected.
Next steps
- Split the configuration across files
- General settings for workspaces and focus
- Key bindings for actions and commands