# sb-builder settings pages sb-builder (a PyQt6 GUI in its own repo, `../sb-builder`) has two TOML configs and no UI to edit either: the GUI's own `$XDG_CONFIG_HOME/sb-builder/config.toml` on this desktop, and the helper's `/etc/sb-builder/config.toml` on the build VM. Both get settings pages here, in the `desktop/` settings window, under a group "SB Builder", the way qtmaildir's four pages sit under "Mail". ## Pages `desktop/modules/sbbuilder/`: - `Sbb.qml`, the singleton both pages share: two drafts (desktop, VM), each with the text last read, `dirty`, `invalid`, `error`, `save()`, `discard()`, `refresh()`, as `Qtm.qml` does for one. - `Toml.js`, a line editor for the TOML these two files use: top-level and `[section]` keys whose values are strings, integers, booleans and arrays of strings, one key per line. It reads a value, sets one (in place, or appended to its section, the section appended when missing), unsets one (commented out with `#` where it stands, reactivated when set again), and lists a section's keys. Comments and order survive. Values it writes are TOML basic strings with `\` and `"` escaped. `test_toml.js` is its check, run with `node`. - **Desktop** page (`SbbDesktopModule.qml`), over the GUI config through a watched, atomic `FileView`: remote target and ssh options, the two refresh intervals, notifications on/off and one switch per event, the VM's libvirt URI, domain and autostart, the initial publish state, the nvchecker keyfile, the repository path. - **Build VM** page (`SbbVmModule.qml`): the helper's thirteen keys and the `[manifests]` table as rows, removable, with an add row (package, URL). Every field follows the settings window's rules (`desktop/README.md`): it edits the draft as typed, Save in the page header writes, Discard drops, a save over a file changed since the draft began is refused. An emptied field unsets its key and the placeholder names the default. Numbers are range-checked (refresh intervals: whole seconds, at least 1), a refused one holds Save back. Lists (`ssh_options`, `overlays`) are one field, entries separated by spaces; an entry holding a space is a `ponytail:` ceiling, editable only by hand. The desktop defaults are mirrored from sb-builder's `config.py` DEFAULTS (`ponytail:` a key added there needs adding here). The VM defaults come from the helper itself. ## The VM side The helper's config is root's file on another machine, and the helper is a trust boundary: it runs a fixed command table and validates what reaches it. So the page never writes the file by hand over ssh. sb-builder's helper gains two commands: - `sbb-remote config-get`: JSON `{"text": , "defaults": , "path": }`. - `sbb-remote config-set`: the new file text on stdin. Parsed with `tomllib`; refused, with the reason as its error, on a parse error, an unknown key or a value of the wrong type (the checks `load_config` already makes, `[manifests]` values strings). Accepted, it copies the old file to `.bak` and replaces it atomically (temp file, rename). stdin input has a precedent in `gpg-unlock`. The page runs `ssh sbb-remote config-get` with the target and options from the desktop page's saved config (not its draft), on every open of the window and from a reload button. Save pipes the draft to `config-set`. The helper's error, or ssh's, lands in the SaveBar. With the VM down the page says so and its fields are read-only. The helper reads its config on every call, so a saved change applies to the next one. The VM draft's "changed on disk" check compares the text config-get last returned against a fresh config-get just before config-set. ## sb-builder's side Owned by that repo, built there: - the two helper commands above, with `test_remote.py` cases: accepted text written and `.bak` made, bad TOML, unknown key, wrong type refused with the file untouched; helper VERSION bumped in `remote/sbb-remote` and `sb_builder/__init__.py`; deploying with `./install.sh --remote` is asked first. - the GUI watches its config file (`QFileSystemWatcher`, re-added after each change since an atomic write replaces the inode) and calls its existing `reload_config`, so a save from the settings page applies live. File, Reload config stays. - a note in its README that both configs have settings pages in Keystone, and that the files remain hand-editable. ## Out of scope The phantom deps file, hint files and anything else the helper reads besides its config. Editing configs of a VM other than the one `remote.target` names.