The skeleton's biggest unproven claim was that absorbing six concerns makes a binary whose whole argument is having no dependencies carry six of them. Measured against origin/main, and the question turns out to ask about the wrong axis. By size the absorption is SMALLER than the machinery that already applies state on a node — 2755 lines of adapters against 3059 lines of meshware, env-sync and config-sync. The host is not a new large thing; it already exists, spread across three core modules. The real risk is direction, and it is two modules wide rather than six concerns wide. Eight of ten adapters already receive derived state and only apply it, so absorbing them moves code that has no dependency to move. Two — wireguard and traefik — open a Postgres connection to the control plane and compute their own configuration, which inside tier 0 would be an upward dependency and is exactly what the tier rule forbids. And the split has already been happening without being named: dnsmasq-app needs the same node data as wireguard and does not query for it, because hand- duplicated state went wrong and someone derived it centrally instead. Eight of ten adapters are on the far side of that migration. So the absorption is not a move, it is a split: deciding stays in tier 2, applying goes to tier 0. The claim survives with its scope corrected — the host carries ONE concern, apply declared state on this machine, of which the six are instances. Stated open rather than glossed: the two unsplit modules are the two hardest, six concerns is still six vocabularies even at zero dependencies, and what the host must carry versus find is issue 007 and unresolved. Question B also recorded as answered by the operator — a node is a managed machine, and a disconnected node is still a node in a different situation. The question posed a class distinction; there is none, and what varies is state.
6.1 KiB
status, initiated, touches, became
| status | initiated | touches | became | ||||
|---|---|---|---|---|---|---|---|
| active | 2026-08-23 |
|
006 — The mesh designed from nothing
What is being investigated
What the mesh would look like if it were laid out today, with the requirements known and none of the accumulated shape — expressed as a skeleton: repositories at the root, modules inside them, and whatever turns out to be the right leaf unit below that.
The deliverables are skeleton.md — tiers, repositories and the four design
moves — and code-skeleton.md — the tier test, what a module looks like on
disk, and where today's catalogue lands.
Why
Every structural decision so far has been a correction: eight contexts replacing thirty-three modules (ADR 0015), domains replacing single-function modules (ADR 0017). A correction inherits the frame of the thing it corrects, and two of the mesh's oldest problems look unsolvable from inside that frame:
- The bootstrap circularity. The mesh needs a database, a bus, a registry and an identity provider. Those are modules the mesh installs. The mesh cannot install them before it exists. This has been worked around repeatedly and never designed away.
- Participation requires privilege. Everything assumes root on a machine whose packages and services the mesh owns. A phone cannot participate on those terms, and neither can a machine someone else administers.
Designing from nothing is a way to find out which parts of the current shape are requirements and which are residue.
And there is more residue than expected, from a knowable source. This began as a
dotfiles repository — the first two days of history adopt dotfiles, add per-node dotfile
overrides, and introduce service symlinking with an ignore file. The flat one-directory-per-tool
catalogue, linking rather than copying, adoption of already-configured machines, per-node
overrides, and the desktop modules are all inherited from that, not chosen for a mesh. Recorded
in 03-DESIGN/00-as-is/10-module-catalogue.md.
That makes this effort's question sharper than "what would we do differently": much of what looks like design is a generalisation of place files on my machines, never revisited because it was never stated as an assumption.
The requirements this is designed against
Stated by the operator, recorded here so the skeleton can be checked against them rather than against taste:
- The mesh manages multiple computers — full control, through modules installed to nodes.
- Mesh state lives in a database: which modules on which nodes, logs, configuration.
- Configuration has several touchpoints — tool surface, web interface, others — all hosted by the mesh itself.
- Connectivity is core: every node reachable from every other over a shared overlay, some nodes publicly exposed, firewalls configured.
- The mesh hosts applications — and requires some of them itself. This is the circularity.
- Arch Linux only for now; ideally any device, including phones, on lighter terms.
- The end goal is to operate an IT company on it — development, design, deployment, full circle, self-hosted. Personal cloud infrastructure.
- Agents make it self-improving and self-healing.
- It is end-to-end testable on one machine (ADR 0016).
Status
A first skeleton exists, with four design moves that the current shape does not have. It is
active because two of them are unproven and one contradicts a record that is already
accepted.
Finding worth stating up front: ADR 0015 names nine bounded contexts and none of them owns connectivity — no overlay, no resolution, no firewall, no ingress. Requirement 4 has no home in the accepted decomposition, while research 005 found reachability to be the only part of the catalogue where modules genuinely change together under one intent. The skeleton adds it.
Open questions
| Question | Why it is open |
|---|---|
| Does the record — the event log contexts integrate through — belong to the substrate or the control plane? | It is infrastructure by shape and domain by content. Placing it wrong reintroduces a circularity. |
| One repository per tier, or per context? | Already open from ADR 0015 as "catalogue destination — one repository or many". The skeleton assumes per tier and does not settle it. |
| Answered 2026-08-25 by the operator: a node is a managed machine inside the mesh, not an unprivileged something — and a disconnected node is still a node, in a different situation. The question posed a class distinction; the answer is that there is none, and what varies is state. Awaiting a decision record. | |
Answered 2026-08-25 — host-size.md. Measured: the absorption is smaller than the machinery that already applies state, and eight of ten adapters already carry no dependency. The risk is not size but direction, and it is two modules wide. The claim survives with its scope corrected — the host carries one concern, apply declared state on this machine, of which the six are instances. |
|
| Four substrate services or five? | The identity provider passes the tier test only if the control plane delegates authentication rather than doing it natively. |
Does feature survive? |
The skeleton splits it in two and argues the conflation is what makes the delivery pipeline hard to reason about. Unproven. |