The mesh models machines but not the people on them — a node record holds no username, and no module places anything under a home. So who you are on each node (jochens/ace/jochen) is unknown to the mesh, and nothing owns ~/.ssh, dotfiles or ~/.config. HAL knew it; the nox mesh dropped it. Proposes the account as a node fact and a home-scoped resource class (the ~/ mirror of ADR 0112's /var/lib placement), with the login key staying the operator's (ADR 0051). Not urgent — HAL's generators still run — load-bearing at node-by-node retirement. Found generating ~/.ssh/config from HAL's registry, which nox has no equivalent for.
4.8 KiB
layer, status, code, updated, decisions
| layer | status | code | updated | decisions | ||
|---|---|---|---|---|---|---|
| to-be | proposed | 2026-09-27 |
|
29 — A node has operator accounts, and the mesh owns what lives under a home
The mesh models machines but not the people on them. A node record holds its name, its
address, its mode — and nothing about who a person is on it: jochens on novox, ace on ace,
jochen on shanks and g14. That username is not incidental. It decides who a file under ~ is
owned by, who a user service runs as, and — the case that surfaced this — which account ssh <node> logs in as. The predecessor knew it (its per-node user:, and the modules that wrote a
person's ~/.ssh/config, ~/.zshrc, ~/.config); the mesh, taking those over, kept the machine
facts and dropped the human one.
Two things are missing, and they are one idea:
1. The account is a node fact
A node has one or more operator accounts: the human logins on it. At minimum a name; the
mesh already knows the node and its address, so <account>@<node> is then a complete answer to
"who am I, where." It is the mesh's to hold because everything below is derived from it, and
because it is exactly the fact that was silently lost — ssh ace failed to ace because nothing
in the mesh said ace's account is ace.
It is not a credential. The account names a login; the key that authorises it is the operator's, placed as a secret or an operator-owned file, never minted by the mesh (ADR 0051).
2. A resource may live under a home, owned by its account
ADR 0112 placed a
module's system data — <root>/<module>, owned by the module. It has no analog for the other
half of the filesystem: the things that belong under a person's home and are owned by that
person. ~/.ssh/config, ~/.ssh/config.d/mesh, ~/.zshrc, ~/.config/hal — every one of these
is a resource the mesh should be able to place and own, resolved against the account's home
rather than a system root, and chowned to the account rather than to root or a module uid.
This is the same move as ${dir:…}, one level over: a resource says home: <account> (or names
an account requirement), and the mesh resolves the home directory and the owning uid on the node
that account lives on. A module that writes operator config — the eventual replacements for
hal/terminal, hal/claude-code, hal/secrets — declares its files this way and names no
/home/... path, exactly as a system module now names no /var/lib path.
Why now, and why not yet
Why it matters: when HAL retires, the generators that keep ~/.ssh/config, shell config and
the operator's ~/.config/hal current retire with it. Without this, adding a node stops adding
its ssh alias, and a fresh machine has no operator dotfiles at all — the mesh would run every
service and leave the human unable to work on the box. The account is also load-bearing for
correctness already: ssh <node> (issue 122's cousin), user-scoped systemd units, and any file a
person rather than a daemon must own.
Why not build it reflexively: it is a real addition to the node model and the resource model, and it must be gotten right, not smuggled in beside a firewall fix. Open questions to settle first:
- One account or several per node? A workstation has one human; a shared box might have more. The model should allow more than one without forcing the common case to name it.
- Where the login key lives. An operator-owned file (ADR 0051) or an accepted secret — never minted. The account fact and the key that authorises it are separate, and only the first is the mesh's to generate.
- The boundary with
sshd. Thesshdmodule (server side) already exists. This is the client and identity side: the account a node offers, and the home-scoped files an operator needs. They meet at the account but are not the same module. - Multi-operator. Today there is one human. The model should not assume it, but the first cut may serve one and leave the shape open.
Not urgent, not blocking. ssh and dotfiles work today because HAL's generators still run as the substrate. This becomes load-bearing in the node-by-node retirement phase, not before — which is the right time to build it, once the account model is decided here.