# Skíðblaðnir — guide (the whole workflow)
> **Class:** `guide` · audience: an operator or product author driving Skidbladnir end to end.
> The *what* is in [`design.md`](design.md); the *why* in [`reasoning.md`](reasoning.md).
> Per-function how-tos are the `*-guide.md` chapters.

## f0 — one deployment across the gap (the whole session)
The end-to-end flow spans several functions. It splits at the gap: everything up to and including
`archive` runs on the **internet side**; everything from `fetch` runs on the **secure side** with
zero network.
```sh
# ── internet side (build host) ──────────────────────────────────────────
# 1. pack a staging tree into a signed tar.zst bundle + per-entry SHA-256 manifest
nornir airgap pack ./staging --out lake.tar.zst
# …carry lake.tar.zst across the gap — a disk, a one-way diode, a courier…
# ── secure side (target): ZERO network ──────────────────────────────────
# 2. verify-on-receipt against the manifest (nothing changed in transit)
nornir airgap fetch lake.tar.zst
# 3. provision the machine (kvm | terraform | redfish); --run to actually drive it
nornir airgap unfold kvm my-vm
# 4. dependency-ordered start → systemd over D-Bus, no shell
nornir airgap start lake.spec.toml
```
The declarative spine is a `LakeSpec` (`lib.rs:129`): a `version`, the `ComponentSpec`s, and one
`PkiSource`. From it, `LakeSpec::start_waves()` (`lib.rs:137`) computes the bring-up order — you
declare the products and their `after` edges once; ordering is derived.
As a library, the same session in Rust:
```rust
use skidbladnir::{archive::TarZstd, pack, fetch, layout::Layout, install, service::Backend, product};
let eng = TarZstd::new();
// internet side
let staging = pack::Staging::new(&staging_root, "20260704")?;
let manifest = eng.pack(staging.root(), "20260704", &bundle_path)?; // Archive::pack
// secure side — verify BEFORE touching anything
let bundle = fetch::fetch_and_verify(&bundle_path, &eng)?; // fetch.rs:74
let layout = Layout::dated(data_dir, log_dir, software_dir);
let spec = product::ComponentSpec::holger();
let outcome = install::install_product(&spec, &layout, &bundle_path, &eng,
Backend::SystemdSystem, "/")?; // install.rs:88
install::apply(&outcome)?; // runs [enable, start]
```
## f1…f10 — per-function how-tos
Each function has its own guide chapter with its CLI/API and worked examples:
- [`pack-guide.md`](pack-guide.md) — build a staging tree, capture deps in a container.
- [`archive-guide.md`](archive-guide.md) — pick `TarZstd` vs `znippy`, delta-pack, selective read.
- [`move-guide.md`](move-guide.md) — verify-on-receipt, out-of-band SHA, per-OS unpack.
- [`pki-guide.md`](pki-guide.md) — self-generated certs vs Vault.
- [`layout-guide.md`](layout-guide.md) — dated dirs, atomic upgrade swap, rollback.
- [`install-guide.md`](install-guide.md) — one `ServiceSpec` → any init; install/update/uninstall.
- [`unfold-guide.md`](unfold-guide.md) — KVM / libvirt / Redfish / Terraform.
- [`orchestrate-guide.md`](orchestrate-guide.md) — dependency waves + telemetry.
- [`matrix-guide.md`](matrix-guide.md) — the live multi-OS install matrix.
- [`msi-guide.md`](msi-guide.md) — Windows MSI packaging.
## Feature flags you choose at build time
The lean core is always available. Turn capabilities on per build (`Cargo.toml:91`):
| feature | adds | default |
|---|---|---|
| `pki` | real ed25519 `SelfGenerated` certs | **on** |
| `znippy` | REAL znippy-core archive engine (seal/read/verify/delta via ../znippy) | off |
| `vault` | Vault PKI HTTP client | off |
| `redfish` | Redfish BMC provisioning | off |
| `terraform` | drive the `terraform` binary | off |
| `machine` / `kvm` / `container` | VM/container lifecycle control | off |
| `matrix` | the live multi-OS install matrix (implies `kvm`) | off |
A build with none of these still packs, archives (tar+zstd), verifies, lays out, installs over
systemd/OpenRC, orchestrates, and emits events — fully offline.