# ⚒ dwarves — for complete beginners
> **📍 THIS DOC LIVES IN `dwarves` (moved from `nornir/.nornir/`, 2026-07-22, move=delete).**
> The code it documents is dwarves' own (`crates/dwarves/src/…`), so the doc follows the
> code. nornir keeps only the read-only viz surface that renders this engine's output.
> Source links below are dwarves-repo-relative.
> **Class:** `idiot-guide` · assumes nothing. What it is: [`dwarves-design.md`](dwarves-design.md). How to use it: [`dwarves-guide.md`](dwarves-guide.md).
## What problem does dwarves solve?
You want a **build server** (like TeamCity or GitHub Actions): something that
watches your repos and, when code changes, automatically builds and tests them.
nordisk already had half of that. A crate called **brokkr** knew how to read a
recipe file (`brokkr.toml`), work out the order to run the steps in, and run one.
But brokkr was like a recipe and a chef with **no kitchen timer and no waiter** —
nothing ever *told it when to cook*. All its clever parts (a queue of jobs, a pool
of workers, a nightly schedule) were written and tested but never actually run.
**dwarves** is the finished kitchen. It has two dwarves:
- **Brokkr** — the smith who *builds* (the recipe + the chef). Already existed.
- **Sindri** — his brother, who *directs the forge* (the timer + the waiter). This
is the new part. Sindri watches the clock and the repos, decides what to cook
and when, hands each job to a free worker, and writes down what happened.
## The three things Sindri does, every "tick"
Think of one tick as the waiter doing a lap of the kitchen:
1. **Clock check (cron).** "Is it 3 a.m.? The nightly build is due — add it to the
queue."
2. **Repo check (poll).** "Did anyone push new code? That repo's pipeline goes in
the queue."
3. **Serve the queue (drain).** "Is there a free worker who can do this job? Yes →
cook it now, and note the result. No → leave it in the queue and say *why*
('all workers busy')." One heavy build at a time (the exclusive gate), so the
machine doesn't melt.
That's the whole idea. Everything else is detail.
## Try it yourself in 60 seconds
Make a recipe file `brokkr.toml`:
```toml
[pipeline]
name = "hello-ci"
[[pipeline.trigger]]
kind = "poll"
events = ["push"]
[[pipeline.stage]]
name = "build"
[[pipeline.stage.step]]
name = "compile"
run = { variant = "server" }
```
Now:
```bash
dwarves # just type it — a friendly banner + "am I ready?" check
dwarves validate # "is my recipe well-formed?" → ✓ valid
dwarves plan # "what order will the steps run?"
dwarves run # "run it now (pretend build)" → passed
dwarves serve --once --poll . # "pretend this repo just changed" → Sindri cooks it
dwarves history # "what has run so far?"
```
`dwarves run --real` does an *actual* `cargo` build (no shell tricks — pure Rust).
Without `--real` it uses a pretend "demo" build so you can see the whole flow
without waiting for a real compile.
## Where does this fit in nornir?
- The `dwarves` program is a standalone tool — you can use it on its own.
- nornir also *contains* dwarves. When the nornir **server** is watching your repos
and notices a change, it quietly asks Sindri to build the changed repo. So just
by running the server, **you already have a CI server.**
- In the desktop app there's a **⚒ Brokkr tab**: press *Run* and watch the little
map light up green, station by station, as each step passes.
## The ⚒ Build-Thing tab — "build me this, one of these ways"
There is also a **⚒ Build Thing** tab. Think of it as a menu of everything in the whole
family of repos that can be built, in every way it can be built. It reads each repo's own
little list of build recipes and shows them to you. You pick one and press **Build**, and it
really compiles it (on a background worker, so the app never freezes) and tells you the truth:
where the file landed, how big it is, and — if it broke — the exact compiler error. If there
are no repos to look at, it says so plainly instead of showing an empty page that looks "fine".
Some recipes make a whole little computer you can **boot** (a container or a virtual machine).
For those you get a **Boot** button, a **↻ Reboot** button, and — for the desktop ones — a
built-in **🖥 screen viewer**.
### Watching korp from a Windows PC
One of those recipes is special. It packages **korp** (another app in the family) as a tiny
window-into-a-remote-server: the app itself runs inside a little Linux desktop you can open
from Windows with the built-in Remote Desktop program (`mstsc`), while the real heavy server
stays on the oden machine. In the ⚒ tab you pick *tunnr → the appliance → the
"rdp-korp-thin" cell* and press **Build appliance**. It honestly tells you two things: the
package is *staged* (built and ready) and *booting it needs a runtime* — it never pretends to
have started something it hasn't.
## How do I open the dashboard?
There is a desktop app called `dwarves-ui`. It needs to know **one** thing: where the
dwarves server is. You tell it with `DWARVES_SERVER`:
```bash
DWARVES_SERVER=http://oden:7900 dwarves-ui
```
That's the whole story. You do **not** set anything about "nornir" — the dwarves server
has nornir built inside it, and the app just talks to the dwarves server. (There is a
nornir door on port `7878`, but that door is for OTHER programs, not this app. The app
never knocks on it.) If some data view can't be shown yet, it says so honestly instead of
going behind the server's back.
## The words, decoded
- **pipeline** — your recipe (`brokkr.toml`): the steps to build/test something.
- **trigger** — *when* to run: on a push (poll), on a schedule (cron), or by hand.
- **step / stage** — one job / a group of jobs; steps can wait for other steps.
- **DAG** — the "who-waits-for-whom" map of the steps (no loops allowed).
- **agent** — a worker that can run a job (it advertises what it can do, like
"cargo" or "macos").
- **queue** — jobs waiting for a free worker.
- **historize** — write down every run's result so you can look back at it.
## What dwarves does NOT do yet (on purpose)
This first version drives the two common triggers (a push and a nightly schedule).
It does **not** yet: receive GitHub webhooks, skip steps whose inputs didn't
change, chain builds across projects, or run workers on other machines. Those are
written up as "next steps" in [`dwarves-design.md`](dwarves-design.md) so nobody
forgets them.