Files
hq/02-DECISIONS/0037-where-a-module-lives.md
T
jschoubben 0871e6ec11 37 — where a module lives, proposed
The module descriptions sit in `examples/` inside the control plane, and
that name has been doing harm: everything there reads as a sketch, and
one shipped naming a container image nothing builds. A directory called
the catalogue would have made "does this work" the obvious question.

The shape of the answer turns on one measurement. Of the 126 modules in
the system being replaced, 47 are software in their own right — the
largest is 182 source files, and a speech-capture module carries a whole
daemon. Another 44 ship helper scripts. Only 35 are a description and
nothing else.

So a catalogue cannot be a folder of manifests, because two thirds of
modules are programs. That splits them four ways, and only two of the
four belong in a catalogue: things the world made that we describe, and
packages with some files. What the mesh is made of stays in the
repositories that build it. What we wrote keeps its description beside
its code, in the same commit, because nothing else can stop the two
drifting.

The mesh's list of modules is a table, not a repository, and it already
records where each module came from and at which commit. Nothing needs
inventing for modules from anywhere; a repository of ours is just the
source we curate.

The check that a description is valid should move to a command on the
control plane's binary. Today a test reaches into the control plane's
internals to parse manifests, and another reads its build file to check
images exist — two jobs tangled. A command would also give the same
check to somebody describing their own application, which is the case
that matters most and has none.

Left open: how a provisioner's image gets published and pinned, and
whether thirty-five install-a-package modules deserve to be modules at
all.
2026-09-01 14:24:53 +02:00

5.6 KiB

topic, status, date, deciders, reconstructed, rests-on
topic status date deciders reconstructed rests-on
building it proposed 2026-09-01 jochen false 02-DECISIONS/0009-modules-and-the-graph.md

37. Where a module lives

The question

The mesh's own module descriptions currently sit in examples/ inside the control plane, beside the small programs that hand out logins. That was fine while there were three of them. It is wrong now, and the name is doing active harm: everything in examples/ reads as a sketch, and one of them shipped naming a container image that nothing in the repository builds. A directory called the catalogue would have made does this actually work the obvious question to ask of it.

So: one repository holding the modules we ship? And if so, where does everything that is not ours go?

What a module actually is, counted

The system being replaced has 126 modules on its main branch. The shape of them is the whole argument, so it is measured rather than assumed:

count what it is
the module is software 47 its own source tree lives inside the module — a daemon, a service, a library
helper scripts only 44 no application of its own; scripts it runs at install time or offers to an agent
a description and nothing else 35 a package to install and some files to write

Two thirds of modules contain code. The largest is a shared library of 182 source files. A speech-capture module carries a complete daemon — audio capture, mixing, transcription, a model runner. Treating a module as a description of something else is true of barely a quarter of them.

That kills the simplest answer. A catalogue cannot be "a folder of manifests" when most modules are programs.

The four kinds, which want different homes

1. What the mesh is made of. The control plane, the host, the shared library, the board. These are not modules that happen to be ours; they are the mesh, expressed as modules so it can install itself. They belong in the repositories that build them, which already exist.

2. Something the world made, that we describe. A forge, a mail system, an identity provider, a media server. Nobody upstream ships a description; somebody has to write one, and it is the same description for everybody who runs it. This is what a catalogue is for. It is also where the small programs that create accounts belong, because such a program is part of describing that service, not part of the mesh.

3. Something we wrote, that runs somewhere. An application, a site, a side project. The description belongs with the code, at the root of its own repository, because the two change in the same commit. A repository that gains an environment variable and a description that gains it elsewhere will drift, and there is no mechanism that could stop it. This is already how it works and it should stay that way.

4. A package and some files. A tool, a font, a shell. Thirty-five of these, and each is a few lines. The catalogue.

The proposal

A mesh-catalog repository holding kinds 2 and 4: descriptions of software we did not write, and the programs that provision it. Not kind 1, which is the mesh itself. Not kind 3, which lives with its own code.

The mesh's list of modules is not this repository. It is a table in the control plane, filled by adding a description to a running mesh. The catalogue is a source to add from — one of several, and the mesh already records which: every module carries where it came from, the branch followed there, and the commit its description was read at. Nothing needs inventing to support modules from anywhere; a repository of our own is simply the source we curate.

A description is checked by the tool, not by a test that imports the tool. Today a test in the control plane parses the example manifests by reaching into the control plane's internals, and another reads the control plane's own build file to check every image a module names can be built. Two jobs tangled. A module check command on the control plane's binary would let the catalogue hold data validated from outside, and would give the same check to somebody describing their own application in their own repository — which is the case that matters most and currently has no check at all.

What this costs, and the argument against

It is early. Ten modules exist, four of them ours. Moving ten files is a morning; moving a hundred is a week — but the hundred is not here yet, and splitting now adds a second repository to release across before there is anything to release.

The counter is that the tangle is already producing faults rather than merely threatening to. A manifest naming an unbuildable image, and a test reading a build file two directories up, are both symptoms of one repository doing two jobs. And the moment the first module is adopted on a real machine, the descriptions stop being examples and become the thing deployments come from. That is the moment this becomes urgent, and it is close.

What it does not settle

Where a provisioning program's image is published, and how a description pins it. A description names an image by digest; the image is built from the catalogue; the catalogue must therefore both produce an image and refer to it, which is the same knot the bootstrap has and solves by writing the digest down after building.

Whether kind 4 deserves a module at all. Thirty-five descriptions that say install this and write these files may be better as one module with settings than as thirty-five modules. Left open deliberately; it is a question about the shape of the catalogue, not about whether to have one.