.. _reference-config: Configuring a runner ==================== A paired runner reads a ``saggar.toml``: ``--config ``, else ``~/.config/saggar/saggar.toml`` (``$XDG_CONFIG_HOME`` honored), else ``/etc/saggar/saggar.toml``. Precedence, increasing: built-in defaults, the config file, ``SAGGAR_*`` environment variables, CLI flags. Unknown keys anywhere are refused: a typo must never silently disable the setting it was meant to set. What you can configure on your runner: ``data_dir = "~/.local/share/saggar"`` Root for everything the runner keeps on disk: build work trees (``work/``), warm caches (``cache/``), cloned or uploaded sources (``sources/``), job logs (``logs/``), the artifact upload spool (``blobs/``) and the scratch root (``scratch/``). Env: ``SAGGAR_DATA_DIR``; flag ``--data-dir``. ``node_id = ""`` The id the runner pairs and appears under. Default: the machine hostname. Env: ``SAGGAR_NODE_ID``. ``[envs]`` Environment resolution: fingerprint → OCI image ref. .. code-block:: toml [envs] "debian:12" = "debian:12" "debian:12 + rust" = "rust:1-bookworm" Entries are optional: each plugin declares its own default image. It is the official one for its toolchain, rolling where the vendor publishes a rolling tag (``rust:1``, ``node``, ``python:3``, ``ruby:3``, ``golang:1``, ``swift``, all on the fingerprint's own Debian release; full variants, never slim), or a fixed ref where it does not: uv pins its own distro, dotnet ships latest, composer and elixir stay pinned by hand and bumped when their line retires. For the JVM family the image derives from the project: gradle reads the toolchain level the build files declare, maven the compiler properties (never below 17). A table entry always wins over a plugin's declaration. Pin images here for the toolchains no plain distro image carries: zig, snap (snapcraft-capable), flatpak (flatpak-builder-capable), rpm (a Fedora/CentOS image), appimage (FUSE + network). A fingerprint for another distro with no entry fails the job; there is no environment to run it in. ``[incremental]`` The warm caches (warm trees and env snapshots share the budget): - ``ttl_hours = 168``: hours an entry may sit unused before eviction. - ``max_total_gb = 20``: total size budget; entries evict least-recently-used first. - ``ccache = false``: bind a persistent host compiler cache into image builds (opt-in; it only pays off on images that carry ccache). Warm caches are runner-local. They speed up whatever lands on this machine, and a job may land on a cold one. ``[network]`` Registry-mirror pinning, deliberately pull-side only: these keys route the runner's own fetches. Arbitrary egress inside a build is not contained by them. - ``registry_mirror``: docker-format base-image pulls go through this pull-through mirror (e.g. ``https://mirror.internal:5000`` fronting docker.io). The podman builder reads a job-scoped ``registries.conf`` pinning ``docker.io`` to it; the ``docker`` daemon builder cannot take a per-invocation registries config and ignores the pin (configure the mirror in ``daemon.json``). Absent: pulls go to the image's own registry. There is no ``apt_mirror`` key: the Debian builds bootstrap their chroot through the pkh library, which exposes no mirror option. ``[atlas]`` ``url``: the pkgatlas resolve instance; omit it and dependency resolution uses heuristics only. When set, missing-native-dependency evidence resolves through it (exact file→package answers for the image's distro, release and arch). ``[plugins.debian]`` ``prune = false``: sweep pkh's residue after every Debian build. Only when Debian builds never overlap on the machine (the sweep cannot tell a live concurrent build's chroot from crashed residue); the runner already sweeps once at startup. ``[plugins.docker]`` - ``builder = "podman"``: daemonless rootless build (works inside an unprivileged container; needs the userns/uidmap/subuid prerequisites). ``"docker"`` opts into the host daemon: it needs the socket shared with the runner. - ``cleanup_image = false``: remove the job's ``saggar/:`` tag from the builder once the image is archived into the store. Off by default: the tag is part of the build's output surface (a following ``docker run`` on the machine uses it). The build cache and base images are always kept. What a runner ignores --------------------- The service-side sections (``listen``, ``token``, ``[storage]``, ``[projects]``, ``[quotas]``, ``[retention]``, ``[auth]`` and the rest) mean nothing where builds run. A ``[storage]`` section on a runner is ignored with a loud warning: every artifact byte streams through the service under the job's lease (see :doc:`worker-api`), and store credentials do not belong on a build machine.