Service Management
ZeroClaw ships with first-class service integration for systemd (Linux), launchctl (macOS), and Task Scheduler / Windows Service (Windows). All three are driven by one CLI surface:
sh
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.
Linux: systemd
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
Manual control (systemd)
sh
systemctl --user start zeroclaw
systemctl --user stop zeroclaw
systemctl --user status zeroclaw
systemctl --user enable zeroclaw # start on login
Logs
sh
journalctl --user -u zeroclaw -f # follow
journalctl --user -u zeroclaw --since "1h ago"
Starting before user login
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:
sh
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).
Linux: OpenRC
Detected automatically when /run/openrc exists (Alpine, some Gentoo configs).
sh
zeroclaw service install # writes /etc/init.d/zeroclaw
rc-service zeroclaw start
rc-update add zeroclaw default # start on boot
macOS: LaunchAgent
zeroclaw service install writes ~/Library/LaunchAgents/com.zeroclaw.daemon.plist and loads it.
sh
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.
Homebrew-managed
If installed via Homebrew, brew services is the preferred interface:
sh
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.
Windows: Task Scheduler
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\):
cmd
type %USERPROFILE%\.zeroclaw\logs\daemon.stdout.log
Manual control (Task Scheduler)
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:
cmd
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.
Config path resolution
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:
sh
zeroclaw status
The output includes the config file path it resolved against.
Auto-update
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).