diff --git a/02-DECISIONS/0001-mesh-brokers-nodes-host-agents-think.md b/02-DECISIONS/0001-mesh-brokers-nodes-host-agents-think.md index 60552ba..dfb74fc 100644 --- a/02-DECISIONS/0001-mesh-brokers-nodes-host-agents-think.md +++ b/02-DECISIONS/0001-mesh-brokers-nodes-host-agents-think.md @@ -81,17 +81,18 @@ Four layers. Naming them honestly is worth more than the word on the tin: | **machines are linked by a private network** | and every machine reaches every other over it | | **one node holds knowledge of all of them** | the control plane, and only it | | **modules are how anything is built and delivered** | this *is* the CI/CD, not something beside it ([ADR 0010](0010-delivery.md)) | -| **agents are hired onto nodes and do the work** | the layer the other three exist to carry | +| **every node is a conversation you can address** | it holds a session, it remembers, and any node can message any other ([ADR 0004](0004-a-node-and-how-it-joins.md)) | +| **workers are hired onto nodes to do tasks** | employees, with a lifecycle — a different thing from the row above ([ADR 0003](0003-agents-are-persistent-employees.md)) | -**The fourth row is where the value is, and the first three are what make it possible.** An agent -hired onto one node can reach any other — a shell, a service, a file — because the private network -makes every node reachable and `identity` decides which agents may reach which. **That is the -capability being built**: not machines that can be configured centrally, which is ordinary, but a -set of machines an agent can work across as though they were one. +**The last two rows are not the same thing and the vocabulary of one does not describe the other.** +A node's own session belongs to the node: nobody hires it, it holds no tasks, it is never +reassigned, and it is gone when the node leaves. A worker is an employee — named, hired, drained, +retired, movable. They are built from the same parts and run on entirely different terms, and +collapsing them is how the employee vocabulary ends up stretched over something it does not fit. -The credential belongs to the **agent**, never to the node it is sitting on -([ADR 0006](0006-the-substrate-and-the-control-plane.md)), which is the same rule as *nodes and -agents are decoupled* below, applied to access. +**Where the value is** is that both can reach across the whole set: a shell, a service, a file, or +simply a question to another node. Not machines that can be configured centrally, which is +ordinary, but a set of machines that can be worked across as though they were one. **This is not a mesh in the peer-to-peer sense and will not become one.** The word describes what machines can reach, not how they are governed: diff --git a/02-DECISIONS/0003-agents-are-persistent-employees.md b/02-DECISIONS/0003-agents-are-persistent-employees.md index 3f26127..5bbe516 100644 --- a/02-DECISIONS/0003-agents-are-persistent-employees.md +++ b/02-DECISIONS/0003-agents-are-persistent-employees.md @@ -51,81 +51,6 @@ when it expires. A temporary employee is still an employee. Some agents are **human**. What differs is modality — how the agent acts — not category. A node itself is an agent of a kind exempt from the hiring lifecycle. -### The node's own session - -*Written 2026-08-29. The sentence above is the whole of this and had been left as one line, which -is why it kept being read as a leftover rather than as the design.* - -**Every node holds one session of its own, permanently.** It listens on its own queue, anything in -the mesh may prompt it, and it remembers — what it was asked ten minutes ago and what it was asked -last week, across every caller, the way any conversation is remembered by both sides. Its system -prompt is the node's **engram**: the personality that makes one node's answers recognisably its -own. - -Nothing about it is request-response. A caller asks, the node answers, the exchange stays. - -**It is the same mechanism as a hired agent, and deliberately not the same lifecycle.** That -distinction is the answer to a question asked repeatedly and worth settling here: - -| the same | different | -|---|---| -| a persistent session, accumulating memory, a system prompt, a scoped tool list, addressable by message | how it comes into existence, and whether it can stop | - -**One implementation, two ways of existing: hired, or inherent to a node.** Building the mechanism -twice is real duplication and the concern was right; collapsing the lifecycles is the other mistake -and it is worse. - -**It is provisioned the ordinary way and made immutable — not held outside the system.** The -sentence above says *exempt from the hiring lifecycle*, and the precision matters: it is exempt -from **hiring**, not from having a lifecycle. Its lifecycle is the **node's** — provisioned when -the node enrols, retired when the node is retired. Same states, a different thing driving them. - -That distinction is what keeps it inside the model. A thing genuinely held outside would have to be -special-cased by everything that lists agents; a thing provisioned normally and constrained is one -row like any other, and the constraints are **checkable** rather than remembered: - -| | | -|---|---| -| **cannot be retired, reassigned, or deleted while its node exists** | it *is* that machine's voice — retiring it leaves a node nothing can talk to, moving it puts one machine's mind on another | -| **exactly one per node** | with two, nothing decides which replies when the node is addressed; with none, the node is mute | -| **may be disabled and re-enabled** | ordinary, and see below | -| **its engram may be changed** | its existence is immutable, its personality is not — that is how a node is configured | - -[ADR 0001](0001-mesh-brokers-nodes-host-agents-think.md)'s *the two agent rows per node merge* is -the same fact from the other side: **one per node** — not zero, and not two. - -**Disabled is a state that answers.** A node prompted while its agent is disabled replies saying -so, immediately, without a model being invoked. It does not time out and it is not silence — the -queue is still consumed, and the answer is the state. - -That is the whole reason disabling is better than not provisioning. A node with no agent is a -silence somebody has to diagnose; a node whose agent is disabled tells you what is wrong in the -reply. It is the same rule the host follows about a service that does not exist, applied here: -**absence must never be indistinguishable from a failure to answer.** - -### What is scoped, and what is not - -**Its tool list is its own and narrower than a session a person drives.** The same scoping any -agent has; a different list. - -**There is no authorisation between nodes.** Every node is the operator's own, and a prompt from -one is a prompt from the operator. Asking a node something is asking a colleague, and colleagues do -not present credentials. - -Stated once so it is not discovered later: **the mesh boundary is therefore the security -boundary.** Anything inside can reach whatever any node can reach, which is what makes the token -and the overlay the entire perimeter ([ADR 0004](0004-a-node-and-how-it-joins.md), -[ADR 0007](0007-connectivity.md)). - -**How a node passes a question on is the node's own choice, not a field in a message.** Asked -something it must ask a third node about, a node may say who is asking or may simply ask — the way -a person relaying a question decides how to phrase it. That follows from the engram, not from a -protocol. What it costs is a machine-readable chain of who ultimately asked; what each node was -asked, and by whom, remains in that node's own record. - -**A node thinks about one thing at a time**, being one session. Callers queue, and a long answer -delays the others. - ## Consequences - Memory, workspace and reputation have a subject to belong to. Policy becomes possible: an diff --git a/02-DECISIONS/0004-a-node-and-how-it-joins.md b/02-DECISIONS/0004-a-node-and-how-it-joins.md index 1725bbc..c8731e5 100644 --- a/02-DECISIONS/0004-a-node-and-how-it-joins.md +++ b/02-DECISIONS/0004-a-node-and-how-it-joins.md @@ -28,6 +28,52 @@ asked to do — and that belongs in the host's profile rather than in the defini 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](0002-nodes-communicate-over-a-broker.md)). +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](0007-connectivity.md)). + +**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](0003-agents-are-persistent-employees.md)). 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