Decision — hostd, the host service
Status: accepted 2026-10-12.
The decision
- One service,
hostd, runs as root on each host. It has two jobs: information about the host (hardware, OS, the MixOS mode, network management state, devices, power) and privileged actions on the host. It is the host agent of the VT-native design: the only MixOS code on the host besidesmix. - No generic exec. No verb runs a caller-supplied command, script or shell string. Each verb does one job, checks its arguments against a schema and does the work natively (writes the file itself, calls networkd, resolved, logind or iwd over Varlink or D-Bus).
- Written in Rust. Mix is the client. A root process that interprets scripts is too much attack surface.
- A verb that can't be reversed is not added. Exception: the two desk
power verbs,
desk.restartanddesk.stop(see Amendments). - Every new verb is reviewed on its own, and the verb list stays short.
Callers and transport
- Local callers use a Unix socket. Identity comes from the kernel
(
SO_PEERCRED) and the caller's cgroup, never from the request. - Reads are also served on the Bus, like any other service's.
- Writes from other nodes are accepted only when signed by a controller key listed in that host's policy, over the target node, a nonce and an expiry. Mesh trust alone never authorises a write. A host with no listed controller accepts no remote writes. Enforcement is on the receiving host.
- Ports below 1024 are not hostd's job. A service that binds one gets
AmbientCapabilities=CAP_NET_BIND_SERVICEin its own unit.
Tiers
| Tier | Examples | Gate |
|---|---|---|
| read | host info, network state, devices | caller identity |
| reversible | Wi-Fi connect, link configuration, device bind, suspend | a standing grant, plus a dead-man check or a kept previous state |
| reversible, wide blast radius | firewall, host package upgrade, reboot | a grant, a second signature from an independent reviewer, and a rate limit |
| irreversible | — | no verb exists |
Autonomy within limits set in advance
- Standing grants, not per-call prompts. A grant names the caller (from the kernel), the verbs, argument limits and an optional expiry. Only creating or widening a grant needs a person, confirmed through physical input that no Bus caller can synthesise.
- Reversible by construction. A verb applies its change, runs a health
check, and reverts unless the check passes in time. It keeps the previous
state (the previous file, or a filesystem snapshot) behind a receipt that
hostd.undorestores. - Limits: a rate limit per caller and verb, a circuit breaker after
repeated rollbacks, and a
freezethat drops hostd to reads only. - Audit: one journal record per call.
Files hostd owns
hostd writes only files it names itself (networkd files are
/etc/systemd/network/50-hostd-*) and never edits a file it didn't write.
Why
- Agents need to change host configuration (network, WireGuard, power,
devices) without
sudofrom a session, and without a person approving each call. - MixOS core has no polkit. hostd is the mechanism and its policy in one small binary, with rules as data instead of scripts.
- Closed verbs make a stolen credential worth far less than a root shell.
Consequences
- Session code never shells out to
sudo; a missing host action is a new hostd verb. - Write verbs arrive one reviewed verb at a time. The first is
net.link.apply; the verbs, grants and refusals are documented in the host service manual. - Root on the host means uid 0 in hostd's own pid and user namespaces, proven through a pidfd. Root inside a container is never root on the host, with or without uid remapping.
Amendments
2026-10-13: desk power verbs are an exception to "no irreversible verbs"
desk.restart and desk.stop restart or power off one desk machine. A
powered-off desk cannot be put back by hostd, so no undo can exist. The
desk must still be able to restart or stop itself, so the two verbs are
admitted as exceptions to the irreversibility rule. They are not a pattern
for other verbs.
Reversibility is replaced by these limits, which apply to both verbs:
- One desk per grant. The verb takes no machine name. The grant's
deskslimit must name exactly one valid machine, and that machine is the only one the verb can touch. A caller with no desk, or two, is refused. - The host is never powered. The verbs run
machinectl rebootormachinectl poweroffon the named machine only. - A standing grant, rate limited. Nothing runs without a grant, and a grant carries a rate limit and an expiry.
- Freeze applies.
hostd.freezerefuses both verbs. - Every call is recorded, as a receipt and in the audit journal.
hostd.undorefuses both verbs.
Deferred (Mark, 2026-10-13): the second signature from an independent reviewer
that the reboot tier requires is not built for desk.*. Security gates are
added once the desktop is ready for daily use, where they are needed. Until
then, the grant's rate limit and expiry are the only second check.