--- status: accepted date: 2026-08-23 deciders: jochen reconstructed: false --- # 30. The repository structure, and the rule that names them ## Context The tiers are settled ([research 006](../01-RESEARCH/006-mesh-from-scratch/code-skeleton.md)) and the product is named ([ADR 0027](0027-the-product-is-novox-mesh.md)), but the repositories themselves were only ever sketched in research. Two consequences had already appeared. [ADR 0029](0029-the-labs-first-scenario-has-no-pipeline.md) makes the lab phase 0 of the entire migration and **could not say where it lives**, because no record named a repository. And the research contradicted an accepted record: it listed `mesh-hq` for this repository, while [ADR 0028](0028-hq-is-company-scoped.md) had decided `novox/hq` and explicitly rejected that name. A design resting on research is a design resting on something that can change without a decision. There is also an implied naming rule that has never been written down. ADR 0027 says repository names take `mesh`; ADR 0028 gives this repository no prefix at all. Both are right, for a reason neither states. ## Considered options Only the naming rule had genuine alternatives; the tier repositories follow from the tiers. 1. **No prefix — `novox/host`, `novox/control`.** The organisation already says Novox, so the prefix reads as stutter. Rejected once it was established that Novox delivers more than the mesh: with several products the prefix is not stutter, it is the product namespace doing real work, and the forge has no nested groups to do it instead. 2. **An organisation per product — `novox-mesh/host`.** Puts the product boundary where the forge's only real grouping primitive lives, so permissions and teams attach to it. Rejected for now as premature: no per-product access boundary exists yet, and it costs `novox-` repeated across every organisation. 3. **Product-prefixed repositories in the company organisation.** Chosen. ## Decision **The naming rule:** a repository that belongs to a product carries that product's prefix. A repository that is company-scoped does not. That is why this one is `hq` and the mesh's are `mesh-*`. Both records were already correct; the rule connecting them is stated here. **The repositories:** | Repository | Tier | Holds | |---|---|---| | `novox/mesh-host` | 0 | the node host — the one binary installed by hand | | `novox/mesh-substrate` | 1 | the four pinned services, as declarations | | `novox/mesh-control` | 2 | the control plane and its contexts | | `novox/mesh-surfaces` | 3 | tools, web, cli — thin, no logic | | `novox/mesh-sdk` | — | contracts shared across tiers: types, not behaviour | | `novox/mesh-lab` | — | the lab: scenario lifecycle, networking, placement | | `novox/hq` | — | this repository. Company-scoped ([ADR 0028](0028-hq-is-company-scoped.md)) | **The lab is its own repository.** Its lifecycle differs from everything else in the list: it is never shipped to a node, it outlives any single tier, and it drives virtualisation on a workstation — which nothing else in the mesh does. Putting it inside the host would couple development tooling to a shipped component; putting it inside the control plane would make the bootstrap scenario depend on a tier that does not exist when it is needed. **Tier 4 is deliberately not decided here.** Whether the catalogue is one repository, one per domain, or one per application remains open from [ADR 0015](0015-mesh-brokers-nodes-host-agents-think.md) and is blocked on [research 005](../01-RESEARCH/005-domain-grouping/00-overview.md): how many repositories hold domains cannot be answered before what the domains are. Recording the gap is the point — `mesh-catalog` appears in the research sketch and is **not** decided by this record. ## Consequences - [ADR 0029](0029-the-labs-first-scenario-has-no-pipeline.md) can name its target. Phase 0 has a home, which was the immediate blocker. - The research sketch stops being load-bearing. It remains what it is — a sketch — and the design layer can now cite a record instead. - **Seven repositories where there is currently one**, for a mesh that today lives in a single monorepo. That is the cost, and it is not small: seven release cadences, seven sets of dependencies, and cross-repository changes that were previously one commit. The offsetting argument is the tier rule — a boundary that only points downward is enforceable across repositories and merely conventional inside one. - The prefix will read as redundant for as long as the mesh is the only product with repositories. That is accepted deliberately: the alternative is renaming everything at the moment a second product appears, which is the class of migration this project is trying to stop performing. - Nothing is created yet. This records what the repositories *are*; creating them is part of phase 0 and after. ## References - [ADR 0027](0027-the-product-is-novox-mesh.md) — the product name the prefix comes from. - [ADR 0028](0028-hq-is-company-scoped.md) — why this repository has no prefix. - [ADR 0029](0029-the-labs-first-scenario-has-no-pipeline.md) — the lab, and why it is first. - [Research 006](../01-RESEARCH/006-mesh-from-scratch/code-skeleton.md) — the tiers, and the sketch this supersedes as a source.