--- status: accepted date: 2026-03-14 deciders: jochen reconstructed: 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`.