Sweets
Configuration

Splitting Your Config

Organize sweets.lua with bounded, root-confined includes

sweets.include(...) executes another Lua file at that point in the current configuration layer. Use it to keep bindings, rules, outputs, and other settings in focused files.

Suggested structure

A personal configuration can use this layout:

~/.config/sweets/
├── sweets.lua
├── bindings.lua
├── rules.lua
└── parts/
    ├── general.lua
    ├── layout.lua
    └── startup.lua

Keep the root file small and include files in the order they should execute:

~/.config/sweets/sweets.lua
sweets.include("parts/general.lua")
sweets.include("parts/layout.lua")
sweets.include("bindings.lua")
sweets.include("rules.lua")
sweets.include("parts/startup.lua")

Each included file uses the normal typed Sweets API:

~/.config/sweets/parts/layout.lua
sweets.layout({
    default = "tile",
    master = 55,
})

sweets.gaps({
    inner = 10,
    outer = 10,
    smart = true,
})
~/.config/sweets/bindings.lua
sweets.bind("MOD+Return", "spawn", { "foot" })
sweets.bind("MOD+D", "spawn", { "fuzzel" })

for number = 1, 9 do
    sweets.bind("MOD+" .. number, "workspace", number)
end

Path resolution

Every include path must be a non-empty relative UTF-8 string. It resolves from the file containing that sweets.include(...) call, not from the process working directory.

~/.config/sweets/parts/general.lua
-- Resolves to ~/.config/sweets/parts/pointer.lua
sweets.include("pointer.lua")

Nested includes therefore work without repeating parent directories.

Absolute paths and any .. component are rejected. Includes cannot escape the directory containing their root sweets.lua. A leading ~ is not expanded to your home directory.

These paths are invalid:

sweets.include("/etc/sweets/shared.lua")
sweets.include("../shared.lua")

sweets.include("~/shared.lua") looks for a literal ~ directory below the including file; it does not refer to your home directory.

. path components are allowed, but simple paths are easier to read.

Each installed or personal root file owns a separate permitted directory. All of its nested includes must resolve to regular files below that directory.

A symbolic link is accepted only when its canonical target is a regular file that remains below the same root. A link to a file outside the configuration root rejects the complete candidate.

The installed and personal configurations are already separate layers. Do not include the installed /usr/share/sweets/sweets.lua from your personal file; Sweets loads installed defaults automatically before the personal layer.

Execution and scope

An include executes immediately in the same constrained Lua VM and the same installed or personal layer as its parent.

  • Sweets declarations take effect in include order.
  • Window rules, input selectors, bindings, and startup commands retain their declaration order across file boundaries.
  • A singleton section such as sweets.general, sweets.layout, or sweets.gaps may appear once across one root and all of its includes.
  • sweets.layout_style may appear once for each layout across one root and all of its includes.
  • The installed and personal layers may each declare the same singleton because personal fields overlay installed fields.

Included chunks share Lua globals. Lexical local values belong only to the file that declares them and are not visible in another included file. A shared global must be assigned before an include reads it; reading a missing global rejects the candidate at the included file and line.

~/.config/sweets/sweets.lua
palette = { accent = "#C27AFF" }
sweets.include("parts/border.lua")
~/.config/sweets/parts/border.lua
-- The global palette is visible here.
sweets.border({ focused = palette.accent })

Prefer file-local helpers and direct API declarations where practical. Shared globals work, but accidental global names can make a large configuration harder to understand.

Repeats and cycles

Every canonical source may participate only once in one candidate. Including the same file twice is an error, even through two different symbolic links.

Include cycles are also errors:

a.lua
sweets.include("b.lua")
b.lua
sweets.include("a.lua")

Sweets reports the include chain so you can find the repeated file or cycle. The complete candidate is rejected; Sweets does not skip the repeated include.

Validation and reload

Validate the standard installed and personal layers with all includes:

sweets --check-config

Validate one standalone root and its includes:

sweets --check-config ./test-config/sweets.lua

The validator uses the same path, sandbox, ordering, and resource rules as startup and reload. Errors identify the included source and Lua line while retaining the root file in the diagnostic.

Sweets watches every observed and resolved source. Saving an included file requests the same transactional reload as saving the root. If an include is missing, Sweets rejects the candidate but watches for that path to be created.

If any source or symlink changes during evaluation, Sweets rejects that candidate instead of combining files from different save states. A later settled save can then reload the complete tree.

Source limits

Limits apply to the complete candidate, including installed and personal roots:

LimitMaximum
Configuration sources32 files
Nested includes below a root16 levels
One source file256 KiB
All source files combined512 KiB
Canonical path length4,096 bytes

The Lua instruction, time, memory, and recursion limits described in Basic Configuration also cover every included file. Exceeding any limit rejects the complete candidate.

Common errors

ErrorCause
include path must be relativeThe include begins at /
include path must not contain ..The path attempts to leave its root
cannot resolve configuration sourceThe file is missing or inaccessible
include target escapes permitted rootA symlink resolves outside the root
source included more than onceTwo includes resolve to the same file
include cycleIncluded files eventually include an active parent
sweets.SECTION may be declared only onceA singleton appears twice in one layer

Fix the source and save it again, or request a manual retry:

sweets msg reload

Inspect the active generation and last reload error with:

sweets msg config

Next steps

On this page