Files
mesh-host/README.md
T
jschoubben 73c010e7ef Stage 1 — the host reports what a machine is and can do
Tier 0's first slice, per novox/hq 03-DESIGN/01-to-be/05-the-node-host.md. It
applies nothing, connects to nothing, listens on nothing. 2.9 MB, static, no
dynamic dependencies: copy it onto a machine and run it is the whole install,
which is the property ADR 0041 rests on.

A capability is detected, never assumed. Every detector runs something that only
succeeds if the thing FUNCTIONS — the daemon is asked for its version, the
package database is queried, the firewall is asked to list a ruleset, which
needs the privilege as well as the tool. 04-ISSUES/007 is the fault this
prevents: a client on disk with its daemon down looks exactly like a working
runtime, and a node assigned work on that basis fails when the work arrives.

Every verdict carries the reason and the method. A capability reported absent
with no reason is the same fault in a new place: something nobody can act on.

Two bugs found by running rather than reasoning, both silent:

systemctl is-system-running exits non-zero for every state except `running` —
including `degraded`, which means units failed and the init is emphatically
there. Reading the exit code reported NO service manager on a machine whose init
it was. That is 007 in the mirror, and both directions place work wrongly. A
verdict now reads what a tool says about itself, not only how it exited.

And `mesh-host inventory --json` printed text: the standard library stops
parsing at the first non-flag argument, so the flag sat unread and the command
exited 0 having ignored what was asked. The parser now takes the subcommand off
the front, and a stray or mistyped argument is refused rather than dropped.

Detection deliberately does NOT follow ADR 0008. That rule governs applying
state, where a failed step means the machine is not what was asked for. A failed
probe is a finding — "absent, because the probe failed" — and aborting would
replace one legible absence with total ignorance of the rest.

25 tests: structure and logic with a fake runner, and the same detectors against
this machine, because a test that fakes the system under detection asserts only
that the fake behaves as expected.
2026-08-26 00:25:08 +02:00

4.3 KiB

mesh-host

Tier 0 of the Novox Mesh. The one thing ever installed by hand, and the only thing that changes a machine.

scp mesh-host root@machine:/usr/local/bin/
mesh-host profile

That is the whole installation. One statically linked binary, nothing else present, no runtime to install first (novox/hq ADR 0041).

What it is for

Apply declared state on this machine. Overlay membership, packet filtering, packages, services, containers and filesystems are not six concerns it carries; they are six instances of the one.

It does not decide. Anything needing knowledge of another node is the control plane's, and the host never queries the mesh database. It receives declarations and applies them.

What exists today

Stage 1 only: it reports. It applies nothing, connects to nothing, and listens on nothing.

mesh-host profile      what this machine can be asked to do
mesh-host inventory    what this machine is, and what it holds
  --json               machine-readable
  --timeout            how long any single probe may take (default 10s)
$ mesh-host profile
linux/amd64

  yes  container-runtime  29.7.2
  no   firewall           nft exited 1: Operation not permitted (you must be root)
  yes  graphical-session  x11: :1
  yes  overlay            wg0
  yes  package-manager    pacman 7.1.0
  no   privileged         effective uid 1000, not 0
  yes  service-manager    degraded

cannot be asked to: [firewall privileged]

Stages 2 to 4 — applying from a pinned bundle, the link and the local store, and enrolment — are designed and not built.

A capability is detected, never assumed

The reason this is the first thing built rather than a detail of it.

An installed package is not a capability. A container client on disk with its daemon down looks exactly like a working runtime, and a node assigned work on that basis fails at the moment the work arrives. So every detector runs something that only succeeds if the thing is functioning — the daemon is asked for its version, the package database is queried, the firewall is asked to list a ruleset, which needs the privilege as well as the tool.

Every verdict says how it knows. A capability reported absent with no reason is a fault nobody can act on. The reason is what a person reads when a node will not take work they expected it to take.

Exit codes are not the whole answer. Found by running against a real machine rather than by reasoning: systemctl is-system-running exits non-zero for every state except running — including degraded, which means some units failed and the init is emphatically there. Reading the exit code reported no service manager on a machine whose init it was. That is the same fault in the mirror — installed-but-broken reported present, working-but-imperfect reported absent — and both place work wrongly.

Building

go test ./...                       structure and logic, and the same checks against this machine
CGO_ENABLED=0 go build -ldflags="-s -w" -o mesh-host ./cmd/mesh-host

Roughly 3 MB, static, no dynamic dependencies. Cross-compiles with GOOS/GOARCH; a host is built once per architecture and copied, never built on the machine it runs on.

Mocking the boundary is forbidden (novox/hq ADR 0034). Every detector is exercised against a fake runner for its logic and against this machine for its behaviour. The tests do not assert which capabilities a machine has — that varies, and is the point of detecting — they assert that detection tells the truth about whatever is there.

Where the reasoning lives

Design and decisions are in novox/hq, not here. This repository carries implementation and does not carry decisions.

  • 03-DESIGN/01-to-be/05-the-node-host.md — what this is and the order it is built in
  • 02-DECISIONS/0037-the-host-applies-it-does-not-decide.md — the one concern
  • 02-DECISIONS/0038-a-node-joins-by-linking-first.md — one behaviour, two sources
  • 02-DECISIONS/0039-the-link-is-the-security-boundary.md — a node owns no password
  • 02-DECISIONS/0041-the-host-depends-on-nothing.md — why this is a static binary, and Go
  • 04-ISSUES/007-an-installed-package-is-not-a-capability — why detection works this way