From 6652ae90ab0c81897524b754fbf7efbc916a4ed9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?m=C3=BCde?= Date: Sun, 17 May 2026 02:58:39 +0200 Subject: [PATCH] tea-login: never fail switch-to-configuration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit a failed tea-login oneshot used to abort `nixos-container update` (switch-to-configuration exits 4), which blocked every rebuild whether the agent needed tea or not. drop `set -e`, exit 0 on every failure path (mkdir, tea login add, missing forge). also fix the unit description, which hardcoded /state (manager-only) — sub- agents have /agents//state. --- nix/templates/harness-base.nix | 37 ++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/nix/templates/harness-base.nix b/nix/templates/harness-base.nix index f6e7354..8b43e7a 100644 --- a/nix/templates/harness-base.nix +++ b/nix/templates/harness-base.nix @@ -186,10 +186,10 @@ # One-shot: configure tea with the agent's forge token if # hive-c0re seeded one and tea hasn't been configured yet. # Runs before the harness service so the first turn can already - # `tea repos create`. Idempotent — exits 0 if config already - # exists, exits 0 if no token file (hive-forge not enabled). + # `tea repos create`. *Always* exits 0 — never fail a NixOS + # switch-to-configuration over a missing/temperamental forge. systemd.services.tea-login = { - description = "configure tea CLI from /state/forge-token"; + description = "configure tea CLI from hive-forge token (best-effort)"; wantedBy = [ "multi-user.target" ]; after = [ "local-fs.target" ]; serviceConfig = { @@ -201,16 +201,20 @@ pkgs.coreutils ]; script = '' - set -eu + # No `set -e`: any subshell failure here (tea exit, mkdir, + # missing forge) must not propagate. A failed unit aborts + # `nixos-container update`, which would block every rebuild. CONFIG=/root/.config/tea/config.yml - # Manager keeps the legacy /state bind; sub-agents have - # /agents//state. Glob covers both — there's exactly one - # hit either way (manager: /state, sub-agent: its own - # /agents/* mount), since each container only sees its own - # state dir. + # Manager bind-mounts state at /state; sub-agents at + # /agents//state. Glob both — each container only sees + # its own mount, so there's exactly one hit either way (or + # zero, when the forge hasn't been seeded yet). TOKEN_FILE="" for f in /state/forge-token /agents/*/state/forge-token; do - [ -f "$f" ] && TOKEN_FILE="$f" && break + if [ -f "$f" ]; then + TOKEN_FILE="$f" + break + fi done if [ -z "$TOKEN_FILE" ]; then echo "tea-login: no forge-token (hive-forge not seeded); skipping" @@ -220,11 +224,14 @@ echo "tea-login: $CONFIG already present; skipping" exit 0 fi - mkdir -p "$(dirname "$CONFIG")" - tea login add \ - --name forge \ - --url ${lib.escapeShellArg config.hyperhive.forge.url} \ - --token "$(cat "$TOKEN_FILE")" + mkdir -p "$(dirname "$CONFIG")" || true + if ! tea login add \ + --name forge \ + --url ${lib.escapeShellArg config.hyperhive.forge.url} \ + --token "$(cat "$TOKEN_FILE")"; then + echo "tea-login: tea login add failed; continuing without tea" + exit 0 + fi echo "tea-login: configured for ${config.hyperhive.forge.url} from $TOKEN_FILE" ''; };