nix: hyperhive.westonRdp.enable — opt-in weston + RDP backend per agent
This commit is contained in:
parent
49f4e9cc89
commit
ba04a5a360
3 changed files with 120 additions and 0 deletions
18
CLAUDE.md
18
CLAUDE.md
|
|
@ -130,6 +130,8 @@ nix/
|
||||||
templates/harness-base.nix shared scaffolding for sub-agents + manager
|
templates/harness-base.nix shared scaffolding for sub-agents + manager
|
||||||
templates/agent-base.nix sub-agent nixosConfiguration
|
templates/agent-base.nix sub-agent nixosConfiguration
|
||||||
templates/manager.nix manager nixosConfiguration
|
templates/manager.nix manager nixosConfiguration
|
||||||
|
templates/weston-rdp.nix optional `hyperhive.westonRdp.enable`
|
||||||
|
— weston + RDP backend systemd unit
|
||||||
|
|
||||||
docs/
|
docs/
|
||||||
conventions.md naming, identity=socket, async forms, commit style
|
conventions.md naming, identity=socket, async forms, commit style
|
||||||
|
|
@ -183,6 +185,22 @@ read them à la carte.
|
||||||
In-flight or recent context that hasn't earned a section yet.
|
In-flight or recent context that hasn't earned a section yet.
|
||||||
Prune freely.
|
Prune freely.
|
||||||
|
|
||||||
|
- **Just landed:** `hyperhive.westonRdp.enable` option. New
|
||||||
|
`nix/templates/weston-rdp.nix` declares a per-agent bool;
|
||||||
|
enabling it runs weston with the RDP backend as a systemd
|
||||||
|
service (software/pixman render, self-signed TLS cert
|
||||||
|
generated first-boot under `/var/lib/weston`). Imported by
|
||||||
|
`harness-base.nix` so every agent has the option; an agent
|
||||||
|
opts in from its own `agent.nix`. Design note: it's a FLAT
|
||||||
|
per-agent option, not `hyperhive.agents.<name>.*` — each
|
||||||
|
agent is its own nixosConfiguration with no cross-agent
|
||||||
|
view, so the `<name>` indirection is meaningless. The unit
|
||||||
|
is `Type = "simple"` with an always-exit-0 `ExecStartPre` so
|
||||||
|
it can never abort `nixos-container update` (a `Type=notify`
|
||||||
|
weston that never signals READY would fail activation every
|
||||||
|
reload — the trap `tea-login` documents). A misconfigured
|
||||||
|
weston degrades to a restart loop in `journalctl`, not a
|
||||||
|
blocked rebuild.
|
||||||
- **Just landed:** `get_logs` now resolves the machine name.
|
- **Just landed:** `get_logs` now resolves the machine name.
|
||||||
`journalctl -M` wants the *machine* name (`h-gui`), not the
|
`journalctl -M` wants the *machine* name (`h-gui`), not the
|
||||||
logical agent name (`gui`) — `get_logs` was the one manager
|
logical agent name (`gui`) — `get_logs` was the one manager
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,11 @@
|
||||||
# this. The systemd service that actually runs the harness binary
|
# this. The systemd service that actually runs the harness binary
|
||||||
# differs per role and lives in the child module.
|
# differs per role and lives in the child module.
|
||||||
|
|
||||||
|
# Optional feature modules. Each declares its own `hyperhive.*`
|
||||||
|
# option(s), default-off, so every agent has them available but
|
||||||
|
# only opts in from its own `agent.nix`.
|
||||||
|
imports = [ ./weston-rdp.nix ];
|
||||||
|
|
||||||
options.hyperhive.allowedRecipients = lib.mkOption {
|
options.hyperhive.allowedRecipients = lib.mkOption {
|
||||||
type = lib.types.listOf lib.types.str;
|
type = lib.types.listOf lib.types.str;
|
||||||
default = [ ];
|
default = [ ];
|
||||||
|
|
|
||||||
97
nix/templates/weston-rdp.nix
Normal file
97
nix/templates/weston-rdp.nix
Normal file
|
|
@ -0,0 +1,97 @@
|
||||||
|
{
|
||||||
|
pkgs,
|
||||||
|
lib,
|
||||||
|
config,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
{
|
||||||
|
# Optional Weston (the reference Wayland compositor) with the RDP
|
||||||
|
# backend, surfaced as a per-agent hyperhive option. An agent turns
|
||||||
|
# it on from its own `agent.nix`:
|
||||||
|
#
|
||||||
|
# hyperhive.westonRdp.enable = true;
|
||||||
|
#
|
||||||
|
# Imported by `harness-base.nix`, so every sub-agent + the manager
|
||||||
|
# has the option available; only those that flip it on get the
|
||||||
|
# service. This is a flat per-agent option (evaluated inside that
|
||||||
|
# agent's own container build) — NOT a `hyperhive.agents.<name>.*`
|
||||||
|
# registry, which can't work: each agent is its own
|
||||||
|
# nixosConfiguration and has no cross-agent view.
|
||||||
|
|
||||||
|
options.hyperhive.westonRdp.enable = lib.mkOption {
|
||||||
|
type = lib.types.bool;
|
||||||
|
default = false;
|
||||||
|
description = ''
|
||||||
|
Run Weston with the RDP backend as a systemd service, for
|
||||||
|
remote-desktop access to the agent's container. A self-signed
|
||||||
|
TLS cert/key pair is generated on first start under
|
||||||
|
`/var/lib/weston`. Renders in software (pixman) — no GPU, DRM,
|
||||||
|
or VT access, so no extra container capabilities are needed.
|
||||||
|
|
||||||
|
The unit is deliberately built so enabling it can NEVER abort
|
||||||
|
the agent's `nixos-container update`: `Type = "simple"` (so
|
||||||
|
`switch-to-configuration` doesn't block on weston readiness)
|
||||||
|
and an `ExecStartPre` that always exits 0. A misconfigured
|
||||||
|
weston degrades to a restart loop visible in `journalctl` — it
|
||||||
|
does not block the rebuild. (Same reasoning as the `tea-login`
|
||||||
|
unit in `harness-base.nix`.)
|
||||||
|
|
||||||
|
Host networking means the RDP port (3389) is reachable on the
|
||||||
|
host. With more than one RDP-enabled agent the port would
|
||||||
|
collide — add a port knob to this option before that happens.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
config = lib.mkIf config.hyperhive.westonRdp.enable {
|
||||||
|
systemd.services.weston = {
|
||||||
|
description = "Weston Wayland compositor (RDP backend)";
|
||||||
|
after = [ "network.target" ];
|
||||||
|
wantedBy = [ "multi-user.target" ];
|
||||||
|
serviceConfig = {
|
||||||
|
# `simple`, not `notify`: switch-to-configuration must not
|
||||||
|
# wait on weston signalling readiness. A `notify` unit that
|
||||||
|
# never sends READY=1 fails after TimeoutStartSec, which
|
||||||
|
# aborts `nixos-container update` on every reload — exactly
|
||||||
|
# the trap `tea-login` documents.
|
||||||
|
Type = "simple";
|
||||||
|
# Creates /var/lib/weston (0700 root) before ExecStartPre.
|
||||||
|
StateDirectory = "weston";
|
||||||
|
Environment = "XDG_RUNTIME_DIR=/run/user/0";
|
||||||
|
# Runtime dir + first-boot cert generation. No `set -e`, and
|
||||||
|
# it always exits 0: a cert hiccup must not fail the unit
|
||||||
|
# start (that would abort the rebuild). If the cert/key end
|
||||||
|
# up missing, weston's own ExecStart fails into the Restart
|
||||||
|
# loop instead — graceful degradation, not a blocked deploy.
|
||||||
|
ExecStartPre = pkgs.writeShellScript "weston-rdp-setup" ''
|
||||||
|
mkdir -p /run/user/0 && chmod 700 /run/user/0 || true
|
||||||
|
CERT=/var/lib/weston/weston-rdp.crt
|
||||||
|
KEY=/var/lib/weston/weston-rdp.key
|
||||||
|
if [ ! -f "$CERT" ] || [ ! -f "$KEY" ]; then
|
||||||
|
if ${pkgs.openssl}/bin/openssl req -x509 -newkey rsa:2048 \
|
||||||
|
-keyout "$KEY" -out "$CERT" -days 3650 -nodes \
|
||||||
|
-subj "/CN=localhost" 2>/dev/null; then
|
||||||
|
chmod 600 "$KEY" 2>/dev/null || true
|
||||||
|
chmod 644 "$CERT" 2>/dev/null || true
|
||||||
|
else
|
||||||
|
echo "weston-rdp-setup: cert generation failed; weston will retry"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
exit 0
|
||||||
|
'';
|
||||||
|
ExecStart = lib.concatStringsSep " " [
|
||||||
|
"${pkgs.weston}/bin/weston"
|
||||||
|
"--backend=rdp-backend.so"
|
||||||
|
"--renderer=pixman"
|
||||||
|
"--rdp-tls-cert=/var/lib/weston/weston-rdp.crt"
|
||||||
|
"--rdp-tls-key=/var/lib/weston/weston-rdp.key"
|
||||||
|
];
|
||||||
|
Restart = "on-failure";
|
||||||
|
RestartSec = "5s";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# weston on the agent's interactive PATH too, so claude can run
|
||||||
|
# Wayland clients / `weston-info` against the compositor.
|
||||||
|
environment.systemPackages = [ pkgs.weston ];
|
||||||
|
};
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue