jschoubben 3d81bf41c6 Convert the resolver from the module it replaces: forward, answer at 127.0.0.1, point the runtime at it
Read against hal/modules/dnsmasq-app (hal dnsmasq-app conversion, hq 08-connectivity).
On the machines it runs, the predecessor's dnsmasq answers every name: the mesh's own
itself, the rest forwarded to 1.1.1.1 and 8.8.8.8, its module's defaults; resolv.conf
names it alone at 127.0.0.1, and the container runtime's dns is the machine's tunnel
address, so the host and every container resolve the world through it. The nox module
forwarded nothing, listened on 127.0.0.55 — a convention of its own beside the one every
machine already followed — and read a machines file that the module's `facts` already
asks the mesh for, so taking it would have left an adopted machine with a resolv.conf
pointing at an address nothing answered on, and no upstream for anything else.

Now the resolver keeps `no-resolv` (the documented loop — finding its own address in
resolv.conf and becoming its own upstream — stays impossible) and forwards to the same
two explicit upstreams; listens on mesh0 and 127.0.0.1, which systemd-resolved does not
hold; requires `mesh-addressing`, since its data is the mesh's addresses; and writes the
runtime's `dns` into daemon.json beside whatever the machine had (ADR 0102), at this
machine's own address — `${machine:address}`, new in the controller. The runtime is not
restarted for it: it reads the key at start, not on reload, and a restart stops every
container; on the machine this replaces the value is already there.

resolv-conf names the resolver alone, as the predecessor's file did; its placeholder second
line was a fallback nothing ever reached. resolved-split-dns follows the address. The
mesh's suffix as a local domain comes with the machines file, so a mesh name the resolver
does not know is refused here rather than asked upstream. mDNS is not carried: no module
does it and the design says mesh names are not multicast names.
2026-09-24 01:09:23 +02:00

mesh-catalog

The Novox Mesh catalogue. The modules the mesh builds, provisions and runs — as manifests, one per module under modules/.

This is data, not a control-plane concern. The manifests describe what a module is: what it provides, what it requires, the seats it claims, the resources the host applies for it. The engine that reads them — parsing, eligibility resolution, sealing, declaration emission — lives in the control plane (novox/mesh-controller, internal/catalogue), which consumes this repository as a build source. The host (novox/mesh-host) applies the declarations the control plane emits. Neither is here.

What a module is, and is not

A module is one thing the mesh can run, named once, described completely by its manifest. A manifest names its image (pinned by digest), the resources the host owns for it (directories, files, the container, the private network it joins), what it requires from a provider and what it provides to consumers, and the sealed secrets it needs filled on the machine.

  • Core mesh components are not modules. The node host, the foundation, the control-plane contexts and the surfaces are the mesh itself; they ship as their own repositories (mesh-host, mesh-foundation, mesh-controller, mesh-surfaces, mesh-sdk), not from here.
  • Standalone applications are not here either. A larger application lives in its own repository with its manifest at the root, registered with the mesh as a build source (novox/hq ADR 0010). This repository holds the modules the mesh maintains as its shared catalogue; an application the mesh merely hosts keeps its manifest beside its own code.

So there is one home for the catalogue the mesh owns, and every application that runs on the mesh rather than being of it carries its own — both reach the pipeline the same way, as a registered source.

Layout

modules/<name>.json      one manifest per module

Flat, because the catalogue's shape carries no meaning: a module is found by its name and described by its manifest, and what relates two modules — a shared seat, a claim, a provider/consumer edge — is data inside the manifests, not a directory the tree encodes (novox/hq, the domain-grouping question closed in favour of seats, claims and tags).

The manifest contract

The shape a manifest must satisfy is owned by the control plane's catalogue engine and is what validates a manifest before a machine ever sees it — a stray key, a consumer contributing the wrong provision field, an image that nothing builds. That validation belongs with this repository and is being re-homed here from mesh-controller; until it is, the pipeline is the gate — it builds each module and refuses a manifest it cannot resolve.

Where the reasoning lives

Design and decisions are in novox/hq:

  • 02-DECISIONS/0002-everything-is-a-module.md — one unit, no second mechanism
  • 02-DECISIONS/0010-applications-live-in-their-own-repository.md — why applications are not here
  • 02-DECISIONS/0030-the-repository-structure.md — the repositories, and the open tier-4 question this repository answers
  • 03-DESIGN/00-as-is/10-module-catalogue.md — the catalogue's shape, and what it records
S
Description
Novox Mesh — the catalogue. Module manifests the mesh builds, provisions and runs. Data, not a control-plane concern.
Readme
1.4 MiB
Languages
TypeScript 89.4%
Dockerfile 9.6%
Shell 1%