ADR 0272: say how the socket keeps ADR 0004, answer the operator and agent accounts only, and keep the bus request out of the SDK (ADR 0039)
mesh/merge-gate pass: the change touches no module of the mesh's graph
mesh/repo-check pass: its merge-check.sh passed
mesh/delivery superseded: a newer head of the same pull request

This commit is contained in:
jochen
2026-10-09 12:01:45 +02:00
parent 95d78f7011
commit 1ad9959b16
2 changed files with 44 additions and 20 deletions
@@ -105,7 +105,7 @@ only: a script, `sudo`, a cron line and any document meant to work everywhere sa
`mesh-cli <command line>` takes the controller's own command line, in the words the controller's commands and
their refusals already use: `mesh-cli settings set zsh '{"execute":"withhold"}' --node <node>` is
`settings set zsh … --node <node>` asked of the controller. It is run as the operator's own account, without
`sudo`: root is not the operator's account, and is answered as any other account (§4).
`sudo`: root is not the operator's account, and is refused (§4).
`mesh-cli` holds no credential and reads no file of the mesh. It does one thing: it asks the node-engine on its own
machine over a local socket, and prints what comes back. A process that carries `MESH_VERB` (a verb's own process)
@@ -129,6 +129,13 @@ The node-engine serves a socket every local account may connect to. For each con
The node-engine is trusted for its own node. Root on a node could claim any account there; root on a node that is
the terminal is already the operator's, and §4 makes no other node the terminal.
**This is no listening control surface** in [ADR 0004](0004-a-node-and-how-it-joins.md)'s sense, and that record's
rule stands. The socket is a file under the node-engine's runtime directory with no network address, so nothing
dials it from another machine. Nothing sent to it acts on the node: the node-engine runs nothing it receives and
changes nothing; it adds what the kernel says and sends the request out over its own link, to a controller that
judges it like any other caller. Only the node's operator account and its agent account are answered, and both
already reach the mesh's verbs through the mesh MCP server (§4).
### 4. The controller judges, and runs the line
A line from node N, vouched as account A, **runs as the controller's terminal** when A is N's operator account
@@ -141,11 +148,16 @@ A line from node N, vouched as account A, **runs as the controller's terminal**
The controller runs it as it runs a verb's line, in a fresh process of its own binary with its own environment, but
without `MESH_VERB`, and records the caller as *A through mesh-cli on N*.
**Every other line is an ordinary call.** It goes through exactly what the `command` verb does with a line: its
refusals today, and its list of reads once ADR 0266 §7 builds one. It runs with `MESH_VERB=mesh-cli`, so every
terminal-only change is refused with the controller's own reason. The answer adds one sentence saying why this
account on this node is not the terminal: an agent account, root, an account that is not the operator's, or a node
whose agents may run as its operator.
**A line from the node's operator account or its agent account that is not the terminal is an ordinary
call.** It goes through exactly what the `command` verb does with a line: its refusals today, and its list of
reads once ADR 0266 §7 builds one. It runs with `MESH_VERB=mesh-cli`, so every terminal-only change is refused
with the controller's own reason. The answer adds one sentence saying why this account on this node is not the
terminal: it is the agent account, or the node's agents may run as its operator. These two accounts already
reach the mesh's verbs through the mesh MCP server, so this widens nothing.
**A line from any other account is refused**, root and every service account included, and the answer says
which account asked and that `mesh-cli` answers the node's operator and agent accounts only. Run as yourself,
not under `sudo`.
**The control-node rule is no wider than today.** On the control-node the operator's account holds `sudo`, and
until ADR 0266 is switched on so do the agents running as it: either could run the controller's binary as root
@@ -159,18 +171,25 @@ and why or why not. `mesh-cli` prints the two streams and exits with the status.
message is cut there and the cut is said; it is never silently short. Standard input is not carried: a command
that reads it gets nothing and fails saying so. Streaming the output and carrying the input are later steps.
### 6. What is shared lives in the SDK
### 6. What is shared, and where it lives
The socket's path, the program's request and answer, and the request on the bus with its subject are one package
of the SDK (`mesh-sdk`), imported by `mesh-cli`, the node-engine and the controller. None of them keeps its own
copy. The list of what is terminal-only is not shared: it stays in the controller, its one judge, and `mesh-cli`
shows the controller's words.
- **The local protocol is the SDK's.** The socket's path and the program's request and answer are one package of
the Go SDK (`mesh-sdk`), imported by `mesh-cli` and by the node-engine. It is a local protocol a module's
program speaks to its node's runtime, which is what the SDK holds
([ADR 0039](0039-what-the-sdk-holds-and-refuses.md), as [ADR 0188](0188-a-modules-own-code-is-bundles-in-any-language-and-a-tools-bundle-speaks-mcp-to-the-runtime.md)
reads it).
- **The bus request is the node-engine's and the controller's**, in their own link code, with a test on each side
holding the field names, as for the engine's health statement. A transport lives in no SDK (ADR 0188's note on
ADR 0039).
- **The list of what is terminal-only is not shared.** It stays in the controller, its one judge, and `mesh-cli`
shows the controller's words.
### 7. In what order it is built
1. **Phase 1.** The SDK package; the node-engine's socket and its request; the controller's answer, with the
control-node as the terminal for its operator account; the `mesh-cli` module on every node. From then on the
operator types `nox …` on the control-node, and gets the ordinary calls on every other node.
operator types `nox …` on the control-node, and gets the ordinary calls on every other node. An agent account
is answered as soon as a node names one (ADR 0266 §1), whichever phase is live.
2. **Phase 2.** The agent-account route of §4 on a node other than the control-node, once ADR 0266 runs there
(on the operator's own machines after the follow-up decision ADR 0266 names).
3. **Later.** Streamed output and standard input; a second factor for a node whose agents must share the
@@ -190,21 +209,24 @@ shows the controller's words.
operator, the operator's account is not the terminal, so this reaches nothing terminal-only there.
- The alias hides any other `nox` in interactive zsh (Arch's `python-nox` installs `/usr/bin/nox`);
`command nox` still reaches it.
- The node-engine gains a listener every local account may reach. It accepts one line per connection, bounded in
size and in time, and runs nothing itself.
- The node-engine gains a local socket every account on the machine may reach. It accepts one line per
connection, bounded in size and in time, runs nothing itself, and is never reachable from another machine
(ADR 0004 stands, §3).
- The controller's own binary is still never on `PATH`. A record that says to type
`mesh-controller <command>` at the terminal means `mesh-cli <command>` on the control-node from this record on.
## How it is checked
- **The SDK:** the request and the answer survive a round trip, and the subject names the node.
- **The SDK:** the request and the answer survive a round trip, and a request over the bound is refused.
- **The bus request:** a test in the node-engine and one in the controller hold the same field names.
- **The node-engine:** a test connects to the socket as the test's own process and the request carries that
process's user id and account; a connection whose credentials cannot be read is refused, never sent as
anyone; a line over the bound is refused.
- **The controller:** tests hold that a line from the control-node's operator account runs without `MESH_VERB`;
that a line from any other account, or from another node without a judged agent account, runs with
`MESH_VERB=mesh-cli` and a terminal-only change is refused with the reason; that a judgement older than
fifteen minutes is not one; and that an ordinary line meets every refusal of the `command` verb.
that a line from the agent account, or from another node's operator account without a judged agent account,
runs with `MESH_VERB=mesh-cli` and a terminal-only change is refused with the reason; that a line from any
other account, root included, is refused and runs nothing; that a judgement older than fifteen minutes is not
one; and that an ordinary line meets every refusal of the `command` verb.
- **The catalogue:** the module's check passes, its archive places one file, and its shell contribution is the
alias.
- **Live, at acceptance (the operator's view):** on the control-node, in the operator's own shell,
@@ -218,7 +240,9 @@ shows the controller's words.
- [Issue 339](../04-ISSUES/339-a-verb-can-place-a-directory-at-the-machines-own/00-report.md),
[issue 340](../04-ISSUES/340-an-agent-can-plant-a-hook-in-every-agent-session-on-the-mesh/00-report.md): what is
terminal-only, and how a verb is told from the terminal.
- [ADR 0004](0004-a-node-and-how-it-joins.md): a node has no listening control surface.
- [ADR 0181](0181-the-operator-account-is-a-node-fact-and-a-home-is-a-placement-root.md): the operator account.
- [ADR 0039](0039-what-the-sdk-holds-and-refuses.md), [ADR 0188](0188-a-modules-own-code-is-bundles-in-any-language-and-a-tools-bundle-speaks-mcp-to-the-runtime.md): what the SDK holds.
- [ADR 0204](0204-a-module-contributes-shell-code-to-the-login-shell-in-named-slots.md): shell contributions.
- [ADR 0267](0267-an-artifact-is-rebuilt-only-when-its-build-source-changes-and-a-module-moves-only-along-build-dependencies-on-artifacts.md):
a module builds from its own source.
@@ -51,9 +51,9 @@ is reached.
Four repositories, in the order they merge:
1. **mesh-sdk:** the socket's path, the program's request and answer, the bus request and its subject.
1. **mesh-sdk:** the socket's path and the program's request and answer, the local protocol (ADR 0039).
2. **`mesh-host`:** the node-engine serves the socket, reads `SO_PEERCRED`, names the account, and asks the
controller on `mesh.control.<node>.cli`.
controller on `mesh.control.<node>.cli`; the bus request is its own link code.
3. **mesh-controller:** the serving controller answers `mesh.control.*.cli`, judges the terminal (ADR 0272 §4),
and runs the line through `runVerb`'s path, without `MESH_VERB` for the terminal and with
`MESH_VERB=mesh-cli` otherwise, after the `command` verb's refusals.