Your browser sucks, JavaScript disabled! Gunnar's console needs JavaScript and WebAssembly. Git over SSH on port 2222 does not.

nordisk/dwarves

README.md

Dwarves

CI/CD software forge inspired by the dwarven craftsmanship that created Odin's spear Gungnir and the gods' treasures, as recorded in the Icelandic Prose Edda (c. 1220 CE).

It binds tightly to Nornir — handling code's time-space dimensional warehouse — and to Holger, the artifact registry guarding your artifacts at rest.

Measured — the forge's planner hot paths

v0.1.4 · oden · 32 cores · 2026-07-22

workload build_ms builds_per_sec cache_hits_per_sec elapsed_ms ids_per_sec iters replan_ms run_ms steps steps_per_sec telem_cores_busy_avg telem_cores_busy_max telem_cpu_pct_avg telem_cpu_pct_max telem_elapsed_ms telem_mem_pct_max telem_mem_peak_mb telem_n_cores
dwarves.dag_build 0.12 8546 2340 20000 150 2 2 6.63 7.04 2342 5.44 16.98 32
dwarves.incremental_cold 78 200 0.39 150 386271 2 2 6.25 6.25 79.07 5.44 17.55 32
dwarves.incremental_warm 520476 144 500 0.29 150 2 2 6.44 6.44 145.91 5.45 17.55 32
dwarves.step_input_id 361 1.38M 500000 2 2 7.03 7.03 361.39 5.46 17.55 32

Dwarves release — usage

Dwarves release is a multi-language, industrialised implementation of cunning, the cargo/crate spec, and academia — built to solve the Codeberg/Nordisk release: 154 crates across 17 repos, cross-repo cycles and all.

dwarves workspace-release .             # DEFAULT dry-run — PLAN ONLY: plan the constellation, no build, no branch
dwarves workspace-release . --verify    # + the pre-publish cargo-test suite
dwarves workspace-release . --rehearse  # + Gate-B: rehearse the cascade into a throwaway local registry
dwarves workspace-release . --execute   # for real — verify + rehearse, then crates.io (only after both gates pass)

The run is tiered and cheap-first, build-last: the default dry-run plans only (deps-first order, ship-versions, the static Gate-A precheck, advisory graph analysis) and STOPS — no build, no cargo test, no branch — in milliseconds. --verify adds the cargo-test suite; --rehearse adds the Gate-B /sparring rehearsal; --execute implies both (a real publish always verifies + rehearses), then uploads. Nothing reaches crates.io until two gates go green — Gate A (static) and Gate B (a rehearsal into a throwaway local registry). A build never runs on an already-failed run, and a --verify/--rehearse dry-run builds into the same target --execute reuses, warming its cache.

In the Dwarves UI, the picture below shows a dry-run error — caught by the static Gate A in milliseconds, before any build. With --rehearse/--execute, Dwarves also builds the whole cascade into a staged Holger (a local repo):

Fix the culprit and run again — green means the cascade publishes deps-first:

Several repositories in one run, and the live dry-run

dwarves release takes several repository paths and runs them in the order given. --only spans all of them. A name that no path publishes, or that two paths publish, is refused. monetize-impl is never published: a run that names it, or finds it, is refused before anything is packaged.

# from the estate's parent directory: read-only, uploads nothing
dwarves release tunnr edda monetize Skidbladnir --only korp-installer,appliance-grow --live-dry-run
# the same line with --execute publishes (byte-identical crates are skipped, a 429 waits and retries)

--live-dry-run asks crates.io what is already published, runs the size gate, and runs cargo publish --dry-run for each crate that would go up, then runs Gate B (the loopback /sparring rehearsal) exactly as --execute would.

The pre-flight size gate

dwarves release <repo> weighs every crate it is about to upload before it uploads anything, because crates.io refuses an oversized upload with a bare HTTP 503 that names neither a size nor a reason — cargo prints failed to get a 200 OK response, got 503 and nothing else.

dwarves release .                       # dry-run: prints the registry's limit and where the number came from
dwarves release . --check-size          # + packages every crate NOW and weighs the .crate
dwarves release . --execute             # the size pass runs automatically, before any upload
dwarves release . --max-upload-mib 20   # a granted limit increase (or another registry's limit)

An over-limit crate refuses the whole cascade — exactly like the same-version drift halt — naming the crate, its compressed size, the limit and its source, and the biggest directories and files in the .crate, so the exclude to write is on screen instead of behind a local cargo package. The two honest remedies are printed with it: ship less, or get the limit raised and pass --max-upload-mib.

The limit is never a magic number. crates.io's 10 MiB is a documented constant (no registry endpoint publishes it, and a staff-granted per-crate increase is invisible to the API); it is overridden by --max-upload-mib, DWARVES_MAX_UPLOAD_BYTES_<ALIAS> or DWARVES_MAX_UPLOAD_BYTES, and for a non-crates.io --registry with no override the limit is honestly unknown and refuses nothing. If a 503 still arrives mid-cascade, it is translated: over the limit ⇒ "this 503 IS the size refusal", within it ⇒ "reads as transient — retrying", never measured ⇒ it says so.

📖 Release pseudocode (Rust) — the dry-run step by step, the two gates, and the formal model, with diagrams.

📐 Release invariants — what a release guarantees, independent of how it is sequenced: the cross-repo dependency model, the invariants upheld today, the ones measured as absent, and why a gate can state the right condition and still be green by construction.

The release process is AI-free — 100% dwarven-forged: deterministic Rust, no model in the loop.

Dwarves tune — the Heimdall tuner

dwarves tune measures a Build Thing row's programs into seccomp profiles, has a person review them, and gates on drift. <artifact> is a row (rusternetes-node, in the checkout you stand in) or <repo>:<row> (tunnr:rusternetes-node, a checkout beside it or under --checkouts).

dwarves tune probe   rusternetes-node                    # probe + gen: profiles beside the row
dwarves tune probe   rusternetes-node --workload smoke   # + the runs of the [[driver]] "smoke"
dwarves tune gen     rusternetes-node                    # regenerate from the probe evidence (no probe)
dwarves tune approve rusternetes-node --note "reviewed"  # record the review in approved.toml
dwarves tune check   rusternetes-node                    # fail on a new call or an unapproved profile
dwarves tune check   tunnr:rusternetes-node --json       # the same, as the stable JSON document
dwarves tune show    rusternetes-node                    # the review: calls, near-misses, approval, kernel join

The row lives in .nornir/profiles/<row>/measure.toml (its programs, runs, optional [[driver]] workload drivers, and the heimdall tool pinned by version and sha256). approve writes approved.toml beside it: per program and libc, the sha256 of each reviewed .json / .oci.json, the reviewer's name from git config user.name (never an e-mail address), the date and the note. After that, check fails on any profile that changed since its approval: not approved: <program> <file> changed since <date>.

A workload driver without command adds corpus runs, named <driver>/<run>. A driver with command drives a served app (the served-app runner comes from lane HEIM-APP; until it lands, such a driver is refused by name). gen and check reuse the drivers the last probe used.

Every verb prints text, or one JSON document with --json (schema dwarves.tune/1: ok, tool, programs, checked, drift, out_of_sync, vm_later, approval, review, problems, next, text; a refusal is {ok: false, error}). The exit code is 0 when ok, 1 on findings and 2 on a refusal. A missing tool, an unbuilt binary or an unknown row is one line that names the fix.

Review in the UI

The Build Thing UI (dwarves-gui) has a Syscall profiles tab in the Build area. Pick a <repo>:<row> (every row under $DWARVES_CHECKOUTS, else $DWARVES_CONSTELLATION, else beside the checkout the UI runs in) and it shows what dwarves tune show answers:

The Check, Probe and Approve buttons (Approve takes a note; the reviewer is git config user.name) run the same verbs through dwarves::tune, each as a queued jera job (dwarves::tune::jobs, kind dwarves_tune). The pane is redrawn from the verb's own JSON document; it reads no profile itself.

The licence boundary: Heimdall is AGPL-3.0-only and dwarves is MIT OR Apache-2.0. dwarves tune calls edda's nornir_build_thing::measure, which runs the heimdall binary as a separate process and reads its JSON. No heimdall crate is linked.


Every crate in the constellation is held to Brokkr's Software Criteria — baremetal, minimal-dependency, zero-copy / multi-core / SIMD.