Guides sandbox:exec
Hermetic task graphs
Sandboxed inputs, a scrubbed environment, and no network — the guarantees that make a maru build reproducible.
Caching is only safe if a task's declared inputs are its only inputs. maru enforces that with a sandbox: every task runs against a tree containing exactly what it asked for, and nothing else is reachable.
The sandbox
Before running a command, maru assembles a temporary root from the task's
inputs, mounts it read-only, and redirects the task's writable area to a
staging directory. When the command finishes, maru checks that every declared
output exists and that nothing was written elsewhere. A task that tries to read
/etc/hostname or a sibling file it never declared simply fails to find it.
[task.render]
inputs = ["content/**/*.md", "templates/*.html"]
outputs = ["public/**"]
cmd = "site render"
sandbox = "strict" # default; "loose" only for debugging
A scrubbed environment
Environment variables leak machine state into builds, so maru clears them and passes through only what a task names:
[task.render.env]
allow = ["LANG", "TZ"]
set = { NODE_ENV = "production" }
Anything not listed is absent inside the sandbox. A task cannot behave one way
because DEBUG=1 happened to be exported in your shell and another way in CI.
No network, on purpose
By default a task has no network access. Fetching a dependency mid-build is the classic way to make a graph non-reproducible: the remote can change, disappear, or rate-limit you. Instead, declare fetches as their own tasks with a pinned digest, so the fetched bytes become a normal, content-addressed input:
[task.deps]
outputs = ["vendor/lib.tar.gz"]
fetch = "https://example.com/lib-2.4.tar.gz"
digest = "blake3:5d9c…f0a2"
network = true
maru downloads the archive once, verifies it against digest, and caches it
like any other output. Every task downstream depends on those exact bytes, not
on the URL being reachable. Run maru build --check-hermetic to have maru run
each task twice in independent sandboxes and confirm the outputs are
byte-identical — the strongest signal that your graph is truly hermetic.