docs/book/src/setup/service.md
ZeroClaw ships with first-class service integration for systemd (Linux), launchctl (macOS), and Task Scheduler (Windows). All three are driven by one CLI surface:
<div class="os-tabs-src">zeroclaw service install # register the service
zeroclaw service start # start it
zeroclaw service stop # stop it
zeroclaw service restart # stop + start
zeroclaw service status # running / stopped, last exit code
zeroclaw service uninstall # remove it
The platform-specific backends are implemented in crates/zeroclaw-runtime/src/service/. You don't have to think about them, but knowing what they produce helps when debugging.
zeroclaw service install writes a user-scoped unit at ~/.config/systemd/user/zeroclaw.service.
The unit:
Type=simple with the agent process staying in the foregroundExecStart={cargo-bin}/zeroclaw daemonRestart=always with RestartSec=3Environment=HOME=%h and PassEnvironment=DISPLAY XDG_RUNTIME_DIR so headless browser tools can create profile/cache dirs and reach the user sessionWantedBy=default.targetsystemctl --user start zeroclaw
systemctl --user stop zeroclaw
systemctl --user status zeroclaw
systemctl --user enable zeroclaw # start on login
journalctl --user -u zeroclaw -f # follow
journalctl --user -u zeroclaw --since "1h ago"
The CLI only ever writes a user-scoped unit (systemctl --user), which by default starts at login and stops at logout. To keep ZeroClaw running on a headless box without an active session, enable lingering for the service user:
sudo loginctl enable-linger $USER
systemctl --user enable --now zeroclaw
If you need a true system-scope unit (root-owned, /etc/systemd/system/, dedicated service account, or hardware groups via SupplementaryGroups), the CLI does not generate one; adapt the system-level template at scripts/zeroclaw.service and install it yourself. On OpenRC hosts, sudo zeroclaw service install does provision a dedicated zeroclaw user and system paths (see below).
Detected automatically when /run/openrc exists (Alpine, some Gentoo configs).
zeroclaw service install # writes /etc/init.d/zeroclaw
rc-service zeroclaw start
rc-update add zeroclaw default # start on boot
zeroclaw service install writes ~/Library/LaunchAgents/com.zeroclaw.daemon.plist and loads it.
launchctl list | grep zeroclaw
launchctl unload ~/Library/LaunchAgents/com.zeroclaw.daemon.plist
launchctl load ~/Library/LaunchAgents/com.zeroclaw.daemon.plist
Logs go to <config-dir>/logs/ as daemon.stdout.log and daemon.stderr.log (for a default install, ~/.zeroclaw/logs/). Homebrew installs write to $HOMEBREW_PREFIX/var/zeroclaw/logs/ instead.
If installed via Homebrew, brew services is the preferred interface:
brew services start zeroclaw
brew services restart zeroclaw
brew services info zeroclaw
Don't mix zeroclaw service CLI commands with brew services, pick one. Both end up writing a plist; having both around confuses launchctl.
zeroclaw service install creates a per-user scheduled task named ZeroClaw Daemon:
/SC ONLOGON)LIMITED (runs as the current user, not elevated)zeroclaw-daemon.cmd, which launches zeroclaw daemonVerify in Task Scheduler GUI (taskschd.msc) under Task Scheduler Library → ZeroClaw Daemon.
Logs go to <config-dir>\logs\ as daemon.stdout.log and daemon.stderr.log (for a default install, %USERPROFILE%\.zeroclaw\logs\):
type %USERPROFILE%\.zeroclaw\logs\daemon.stdout.log
The task is driven through zeroclaw service start|stop|status, which wrap schtasks /Run, /End, and /Query against the ZeroClaw Daemon task. You can also manage it directly:
schtasks /Run /TN "ZeroClaw Daemon"
schtasks /End /TN "ZeroClaw Daemon"
schtasks /Query /TN "ZeroClaw Daemon" /FO LIST
The CLI installs only a per-user ONLOGON task; it does not register a LocalSystem Windows Service. For a true system service, wrap the binary with a third-party supervisor (e.g. NSSM) yourself.
The service reads config from whichever directory resolved at install time. Precedence (first match wins):
$ZEROCLAW_CONFIG_DIR (config lives directly under $ZEROCLAW_CONFIG_DIR)$ZEROCLAW_DATA_DIR$ZEROCLAW_WORKSPACE (deprecated, prefer ZEROCLAW_DATA_DIR; resolves either $ZEROCLAW_WORKSPACE or the legacy sibling .zeroclaw/)$HOMEBREW_PREFIX/var/zeroclaw/) when installed via Homebrew~/.zeroclaw/ (Linux/macOS) or %USERPROFILE%\.zeroclaw\ (Windows)ZEROCLAW_CONFIG_DIR overrides everything; setting it alongside ZEROCLAW_DATA_DIR or ZEROCLAW_WORKSPACE logs a warning and ignores the others.
If your service seems to ignore config changes, check which path the daemon resolved against, zeroclaw status reports the active config file, and the runtime logs a resolution-source line at startup:
zeroclaw status
The output includes the config file path it resolved against.
The service does not auto-update. That's deliberate; you pick when to take new code. Subscribe to the GitHub release feed or the Discord #releases channel (see Contributing → Communication).