ADR 0272 (proposed) and issue 343: the controller's terminal has no command
The records send the operator to "the controller's terminal", and on the control-node `mesh-controller` is not a command: the controller is a mesh process with its own account and environment, and nothing puts anything on PATH. The record proposes mesh-cli, a module on every node whose program asks the node-engine over a local socket; the node-engine vouches for the account from the kernel and asks the controller on its node's own subject; the controller runs the line as the terminal only for the operator's account where no agent can be that account. The glossary gains mesh-cli, nox (its zsh alias) and the controller's terminal.
This commit is contained in:
+14
-1
@@ -272,6 +272,11 @@ and the operator act. **Recorded by** the controller's `identity` and `licences`
|
||||
`release`, an identifier to rename.
|
||||
- **proof** — what an authorising answer carries: a verified sender, a one-time code, a security key's
|
||||
touch (ADR 0234). How much proof a kind of ask needs is its **assurance level**.
|
||||
- **controller's terminal** — a command line the controller runs as typed by its operator, not asked through a
|
||||
verb, so a change that is the terminal's alone is taken (issue 339, issue 340). In the controller's code it is a
|
||||
line run without `MESH_VERB`. The operator reaches it with `mesh-cli` from their own account on a node where no
|
||||
agent can run as that account: the control-node, and a node whose agents run under an account of their own
|
||||
([ADR 0272](../02-DECISIONS/0272-the-operator-reaches-the-controller-with-mesh-cli-on-every-node-and-a-node-is-the-terminal-only-where-no-agent-runs-as-its-operator.md)).
|
||||
|
||||
## Change and delivery — a commit on its way to the nodes
|
||||
|
||||
@@ -437,7 +442,7 @@ it should not. **Recorded by** the controller. **Upstream of** Provisioning and
|
||||
trust. **Recorded by** the router and the controller (authorising asks).
|
||||
**Downstream of** Health and repair, Change and delivery, and Identity and access. An authorising
|
||||
answer acts in whichever domain asked, through that domain's own verb; the conversation owns the
|
||||
asking, never the act. **Decided by** ADR 0152, 0175, 0234.
|
||||
asking, never the act. **Decided by** ADR 0152, 0175, 0234, 0272.
|
||||
**Uses:** operator, person, proof (Identity and access), release (Change and delivery).
|
||||
|
||||
- **mesh MCP server** — the endpoint on a node's loopback through which every agent and person on that
|
||||
@@ -446,6 +451,14 @@ asking, never the act. **Decided by** ADR 0152, 0175, 0234.
|
||||
not a module of its own. "Console" suggested a terminal or a shell, and the module `mesh-console` it
|
||||
once named no longer exists; "the tool bridge" and "the brain" named the predecessor's program.
|
||||
*Not:* ~~console~~ (hq), ~~mesh-console~~, ~~tool bridge~~
|
||||
- **mesh-cli** — the module on every node that places the operator's command, and the command itself:
|
||||
`/usr/local/bin/mesh-cli <command line>` asks the controller to run one of its command lines. It asks the
|
||||
node-engine on its own machine, which says to the controller which account is asking; the controller runs the
|
||||
line as the **controller's terminal** or as an ordinary call
|
||||
([ADR 0272](../02-DECISIONS/0272-the-operator-reaches-the-controller-with-mesh-cli-on-every-node-and-a-node-is-the-terminal-only-where-no-agent-runs-as-its-operator.md)).
|
||||
- **nox** — `mesh-cli`'s alias, in interactive zsh only. A script, `sudo` and a document meant to work everywhere
|
||||
say `mesh-cli`. The operator also calls the mesh itself *nox mesh*; on this page and in the records *nox* is the
|
||||
alias alone.
|
||||
- **channel / intake** — the two kinded benches the mesh talks to its operator through: `channel`
|
||||
sends, `intake` turns what arrives into one envelope. A holder of either declares **capabilities** from
|
||||
the fixed vocabulary `channel-capabilities/1`. Not *notifier* (that is the desktop's node seat, one
|
||||
|
||||
+226
@@ -0,0 +1,226 @@
|
||||
---
|
||||
topic: the tiers
|
||||
status: proposed
|
||||
date: 2026-10-09
|
||||
deciders: jochen
|
||||
reconstructed: false
|
||||
extends: 02-DECISIONS/0181-the-operator-account-is-a-node-fact-and-a-home-is-a-placement-root.md
|
||||
---
|
||||
|
||||
# 272. The operator reaches the controller with `mesh-cli` on every node, and a node is the controller's terminal only where no agent runs as its operator
|
||||
|
||||
## Context
|
||||
|
||||
Some changes to the mesh are made **at the controller's terminal** only:
|
||||
|
||||
- the places and accesses a module's settings name, and the keys a provider's trust or a trusted file reads
|
||||
([issue 339](../04-ISSUES/339-a-verb-can-place-a-directory-at-the-machines-own/00-report.md));
|
||||
- the agent module's managed settings, tool servers and shared text
|
||||
([issue 340](../04-ISSUES/340-an-agent-can-plant-a-hook-in-every-agent-session-on-the-mesh/00-report.md));
|
||||
- a node's agent account (ADR 0266, hq pull request 225, not yet merged), typed as
|
||||
`mesh-controller node agent-account <node> <account>`.
|
||||
|
||||
In the controller's code "the terminal" is a negative: a command line that did not come through a verb. The
|
||||
serving controller names the verb in the environment of every command it runs for one (`MESH_VERB`, issue 327),
|
||||
and a terminal-only change is refused when that variable is set. Nothing says who the terminal is, and nothing
|
||||
lets the operator reach it.
|
||||
|
||||
On 2026-10-09 the operator typed `mesh-controller …` on the control-node and the shell answered
|
||||
`zsh: command not found: mesh-controller`
|
||||
([issue 343](../04-ISSUES/343-the-controllers-terminal-has-no-command/00-report.md)). The controller runs as a
|
||||
mesh process: the node-engine unpacks its bundle under the mesh's own directory, and writes a unit that runs it as
|
||||
the `mesh-controller` account with an environment composed from the controller's module (its stores' credential
|
||||
files under a directory only that account may enter, the stores' and the bus's ports). Nothing puts a command on
|
||||
any `PATH`, and running the binary by hand would mean rebuilding that environment under `sudo`.
|
||||
|
||||
The operator's directions of 2026-10-09 shape what follows: no wrapper script and no link (the mesh creates no
|
||||
symbolic links); the operator's command is a real program, its own module, on every node; it reaches the
|
||||
controller over the mesh, not by running the controller's binary; and the person is proven by the account the
|
||||
command runs from, vouched for by the operating system, never by a credential file a copy of which is as good as
|
||||
the original.
|
||||
|
||||
## Considered Options
|
||||
|
||||
### How the operator reaches the controller
|
||||
|
||||
1. **A link to the controller's binary on `PATH`.** Refused by the hard rule, and not enough: the binary needs the
|
||||
unit's account and environment.
|
||||
2. **A wrapper the controller's module places on the control-node**, running the controller's binary as its
|
||||
account with the unit's environment through `sudo`. Rejected. It is a second copy of the unit's environment to
|
||||
keep in step (or a new process field for the node-engine to render), it reaches the controller from the
|
||||
control-node only, and its proof is `sudo`, which every agent on the control-node holds until ADR 0266 is
|
||||
switched on.
|
||||
3. **A program on every node that asks the controller over the mesh.** Chosen. The controller already runs every
|
||||
command line a verb asks for in a fresh process of its own binary, with its own environment (`runVerb`); one
|
||||
more way of asking needs no copy of that environment anywhere.
|
||||
|
||||
### Where the program comes from
|
||||
|
||||
1. **A second artifact of the controller's module.** Rejected: that module is assigned to the control-node only,
|
||||
so its files reach no other node.
|
||||
2. **A module of its own, assigned to every node.** Chosen. It builds from its own directory, so a change to it
|
||||
rebuilds it alone and a change to the controller does not rebuild it
|
||||
([ADR 0267](0267-an-artifact-is-rebuilt-only-when-its-build-source-changes-and-a-module-moves-only-along-build-dependencies-on-artifacts.md)).
|
||||
|
||||
### How the person is proven
|
||||
|
||||
1. **A credential file in the operator's home.** Rejected. Any agent running as the operator reads it, and a copy
|
||||
works anywhere.
|
||||
2. **`sudo`.** Rejected as the proof. It asks the account's password, or nothing where the rule says so, and
|
||||
agents on the control-node hold the same `sudo` today.
|
||||
3. **The account the program runs from, read by the node-engine from the kernel.** Chosen. The program connects to
|
||||
a local socket the node-engine serves; the kernel tells the node-engine the connecting process's user id
|
||||
(peer credentials). Nothing is presented, so nothing can be copied. The node-engine is on every node and runs
|
||||
as root, so it is the one part of the mesh that can vouch for a local account.
|
||||
4. **A second factor**: a one-time code or an approval on a verified channel
|
||||
([ADR 0234](0234-the-mesh-holds-a-conversation-with-its-operator.md), ADR 0259). Not now. It is the route for
|
||||
a node whose agents must share the operator's account, and it waits for the approval flow (research 039).
|
||||
|
||||
### Which account on which node is the terminal
|
||||
|
||||
1. **The operator's account on any node.** Rejected. On every node but the control-node, and on the control-node
|
||||
until ADR 0266 is switched on, agents run as that account. An agent would be the terminal.
|
||||
2. **The operator's account on the control-node only.** Safe, and too narrow for later.
|
||||
3. **The operator's account on a node where agents cannot be that account**: the control-node, and any node that
|
||||
names an agent account of its own judged unable to become root without a person (ADR 0266 §1, §3, §4).
|
||||
Chosen.
|
||||
|
||||
## Decision
|
||||
|
||||
### 1. `mesh-cli` is a module and the command it places
|
||||
|
||||
**`mesh-cli` is a module of the catalogue, assigned to every node.** It builds one Go bundle from its own
|
||||
directory, and an `archive` resource unpacks it into `/usr/local/bin`, so the program is
|
||||
`/usr/local/bin/mesh-cli` on every node. It is the bundle's own file: no link, no second copy. The node-engine
|
||||
moves it in beside what is there, refuses to write over a file it did not place, and takes out only what it
|
||||
placed when the module goes.
|
||||
|
||||
**`nox` is its alias**, `alias nox=mesh-cli`, contributed by the module to zsh's `normal` slot
|
||||
([ADR 0204](0204-a-module-contributes-shell-code-to-the-login-shell-in-named-slots.md)). `/usr/local/bin` is
|
||||
already on every account's `PATH`, so the module contributes no environment. The alias exists in interactive zsh
|
||||
only: a script, `sudo`, a cron line and any document meant to work everywhere say `mesh-cli`.
|
||||
|
||||
### 2. What the operator types
|
||||
|
||||
`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).
|
||||
|
||||
`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)
|
||||
is refused at once, and told why: a verb is never a person.
|
||||
|
||||
### 3. The node-engine vouches for the account
|
||||
|
||||
The node-engine serves a socket every local account may connect to. For each connection it:
|
||||
|
||||
1. reads the connecting process's user id from the kernel (`SO_PEERCRED`), and names the account from the
|
||||
machine's user database;
|
||||
2. sends the line, the account and the user id to the controller on `mesh.control.<node>.cli`, as a request on
|
||||
core NATS. Only that node's engine may publish under `mesh.control.<node>.`: its bus account is granted that
|
||||
prefix and nothing of any other node's, so **the node is a fact the bus server enforces and the account is a
|
||||
fact the kernel gives**. The CONTROL stream names its own subjects, so the request is never persisted;
|
||||
3. says with it whether the node's declaration names an agent account, and the engine's latest judgement of it
|
||||
(ADR 0266 §3);
|
||||
4. answers the program with what the controller answered, or says that the controller did not answer within its
|
||||
call bound.
|
||||
|
||||
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.
|
||||
|
||||
### 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
|
||||
([ADR 0181](0181-the-operator-account-is-a-node-fact-and-a-home-is-a-placement-root.md)) and either:
|
||||
|
||||
- N is the control-node; or
|
||||
- N names an agent account of its own (ADR 0266 §1), and the controller's own record of the engine's judgement,
|
||||
heard within ADR 0266 §4's fifteen minutes, says it cannot become root without a person.
|
||||
|
||||
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.
|
||||
|
||||
**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
|
||||
with its environment. `mesh-cli` gives that account the same reach and no more. Once agents there run as `agent`,
|
||||
`agent` is never the terminal.
|
||||
|
||||
### 5. What comes back
|
||||
|
||||
The answer is the command's standard output, its standard error, its exit status, whether it ran as the terminal,
|
||||
and why or why not. `mesh-cli` prints the two streams and exits with the status. An answer larger than one bus
|
||||
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
|
||||
|
||||
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.
|
||||
|
||||
### 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.
|
||||
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
|
||||
operator's account.
|
||||
|
||||
## Consequences
|
||||
|
||||
- The operator has one command on every node, built, checked and moved like every other module, and the records'
|
||||
"at the controller's terminal" names something that exists: `mesh-cli` (or `nox`) on the control-node.
|
||||
- A terminal-only change typed on any other node is refused there with the reason, instead of being impossible to
|
||||
type at all.
|
||||
- No agent on the control-node gains anything it did not have; once ADR 0266 is switched on there, agents lose the
|
||||
terminal entirely.
|
||||
- **Same-account limits stay ADR 0266's boundary.** While an agent runs as the operator, it can do what the
|
||||
operator's account can: put a `mesh-cli` of its own earlier on `PATH` (the zsh module puts the account's
|
||||
`~/.local/bin` first), or redefine the alias outside the mesh's block. On a node where agents run as the
|
||||
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 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 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.
|
||||
- **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,
|
||||
`nox settings show zsh --node <node>` answers as the terminal, and a terminal-only `nox settings set …` is taken.
|
||||
On another node, the same `settings set` is refused and says why. From `agent`, once that account exists, it is
|
||||
refused too.
|
||||
|
||||
## References
|
||||
|
||||
- [Issue 343](../04-ISSUES/343-the-controllers-terminal-has-no-command/00-report.md): the gap.
|
||||
- [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 0181](0181-the-operator-account-is-a-node-fact-and-a-home-is-a-placement-root.md): the operator account.
|
||||
- [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.
|
||||
- [ADR 0234](0234-the-mesh-holds-a-conversation-with-its-operator.md): proof and assurance.
|
||||
- ADR 0266 (hq pull request 225) and ADR 0259 (hq pull request 211): not yet merged, so named without links.
|
||||
@@ -0,0 +1,62 @@
|
||||
---
|
||||
status: located
|
||||
opened: 2026-10-09
|
||||
located-in: [mesh-catalog (a new module, mesh-cli), mesh-host (a local socket the node-engine serves), mesh-controller (the answer on the bus), mesh-sdk (the shared request)]
|
||||
fixed-by:
|
||||
amended-design:
|
||||
---
|
||||
|
||||
# 343. The controller's terminal has no command
|
||||
|
||||
## Symptom
|
||||
|
||||
On 2026-10-09 the operator, on the control-node in their own shell, typed a `mesh-controller` command line to make
|
||||
a change the records say is made at the controller's terminal. The shell answered:
|
||||
|
||||
zsh: command not found: mesh-controller
|
||||
|
||||
The same day, read through the mesh's tools: the controller runs on the control-node as the unit
|
||||
`mesh-controller.service`, which the mesh declared and wrote (the control-node's `node-service-manager.status`: active, running,
|
||||
`FragmentPath` `/etc/systemd/system/mesh-controller.service`, `mesh_declared` true).
|
||||
|
||||
## Why it is an issue
|
||||
|
||||
**The records name a command that does not exist.** Issue 339, issue 340, ADR 0266 (hq pull request 225, not yet
|
||||
merged) and the agent module's README say that certain changes are made "at the controller's terminal" alone, and
|
||||
some give the line to type, such as `mesh-controller settings set claude-code '<json>'` and
|
||||
`mesh-controller node agent-account <node> <account>`. None of them says how the operator reaches that terminal, and
|
||||
nothing in the mesh provides it:
|
||||
|
||||
- The controller is a mesh process. The node-engine unpacks its bundle under the mesh's own directory and writes a
|
||||
unit that runs it as the `mesh-controller` account, with an environment composed from the controller's module:
|
||||
the files holding its stores' credentials, under a directory only that account may enter, and the ports of the
|
||||
store and the bus as the mesh resolved them. No module puts a command on any `PATH`.
|
||||
- Run by hand, the binary needs that account and that environment, rebuilt by hand under `sudo`. That is a
|
||||
work-around, and the operator rejects it.
|
||||
- In the controller's code the terminal is only a negative: a command line that did not come through a verb (no
|
||||
`MESH_VERB`). Nothing says who the terminal is.
|
||||
|
||||
**Impact on the operator.** Every terminal-only change waits: the agent module's managed settings, tool servers and
|
||||
shared text (issue 340's steps), the places and accesses of issue 339, and a node's agent account (ADR 0266). The
|
||||
refusals the controller gives through a verb send the operator to a terminal they cannot open.
|
||||
|
||||
## Acceptance test (the operator's view)
|
||||
|
||||
On the control-node, in my own shell and without `sudo`, I type `nox settings set zsh '{"execute":"withhold"}'
|
||||
--node <node>` (or any other command line) and it runs against the live controller as the terminal. On any other
|
||||
node the same terminal-only line is refused and says why. An agent session cannot use it to get round a
|
||||
terminal-only refusal: as `agent` on the control-node it is refused, and on a node where agents run as the operator
|
||||
that account is not the terminal.
|
||||
|
||||
## The fix
|
||||
|
||||
[ADR 0272](../../02-DECISIONS/0272-the-operator-reaches-the-controller-with-mesh-cli-on-every-node-and-a-node-is-the-terminal-only-where-no-agent-runs-as-its-operator.md)
|
||||
(proposed): a module `mesh-cli` on every node places `/usr/local/bin/mesh-cli`, with the alias `nox` in
|
||||
interactive zsh. It asks the node-engine over a local socket; the node-engine reads the account from the kernel and
|
||||
asks the controller on its own node's subject; the controller runs the line as the terminal for the control-node's
|
||||
operator account, and as an ordinary call for every other account and node. The diagnosis says what was read and
|
||||
what each repository does.
|
||||
|
||||
## How it will be checked
|
||||
|
||||
The checks ADR 0272 lists, and the acceptance test above, run live on the control-node and on one other node.
|
||||
@@ -0,0 +1,75 @@
|
||||
# 343 — Diagnosis
|
||||
|
||||
## 2026-10-09: what was read
|
||||
|
||||
The record was searched first: `records_search` for "command not found mesh-controller" found nothing, and for
|
||||
"controller's terminal" found issue 340 and research 039, which use the words and say nothing of how the terminal
|
||||
is reached.
|
||||
|
||||
### The controller
|
||||
|
||||
- Its module declares one process, run as the `mesh-controller` account, `./mesh-controller serve`, with an
|
||||
environment of credential files under its own directory (mode 0700, owned by that account) and the ports of the
|
||||
store and the bus as `${seat:…}` references the controller resolves at composition.
|
||||
- `throughAVerb` (`cmd/mesh-controller/modules.go`) is the whole of the terminal: a command line runs as the
|
||||
terminal when `MESH_VERB` is not in its environment. `runVerb` (`cmd/mesh-controller/seatverbs.go`) sets it for
|
||||
every line a verb runs, the named verbs and the generic `command` alike, and runs the line in a fresh process of
|
||||
the controller's own binary with the serving process's environment.
|
||||
- The generic `command` verb runs any command line today, except `settings set` and `settings clear` and a repair
|
||||
without `--why`. ADR 0266 §7 makes it a list of reads; that is not built.
|
||||
|
||||
### The node-engine
|
||||
|
||||
- It writes a process's unit under `/etc/systemd/system`, and unpacks its bundle into
|
||||
`/var/lib/mesh/daemons/<name>`. A witnessed process's running build is moved aside when the next is placed, so
|
||||
the path holds the build the unit runs, not always the build that is running (issue 289).
|
||||
- It runs as root, and holds one bus account per node, granted to publish under `mesh.control.<node>.` and
|
||||
nothing of another node's. It knows nothing of the node's operator account; the controller does (the node
|
||||
record's `account`).
|
||||
- An `archive` resource unpacks a bundle into a directory, moves its files in one by one where the directory was
|
||||
not made by the mesh, refuses to write over a file it did not place, and on removal takes out only what it
|
||||
placed. The node-engine's own module places its versions this way.
|
||||
- No part of the mesh serves a local socket that reads a peer's credentials.
|
||||
|
||||
### The bus
|
||||
|
||||
- The controller subscribes `mesh.control.>` and may answer a request. The CONTROL stream names its subjects
|
||||
(`mesh.control.*.report`, `mesh.control.enrol`), so a request on another subject under the prefix is not
|
||||
persisted.
|
||||
|
||||
## Ruled out
|
||||
|
||||
- **A link to the binary on `PATH`.** The mesh creates no symbolic links, and the binary needs the unit's account
|
||||
and environment.
|
||||
- **A wrapper the controller's module places.** Designed first, on 2026-10-09: a file under `/usr/local/bin`
|
||||
that runs the binary through `sudo` with the unit's environment, or a new process field from which the
|
||||
node-engine writes one. Rejected by the operator: it is a work-around, it is a second copy of the unit's
|
||||
environment, it reaches the control-node only, and its proof is `sudo`, which agents on the control-node hold.
|
||||
- **The program as a second artifact of the controller's module.** That module is on the control-node only.
|
||||
|
||||
## Located
|
||||
|
||||
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.
|
||||
2. **`mesh-host`:** the node-engine serves the socket, reads `SO_PEERCRED`, names the account, and asks the
|
||||
controller on `mesh.control.<node>.cli`.
|
||||
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.
|
||||
4. **mesh-catalog:** the module `mesh-cli` (its program, its archive into `/usr/local/bin`, its zsh alias `nox`),
|
||||
assigned to every node; and the agent module's README, whose `mesh-controller settings set …` becomes
|
||||
`mesh-cli settings set …`.
|
||||
|
||||
Each code change is a branch and a pull request, merged by the operator after ADR 0272 is accepted. The records
|
||||
that tell the operator to type `mesh-controller <command>` at the terminal mean `mesh-cli <command>` on the
|
||||
control-node once phase 1 is live; ADR 0266's `mesh-controller node agent-account` line is changed on its own
|
||||
branch, which is not yet merged.
|
||||
|
||||
## Later
|
||||
|
||||
- Phase 2 of ADR 0272: a node other than the control-node becomes the terminal for its operator account once its
|
||||
agents run under an account of their own (ADR 0266), judged.
|
||||
- A node whose agents must share the operator's account (the operator's own machines) needs proof that it is the
|
||||
operator: a second factor, or an approval on a verified channel (ADR 0234, ADR 0259, research 039). Not built
|
||||
here.
|
||||
Reference in New Issue
Block a user