Files
mesh-host/examples
jschoubben a4445f5c0a A machine joins the mesh it raised
The last step of the first-node path, and the bundle now carries all of it: a
container runtime, the store, a database per context, their schemas, the broker
with a certificate it generated itself, and the control plane running.

Then the machine enrols against the mesh on its own disk. It dials the broker
over TLS, refuses anything but the pinned certificate, presents the one-time
secret with a public key it generated, and is told the name the mesh has for
it. Its specialness lasted two commands, which is what ADR 0004 asked for.

The identity is saved only after the mesh says it knows this node. A node
holding an identity the mesh never recorded would believe it had joined and be
believed by nobody, which is worse than not joining because nothing looks wrong.

An already-enrolled machine refuses a valid token rather than quietly acquiring
a second identity, and a spent token is refused by the mesh. Both checked.

Containers gained a network field. The control plane must reach the store and
the broker on the machine it was raised on, before there is any mesh to arrange
that; the alternative was publishing ports and guessing an address that works
from inside a container, which fails in a worse way.

The control plane talks to the broker over loopback in plaintext, deliberately.
The TLS on 5671 exists so a node crossing a network can pin a certificate, not
for a hop that never leaves the machine.

Verified on a sealed lab machine: eleven resources applied from bare, the
control plane consuming, a token issued from inside it, and the machine
enrolled -- with the recorded public key matching what the host printed, the
token marked spent, and the profile stored.
2026-08-29 16:03:15 +02:00
..

Examples

substrate-first-node.lock

What a machine must be before a mesh exists — steps 0 to 4 of the bootstrap in novox/hq 07-the-substrate.md:

0  a container runtime
1  the store runs
2  a database per context        one today, `inventory`
3  that context's schema         mesh-control migrate
4  the broker runs

It stops there, and the file says why. Step 5 is a virtual host, a credential and a certificate; step 6 is the control plane running. Nothing consumes any of them yet, and a bundle whose last step cannot be checked is worse than a shorter one.

Build a host carrying it:

make host SYSTEM=arch BUNDLE=examples/substrate-first-node.lock

The registry address and digests have to be replaced before this is useful. They are written as 192.0.2.250:5000/…@sha256:… because a digest belongs to whatever registry serves it — here, one a lab scenario raises, which reports its digests when it comes up. That is not a placeholder to be tidied away: a bundle is built for a target, and which registry that target pulls from is part of the target.

What was verified, and how

On a lab machine confirmed sealed — curl https://example.com times out, the lab registry answers 200 — the whole bundle applied from bare: eight resources, inventory created and mesh nowhere, the node table present with its indexes, the migration recorded, and LavinMQ answering lavinmqctl status with AMQP listening on 5672.

Three consecutive reconciles after that: already matches — 8 resource(s) checked, each time.

Then the machine was rebooted, and everything came back: docker from boot: enabled, both containers because the host creates every container --restart unless-stopped (internal/apply/apply.go), the schema intact in its named volume, and reconcile still finding nothing to do.

The reboot is worth doing rather than assuming. Nothing in the declaration asks for a container to return, so that it does is a property of the host, and the only way to know it holds is to take the machine away and give it back.