Files
hq/02-DECISIONS/0181-the-operator-account-is-a-node-fact-and-a-home-is-a-placement-root.md
T
jochen 7b1dabbce0 The operator's agent and its licence manager are modules: ADR 0181–0183, to-be 36 and 39
The predecessor's agent module was retired and its six files stayed on both workstations telling
every session to use tools that no longer exist. This is its successor's design, revised during
review on the operator's directions: the host is module-agnostic, the controller has no part, and a
real licence manager hands out the correct licence in every situation.

- ADR 0181 (reconstructed): the operator account is a node fact stated by the operator; the home is
  derived unless stated; a resource may be placed under it owned by the account; a node with no
  account refuses one. What the controller shipped on 2026-09-27 without a record.
- ADR 0182: inside a home the module owns the directory and the files it places, writes into the
  tool's own files for its few keys, never declares a credential's content, and holds everything
  else as found; a predecessor's leftovers are the operator's to remove once.
- ADR 0183: claude-licence-manager holds the mesh seat anthropic-licence-manager and owns the
  Anthropic licences, grants (encrypted with a key the vault made for it), bindings per touchpoint,
  usage and audit; one rotation source under a lease; a token travels module to module sealed to
  each node's module key on request/reply, never as an event; the agent module alone writes what
  the agent reads; the host delivers package and state and knows nothing else. A bounded exception
  to ADR 0113; dated mechanism notes on ADR 0050 and 0113.
- To-be 36 (claude-code): the mesh's part of the agent's configuration lives in the agent's
  machine-wide managed directory, owned whole by the module and written by its code; nothing under
  the home but the credentials file of a subscription licence; the API-key licence through the
  key-helper; the console as a node-scoped provision (to-be 34 amended); MCP servers as settings
  with an mcp_configure tool; one agent directory per machine shared by every session.
- To-be 39 (claude-licence-manager): store, the two licence kinds, keeping a grant alive, the
  hand-over, who gets which licence with the predecessor's fallbacks, adoption with the identity
  guard, the seat's verbs.

Numbers taken across main and every open branch at the time of the merge; to-be 14, 29 and 34
carry dated notes; the glossary gains "operator account".
2026-10-02 17:22:12 +02:00

7.7 KiB

topic, status, date, deciders, reconstructed, extends
topic status date deciders reconstructed extends
what runs on it accepted 2026-09-27 jochen true 02-DECISIONS/0112-a-module-definition-names-no-node-mesh-or-path.md

181. The operator account is a node fact, and a home is a placement root

Reconstructed. The controller shipped this on 2026-09-27 and to-be 29 recorded it as built without a decision behind it. This record states what was decided, from the code and the design, and adds the two rules the code left implicit — what an empty account means for a module, and that the account is stated rather than discovered. Written 2026-10-02.

Context

ADR 0112 took every host path out of a module definition and gave a module's system data a place: a directory the mesh resolves under the node's root, owned by the module. It said nothing about the other half of a filesystem — the files that belong under a person's home and are owned by that person. The predecessor wrote several of those: the ssh client configuration, the shell's configuration, an agent's instruction files. It knew whose home it was writing into because each of its node records carried a login name. The mesh took the machine facts over and dropped the human one.

The loss was found the ordinary way: ssh <node> logged into the home-server under the workstation's own login name, because nothing in the mesh said the home-server's account was a different one (to-be 29, issue 172).

What the controller does since 2026-09-27: a node record carries an operator account and, optionally, its home; the account and its home are machine facts a definition may name in a resource's path, owner and content; a roster file may say it lives under the home, and is then rendered per node, placed under that node's account's home, owned by the account, and left out on a node with no account. On 2026-10-02 all four nodes of the live mesh carry an empty account: the fact exists and nobody has stated it, so no home-scoped resource can land anywhere yet.

Considered Options

  1. The definition names the login. owner: <name> in the module. Rejected: it is the installation written into a definition, which ADR 0112 forbids and ADR 0155 checks for, and it is wrong on the first machine whose login differs — which is exactly the machine that surfaced this.
  2. The host discovers the account. The first non-system user, or whoever ran the enrolment. Rejected: a guess. A shared machine has several people on it, a server may have none, and a host deciding whose files these are is a decision the mesh then cannot see, state or correct.
  3. The account is a fact the operator states on the node record, and the home is derived from it unless stated. Chosen.

Decision

A node has an operator account: the login name of the person who works on it. It is stated by the operator on the node record, the way a node's address or mode is held there, and it is empty for a machine nobody logs into. Empty is a real state, not a missing value. The mesh holds the fact because everything below derives from it, and because it is precisely the fact that was lost when the predecessor's records were not carried over.

The account's home is derived unless stated. The superuser's home for the superuser, the distribution's conventional per-user home otherwise; a node whose account lives elsewhere states its home. One place computes the default, so a fact and the record cannot disagree about it.

A resource may be placed under the home, owned by the account. This is ADR 0112's move one level over: as a module's system directory is resolved under the node's root, a file under a person's home is resolved against the account's home, and owned by the account rather than by root or a module's own account. A definition names the account and its home as machine facts, never as a path; a roster fact may say it is a home file and is then placed and owned the same way. The controller resolves both at composition, and the host chowns what it creates.

A node with no account cannot carry a home-scoped resource, and says so. A roster fact that lives under the home is left out of that node's declaration rather than written to nowhere. A resource naming the account fact on such a node is refused at composition, naming the fact the machine does not have. A module that writes a person's files is thereby unassignable to a machine with no person on it, which is the right refusal.

One account per node is what this record decides. Several people on one machine is left open, with the constraint that allowing it must not force the common case — one workstation, one person — to name anything.

Consequences

  • The operator states the account before any home-scoped module lands. Today none is stated, so the first assignment of such a module begins with four node records.
  • The roster carries each node's account, so a composed ssh configuration logs in as the right person on every machine — the gap that surfaced this, closed by the same fact.
  • A family of modules becomes writable: everything the predecessor placed under a home — ssh client, shell, the agent's instruction files — is now a module naming a fact rather than a path (to-be 29 §2).
  • What got harder: a definition cannot say "my user's home" without the mesh knowing who the user is, so a module of this family is refused on a freshly enrolled machine until a person is named on it. That is a prompt, not an obstacle.
  • Not decided here: several accounts per node; a service unit running as the account rather than as root or a module; a one-off step run as the account. Each is a record of its own.

How it is checked

Rule Checked by
A resource's path and owner resolve the account and its home controller tests on machine-fact resolution: a file naming the account facts lands under the account's home, owned by the account
The home is derived unless stated a controller test: the superuser's home for the superuser, the conventional home otherwise, the stated home when one is stored
A home roster fact is left out on a node with no account a controller test on roster composition: the file is absent from that node's declaration and present on a node with an account
A resource naming the account on a node with no account is refused by name a controller test on machine-fact resolution: the refusal names account and lists the facts the machine does have
No definition names a home path ADR 0112's catalogue test on host paths, which a /home or /root literal fails

References

  • to-be 29 — the design this record gives a foundation to, and its "what has shipped" section
  • ADR 0112 — the system-path placement this mirrors; ADR 0155 — why a login name may not be in a definition
  • ADR 0120 — the roster fact a home file may be
  • ADR 0182 — what the mesh may and may not do inside the home this record lets it reach
  • mesh-controller internal/inventory/nodes.go (the account and its home on the node record), internal/catalogue/machine_into_files.go and roster.go (resolution and the home fact)