diff --git a/nix/templates/harness-base.nix b/nix/templates/harness-base.nix index 6175d22f..627e66a9 100644 --- a/nix/templates/harness-base.nix +++ b/nix/templates/harness-base.nix @@ -1018,15 +1018,30 @@ in ''; }; + # Path-trigger sibling: re-fires forge-avatar-sync the moment + # `/forge-token` appears. Mirrors the matrix-avatar-sync + # pattern — on first agent deployment the container boots before + # hive-c0re has provisioned the forge-token, so the service fires + # too early and exits with "no forge-token found". Without this path + # unit, RemainAfterExit=true would prevent systemd from ever + # re-running the service. See docs/persistence.md::forge-avatar-sync. + systemd.paths.forge-avatar-sync = { + description = "trigger forge-avatar-sync when forge-token appears"; + wantedBy = [ "multi-user.target" ]; + pathConfig.PathExistsGlob = "/agents/*/state/forge-token"; + }; + # One-shot: hyperhive.icon → Forgejo profile avatar. Shape contract: # docs/conventions.md::Best-effort oneshot services. + # RemainAfterExit = false (unlike the old true) so the .path trigger + # above can re-fire this unit when the forge-token arrives after boot. systemd.services.forge-avatar-sync = { description = "sync agent icon to Forgejo user avatar (best-effort)"; wantedBy = [ "multi-user.target" ]; after = [ "tea-login.service" ]; serviceConfig = { Type = "oneshot"; - RemainAfterExit = true; + RemainAfterExit = false; }; path = [ pkgs.curl @@ -1320,4 +1335,3 @@ in system.stateVersion = "25.11"; }; } -