[workspace]
members = [
"traits",
"server/lib",
# The file and archive inspector + the ClamAV/YARA malware hook (lane S3).
# A network-free leaf; server-lib's intake chain runs it on every ingest.
"server/inspect",
# The scan sandbox (lane SANDBOX-SCAN, owner 2026-10-23): every scan that unpacks,
# parses or runs an engine over an artifact runs in a hardened rootless podman
# container, never in the server process. A network-free leaf.
"server/sandbox",
# The scan worker: the one program the sandbox runs (server-lib's own scanners).
"server/scan-worker",
"server/downstream",
"server/cli",
# DEV-NARRATE's Holger half (A28 L12): holger-server and holger-estate-front share it.
"server/dev-narrate",
"server/repository/*",
# NOTE: the pluggable auth PROVIDER sub-crates were MOVED to edda (reuse-law):
# `nornir-auth-{bearer,oidc}` now live in `edda/crates/` beside the shared
# `nornir_service::AuthProvider` seam, so korp + dwarves reuse them too. holger's
# server-lib consumes them by path (see `server/lib/Cargo.toml`); they are no
# longer holger workspace members. See `.nornir/auth-providers.md`.
"agent/lib",
"agent/cli",
"agent/connector/*",
"mannequin",
"bench-scenarios",
# The build declaration (holger-recipe, holger-build-thing, build-space,
# holger-build) and xtask are members of `estate/` (H1); see `exclude`.
# The Secure Update Gateway bundle core: a NETWORK-FREE crate defining the signed
# `holger.update-bundle/v1` format + offline verifier (holger-verify) + authoring
# CLI (holger-bundle). No server/UI/connector/reqwest deps — reusable by tooling,
# the offline server import path, and backup/scrub. See docs/secure-update-gateway-*.
# The FROZEN `holger-<subsystem>-<n>` application error-code registry. A leaf
# with ZERO dependencies so the network-free `update-bundle` core can use it —
# keeping ONE place where codes are allocated, hence ONE global uniqueness gate.
"errcode",
"update-bundle",
# The SYNC PROTOCOL (Holger v2.0 H4): the signed sync manifest (generation, packages
# added, invalidations), the downstream's signed ack, the upstream's per-downstream
# ledger and its alarm. Network-free and server-free; server-lib `sync` runs it.
"sync",
# Offline vulnerability intelligence (S7): OSV / NVD / KEV -> one advisory set ->
# a signed update-bundle (product holger.intel/v1) -> verified local advisory DB.
# Network-free unless `fetch` (the online `intel build` side only).
"intel",
# The PROVENANCE verifier (lane G3a): DSSE + in-toto + SLSA, Sigstore bundles, PEP 740,
# npm provenance and cosign attachments, verified OFFLINE against a pinned trust root
# carried as a signed update bundle. Network-free; the intake scanner wraps it.
"provenance",
# THE WASM PACKAGE-HANDLER LANE. Every package handler can be written native
# or as WASM; a handler is a `PackageHandler` (format logic, target-independent)
# over a `BlobStore` (bytes, host-owned), and `holger-plugin-host` projects
# either shape into ONE `RepositoryBackendTrait` so `fast_routes.rs` cannot
# tell a linked handler from a loaded one. The `-wasm` crates hold no logic:
# they depend on the native crate beside them and export only the ABI.
# Design + the verb-by-verb rationale: `plugin/abi/src/lib.rs` rustdoc.
"plugin/abi",
"plugin/host",
"plugin/handler-bundle-core",
"plugin/handler-skidbladnir",
"plugin/handler-skidbladnir-wasm",
"plugin/handler-rust-toolchain",
"plugin/handler-rust-toolchain-wasm",
# THE METER LANE (ABI v2). `guest-allocation` is holger's OPEN meter guest:
# it declares the storage meters, reports how much storage there IS and is
# servable, cross-checks that figure, and returns Allow unconditionally --
# there is no ceiling of any kind in it. The `-wasm` crate beside it holds no
# logic, only the ABI shim, exactly like the handler pairs above.
"plugin/guest-allocation",
"plugin/guest-allocation-wasm",
# holger.rs's PUBLIC FRONT PAGE. A leaf with two dependencies: `server/lib`
# mounts it, so it can depend on nothing that depends on `server/lib`.
# The page, the three-column release row and the whole door are one pure
# function there, testable without the server graph. See `holger-front/`.
"holger-front",
# THE THIN CLIENT (lane B3, .nornir/SUITES.md `cli`): `holger-cli`, every console
# action as a command over the same gRPC services. No server code, no HTTP client but
# tonic's channel; `cargo install --path holger-cli` from a lone clone.
"holger-cli",
# The monetize guest (crates/holger-monetize-guest), holger-live and holger-fleet are
# members of `estate/` (H1); server-lib `metered` and server/cli `paired` still name
# holger-fleet and holger-live by path until H2 cuts those edges.
]
# The ESTATE (`holger-rs/`) is its own workspace and is excluded from this one:
# it talks to Cloudflare and writes a picture, and has no business inheriting
# the `[patch.crates-io]` sibling-checkout requirement below.
# `estate/` (H1, docs/HOLGER-V2.md): the estate, appliance and build-description crates
# are members of their OWN workspace, so a lone clone resolves only the open core.
# Its members outside `estate/` (xtask, the build declaration, the monetize guest,
# estate-tests) name it with `package.workspace`.
exclude = ["holger-rs", "holger-estate-front", "estate", "estate-tests", "xtask", "xtask/boot", "holger-recipe", "holger-build-thing", "build-space", "holger-build", "crates/holger-monetize-guest"]
resolver = "2"
# A plain `cargo build` / `cargo build --release` at the root builds the SERVER only
# (owner 2026-10-22): `target/release/holger`. Every other member builds by name
# (`-p <pkg>`, `--workspace`), and the declared variants through `cargo xtask build`.
default-members = ["server/cli"]
# znippy 0.9.0 (with package-handler register + skeleton handlers) is on
# crates.io. No local patches needed.
# facett look & feel — holger adopts the unified `facett_core::look::Theme` +
# `apply()`. The look work shipped in facett 0.1.2 on crates.io (0.1.1 was the
# pre-look release), so the GUIs pull it straight from the registry — no local
# `[patch.crates-io]` block. egui pins match (holger ↔ facett are both egui
# 0.35.x). See `.nornir/facett-look-and-feel.md`.
# nornir-testmatrix functional-status emitter — holger's tests feed the
# `nornir test` matrix one `functional_status` row per real check, gated behind
# the `testmatrix` feature (compiled OUT for release). It IS patched to the sibling
# edda checkout now (see the `[patch.crates-io]` entry below) — the old objection was
# to the ABSOLUTE external-drive path (/run/media/...T9), which made the workspace
# unbuildable unless that disk was mounted, not to patching the crate at all. A
# RELATIVE `../edda` sibling is the same convention facett/znippy/nornir-robotui
# already use here.
# The version of the SUBJECT this repo is, so a benchmark row can be labelled.
#
# Added 2026-09-20. `nornir_bench::runner::subject_version` reads a repo root for
# `[package].version` then `[workspace.package].version` then an eponymous member,
# and holger had NONE of the three — its own source calls this out by name ("Tier
# 4: unknown (holger, edda …)"). With no answer the runner leaves
# `NORNIR_BENCH_VERSION` unset and `nornir_bench::api::run_main_json` falls back to
# its OWN `CARGO_PKG_VERSION`, so every holger bench row recorded so far is stamped
# `0.1.8` — the version of the harness crate, not of holger. Every row in
# `bench_history.jsonl` and in the warehouse written before this commit carries
# that wrong label and must be read as "holger at that commit", not "holger 0.1.8".
#
# The value is `0.6.10`, which is what `traits`, `server/lib`, `server/cli` and
# `agent/cli` all declare today, so a row's label names a crate set that exists.
# It is INERT for publishing: no member says `version.workspace = true`, so each
# member keeps its own `version` and nothing is re-versioned by this key. The
# `v0.7.1` git tag (2026-06-15) disagrees with every crate version in the tree;
# that mismatch is a separate question and is not settled here.
[workspace.package]
version = "2.0.0"
# LOCAL DEV: build against the local znippy checkout for the plugin READ API
# (typed as_rust()/as_maven()/as_python() views). The sibling znippy is on
# branch feat/plugin-read-api. REMOVE before publishing (per WORKSPACE.md release
# gate) — the crates.io versions ship the same API once znippy is released.
# ── THE SIBLING PATCHES LEFT THIS FILE (owner order 2026-10-22, the lone clone) ──
# A lone clone of holger has no ../edda, ../Skidbladnir, ../monetize, ../tunnr, and
# cargo refuses a workspace with a missing [patch] path. Every sibling patch (the four
# that were here: monetize-embed, monetize-product, monetize-product-guest,
# korp-installer) and every member's `path = "../<sibling>/…"` is now ONE table,
# `.cargo/estate-siblings.toml`, copied to the uncommitted `.cargo/siblings.toml` in an
# estate checkout (`cargo xtask siblings`; every `cargo xtask` verb refreshes it).
# `xtask/tests/lone_clone.rs` holds it. The history below is kept for its reasons.
# LOCAL DEV, the metered build: monetize-embed's `fleet` (the pull channel's signed forms)
# and monetize-product's `pull` (the order bodies, the product report) are on the sibling
# monetize checkout and not yet on crates.io. Only `metered` links either; the open
# build links no monetize crate. REMOVE with the other patches once both are published.
# 2026-10-05 (merge to main): crates.io serves facett and nornir-robotui (published
# 2026-10-04): their rows are gone. robotui's sibling differs by one test cfg; facett's
# main moved on after the publish (flow pipeline), but holger's line was proven on an
# older facett (03464fbb), which 0.2.0 contains.
# LOCAL DEV: the now-beautiful facett Graph3D (neon glow/shockwave/dim via
# EffectsPolicy/DecorPolicy) lives in the sibling facett checkout ahead of the
# crates.io release — holger's Graph tab wires it (server→repo→artifact/upstream,
# click-to-light). REMOVE before publishing once facett ships the decor API.
# LOCAL DEV: nordisk siblings are checked out next to holger (the documented dev
# layout — see CLAUDE.md "Local dev setup"). Paths are RELATIVE so they work on any
# machine that follows the sibling convention — never an absolute/external-drive
# path. znippy is patched in because crates.io znippy-common still lacks the `sign`
# feature holger's package repo requires (drops out once znippy 0.9.7 publishes).
# REMOVE all patches before publishing (release gate, WORKSPACE.md).
# korp-installer — ONE installer in this lock. xtask takes it by path from the tunnr
# sibling (=0.1.20, xtask/Cargo.toml) and edda's appliance-grow (server/lib, the grow
# machine) took the REGISTRY 0.1.20, so Cargo.lock carried korp-installer twice and the
# medium compose refused "pins korp-installer 0.1.20 AND 0.1.20"
# [installer-source-not-the-pin] (holger estate on the mock, run mock1, 2026-09-27):
# the appliance binary's grow code and the medium's installer must be one source.
# REMOVE with the other patches before publishing.
# egui 0.36 (facett lane H2, 2026-10-02): crates.io's newest nornir-robotui (0.3.4) is
# built on egui/egui_kittest 0.35, so its Harness would be a SECOND egui beside this
# workspace's 0.36. The sibling edda (branch `egui-0.36`) carries it on 0.36. REMOVE
# when a nornir-robotui on egui 0.36 is published.
# nornir-robotui — the path patch to the sibling edda checkout is GONE, and that is the
# condition the old comment named: it said "REMOVE once edda's nornir-robotui ≥0.2.5 ships
# to crates.io", and **0.3.0 is published** — the egui-0.35, glow-free release, carrying
# `wire`/`cmd_json` (the reason the patch existed at all). The sibling edda checkout is
# parked on an unpublished 0.2.6 that is still egui 0.34, so patching to it would drag a
# SECOND egui into the graph — the very failure this migration fixes. Registry 0.3 it is.
# nornir-testmatrix — pinned to the sibling edda checkout for TWO reasons.
# 1. `xtask/tests/silenced_tests_guard.rs` calls `nornir_testmatrix::audit_repo`,
# the silenced-test guard. crates.io's newest is 0.2.7 and does not contain the
# `gatedtests` module at all; the guard exists only in edda's unpublished 0.2.8.
# 2. It ends a split that was already here: `mannequin` path-dep'd edda's copy
# while every other crate resolved 0.2.2 from the registry, so `Cargo.lock`
# carried nornir-testmatrix TWICE — two distinct `TestResultRow` types in one
# workspace, the exact hazard korp's manifest warns about. One source now.
# REMOVED 2026-08-23 — five patches whose own stated conditions are all MET, checked
# against the live registry rather than assumed:
# nornir-testmatrix the line above said "REMOVE … once ≥0.2.8 ships"; registry 0.2.9
# znippy-common registry 0.9.14 == local 0.9.14
# znippy-compress registry 0.9.13 == local 0.9.13
# znippy-plugin-python registry 0.9.9 == local 0.9.9
# znippy-plugin-maven registry 0.9.10 == local 0.9.10
#
# These were not conveniences, they were THE publish blocker for most of this repo.
# `patch_fork_blockers` treats a `[patch.crates-io]` target the scanned repo does not
# itself produce as a FOREIGN FORK, and every crate transitively above it is held from
# crates.io — 19 of holger's crates, `holger-traits` among them. holger-traits is what
# published `holger-server-lib` needs, which is what `nornir 0.5.5` needs.
#
# The `facett` patch below STAYS: local facett is 0.1.16 and the registry is at 0.1.15,
# so that one has not expired. It is the only remaining foreign fork here.
# The two graph crates' opt-level (holger-build's fixpoint) moved with holger-build to
# `estate/Cargo.toml` (H1).
# sha2 in a debug build hashes a gigabyte in a minute; the streamed-upload
# guard (`a_one_gib_put_never_holds_the_whole_body`) pushes one through the
# raw store, which digests it for the listing memo. Same precedent as above.
[profile.dev.package.sha2]
opt-level = 3
# Rickard, 2026-09-05: test artifacts carry line tables only — full DWARF in every test
# binary and its deps was the bulk of a target dir (gunnar/target 271 GB, korp/target 852 GB
# on the day the disks filled); backtraces still show file:line.
[profile.test]
debug = "line-tables-only"
# ★ DEV media only (lane N1, 2026-10-20, Gunnar's `[profile.dev-media]`): the `…-narrate`
# rows — the TEST estates' media, never a release — build with this. Release's
# optimisation level without the whole-program passes; its own profile is also what gives
# a `…-narrate` row its OWN artifact path (target/<triple>/dev-media/), so it never emits
# the binary its base release row emits.
[profile.dev-media]
inherits = "release"
lto = false
codegen-units = 16