Tier 0: the questions answered, the decisions taken, and the design #9

Merged
jschoubben merged 16 commits from design/close-the-record into main 2026-08-25 22:56:07 +00:00
4 changed files with 92 additions and 4 deletions
Showing only changes of commit 92e8c74ce4 - Show all commits
+4
View File
@@ -268,6 +268,10 @@ Data access, business logic and the interface layer are separate.
### Types
*Scope: the mesh's services and surfaces. Tier 0 is a statically linked binary that must depend
on nothing installed first, and is written in Go —
[ADR 0041](../02-DECISIONS/0041-the-host-depends-on-nothing.md).*
- TypeScript throughout; no new untyped JavaScript.
- Strict, with no implicit `any` and no unchecked index access.
- Public functions state their return type. Prefer `unknown` with a guard over `any`. Errors
+2 -2
View File
@@ -21,13 +21,13 @@ and a forge address is an operational detail (see [`README`](../README.md)).
## What the mesh becomes
[ADR 0030](../02-DECISIONS/0030-the-repository-structure.md) records the repositories the
monorepo decomposes into. **Only `mesh-lab` exists so far** — it is built first
monorepo decomposes into. **`mesh-lab` and `mesh-host` exist so far** — the lab is built first
([ADR 0029](../02-DECISIONS/0029-the-labs-first-scenario-has-no-pipeline.md)); the rest are the
target, not the present.
| Repository | Tier | Holds |
|---|---|---|
| `mesh-host` | 0 | the node host — the one binary installed by hand |
| `mesh-host` | 0 | **exists.** The node host — one statically linked binary, requiring nothing present ([ADR 0041](../02-DECISIONS/0041-the-host-depends-on-nothing.md)) |
| `mesh-substrate` | 1 | the four pinned services, as declarations |
| `mesh-control` | 2 | the control plane and its contexts |
| `mesh-surfaces` | 3 | tools, web, cli |
@@ -0,0 +1,78 @@
---
status: accepted
date: 2026-08-26
deciders: jochen
reconstructed: false
extends: 0037-the-host-applies-it-does-not-decide.md
---
# 41. The host depends on nothing that must be installed first
## Context
[ADR 0030](0030-the-repository-structure.md) calls tier 0 *"the one binary installed by hand"*,
and [research 006](../01-RESEARCH/006-mesh-from-scratch/00-overview.md) states the property the
whole tier rests on: *"a binary whose whole argument is that it has no dependencies"*.
Building it forced the question that phrase had been carrying unexamined. Everything else in
the mesh is TypeScript, and `how-we-build` §8 says so. A TypeScript host needs a runtime present
before it can run — so the thing installed by hand becomes **two** things, and the second must
be installed by the means the host exists to replace.
## Considered options
1. **TypeScript, with a runtime installed first.** Simplest, and matches every other
repository. Rejected: it breaks the property the tier is built on. A host that cannot run
until something else has been installed by hand is not the bottom of the stack.
2. **TypeScript, bundled as a single executable.** Preserves the language and produces one
file. Rejected on two grounds: it carries roughly ninety megabytes of runtime to preserve a
language choice, and single-executable bundling is a young feature — tier 0 is the worst
place in the system to discover its edges.
3. **A statically linked binary in a language built for it.** Chosen; Go.
## Decision
**The host is a single statically linked binary that requires nothing to be present.** Copy it
onto a machine and run it. That is the whole installation.
**It is written in Go.** The job is system-level — run commands, write files, speak to the
firewall, the overlay, the service manager and the package manager — which is what Go's
ecosystem is for, and it cross-compiles to every architecture the mesh might reach, including
the lighter devices requirement 6 anticipates.
**The second language costs less here than anywhere else it could appear**, and the reason is
architectural rather than convenient. [ADR 0037](0037-the-host-applies-it-does-not-decide.md)
means the host never queries the mesh database.
[ADR 0039](0039-the-link-is-the-security-boundary.md) means it only ever receives declarations.
So the host shares **no code** with any other tier — not a client, not a schema, not the SDK.
It is joined to the mesh by a message contract and nothing else.
The language boundary therefore falls exactly on an architectural boundary that already exists.
A second language usually costs duplicated logic; here there is none to duplicate.
## Consequences
- **`how-we-build` §8 needs a scope.** It reads *"TypeScript throughout"*, which was true when
everything was a service or a surface. It is now scoped to those, with tier 0 named as the
exception and this record as the reason. That is a constitution change, and the sync it owes
is part of it.
- **Agents must write Go to work on the host.** A real cost, and the one genuine argument
against this. It is bounded by the host being the only thing in tier 0 — nothing else in the
mesh acquires a second language because of this.
- **The dependency-direction lint the design calls for gets easier, not harder.** A Go module
cannot accidentally import a TypeScript control-plane client; the boundary is enforced by
there being no path across it.
- **Cross-compilation replaces per-node builds.** The host is built once per architecture and
copied, rather than built on the machine it runs on — which is what makes *"copy it and run
it"* true rather than nearly true.
- **Two toolchains in the lab.** Scenarios that place a host need a Go build available, and the
lab is TypeScript. The binary is built before the scenario runs, not inside it.
- **This is reversible at a cost that will only grow.** It is being taken at the moment the
first line is written, which is the cheapest point it will ever be taken.
## References
- [ADR 0030](0030-the-repository-structure.md) — *the one binary installed by hand*.
- [ADR 0037](0037-the-host-applies-it-does-not-decide.md) — why the host shares no code.
- [ADR 0039](0039-the-link-is-the-security-boundary.md) — why it receives declarations only.
- [`05-the-node-host.md`](../03-DESIGN/01-to-be/05-the-node-host.md) — the design this serves.
+8 -2
View File
@@ -1,7 +1,7 @@
---
layer: to-be
status: designed
code: []
status: in-progress
code: [mesh-host]
updated: 2026-08-26
decisions:
- 02-DECISIONS/0030-the-repository-structure.md
@@ -10,6 +10,7 @@ decisions:
- 02-DECISIONS/0038-a-node-joins-by-linking-first.md
- 02-DECISIONS/0039-the-link-is-the-security-boundary.md
- 02-DECISIONS/0008-a-failed-step-fails-the-job.md
- 02-DECISIONS/0041-the-host-depends-on-nothing.md
---
# The node host
@@ -18,6 +19,11 @@ Tier 0. The one thing ever installed by hand, and the only thing that changes a
## What it is
A **statically linked binary that requires nothing to be present** — copy it onto a machine and
run it, and that is the whole installation
([ADR 0041](../../02-DECISIONS/0041-the-host-depends-on-nothing.md)). Written in Go, because the
job is system-level and because the host shares no code with any other tier.
A single binary with one job: **apply declared state on this machine**
([ADR 0037](../../02-DECISIONS/0037-the-host-applies-it-does-not-decide.md)). Overlay
membership, packet filtering, packages, services, containers and filesystems are not six