Files
hq/01-RESEARCH/027-the-system-layer-as-modules/03-the-accounts-own-tools.md
T

9.4 KiB

03 — The account's own tools: ssh, scripts, mail

Three further directions from the operator on 2026-10-04. Each is account-level, like the shell (to-be 41).

~/.ssh is one module's

"A module owns ~/.ssh, so it is its responsibility that every folder is set up consistently and correctly."

Measured:

  • The catalogue's ssh-client module owns the directory (mode 0700) and one region of ~/.ssh/config: a Host block per machine of the mesh. It owns nothing else.
  • On one workstation, a predecessor's header, Include and hand-written host block sat above the mesh's region. ssh takes the first match, so the predecessor's entries were the ones in force, for the same machines. Removed on 2026-10-04.
  • On the control machine, two keys of a retired CI system were still in the operator's authorized_keys, able to log in as the operator. Removed the same day.
  • Permissions differ by file and by machine. Backups of the configuration lie beside it.

Starting position: ssh-client becomes the holder of everything under ~/.ssh, classified as ADR 0182 asks:

path class how
~/.ssh/, its mode, every file's mode owned the directory resource, plus a check verb that reports a file with the wrong mode
~/.ssh/config written into, the mesh's block at the start the mesh's hosts win; the operator's lines after it are kept; an Include config.d/* line in the block
~/.ssh/config.d/<module> owned by the contributing module ssh's own drop-in: a work module adds its forge's host there (research 026 C1)
~/.ssh/authorized_keys written into, the mesh's block the operator's keys as the mesh records them, and nothing a retired system left. The operator's own lines are kept below the block
~/.ssh/known_hosts written into, the mesh's block every mesh machine's host key, so the first connection never asks
private keys found never read and never written by the mesh; a key the mesh should hand out comes from the vault, through the module's own process (ADR 0182, third class)

The sshd module is the other half: the machine's side. It is already in the catalogue.

Scripts on every machine, shared and machine-specific

"All nodes should get some custom scripts, both node-specific and mesh-specific (shared)."

Measured: the operator's script folder holds 64 entries plus 33 in its bin/. It is under no version control, and exists only where it was copied. It mixes three kinds:

  1. scripts belonging to a module (the desktop's watchers, lock, menus; a laptop model's brightness);
  2. the operator's own tools;
  3. installers that modules have replaced.

Starting position:

  • The operator's scripts live in a repository of their own, registered as any application is (ADR 0015), built as archives, unpacked into a directory the module owns under the home. bin/ goes on PATH through an environment contribution (ADR 0203), and small functions go into the shell through a shell contribution (ADR 0204).

  • "Machine-specific" is said by assignment, never by naming a machine (ADR 0112). One repository holds several modules:

    • scripts (shared, on every machine);
    • scripts-workstation;
    • scripts-media;
    • and so on, each assigned where it applies.

    A script that belongs to a piece of software or hardware moves into that module instead. A flavor inside one module is what research 026/03 says not to repeat.

  • A script can also be a tool. A script with a one-line description is served by the node's runtime, so it can be called through the mesh on any machine that has it.

  • A script that needs a secret gets it through question 2's mechanism, never from a file of environment secrets.

The keyring

"A keyring is also a good thing to create a module for."

Measured on the two workstations, which both run GNOME Keyring:

  • On one, the keyring unlocks at login. The login manager's PAM service includes login, which carries pam_gnome_keyring.
  • On the other, it does not. The PAM line is only in the screensaver's service, so at session start the window manager runs a script that asks for the password a second time and unlocks the keyring with it.
  • On both, the session's start script starts the daemon again with the ssh and gpg components, and exports the ssh agent's socket. The keyring's current release serves the ssh agent through a separate per-user socket unit instead.

Starting position: a gnome-keyring module that holds a node seat, node-secret-service (the holder of the desktop's secret service; a password manager could hold it instead). It declares:

  • the package;
  • its lines in the login manager's PAM file, written into, never over (ADR 0102), so login unlocks it on every machine;
  • the ssh agent's user socket, once user-scoped units ship;
  • the agent's socket path as an environment contribution, which needs a machine fact for the account's runtime directory. ADR 0203 forbids $ in values, so $XDG_RUNTIME_DIR cannot be written in one.

The second unlock prompt and the second daemon start go away.

Mail as events

"Ideally a mail consumer with all my mail accounts configured, so my mail is recorded in the bus."

Measured:

  • The predecessor polled one work mailbox every minute. It read an access token out of the mail client's process memory, called a mail API with it, and raised a desktop notification per unread message. It worked only while the mail client ran, and stopped silently when the predecessor's units were retired.
  • Two further predecessor modules served mail tools, for one provider and for IMAP.
  • The mesh runs a mail server of its own for its domains.

Not decided here; it needs an effort of its own. The questions it would have to answer:

  • Accounts and how each authenticates:

    • IMAP with an app password;
    • a provider's OAuth with a registered application;
    • the mesh's own mail server, which can publish delivery itself.

    An employer's tenant may forbid registering an application at all.

  • What the bus records:

    • headers and a summary as events;
    • bodies and attachments in an object store the event points at;
    • retention, since mail is the most personal data the mesh would hold.
  • What consumes it: a notifier bridge to the desktop (the predecessor's notifications), search, an agent's context.

  • Where it runs: one long-running module, not per machine (ADR 0198).

The obvious first step is the mail server the mesh already runs.

Power management on the laptop

"Power management for the laptop."

Measured on the laptop (a gaming model with a hybrid GPU):

  • The platform profile is driven by a vendor daemon (asusd) and its CLI. The vendor CLI is now in the official repositories; the copy installed came from elsewhere. A predecessor script runs as a user unit and switches the profile every five seconds: quiet on battery, balanced on mains, performance above 50 % CPU.
  • The hybrid GPU's mode (now hybrid) is held by a second vendor daemon (supergfxd), which is not in the official repositories. Kernel-module options for the discrete GPU's power state and its suspend, hibernate and resume units are set by hand. Its own power daemon is masked.
  • The battery charge limit is 80 %, set by the vendor daemon.
  • The lid and power key suspend. The brightness key is ignored by logind and handled by the vendor-key path. Both are logind drop-ins.
  • Memory pressure: compressed swap in RAM (zram) beside a swap file and a partition; systemd-oomd with drop-ins; a predecessor memory guard user unit that notifies before the OOM killer acts.
  • upower runs. There is no power-profiles-daemon, tlp, auto-cpufreq or thermald, so nothing competes with the vendor daemon, by design.

All of it came from two predecessor modules, one of which was a laptop-model flavor. A desktop received part of it (research 026/01).

Starting position:

  • A hardware module per machine model (here, the laptop's model). It holds the vendor daemon and its profile configuration, the GPU mode daemon (ADR 0205's case, or the build machine's package repository of research 027 question 1), the discrete GPU's module options and suspend units, the logind drop-ins, the battery charge limit, and the vendor keys and brightness. It is assigned to the one machine of that model, and to any second one later.
  • The profile switching moves from a polling script to the module's own long-running code (ADR 0198). It reacts to the power-supply change event instead of polling, and its thresholds become settings (issue 168).
  • Memory pressure is not the laptop's alone. zram and systemd-oomd with the notifier are a memory-pressure module, assigned wherever wanted. The swap layout stays the machine's (kernel module, question 3).
  • A node-power-profile seat (vendor daemon, or power-profiles-daemon on other hardware) gives the mesh one verb, profile, the same on every machine that has one.