[Unit] Description=GitHub Actions self-hosted runner (multideal) After=network-online.target Wants=network-online.target [Service] Type=simple Slice=ci.slice WorkingDirectory=%h/actions-runner-multideal ExecStart=%h/actions-runner-multideal/run.sh Restart=always RestartSec=5 # KillMode=process signalled only run.sh, which does not forward to its child, so # every stop left Runner.Listener alive still holding the GitHub session: the runner # kept reporting online and the next start died with SessionConflict, silently # killing the recruit path (one such orphan ran 7.4h). control-group signals the # listener too, which exits cleanly on TERM. ci-fallback never stops a busy runner, # so no job is cut short. KillMode=control-group TimeoutStopSec=90 # PATH puts the cpu-guard shims (.claude/bin) FIRST so pnpm/npm/vitest/tsc are # CPU-affinity-pinned for CI containment; .npm-global/bin carries the real pnpm # the shim delegates to. Environment=PATH=%h/.claude/bin:%h/.npm-global/bin:%h/.local/bin:/usr/local/bin:/usr/bin:/bin Environment=BUILD_SCHED_IDLE=0 Environment=BUILD_LOCK_FILE=%h/.cache/ci-box/.build.lock Environment=BUILD_PER_JOB_CPU=200 Environment=BUILD_NODE_HEAP=4096 Environment=BUILD_SLOTS=1 Environment=BUILD_SLOT_FIXED=1 # ci-fallback only ever starts this runner when debian1 cannot serve, so its jobs # must be allowed to build here. Under the agents' REMOTE-ONLY config they would # offload to the box that is down and exit 97 after remote_wait_sec. Still # remote-first; the ci.slice caps above bound what lands locally. Environment=BUILD_REMOTE_LOCAL_FALLBACK=1 [Install] WantedBy=default.target