ZeroClaw ships with first-class service integration for systemd (Linux), launchctl (macOS), and Task Scheduler (Windows). All three are driven by one CLI surface:
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 itThe 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=simplewith the agent process staying in the foregroundExecStart={cargo-bin}/zeroclaw daemonRestart=alwayswithRestartSec=3Environment=HOME=%handPassEnvironment=DISPLAY XDG_RUNTIME_DIRso headless browser tools can create profile/cache dirs and reach the user sessionWantedBy=default.target
systemctl --user start zeroclaw
systemctl --user stop zeroclaw
systemctl --user status zeroclaw
systemctl --user enable zeroclaw # start on loginThe 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:
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 bootzeroclaw 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.plistLogs 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:
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:
- Trigger: at logon (
/SC ONLOGON) - Run level:
LIMITED(runs as the current user, not elevated) - Action: runs the install wrapper
zeroclaw-daemon.cmd, which launcheszeroclaw daemon
Verify 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\):
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 LISTThe 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, preferZEROCLAW_DATA_DIR; resolves either$ZEROCLAW_WORKSPACEor the legacy sibling.zeroclaw/)- On macOS only, the Homebrew config dir (
$HOMEBREW_PREFIX/var/zeroclaw/) when installed via Homebrew - Default
~/.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:
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).