Files
hq/adr/0002-everything-is-a-module.md
T
jschoubben 702efca6bb Base layer: the mesh as it is, under the mesh as it should be
HQ held only the to-be. Every reader had to already know the system the
decisions were about, and an as-is claim had nowhere to live except inside
an intention.

Adds 02-DESIGN/00-as-is — eleven documents written from the implementation
and the operational record, not from intent, including the parts nobody
would choose again. The two existing designs move under 01-to-be. Layers
are declared in frontmatter and never mix: a design that ships does not
move, its as-is counterpart is written, and both stand.

Back-fills adr/0001-0014 for decisions taken in implementation and never
recorded — the broker, the module abstraction, the mesh database, managed
files, provisioning, migrations, the workspace removal, failing loudly,
the constitution, application placement, linking, the employee model, the
artifact, the three silos. Each marked reconstructed, dated from the
history, and citing the evidence it was recovered from. The two existing
records renumber to 0015 and 0016 so the ledger runs oldest first;
0017 extends 0015 to modules outside the core, principle only — the
domain list is deliberately not invented here.

how-we-build.md becomes the source of the mesh constitution, with a sync
playbook, so the enforced copy stops being the only one that is true.

Process becomes explicit: five playbooks, eight thin skills that defer to
them, a repository map, and AGENTS.md with CLAUDE.md as its include.

The five Observations become 04-ISSUES 001-005 where they can be owned and
closed. 006 is new and uncomfortable: HQ is not indexed into the knowledge
base. That claim is what decision 27 rests on, it was never checked, and
the README now says so instead of repeating it.

Also corrects the ADR index into something generated, the "02-DESIGN is
empty" claim, the VISION.md pointer that did not survive the repo split,
and a note asserting the symlink rule was contradicted — it was a
misreading; the rule forbids hand-made links, the installer links by design.
2026-08-23 03:08:26 +02:00

3.3 KiB

status, date, deciders, reconstructed
status date deciders reconstructed
accepted 2026-03-14 jochen true

2. Everything is a module, and one manifest describes all of them

Reconstructed after the fact from the evidence cited below.

Context

The mesh carries several kinds of thing: containerised services with data and ports, pure capability providers with no service at all, and bare markers whose only content is that a node has them. Before this decision these were separate concepts with separate handling — the earlier vocabulary was capabilities, and services were installed by a different path than tools.

Every distinct kind of thing needs its own install path, its own change detection, its own place in the delivery pipeline, and its own documentation. Three kinds means three of each, and every new feature has to be built three times or, more commonly, once — leaving two kinds quietly unsupported.

Considered options

  1. Separate concepts per kind — a service registry, a tool registry, a node feature flag list. Rejected: it is what existed, and the cost was paid in every cross-cutting change.
  2. One manifest, kind inferred from directory contents. Chosen.
  3. One manifest with an explicit type: field on every module. Partly adopted — a service still declares itself — but the general rule became inference, because a declared list and the directory it describes drift, and the directory is the one that is true.

Decision

Everything the mesh installs is a module: a directory with a manifest. The manifest declares identity, environment variables, what the module provides, what it requires, and how it is exposed. What kind of module it is follows from what the directory contains:

Contains Is
a compose definition a service
a tools directory a capability provider
a daemon or unit directory a long-running process
a configs directory a source of managed files
nothing but a manifest a flag — presence is the whole content

A module may be several of these at once. Each is a feature, and the delivery pipeline addresses features, not modules.

The mesh's own components are modules on exactly these terms. They get no privileged install path, no separate registry, and no exemption from the pipeline.

Consequences

  • One mechanism to learn, one to document, one to fix. A pipeline improvement reaches everything the mesh carries.
  • Dogfooding stops being a discipline and becomes structural: if the mesh's own components need an exception, the machinery is unfinished, and that is visible immediately.
  • Feature detection from directory contents means a directory rename silently changes what a module is. This has bitten repeatedly — a hook named for a feature the module does not have is skipped without complaint.
  • The manifest becomes load-bearing and grows. It is now the largest single point of coupling in the mesh.

References

  • Rename capabilities → modules across the entire codebase, 2026-03-14.
  • Merge fail2ban, ufw, firewall apps into modules, 2026-03-15 — the first modules to arrive by conversion rather than by creation.
  • Knowledge base: modules, modules/manifest-reference, conventions/modules.
  • The rename-breaks-detection shape: troubleshooting/hooks-named-for-missing-feature, troubleshooting/health-check-tools-index-false-positive.