Every configurable thing on a node is a module, the home included, and a module is whatever it declares (0173, extending 0040). A node varies a module only through a setting rendered into the file or a kept region, never an edit (0174, extending 0011; issue 168 first). One tool runtime per node serves every module's tools on the host side, never in a container; the console is its serving mode, renamed node-tools (0175, extending 0150; 0047/0150/0152 carry dated notes). The login shell is a node seat held by one shell module with `execute` as its contract (0176). A unit may be user-scoped and the service manager is a node seat held by systemd (0177). To-be 37 is handed off in-progress to mesh-host, mesh-controller, mesh-tools and mesh-catalog, with the build in order: the account on every node, the runtime, zsh, systemd, then the graphical stack. To-be 29 keeps ~/.ssh and points at 37; 33 §6 and 34 are amended; the glossary gains node tools, bundle, kept region, installed/holding, and retires flavor.
4.8 KiB
topic, status, date, deciders, reconstructed, extends
| topic | status | date | deciders | reconstructed | extends |
|---|---|---|---|---|---|
| what runs on it | accepted | 2026-10-02 | jochen | false | 02-DECISIONS/0121-a-system-seat-is-named-for-its-scope-and-modules-define-their-own.md |
177. A unit may be user-scoped, and the service manager is a node seat whose holder answers for the units
Context
The host's service shape puts a system unit into a state. It has no user scope.
To-be 29 states the gap: a
workstation's per-user daemons have no form the mesh can send. Four of the predecessor's
environment modules ship user units — the desktop's reload watcher and bar watchdog, the audio
module's masks, the power module's memory guard, the thermal daemon's profile switcher — and the
predecessor needed a hook to enable them because shipping a unit file does not run it; one unit
was deployed for months and ran on one machine only.
ADR 0040 says the host hardcodes no supervisor, and a swappable
machine mechanism is a module implementing a capability — which is what the nftables module is for
the packet filter (ADR 0170). The service manager is
reported today as a capability, service-manager, and held by nobody. The operator's proposal: a
systemd module that holds the seat and serves the tools about units, system and user.
Considered Options
- Keep user units as a module concern — each module runs
systemctl --userin a hook. Rejected: that is the hook that silently never ran, and an action over the link is refused. - The service-manager module applies units on behalf of others, as a provision. Rejected by the operator: provisioning is for resources a provider creates for a consumer; a unit is declared state the host applies, as every resource is.
- The host's
serviceshape gains a user scope; a systemd module holds the service-manager seat and serves the verbs about units. Chosen.
Decision
1. The service shape gains scope: system (the default) or user. A user-scoped unit
is applied as the operator account through the account's own service manager: enabled, started,
stopped, reloaded on its triggers, exactly as a system unit is, and refused on a node with no
account, naming the fact. The host applies it; no module does.
2. node-service-manager is a seat of the mesh's own, node-scoped, seeded by the controller
under this record, as ADR 0121 requires of a node-* name. The systemd module claims it and is
assigned to every machine whose profile reports service-manager.
3. The seat's verbs answer for every unit on the machine, each taking an optional scope:
units, status, start, stop, restart, enable, disable, journal. The host applies what
is declared; the holder answers questions and operator acts about it, and says, for a mesh-held
unit, that the host will restore what its declaration says.
Consequences
- The host's vocabulary grows by one field on one shape, asserted by its count test (to-be 05); an older host refuses a declaration carrying it, so the host rolls before the first module that uses it.
- The predecessor's four user-unit modules become declarable without a hook.
- The seat's holder is the first system seat held by a module that runs nothing of its own: its verbs are served by the node tools runtime (ADR 0175).
- What got harder:
journalandstatuson a user unit need the account's manager reachable from the runtime's process, which runs as the node's account; the holder's tool escalates or switches user as it needs, which is ADR 0175 §4 applied.
How it is checked
| Rule | Checked by |
|---|---|
A service with scope: user is enabled and started under the account, and refused with no account |
the host's tests with a fake service manager |
| The seat declares its verbs; a claim serving fewer is refused by name | the catalogue's seat tests |
| The verbs act on a named unit in the named scope and name the unit's holder when the mesh declares it | the module's tests over a fake runner |
| Live | the desktop's reload watcher declared scope: user on a workstation; node-service-manager.status@<node> reports it active |