Azazel is a deterministic, declarative build-model layer for Zig. CUE validates a stable project model; Azazel generates typed Zig build data; Zig remains the build executor.
project.cue -> CUE validation -> build_spec.zig -> std.Build -> artifacts
human constraints typed IR Zig
The point is not to hide Zig. The point is to keep project configuration stable while Azazel absorbs std.Build API churn, and to make the build graph available as validated data for analysis, tooling, compatibility work, and eventually safe remote caching.
The core build pipeline is production-supported on Zig 0.14.1, 0.15.2, and 0.16.0. CI runs the same canonical CLI path users run, forces code generation twice to verify determinism, builds, and runs the test suites on every supported lane.
Azazel is still pre-1.0. Pin the revision or release you adopt and upgrade deliberately. The exact support contract and release gate are in docs/PRODUCTION.md.
The shared artifact cache is experimental and disabled by default. It must not be used for release artifacts until its key proves a complete input closure. See CACHE.md.
package build
core: #Module & {
kind: "module"
root: "src/core.zig"
}
app: #Module & {
kind: "exe"
root: "src/main.zig"
deps: ["core"]
profile: "release"
}For a pure Zig dependency, kind: "module" is consumed through @import and produces no separate artifact. ABI-linked static/shared libraries remain available for C/C++ interoperability and explicit binary boundaries.
Prerequisites are Zig, CUE, and Python 3.
brew install cue zig
git clone https://github.com/godofecht/azazel.git
cd azazel
./setup.shThe canonical CLI is the root azazel script:
python3 azazel check # validate CUE, exported contract, roots, graph
python3 azazel gen # generate build_spec.zig
python3 azazel build # check + generate + zig build
python3 azazel build -Dfoo=true # forward normal Zig build arguments
python3 azazel info # print the resolved build model
python3 azazel cleanThe CLI does not contain a second generator. gen_build_spec.sh is the single CUE-to-Zig implementation used by both direct and CLI workflows.
The equivalent low-level path is:
./gen_build_spec.sh
zig build
zig build test --summary allA hand-written build.zig is executable build logic. Azazel moves the project description into a validated model and keeps the compatibility/execution layer separate.
That gives the project a representation which can be checked before compilation, diffed as data, consumed by editor tooling, replayed against multiple Zig lanes, translated into a build graph, and pressure-tested against real repositories without treating arbitrary build-script behavior as the configuration format.
The generated build_spec.zig is typed Zig source. The executor does not parse JSON at build time.
#Module currently models:
| Field | Purpose |
|---|---|
kind |
exe, static, shared, or module-only target |
root |
Zig root source file |
artifact_name |
Produced artifact name when it differs from the graph/import name |
deps |
Internal module dependencies |
profile |
Debug or release optimization profile |
link |
import or ABI consumption |
pre, post |
Explicit build-time commands |
install_dirs |
Runtime/resource directory staging |
pkg_imports |
Zig package module imports |
pkg_artifacts |
Artifacts exported by Zig packages |
pkg_library_paths |
Package-provided library search paths |
build_options |
User-selectable typed build options |
option_values |
Fixed typed values injected into an options module |
gen_imports |
Zig modules generated by declared host tools |
build_options_import |
Import name for generated build options |
native |
C sources, includes, objects, system libraries, frameworks, libc/libc++ linkage |
The full schema is in schema.cue and the worked reference is in docs/WIKI.md.
A field is considered implemented only when it survives all four layers: schema, CUE export, generated spec, and Zig executor. python3 azazel check validates the exported module contract so silently dropped fields fail before compilation.
Projects may declare accepted lanes:
toolchain: zig: {
lanes: ["0.14", "0.15", "0.16"]
preferred: "0.15"
}The generated build spec records those lanes and build.zig rejects an unsupported Zig lane before doing real build work.
Release CI currently covers 0.14.1, 0.15.2, and 0.16.0. Zig 0.17 support exists for corpus work but remains best-effort while 0.17 is a moving development target.
Azazel distinguishes two internal dependency shapes.
link: "import" merges a Zig dependency into the consumer compilation and exposes it through @import("name"). It avoids a separate artifact/link step and is the normal choice for pure Zig module edges.
link: "abi" keeps a separately compiled artifact and links it across an ABI boundary. Shared libraries are always ABI targets. This is the appropriate shape for C/C++ interoperability and deliberate binary boundaries.
Large projects can combine the two into clusters: import-connected modules inside a cluster, with ABI boundaries between clusters. See examples/06-clusters.
Azazel maintains a corpus built around ZLS, libxev, River, Mach, MicroZig, libvaxis, Capy, zig-gamedev, TigerBeetle, and Ghostty. The corpus is used to discover missing build-model primitives and toolchain/API failure modes.
Executable parity is claimed only for modeled target slices that actually compile through the Azazel-generated graph. An upstream project's own successful zig build is tracked separately and is not reported as Azazel replacement parity.
See docs/HUGE_PROJECT_CORPUS.md.
The production build path does not depend on the shared cache, corpus automation, IDE prototypes, or Danzig.
cache_build.sh is an explicitly gated cache experiment. tools/huge_corpus.py is validation/research infrastructure. ide/ contains editor experiments. src/danzig/ is retained as a substantial integration/dogfood workload rather than as part of Azazel's build-system API.
Keeping those boundaries explicit is intentional: experimental surfaces may inform the build model without silently becoming production dependencies.
The complete reference lives in docs/WIKI.md. Production guarantees are defined in docs/PRODUCTION.md. Contribution requirements are in CONTRIBUTING.md, and security reporting guidance is in SECURITY.md.
The generated documentation site is published from the repository's documentation sources on GitHub Pages.
Azazel is the declarative configuration frontend for Zaza, a Zig-driven build system for C, C++, Zig, CMake interoperability, and WebAssembly. Azazel can also be used directly for Zig projects.
MIT