The shell and the account's environment as modules: node-env, zsh, powerlevel10k, two plugins, and systemd finished (hq to-be 41 WP3, WP4) #255

Merged
mesh-admin merged 9 commits from feat/the-shell-and-its-environment into main 2026-10-04 08:55:11 +00:00
Contributor

hq to-be 41 WP3 and WP4. This replaces #253.

  • systemd:
    • system-scope acts go through sudo -n when not root, with refusals named by how they failed;
    • user scope sets XDG_RUNTIME_DIR and the session bus;
    • a failed call is an error, never an empty list;
    • the package resource is gone (it collided with systemd-networkd);
    • status says whether the mesh wrote the unit;
    • tests use a fake runner.
  • node-env (new): claims node-environment and writes ~/.config/mesh/environment.sh and ~/.config/environment.d/50-mesh.conf from the controller's placeholders.
  • zsh:
    • claims node-login-shell and declares no seat;
    • its environment is a contribution;
    • a .zshenv block sources the environment;
    • the .zshrc block is at the start, holding the shared defaults and the three slots;
    • execute is bounded: 20 s by default and 25 s at most, kills its process group, caps output, runs in the home, and gets no MESH_* variables;
    • the README lists the one-off migration.
  • powerlevel10k (new): upstream v1.20.0 vendored as a pinned archive (ADR 0205, 1.4 MB, licence kept), plus today's prompt configuration. Its loader goes in the normal slot.
  • zsh-autosuggestions and zsh-syntax-highlighting (new): the distribution's package each, plus one line in the normal and last slots.

Tests: systemd 15/15, zsh 16/16 (real child processes), powerlevel10k 5/5. mesh-controller module check modules/*/module.json with mesh-controller's feat/the-shell-and-its-environment passes all 73 manifests. This needs that controller first: the current controller does not know the new fields or seats.

hq to-be 41 WP3 and WP4. This replaces #253. - **systemd:** - system-scope acts go through `sudo -n` when not root, with refusals named by how they failed; - user scope sets `XDG_RUNTIME_DIR` and the session bus; - a failed call is an error, never an empty list; - the package resource is gone (it collided with systemd-networkd); - `status` says whether the mesh wrote the unit; - tests use a fake runner. - **node-env (new):** claims `node-environment` and writes `~/.config/mesh/environment.sh` and `~/.config/environment.d/50-mesh.conf` from the controller's placeholders. - **zsh:** - claims `node-login-shell` and declares no seat; - its environment is a contribution; - a `.zshenv` block sources the environment; - the `.zshrc` block is at the start, holding the shared defaults and the three slots; - `execute` is bounded: 20 s by default and 25 s at most, kills its process group, caps output, runs in the home, and gets no `MESH_*` variables; - the README lists the one-off migration. - **powerlevel10k (new):** upstream v1.20.0 vendored as a pinned archive (ADR 0205, 1.4 MB, licence kept), plus today's prompt configuration. Its loader goes in the `normal` slot. - **zsh-autosuggestions and zsh-syntax-highlighting (new):** the distribution's package each, plus one line in the `normal` and `last` slots. Tests: systemd 15/15, zsh 16/16 (real child processes), powerlevel10k 5/5. `mesh-controller module check modules/*/module.json` with mesh-controller's `feat/the-shell-and-its-environment` passes all 73 manifests. **This needs that controller first:** the current controller does not know the new fields or seats.
mesh-admin added 9 commits 2026-10-04 08:33:09 +00:00
The first module of the operator's environment (novox/hq to-be 37 §1, ADR 0173,
0176). A package, the mesh's default configuration as a block inside the
account's ~/.zshrc so the operator's own lines around it survive every push
(ADR 0174 as the host's `into: block` realises it), a `user` shape that makes
zsh the account's login shell, the `login-shell` seat declared with its one
verb, and a tools bundle: `execute` under the seat's name, `zsh_config` under
the module's. No container, no process: the tools are served by the node tools
runtime (ADR 0175), which does not exist yet — the bundle builds and the
manifest registers ahead of it. `module check` passes; the tools type-check
against the SDK.

Two things the manifest cannot yet say, left for the controller: the `user`
shape applies wherever the module is assigned, not only where it holds the
seat; and the runtime learns the account from MESH_OPERATOR_ACCOUNT, which
nothing sets yet.
The holder of the seat the controller seeds under novox/hq ADR 0177. Eight
verbs under the seat's name — units, status, start, stop, restart, enable,
disable, journal — each taking an optional scope, "system" by default or
"user" for the operator account's own manager, reached as
`systemctl --user --machine=<account>@` when the runtime is not that account.
One tool of its own, systemd_failed, for every failed unit in both scopes.
A package, a claim and a bundle; no container, no process: served by the node
tools runtime (ADR 0175) once it exists. `module check` passes against a
controller that carries the seat; the tools type-check against the SDK.
The node tools runtime runs as the operator account, not root, and gives its bundles no
session words (novox/hq ADR 0175, 0188, 0193). So, per hq to-be 41 WP4:

- system-scope start/stop/restart/enable/disable go through sudo -n when not root, as the
  packet filter and intrusion prevention do, and a refusal is named by how it failed;
- user scope is plain --user with XDG_RUNTIME_DIR and the session bus of /run/user/<uid>;
  the dead --machine branches are gone;
- a failed systemctl or journalctl is an error, and an unreachable user manager is said
  even when systemctl exits 0; systemd_failed reports it beside the other manager's answer
  instead of claiming nothing failed;
- status says whether the mesh declares the unit: its loaded unit file begins with the
  header the host writes for a module's process. Only such a unit carries the restore note;
- the package resource goes: the service manager is always present, and it collided with
  systemd-networkd's identical declaration;
- calls are bounded below the runtime's call limit, a unit name is never an option, and
  the runner is injected so the tests use a fake one.
Every module contributes variables and PATH entries as facts, and one holder of
node-environment places them (novox/hq ADR 0203, to-be 41 WP3). This is that holder: no
package, no process, no tools — the directories it owns under the home and two files the
controller fills, the POSIX file at the path the seat fixes (~/.config/mesh/environment.sh,
sourced by the login shell) and environment.d's 50-mesh.conf for the account's service
manager and graphical session.
The seat is now the mesh's node-login-shell, which a shell module claims rather than
declares (novox/hq ADR 0204), and the environment is one module's that every module
contributes to (ADR 0203). Per hq to-be 41 WP3:

- no seat declaration; the claim is node-login-shell serving execute;
- EDITOR, VISUAL, XDG_CONFIG_HOME and the three PATH entries are an environment
  contribution, not exports in the block;
- a ~/.zshenv block sources ~/.config/mesh/environment.sh, so a script, a login and
  execute all see the environment;
- the ~/.zshrc block goes at the start, so the operator's lines run after it, and holds
  today's shared defaults between the first, normal and last slots. The prompt, the
  plugins and the operator's own lines are no longer in it;
- execute is bounded below the runtime's call limit (20 s default, 25 s at most), kills its
  whole process group on timeout, cuts each stream at 256 KiB and says so, runs in the
  account's home without the mesh's words, with the account's session words. The dead
  runuser branch is gone, because the runtime is the account;
- zsh_config shows both files with their block line counts;
- the README lists the one-off migration (ADR 0182).
The distribution does not package the theme, and the predecessor cloned whatever
upstream's default branch held the day a hook ran (novox/hq ADR 0205). So upstream's
v1.20.0 release is vendored verbatim, with its licence, and shipped as an archive the
host unpacks under the account's home and checks by digest.

The prompt's configuration is today's ~/.p10k.zsh byte for byte, as a second archive.
Inline, its 86 KB would ride in every declaration and be unreviewable JSON. The zsh code
that loads both is a contribution to the normal slot (ADR 0204). Instant prompt stays off,
as it is today.
The distribution packages both, so they are installed as packages rather than cloned or
vendored (novox/hq ADR 0205). Each contributes the line that loads the package's own
copy, from the path the Arch package installs, to a slot of the login shell's block
(ADR 0204). Syntax highlighting goes in last, as its upstream asks.
mesh-admin merged commit 22e8714040 into main 2026-10-04 08:55:11 +00:00
mesh-admin deleted branch feat/the-shell-and-its-environment 2026-10-04 08:55:12 +00:00
Sign in to join this conversation.
No Reviewers
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: novox/mesh-catalog#255