7. Configuration
A config block declares knobs. The base block is unnamed; named overlays are applied on top with @name at invocation. Values are declared on the var sink…
A config block declares knobs. The base block is unnamed; named overlays are
applied on top with @name at invocation. Values are declared on the var sink
(var.NAME = ...), read only through $<...> placeholders, and every consulted
one folds into the cache key. A config body is a sandbox: its one external channel
is the host surface — host.os, host.arch, host.env("NAME", "default"), and
host.read("path") — so the block stays a pure function of the facts it reads.
config var.MODE = host.env("MODE", "debug")
config release var.MODE = "release"
recipe build gather "src/*.c" cook "build/$<in.stem>.o" { gcc -c -DMODE=$<MODE> $<in> -o $<out> }cook build # MODE=debug (the base)cook build @release # apply the `release` overlay → MODE=releasecook --set MODE=tiny build # a one-shot override that wins over everythingFlipping a declared value cleanly busts only the units that consumed it. A
$<KEY> for a variable you never declared is a hard error, and a var.* value
never enters a step’s process environment — the only way to read it is $<KEY>,
which keeps it in the cache key. No accidental shell leaks.