Incremental builds · content-addressed cache · hermetic tasks
maru
Build only what changed. Cache by content, not by clock.
curl -fsSL https://get.maru.build | sh
Verified, reproducible, and about 1.8 MB. Also on Homebrew: brew install maru.
Start here
- Installing maru Install the maru binary, verify it, and scaffold a project in under a minute.
- Your first build Declare a task with explicit inputs and outputs, then watch maru skip it when nothing changed.
- Content-addressed caching How maru builds a cache key from content, dependencies, and toolchain — and how to share it across a team.
- Hermetic task graphs Sandboxed inputs, a scrubbed environment, and no network — the guarantees that make a maru build reproducible.
The model in three ideas
Incremental by digest
maru never trusts timestamps. Every task has a cache key derived from the exact bytes of its inputs, the command it runs, the outputs of the tasks it depends on, and the pinned toolchain. Change a comment in a file that nothing reads and maru does nothing. Change one byte that a hundred tasks depend on and maru rebuilds exactly those hundred tasks, in dependency order, and not one more.
Hermetic by default
A task sees only what it declares. maru runs each command in a sandbox where the working tree is a read-only tree of the declared inputs, the environment is scrubbed to a known allowlist, and the network is off unless you opt in. A build that passes on your laptop passes in CI because there is nothing left to differ.
One graph, many machines
The build is a single directed acyclic graph of tasks. Because cache keys are content addresses, the entry a colleague produced this morning is the entry your machine would have produced — so maru can pull it from a shared cache instead of rebuilding. The graph is the contract; the cache is just memoized truth.