Files
hq/02-DECISIONS/0004-a-node-and-how-it-joins.md
T
jschoubben 066f14b5f8 A node is a conversation, and that is not the employee model
Moving this out of 0003 and out of its vocabulary. I had spent three attempts
fitting the node's own session into the agent-as-employee record, each time
bending hired, draining, reassigned and retired to cover something none of them
describe. 0003 is back to its original text.

It belongs in 0004, under what a node is, because that is what it is -- not a
program installed on a node but part of the node. It holds one session
permanently, anything in the mesh can message it, and it remembers across
callers and across weeks. Its system prompt is the engram, which is recorded
here for the first time despite running on every node.

Also recorded: it has its own narrower tool list, so it can go and look rather
than only report about itself; there is no authorisation between nodes, because
every node is the operator's own; and how a node passes a question on is its
own business rather than a protocol field.

Switched off it still answers, and that is the point of having an off state
rather than an absent one. A node with nothing there is a silence somebody has
to diagnose. A node that says it is switched off is not. Same rule the host
follows about a service that does not exist.

0001's summary is corrected too: it had one row for "agents", which is the
conflation being complained about. Two rows now. A node's own session and a
hired worker are built from the same parts and run on entirely different terms.

Left standing and NOT resolved here: 0001 says a node does not authenticate to
a model provider, agents do. A node that holds a session does. That is a real
conflict between what is recorded and what runs, and it needs deciding rather
than a fourth reconciliation from me.
2026-08-29 14:17:25 +02:00

9.5 KiB

topic, status, date, deciders, reconstructed
topic status date deciders reconstructed
the tiers accepted 2026-08-28 jochen false

4. A node, and how it joins

Consolidated 2026-08-28 from four records.

What a node is

A managed machine inside the mesh. Not a device that is merely known about, not an unprivileged something. If the mesh does not manage it, it is not a node — it is a client, a peer, or a thing on the network, and those want their own names rather than a weakened version of this one.

A disconnected node is still a node, in a different situation. Reachability is state, not class. A machine switched off, roaming, or behind a connection that has dropped has not become a lesser kind of thing; it has a last-known state and a pending set of declarations.

The distinction people reach for is real, but it is capability — what this machine can be asked to do — and that belongs in the host's profile rather than in the definition of a node.

This is the rule that does the most work elsewhere. A single control plane is tolerable because its absence is every node in the ordinary disconnected situation at once. An episodic host on a phone is that situation more often. Neither needed a new mechanism.

A node is also a conversation

Written 2026-08-29. It runs on every node today and appeared in no record, which is how something deliberate comes to look accidental.

A node holds one session, permanently, and it is part of what the node is — not a program installed on it. Anything in the mesh can send it a message; it replies; and it remembers. What it was asked ten minutes ago is still there next week, alongside what everything else asked in between, the same way both sides of any conversation remember it.

Its system prompt is the node's engram — what makes one node's replies recognisably its own rather than generic.

It has its own tools, and fewer than a session a person is driving directly. So a question can be answered by going and looking: what is in our forge, not only what is your battery.

Messages travel the broker like everything else (ADR 0002). There is no second transport and nothing is dialled.

Any node can message any node, and this is the one part of the system that is genuinely a mesh — symmetric, with no centre. A node that is asked something it does not know can ask another, and how it passes the question on is its own business: it may say who wants to know, or simply ask. A person relaying a question makes the same choice, and it follows from the engram rather than from a message format.

There is no authorisation between nodes. Every node is the operator's own, so a message from one is a message from them, and asking a node something is asking a colleague rather than presenting credentials. Stated once so it is not discovered later: the mesh boundary is therefore the security boundary — anything inside can reach what any node can reach, which is what puts the whole perimeter on the token and the overlay (ADR 0007).

It can be switched off, and switched off it still answers. A node whose session is disabled replies saying so, at once, with no model involved — the queue is still read, and the state is the reply. That is deliberate and it is the same rule the host follows about a service that does not exist: absence must never be indistinguishable from a failure to answer. A node with nothing there is a silence somebody has to go and diagnose; a node that says I am switched off is not.

One per node, always, and it cannot be moved to another machine. Two and nothing decides which replies; none and the node is mute; moved, and one machine is answering as another.

It is not an employee (ADR 0003). Nobody hires it, it holds no tasks, it drains nothing and it is never reassigned — that vocabulary was written for workers and does not describe this. It exists because the node does, and it is gone when the node leaves.

How it joins

The host has one behaviour and two sources of declaration. What differs between the first node and the fiftieth is not what the host does but where the declaration comes from — and, as above, that is a situation rather than a class.

declaration comes from
no mesh reachable the pinned bundle the host carries
mesh reachable the control plane, over the link

The first node is not a different kind of node. It is a node whose mesh is not up yet. It applies the bundle it carries, the control plane comes up on top of it, and from that moment it takes declarations like everything else. Its specialness is temporary and self-erasing, which is what the hand-run bootstrap scripts never were.

A joining node does the minimum to be reachable and nothing else — an identity, an address, and one peer to reach. It does not compute the overlay: the whole peer set is derived centrally and pushed down.

That is also why the migration is smaller than it looked. The hard part of the overlay — every node's key, address, site and reachability — is only needed to compute the whole mesh, and a joining node needs one peer.

Everything reaching a node arrives one way, and four properties make that a boundary rather than a pipe.

It is outbound and node-initiated. The node dials the control plane; nothing dials a node. Not only defensive — most nodes sit behind a household connection with no forwarded port, so an inbound control channel would work for one node and not the rest, and the difference would be invisible until it mattered. A node has no listening control surface at all.

A node holds its own identity and nothing else. No shared secret, no credential to anything it does not own. Compromise of a node is compromise of that node — which the current arrangement does not have, because every node permanently holds the same database and object-store credentials, and there is no mechanism that rotates one and informs everything holding it.

Authority is mutual. The node proves it may join, and the control plane proves it is the mesh. One-way is not enough: the host applies whatever the link delivers, so a node that cannot tell the mesh from something impersonating it will apply that something's declarations.

What may be pushed is bounded by form, not by trust. Declarations of known shape, never a command to run. Stated honestly, this bounds form and not impact: a compromised control plane can declare harmful state and the host will apply it faithfully, because that is what it is for. What the property buys is that the blast radius is describable — exactly what the declaration language can express, which can be reviewed. An arbitrary command channel has no such bound.

The enrolment token carries the mesh

Mutual authority needs the node to verify something before it trusts anything, and that is a circle: verifying the mesh needs the mesh's certificate authority, and obtaining one means trusting whoever hands it over. There is a second circle beside it — a node must reach the mesh before the mesh has configured it, so it can resolve no mesh name.

Both are the same shape: a node needs a fact about the mesh before it has any trustworthy way to obtain one. So that fact arrives by a path other than the mesh.

The token carries four things, and it is the only thing a joining node needs:

where the broker's address, not a name — there is no resolution yet, and this is why none is needed
what it is connecting to the fingerprint of the broker's certificate
who it will believe the control plane's signing identity
the right to join a one-time secret, useless once used and useless after it expires

Carried out of band, by the person adopting the machine. That is what breaks both circles: its authenticity comes from the channel it travelled, not from anything the node can check afterwards. Trust on first use, with the first use moved out of band — the difference between a pin and a guess.

The endpoint and the authority are two identities. A node connects to the broker and takes instruction from the control plane behind it. Pinning only the broker would make the control plane's authority transitive, and a compromised broker could then forge declarations — which, since the host applies whatever the link delivers, is the whole machine. So the transport is verified once at connect, and each declaration is verified by its signature, every time.

What this settles: the mesh's certificate authority is not a bootstrap concern — it certifies internal names once a node is a member. Nothing needs name resolution before the link. And nothing is placed on disk beforehand except the token, which is the first moment a node holds only its own identity becomes true rather than aspirational.

Consequences

  • Declarations must be signed, and the host must tell this is not from the mesh I joined apart from this is malformed. Rotating the signing identity is a fleet-wide operation with an overlapping rollover, and that is the cost of not trusting the broker.
  • The token becomes security-critical, because it carries the pin. Tampering substitutes the mesh — which is strictly better than the alternative, where there is nothing to tamper with and the node trusts the first answer unconditionally.
  • A rejoining node is ordinary. There is no long-lived secret to recover, so a node that lost its identity gets a new token.