Research 018: the operator's machine as modules #291
@@ -0,0 +1,80 @@
|
|||||||
|
---
|
||||||
|
status: active
|
||||||
|
initiated: 2026-10-02
|
||||||
|
touches:
|
||||||
|
- 02-DECISIONS/0040-what-a-module-is.md
|
||||||
|
- 02-DECISIONS/0011-managed-files-are-generated-never-edited.md
|
||||||
|
- 02-DECISIONS/0132-a-seat-carries-the-tools-its-holder-must-serve.md
|
||||||
|
- 02-DECISIONS/0150-a-modules-own-code-runs-as-supervised-processes-under-one-account.md
|
||||||
|
- 02-DECISIONS/0152-the-operators-surface-is-a-module-the-console.md
|
||||||
|
- 02-DECISIONS/0161-what-deserves-a-seat.md
|
||||||
|
- 03-DESIGN/01-to-be/05-the-node-host.md
|
||||||
|
- 03-DESIGN/01-to-be/29-a-node-has-operator-accounts.md
|
||||||
|
- 03-DESIGN/01-to-be/33-the-tools-the-mesh-answers.md
|
||||||
|
- 03-DESIGN/01-to-be/34-the-console.md
|
||||||
|
- 03-DESIGN/00-as-is/10-module-catalogue.md
|
||||||
|
- 04-ISSUES/160-a-machine-says-little-about-itself-and-only-when-asked/00-report.md
|
||||||
|
- 04-ISSUES/168-a-setting-reaches-every-file-and-contribution/00-report.md
|
||||||
|
became: []
|
||||||
|
---
|
||||||
|
|
||||||
|
# 018 — The operator's machine as modules
|
||||||
|
|
||||||
|
**What.** The mesh owns the whole machine, not only the services on it. Everything a person
|
||||||
|
configures on a node — the login manager, the display server, the window manager, the shell, the
|
||||||
|
terminal, the launcher, the notifier, the audio setup, the boot images, the downloads folder, the
|
||||||
|
agent at the terminal — is a module: a package, the files it owns under `/etc` and under the
|
||||||
|
operator's home, the seat it holds, the tools it serves. One default configuration per module,
|
||||||
|
varied per node only through settings rendered into the file or a kept operator region, never
|
||||||
|
through an edit. The servers take the universal modules (shell, prompt, git, the agent); the
|
||||||
|
workstations take those and the graphical stack, which a capability the machine reports gates.
|
||||||
|
This effort writes that behaviour down, measures what the predecessor's desktop modules actually
|
||||||
|
contain, and settles what the mesh must gain before the first of them can be written.
|
||||||
|
|
||||||
|
**Why.** The predecessor is retired on every node. What it still owned on the two workstations —
|
||||||
|
about thirty modules' worth of dotfiles, user units and `/etc` files — is now owned by nothing:
|
||||||
|
no generator regenerates them, and a fix to one of them is a hand edit that nothing records. The
|
||||||
|
migration scoped these modules out as *the workstation's own environment*, and
|
||||||
|
[to-be 29](../../03-DESIGN/01-to-be/29-a-node-has-operator-accounts.md) names them as the last
|
||||||
|
thing the predecessor was keeping alive. To-be 29 covers one directory, `~/.ssh`, and draws a
|
||||||
|
boundary inside it. The operator wants no boundary: the machine is the mesh's, as far as it makes
|
||||||
|
sense to configure it. That is a wider scope than any design states, and it reaches three records
|
||||||
|
that were written for services: what a module is, where a module's tools run, and what a managed
|
||||||
|
file may be.
|
||||||
|
|
||||||
|
**What it touches.** The module definition ([ADR 0040](../../02-DECISIONS/0040-what-a-module-is.md)),
|
||||||
|
seats and their contracts ([ADR 0132](../../02-DECISIONS/0132-a-seat-carries-the-tools-its-holder-must-serve.md)),
|
||||||
|
where a module's tools run ([ADR 0150](../../02-DECISIONS/0150-a-modules-own-code-runs-as-supervised-processes-under-one-account.md),
|
||||||
|
[ADR 0152](../../02-DECISIONS/0152-the-operators-surface-is-a-module-the-console.md),
|
||||||
|
[to-be 33](../../03-DESIGN/01-to-be/33-the-tools-the-mesh-answers.md) §6), the host's vocabulary
|
||||||
|
([to-be 05](../../03-DESIGN/01-to-be/05-the-node-host.md)), managed files and settings
|
||||||
|
([ADR 0011](../../02-DECISIONS/0011-managed-files-are-generated-never-edited.md),
|
||||||
|
[issue 168](../../04-ISSUES/168-a-setting-reaches-every-file-and-contribution/00-report.md)),
|
||||||
|
and the catalogue's shape ([as-is 10](../../03-DESIGN/00-as-is/10-module-catalogue.md)).
|
||||||
|
|
||||||
|
**Documents.**
|
||||||
|
|
||||||
|
- [01 — The intended behaviour](01-the-intended-behaviour.md): the operator's wish, written as
|
||||||
|
how the mesh behaves, in the mesh's own words.
|
||||||
|
- [02 — What exists, and what is missing](02-what-exists-and-what-is-missing.md): the
|
||||||
|
predecessor's desktop modules measured; which records already say what is wanted; the gaps.
|
||||||
|
- [03 — One tool executor per node](03-one-tool-executor-per-node.md): where a module's tools
|
||||||
|
run. The direction the operator set, the evidence for it, and what it supersedes.
|
||||||
|
- [04 — The seats of the environment](04-the-seats-of-the-environment.md): the roles a machine
|
||||||
|
has once, their candidate contracts, and what gates each.
|
||||||
|
|
||||||
|
**What this must settle before it graduates.**
|
||||||
|
|
||||||
|
1. A module is one *managed thing*, software or not, and every module may serve tools — or ADR
|
||||||
|
0040 already says this and only its examples are narrow.
|
||||||
|
2. One tool executor per node, host-side, module-agnostic; which records it supersedes and
|
||||||
|
in what form the console continues.
|
||||||
|
3. Per-node variation is a setting rendered into the file or a kept region, never an edit —
|
||||||
|
ADR 0011 stands — and issue 168 is fixed before any environment module carries a setting.
|
||||||
|
4. User-scoped units on the host's `service` shape, and a service-manager seat whose holder
|
||||||
|
serves the tools about them.
|
||||||
|
5. The operator account stated on every node; today no node record carries one.
|
||||||
|
6. The seats of the environment and their verbs, one record per seat, slowly, because a
|
||||||
|
seat's tools bind every future holder.
|
||||||
|
7. Where the environment modules live: this catalogue, or one of their own as the media chain
|
||||||
|
has; and whether a third-party organisation's tooling belongs in a public catalogue at all.
|
||||||
@@ -0,0 +1,99 @@
|
|||||||
|
# 01 — The intended behaviour
|
||||||
|
|
||||||
|
*Written 2026-10-02 from the operator's words, in the mesh's words. What is wanted, before what
|
||||||
|
exists. Where a sentence restates a record, the record is named; where it goes further, that is
|
||||||
|
said.*
|
||||||
|
|
||||||
|
## The machine is the mesh's
|
||||||
|
|
||||||
|
**Everything configurable on a node is declared by a module.** Not only the services the mesh
|
||||||
|
runs: the login manager, the display server, the window manager, the bar, the launcher, the
|
||||||
|
notifier, the compositor, the lock screen, the terminal emulator, the clipboard, the shell and its
|
||||||
|
prompt, the editor, the audio setup, the boot images, the package manager's configuration, the
|
||||||
|
agent a person runs at a terminal, and the folders a person works in — a downloads folder that is
|
||||||
|
tidied, backed up, distributed to other nodes and asked questions of. System folders and the
|
||||||
|
operator's home alike. The operator is the only person on every node, so the mesh manages the
|
||||||
|
person's machine, not a machine with a person on it.
|
||||||
|
|
||||||
|
This is [ADR 0040](../../02-DECISIONS/0040-what-a-module-is.md)'s definition applied without
|
||||||
|
the service bias its examples carry. A module is one managed thing, named once, described
|
||||||
|
completely by its manifest. It may have a package, files, a container, a unit, a binary, a seat it
|
||||||
|
holds, and tools it serves — any one of these, or all, or two. There is **no kind of module**: zsh
|
||||||
|
has a package, files, a seat claim and the tools that claim obliges it to serve; downloads has a
|
||||||
|
folder, a process and tools; nftables has a package, files, a service, a seat and tools. The
|
||||||
|
difference is what each declares, not what each is.
|
||||||
|
|
||||||
|
**The home has no boundary.** [To-be 29](../../03-DESIGN/01-to-be/29-a-node-has-operator-accounts.md)
|
||||||
|
owns one directory under the home and draws a line inside it between the mesh's and the person's.
|
||||||
|
Here the line is drawn only by what the modules declare: every file some module places is the
|
||||||
|
mesh's; what no module declares is found and left alone, exactly as the adoption rules already
|
||||||
|
say for a machine. The reach is bounded by sense, not by a rule — the mesh configures what can
|
||||||
|
be configured, and a person's documents, projects and history are data under
|
||||||
|
[ADR 0051](../../02-DECISIONS/0051-shared-data-is-the-operators.md), not configuration.
|
||||||
|
|
||||||
|
**A module names no node and no path.** The operator account is a node fact and the home is
|
||||||
|
derived from it ([to-be 29](../../03-DESIGN/01-to-be/29-a-node-has-operator-accounts.md) §1–2,
|
||||||
|
shipped in the controller; its record is proposed in an open change). A module places a file
|
||||||
|
*under the home, owned by the account*, and the same manifest lands on a server and a laptop.
|
||||||
|
|
||||||
|
## One default, varied by settings, never by edits
|
||||||
|
|
||||||
|
**One module, one default configuration.** The window manager module ships the configuration
|
||||||
|
that is right for every node. There are no flavors: the predecessor's one desktop module carried
|
||||||
|
four, one per class of machine, and what differed between them is what settings are for.
|
||||||
|
|
||||||
|
**A node varies a module in exactly two ways.** A **setting**, declared by the module with its
|
||||||
|
type, meaning and default (proposed alongside the container-runtime records), set for the mesh
|
||||||
|
or for one node, and rendered into the file at composition — the value is in the file, not in an
|
||||||
|
environment variable the file reads. Or a **kept region**: a block in a file the mesh writes
|
||||||
|
*into*, where the operator's own lines survive every push
|
||||||
|
([ADR 0102](../../02-DECISIONS/0102-the-mesh-writes-into-a-shared-file-never-over-it.md)). An
|
||||||
|
edit to a managed file outside such a region is not a third way; it is overwritten, as
|
||||||
|
[ADR 0011](../../02-DECISIONS/0011-managed-files-are-generated-never-edited.md) says, and the
|
||||||
|
predecessor's habit of adopting disk drift back into its database is not carried over.
|
||||||
|
|
||||||
|
The predecessor's theming — some ninety environment variables substituted into templates at sync
|
||||||
|
time, with tools to list and set them — is the same idea with the wrong rendering. The knobs
|
||||||
|
become declared settings; the file carries the value.
|
||||||
|
|
||||||
|
## Roles a machine has once are seats, and seats carry tools
|
||||||
|
|
||||||
|
**A role a machine fills at most once is a node-scoped seat**, declared by a module
|
||||||
|
([ADR 0121](../../02-DECISIONS/0121-a-system-seat-is-named-for-its-scope-and-modules-define-their-own.md),
|
||||||
|
[ADR 0126](../../02-DECISIONS/0126-a-module-declares-its-own-seats.md)): the login shell, the
|
||||||
|
display session, the display server, the terminal emulator, the launcher, the notifier, the
|
||||||
|
compositor, the lock screen, the service manager, the boot loader. Several modules may be able to
|
||||||
|
hold one — zsh, fish and bash can all hold the login shell — and the assignment on each node says
|
||||||
|
which does. Installing a shell is installing software; holding the seat is being *the* shell.
|
||||||
|
|
||||||
|
**A seat's contract is its tools** ([ADR 0132](../../02-DECISIONS/0132-a-seat-carries-the-tools-its-holder-must-serve.md)).
|
||||||
|
Every holder of the login-shell seat serves `execute`, which takes one string, the command, and
|
||||||
|
runs it on the node the seat is scoped to. Every holder of the boot seat serves "rebuild the boot
|
||||||
|
images", so *"rebuild your boot images"* is a verb addressed to a machine, not a one-off step in
|
||||||
|
a hook. Every holder of the service-manager seat answers for the units on the machine, system and
|
||||||
|
user scope. A module may serve its own tools beside the seat's
|
||||||
|
([ADR 0170](../../02-DECISIONS/0170-the-firewall-seat-serves-its-verbs.md) §2): show the rendered
|
||||||
|
configuration, set a theme value, report status.
|
||||||
|
|
||||||
|
**Any tool may be called from any node.** The operator's statement, and the grant model it
|
||||||
|
implies: the executor on each node may call everything, as the console already may. A verb that
|
||||||
|
needs root on the machine is the module's concern — the tool escalates, the executor and the
|
||||||
|
caller do not know.
|
||||||
|
|
||||||
|
## Servers and workstations differ by capability, not by catalogue
|
||||||
|
|
||||||
|
The same catalogue serves every node. A module declares what it needs — a graphical session, a
|
||||||
|
display server, a container runtime — and the machine reports what it has, as the profile already
|
||||||
|
reports eight capabilities today ([issue 160](../../04-ISSUES/160-a-machine-says-little-about-itself-and-only-when-asked/00-report.md)).
|
||||||
|
Assignment refuses the wrong placement by name
|
||||||
|
([ADR 0161](../../02-DECISIONS/0161-what-deserves-a-seat.md) §3). So every node takes the shell,
|
||||||
|
the prompt, git and the agent; only a node with a graphical session can take the display server,
|
||||||
|
and only a node holding the display server can take a window manager. Nothing in a module says
|
||||||
|
"workstation".
|
||||||
|
|
||||||
|
## What the operator would say to the mesh
|
||||||
|
|
||||||
|
*Set the login shell on the build node to fish. Rebuild the laptop's boot images. Show me the
|
||||||
|
window manager's effective configuration on the desktop and where each value comes from. Give
|
||||||
|
the downloads folder on the laptop to the home server. Run `uptime` on every node.* Each of these
|
||||||
|
is a seat verb or a module tool, addressed to a node, answered by whatever holds the role there.
|
||||||
+91
@@ -0,0 +1,91 @@
|
|||||||
|
# 02 — What exists, and what is missing
|
||||||
|
|
||||||
|
*Measured 2026-10-02 on one installation: two workstations, two servers, all four converged to
|
||||||
|
the mesh; the predecessor retired on the last workstation the day before. Numbers are from the
|
||||||
|
machines and the repositories, not from memory.*
|
||||||
|
|
||||||
|
## 1. What the predecessor's desktop looks like
|
||||||
|
|
||||||
|
The predecessor's catalogue on the laptop held **34 modules**, of which **28** are the operator's
|
||||||
|
environment rather than services. By what they declare:
|
||||||
|
|
||||||
|
| shape | count | examples |
|
||||||
|
|---|---|---|
|
||||||
|
| package only | 9 | browser, mail client, process monitor, media player, file manager, chat |
|
||||||
|
| package + `/etc` files + system service | 5 | login manager, display server, power and thermal daemons, package manager configuration |
|
||||||
|
| package + files under the home | 6 | shell and prompt, the agent at the terminal, scripts, the sync client, a music player |
|
||||||
|
| files under the home + user units + hooks | 2 | the desktop environment, audio |
|
||||||
|
| third-party organisation tooling | 6 | out of scope here |
|
||||||
|
|
||||||
|
**The desktop module alone** declares **88 files**, **4 flavors** (the window-manager stack, and
|
||||||
|
one per class of machine), **2 user units** with a hook to enable them, 8 files under `/etc`, a
|
||||||
|
wallpaper shipped as an asset, and reads **about 90 environment variables** as theme knobs,
|
||||||
|
substituted into its templates at sync time and set through a theming tool. Its hook exists
|
||||||
|
because *shipping a unit file does not run it*: one unit had been deployed for months and ran on
|
||||||
|
one machine only, because somebody had enabled it there by hand.
|
||||||
|
|
||||||
|
**The shell module** ships `~/.zshrc`, the prompt configuration, an `~/.ssh/config` that the
|
||||||
|
predecessor generated from its registry, and a `LOGIN_SHELL` variable applied with `chsh` by a
|
||||||
|
hook. Two flavors: the prompt theme, and autocompletion.
|
||||||
|
|
||||||
|
**Other modules write into the desktop module's files.** The chat client places i3 and notifier
|
||||||
|
snippets into `config.d` directories the desktop module owns, and its launch flags, window
|
||||||
|
placement and notification colours are each a variable with a default.
|
||||||
|
|
||||||
|
**One-off steps live in hooks** across the set: enable user units, `chsh`, create a swap file,
|
||||||
|
`mkinitcpio`, enable a vendor VPN service the package ships disabled. Every one is state the
|
||||||
|
host could declare or a verb a seat could serve; none is today.
|
||||||
|
|
||||||
|
## 2. What the migration did with them
|
||||||
|
|
||||||
|
The migration's module to-do scoped the whole set out as *desktop / workstation ricing — the
|
||||||
|
workstation's own environment* and *node/OS tooling — managed on the node, never catalogue*. The
|
||||||
|
last workstation's runbook then split the same set three ways: **A**, system scope, which the
|
||||||
|
host's vocabulary can express today (the login manager, the display server, the power daemons,
|
||||||
|
the package manager, the container runtime); **B**, under a home or a user unit, waiting on
|
||||||
|
to-be 29; **C**, package only, the operator's call. The migration log closes the workstation with
|
||||||
|
*the operator's desktop awaiting its design*.
|
||||||
|
|
||||||
|
Two things followed from scoping them out. Nothing regenerates those files now, so a fix is a hand
|
||||||
|
edit — the login manager's session script was fixed this way on the day of writing, and recorded
|
||||||
|
in a repository nothing deploys from. And the one piece of this family written as a mesh module,
|
||||||
|
the ssh client, was closed on hold in the catalogue until the controller carried the account fact.
|
||||||
|
|
||||||
|
## 3. What the records already give
|
||||||
|
|
||||||
|
| wanted | record | state |
|
||||||
|
|---|---|---|
|
||||||
|
| one module per managed thing; every module may have tools | [ADR 0040](../../02-DECISIONS/0040-what-a-module-is.md) | accepted; examples are services, and the shell is named as a *shared* seat |
|
||||||
|
| a module declares its own node-scoped seat | [ADR 0121](../../02-DECISIONS/0121-a-system-seat-is-named-for-its-scope-and-modules-define-their-own.md), [ADR 0126](../../02-DECISIONS/0126-a-module-declares-its-own-seats.md) | accepted |
|
||||||
|
| a seat's contract is its tools; a holder may add its own | [ADR 0132](../../02-DECISIONS/0132-a-seat-carries-the-tools-its-holder-must-serve.md), [ADR 0170](../../02-DECISIONS/0170-the-firewall-seat-serves-its-verbs.md) | accepted; one node seat serves verbs live |
|
||||||
|
| a capability the machine reports gates a holder | [ADR 0161](../../02-DECISIONS/0161-what-deserves-a-seat.md) §3 | accepted; the profile already reports `graphical-session` |
|
||||||
|
| the account as a node fact; a file under the home owned by it | [to-be 29](../../03-DESIGN/01-to-be/29-a-node-has-operator-accounts.md) §1–2 | built in the controller; its record proposed in an open change |
|
||||||
|
| inside a home: owned, written into, written by the module, found | proposed in the same change | proposed |
|
||||||
|
| a setting declared with type, meaning, default and cost | proposed with the container-runtime records | proposed |
|
||||||
|
| a managed file is derived; an edit is overwritten | [ADR 0011](../../02-DECISIONS/0011-managed-files-are-generated-never-edited.md) | accepted |
|
||||||
|
| the mesh writes into a shared file, never over it | [ADR 0102](../../02-DECISIONS/0102-the-mesh-writes-into-a-shared-file-never-over-it.md) | accepted |
|
||||||
|
| a module names no path; the host resolves the home | [ADR 0112](../../02-DECISIONS/0112-a-module-definition-names-no-node-mesh-or-path.md) | accepted |
|
||||||
|
| the `user` shape: a login shell is declared state | [to-be 05](../../03-DESIGN/01-to-be/05-the-node-host.md) | designed; used by no module |
|
||||||
|
|
||||||
|
## 4. What is missing
|
||||||
|
|
||||||
|
1. **The account is recorded nowhere.** The node record has the column; on all four nodes it
|
||||||
|
is empty. Every home-scoped module is unassignable until the operator states it.
|
||||||
|
2. **User-scoped units.** The host's `service` shape has no user scope. To-be 29 says it
|
||||||
|
plainly: *a workstation's per-user daemons have no form the mesh can send.* The desktop
|
||||||
|
module's two units, the audio masks, the power module's memory guard and the thermal
|
||||||
|
daemon's profile switcher all need it.
|
||||||
|
3. **One-off steps.** `mkinitcpio`, `chsh`, creating a swap file. Each is either declared
|
||||||
|
state the host lacks a shape for, or a verb a seat should serve. An action in a declaration
|
||||||
|
is refused over the link, and rightly.
|
||||||
|
4. **Settings leak** ([issue 168](../../04-ISSUES/168-a-setting-reaches-every-file-and-contribution/00-report.md)):
|
||||||
|
a setting reaches every mergeable file and every contribution of its module. Ninety theme
|
||||||
|
knobs on that mechanism would reach ninety files. The proposed settings record says a setting
|
||||||
|
names the file it lands in; that has to ship first.
|
||||||
|
5. **Where tools run.** Every module that serves a tool today does so from its own container
|
||||||
|
per node. See [03](03-one-tool-executor-per-node.md).
|
||||||
|
6. **A seat's verbs are undecided for every seat but three.** To-be 33 leaves which verbs each
|
||||||
|
seat serves as *a decision per seat, slowly*. The environment adds a dozen seats.
|
||||||
|
7. **Catalogue placement.** The media chain left this catalogue for its own; whether the
|
||||||
|
environment does the same, and whether a third-party organisation's tooling belongs in a
|
||||||
|
public catalogue, are unasked.
|
||||||
@@ -0,0 +1,88 @@
|
|||||||
|
# 03 — One tool executor per node
|
||||||
|
|
||||||
|
*The direction the operator set on 2026-10-02, the evidence it rests on, and what it supersedes.
|
||||||
|
A direction, not yet a decision: the record is written when this effort graduates.*
|
||||||
|
|
||||||
|
## Where tools are served today
|
||||||
|
|
||||||
|
[To-be 33](../../03-DESIGN/01-to-be/33-the-tools-the-mesh-answers.md) names three families — a
|
||||||
|
role's tools on the seat, a module's own tools on the module, the mesh's own verbs on the
|
||||||
|
controller seat — and [ADR 0160](../../02-DECISIONS/0160-the-mesh-issues-an-assignments-subjects-and-a-runtime-serves-what-it-is-issued.md)
|
||||||
|
says a runtime serves the subjects its membership issues. What *runs* that runtime is
|
||||||
|
[ADR 0150](../../02-DECISIONS/0150-a-modules-own-code-runs-as-supervised-processes-under-one-account.md):
|
||||||
|
one supervised process per module, under the module's own account, carrying that module's
|
||||||
|
compiled tools. Measured on the live mesh:
|
||||||
|
|
||||||
|
| who answers | how it runs | count |
|
||||||
|
|---|---|---|
|
||||||
|
| the mesh's own verbs | the controller binary, on its node | 17 verbs |
|
||||||
|
| the store seat | the store's own runtime | 2 verbs |
|
||||||
|
| the packet-filter seat | **a container per node**, built on the tool-runtime base image, with the network namespace and `NET_ADMIN`, on all four nodes | 3 verbs and 1 own tool |
|
||||||
|
| every module's own tools | the module's container, one per node it runs on | 67 tools across the catalogue |
|
||||||
|
| the console | a container per node, loopback MCP, `invokes: *` | serves none, calls all |
|
||||||
|
| the host | — | serves nothing; answers no question about the machine |
|
||||||
|
|
||||||
|
**The packet-filter holder is the case to look at.** The module is a package, three files and a
|
||||||
|
system service. To serve three verbs it also declares a built image and a container on every
|
||||||
|
node whose only job is to answer them. Scaled to the environment — a shell, a prompt, a launcher,
|
||||||
|
a notifier, a compositor, a login manager, a service manager, a boot loader, a downloads folder —
|
||||||
|
that is one container per module per node for software that is itself not a container, and the
|
||||||
|
operator's judgement is that tools should not run inside a container at all.
|
||||||
|
|
||||||
|
## The direction
|
||||||
|
|
||||||
|
**One tool executor per node, on the host side.** A process the host supervises, the way the
|
||||||
|
launcher supervises the host ([ADR 0005](../../02-DECISIONS/0005-the-node-host.md)): not a
|
||||||
|
container, one bus credential for the node, module-agnostic. It loads the tool code of every
|
||||||
|
module assigned to the node and serves each module's tools and each held seat's verbs on the
|
||||||
|
subjects the membership issues — nothing changes in what [ADR 0159](../../02-DECISIONS/0159-a-tool-call-names-the-machine-and-a-holder-serves-its-seats-verbs.md)
|
||||||
|
and [ADR 0160](../../02-DECISIONS/0160-the-mesh-issues-an-assignments-subjects-and-a-runtime-serves-what-it-is-issued.md)
|
||||||
|
say about subjects, grants and memberships; what changes is that one process subscribes for the
|
||||||
|
node instead of one per module.
|
||||||
|
|
||||||
|
- **A module brings its tools as a built artifact**, a bundle the pipeline produces, never an
|
||||||
|
image. The executor knows bundles and subjects; it knows nothing of zsh or nftables.
|
||||||
|
- **A tool is code the module wrote**, one function behind an MCP verb. `execute` on the shell
|
||||||
|
seat is a function with a string argument. The executor does not declare, template or
|
||||||
|
interpret tools; it runs them.
|
||||||
|
- **Root is the module's concern.** A tool that must change the packet filter or rebuild boot
|
||||||
|
images escalates itself. The executor does not run as root for everyone, and the caller does
|
||||||
|
not know.
|
||||||
|
- **Any node may call any tool on any node.** The executor's credential may call everything,
|
||||||
|
as the console's already does; per-module grants on the calling side are not kept.
|
||||||
|
- **The mesh's own verbs stay with the controller** ([ADR 0154](../../02-DECISIONS/0154-the-meshs-own-verbs-are-the-controller-seats-tools.md)),
|
||||||
|
and a mesh-scoped seat's verbs run on the node that holds it
|
||||||
|
([ADR 0121](../../02-DECISIONS/0121-a-system-seat-is-named-for-its-scope-and-modules-define-their-own.md)).
|
||||||
|
No hub is added; the controller's node is already one.
|
||||||
|
|
||||||
|
**The console is the executor, renamed.** It already runs on every node with a credential that
|
||||||
|
may call everything, and it already serves the mesh's tools to whoever is on the machine over
|
||||||
|
MCP on loopback ([ADR 0152](../../02-DECISIONS/0152-the-operators-surface-is-a-module-the-console.md)).
|
||||||
|
It moves out of its container into the host's process tree, gains the serving half, and takes a
|
||||||
|
name that says what it is — *the node's tool runtime* or simply *node tools*; "console" names
|
||||||
|
the operator's half only.
|
||||||
|
|
||||||
|
## What it supersedes, and what it keeps
|
||||||
|
|
||||||
|
| record | effect |
|
||||||
|
|---|---|
|
||||||
|
| [ADR 0047](../../02-DECISIONS/0047-a-module-runs-its-code-as-its-own-process-with-its-own-account.md), [ADR 0150](../../02-DECISIONS/0150-a-modules-own-code-runs-as-supervised-processes-under-one-account.md) | superseded *for tools*: one process per node runs every module's tool code, under one account. A module's long-running service — a daemon, a container — is untouched; the executor runs tools, not services. The record must say why one account for every module's tools is acceptable: every tool may be called from every node anyway, and root is taken by the tool, not granted to the process |
|
||||||
|
| [ADR 0152](../../02-DECISIONS/0152-the-operators-surface-is-a-module-the-console.md) | kept in substance — a module, assigned per node, loopback MCP, the machine's login is the authority — changed in form: host-side, not a container; serves as well as calls; renamed |
|
||||||
|
| [to-be 33](../../03-DESIGN/01-to-be/33-the-tools-the-mesh-answers.md) §6, [to-be 34](../../03-DESIGN/01-to-be/34-the-console.md) | amended the same way |
|
||||||
|
| [ADR 0170](../../02-DECISIONS/0170-the-firewall-seat-serves-its-verbs.md) §3, *a container may ask for a capability* | moot for that holder: the verbs run on the host side and escalate as they need |
|
||||||
|
| the container-runtime seat, proposed in an open change: *the holder runs as a supervised process and serves the verbs locally to the host and on the bus* | consistent — a supervised process serving verbs is what the executor is; the open question is whether that holder keeps its own process or serves through the executor like everyone else |
|
||||||
|
| the tool-runtime base image | no longer the way tools reach a node; may remain the way a module's *service* is built |
|
||||||
|
|
||||||
|
## What stays open
|
||||||
|
|
||||||
|
- **The executor's language.** The host is a static Go binary and loads no plugins, so the
|
||||||
|
executor is a sibling process, and its language decides the language of every tool bundle.
|
||||||
|
One decision, taken once.
|
||||||
|
- **How a bundle reaches the node.** An artifact of the module's build, delivered as the host
|
||||||
|
delivers everything else; whether it is a file resource in the declaration or a thing the
|
||||||
|
executor fetches by digest.
|
||||||
|
- **Reload.** A push that adds or upgrades a module's bundle reaches a running executor as a
|
||||||
|
reload, not a restart, or every tool on the node blinks on every push.
|
||||||
|
- **The host's own questions.** [Issue 160](../../04-ISSUES/160-a-machine-says-little-about-itself-and-only-when-asked/00-report.md)
|
||||||
|
wants a machine to say more about itself. With an executor on every node, "what is this
|
||||||
|
machine made of" is a seat verb like any other, served there.
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
# 04 — The seats of the environment
|
||||||
|
|
||||||
|
*Candidates, not decisions. To-be 33 says which verbs a seat serves is a decision per seat,
|
||||||
|
taken slowly, because a seat's tools bind every future holder. This document lists the roles the
|
||||||
|
operator's machine has once, who could hold each, what gates it, and a first verb or two — so
|
||||||
|
each record has a starting point.*
|
||||||
|
|
||||||
|
## The rule for what is a seat here
|
||||||
|
|
||||||
|
A role the machine fills **at most once** is a node-scoped seat, declared by the module family
|
||||||
|
that fills it ([ADR 0126](../../02-DECISIONS/0126-a-module-declares-its-own-seats.md)). A thing
|
||||||
|
several of which coexist without contention — editors, browsers, media players — is not a seat;
|
||||||
|
each is a module with its own tools, and nothing is singular about it. A seat is held by one
|
||||||
|
assignment per node; other modules of the same family may be installed beside it without
|
||||||
|
holding it ([ADR 0040](../../02-DECISIONS/0040-what-a-module-is.md) §1, read with the sharper
|
||||||
|
distinction: *installed* is not *holding*).
|
||||||
|
|
||||||
|
## Candidate seats
|
||||||
|
|
||||||
|
| seat | holders | gated by | first verbs |
|
||||||
|
|---|---|---|---|
|
||||||
|
| **login shell** | zsh, fish, bash | nothing: universal | `execute(command)`; `show-config`; the holding itself sets the account's login shell through the host's `user` shape |
|
||||||
|
| **service manager** | systemd | the `service-manager` capability the profile reports | units: list, status, start, stop, restart, enable, journal; **user scope** on each |
|
||||||
|
| **boot** | grub, systemd-boot | a machine that boots itself (not a container host) | `rebuild-images`; `entries` |
|
||||||
|
| **package manager** | pacman, apt | the `package-manager` capability | search, installed, upgrade, orphans; today a capability the host uses, not a seat anyone holds |
|
||||||
|
| **display server** | xorg, wayland compositors that are their own server | the `graphical-session` capability | `displays`; `layout` |
|
||||||
|
| **display session** | i3, sway | the display server seat held on the node; i3 needs x11, sway needs wayland | `reload`; `workspaces`; `windows`; `move` |
|
||||||
|
| **terminal emulator** | xterm, alacritty, foot | display session | `open`; `font` |
|
||||||
|
| **launcher** | rofi, dmenu | display session | `show`; `theme` |
|
||||||
|
| **notifier** | dunst, mako | display session | `send`; `history`; `rule` |
|
||||||
|
| **compositor** | picom | display server (x11 only) | `restart`; `effects` |
|
||||||
|
| **lock screen** | i3lock, swaylock | display session | `lock` |
|
||||||
|
| **bar** | i3status-rust, waybar | display session | `reload`; `blocks` |
|
||||||
|
| **login manager** | lemurs, greetd | graphical session | `sessions`; `default-session` |
|
||||||
|
| **audio** | pipewire, pulseaudio | the machine reports a sound device | `sinks`, `sources`, `default`, `volume`, `mute` |
|
||||||
|
| **clipboard** | greenclip, cliphist | display session | `history`; `clear` |
|
||||||
|
|
||||||
|
Not seats, modules with their own tools: the editor, the browser, the mail client, the file
|
||||||
|
manager, the media player, the chat client, the agent at the terminal, the downloads folder, the
|
||||||
|
scripts folder, the sync client, the power and thermal daemons that are specific to one machine's
|
||||||
|
hardware.
|
||||||
|
|
||||||
|
## What the table implies
|
||||||
|
|
||||||
|
**Capabilities come first.** `graphical-session`, `service-manager` and `package-manager` are
|
||||||
|
reported today. *A display server is held* is not a capability but a seat being held, and a
|
||||||
|
module that needs it declares a dependency on the seat, not on a capability: *i3 needs the
|
||||||
|
display server seat held by xorg*. Whether a held seat can gate another's assignment is a
|
||||||
|
question for the controller's resolver, and the first environment module after the shell will
|
||||||
|
ask it.
|
||||||
|
|
||||||
|
**The service manager comes early.** Four of the predecessor's modules ship user units, and the
|
||||||
|
executor itself is a unit. User scope on the host's `service` shape is a host change whichever
|
||||||
|
module holds the seat; the seat's holder answers the questions about units, it does not apply
|
||||||
|
them — the host does, as it does for every declared resource.
|
||||||
|
|
||||||
|
**The shell comes first.** Universal, no capability, one verb that is immediately useful on
|
||||||
|
every node, and the `user` shape already makes the login shell declared state. It is the module
|
||||||
|
that proves the pattern: a package, files under the home owned by the account, a seat claim,
|
||||||
|
tools served by the executor, settings for the few things that vary per node, and a kept region
|
||||||
|
for the operator's own lines.
|
||||||
|
|
||||||
|
**The login manager is the first system-scope one**, because it needs nothing new: a package,
|
||||||
|
two files under `/etc`, a service — the same shape the ssh daemon module has today — and the
|
||||||
|
session script it owns is the file that was hand-fixed the day this effort opened.
|
||||||
Reference in New Issue
Block a user