Files
clawmates/deploy/fleet/herdr-persistence/herdr.service
T
Omar Sobh 0d4cb2c2bc herdr phase 0 follow-up: persistent daemon via systemd/launchd
Phase 0 started Herdr via nohup — died on reboot / logout. Replaces
that with proper service management:

  - deploy/fleet/herdr-persistence/herdr.service — systemd user unit
    (Linux). Restart=on-failure with an 8-in-24h burst cap so a
    broken binary doesn't hot-loop. Requires linger enabled so the
    user's systemd manager runs without a login session; install.sh
    does that via loginctl.
  - deploy/fleet/herdr-persistence/dev.herdr.plist — launchd
    LaunchAgent (macOS). ProgramArguments + PATH templated so the
    install script substitutes actual paths at deploy time.
  - deploy/fleet/herdr-persistence/install.sh — idempotent installer
    that autodetects OS, drops the unit/plist in the right place,
    enables + starts, prints status.

Rolled to tank + architect + morpheus (systemd) + smith + macbook
(launchd). All 5 nodes confirmed `status: running` post-install.

Phase 0 gap closed: Herdr now survives node reboots and logouts,
which is the prerequisite for the fleet_herdr dispatch path to be
reliable across mission_orchestrator restarts.
2026-07-20 11:27:35 -07:00

25 lines
858 B
Desktop File

[Unit]
Description=Herdr headless server (terminal multiplexer for coding agents)
Documentation=https://herdr.dev/docs/
After=network-online.target
Wants=network-online.target
[Service]
# Reads $HOME/.local/bin/herdr; the resolver in fleet_herdr expects this path.
ExecStart=%h/.local/bin/herdr server
# Herdr's socket lives under ~/.config/herdr/herdr.sock — the daemon
# creates its own state dir, no need to pre-provision anything.
Restart=on-failure
RestartSec=5
# 24 hours between restart bursts so a crashing binary doesn't hot-loop.
StartLimitIntervalSec=86400
StartLimitBurst=8
# Herdr owns its own logs (~/.config/herdr/herdr-server.log); systemd
# journal captures anything that escapes.
StandardOutput=journal
StandardError=journal
[Install]
# WantedBy=default.target for user units — no wants for multi-user.target.
WantedBy=default.target