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.
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
- 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.
- One manifest, kind inferred from directory contents. Chosen.
- 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.