Configuration

Six small files under /etc/scraplinux/, each with one job, instead of one large file covering everything. Edit one, then run scraplinux-rebuild to apply it.

FileCovers
pkgs.confa mirror of what's explicitly installed - never hand-edited, never reconciled against
network.confsaved wifi credentials, written by wifi-connect
users.confdeclared accounts, additive only
services.confthe enabled service list
hardware.confgpu, microcode, bootloader, boot timeout
identity.confhostname, timezone, locale, keymap

The file format

A bracketed block grammar, not shell - reading a value never means . file-sourcing something a package or a service wrote, which is a real quoting/injection risk once anything on the machine writes into these automatically.

block.name[
value one per line
another value
]

another.block[
value
]

;;

Every file ends in a lone ;; line - a hard sentinel a reader can check for, so a write interrupted partway through is detectable rather than silently read as an empty, valid file. conf.lib (sourced by wifi-connect, scraps, and scraplinux-rebuild) provides conf_get/conf_get1/conf_set/conf_set1 - the only supported way to read or write one of these files.

pkgs.conf is a mirror, not a wishlist

pkgs.scraplinux[] is rewritten by scraps itself after every add/rem to match exactly what's explicitly installed right now. Nothing ever reconciles the machine to this file - editing it by hand changes nothing, the next scraps add/rem just overwrites the edit with reality again.

This is deliberate, and the reason is a real incident: an earlier design used a declared package list that a rebuild diffed against and enforced, and a machine that had a couple of packages installed by hand outside of that file had both silently removed the next time a system upgrade ran its own reconciliation. Making the ledger a pure mirror instead of a diff target removes that whole failure class structurally, rather than trying to get the diffing logic more careful.

pkg.save[] is the opposite - a hand-maintained protect-list. Anything named there refuses removal outright (scraps rem included, and any orphan sweep), regardless of why it was installed, unless overridden with SCRAPS_FORCE=1.

network.conf

wifi-connect writes wifi.ssid[], wifi.psk[] and wifi.iface[] here on a successful connect. rc.d/wifi reads it back on every boot and reconnects in the background - see networking.

users.conf, services.conf, hardware.conf, identity.conf

These four are what scraplinux-rebuild actually reconciles. users.declared[] holds one name:shell:groups line per user - additive only, an account that exists but isn't listed is left alone rather than deleted. services.enabled[] is the full, authoritative service list - a name removed from it gets disabled on the next rebuild. hw.gpu[]/hw.microcode[] default to auto, re-detecting from the PCI bus/cpuinfo every rebuild rather than pinning whatever the machine had the day it was set. hw.bootloader[] is reported on mismatch, never switched automatically - that means reinstalling boot sectors, which stays a manual step.

Every file that starts genuinely empty gets seeded from what the machine already is on the first scraplinux-rebuild, rather than being reconciled against as if empty meant "remove everything" - an empty services.conf does not mean "disable every service currently running."

scraplinux-rebuild

scraplinux-rebuild             make the system match the declared files
scraplinux-rebuild --dry-run   show what would change, do nothing

Also finishes what a chroot install couldn't: activates any kernel package still marked -nomod, and writes limine.conf/grub.cfg from the real /etc/fstab//etc/crypttab - config only, never the deploy command. Every successful run snapshots (on btrfs) and records a generation, so a bad edit is one scraplinux rollback away - see generations.

More: scraplinux linux docs · install · packages · kernels & generations · networking, desktops & init · troubleshooting & reference