From 856c047a6cad0cff20cc0e1995f92826a7280dba Mon Sep 17 00:00:00 2001 From: Bruce MacDonald Date: Mon, 16 Mar 2026 13:50:04 -0700 Subject: [PATCH] cmd/launch: skip --install-daemon when systemd is unavailable (#14883) In container environments without systemd, `openclaw onboard --install-daemon` exits non-zero because it cannot create a systemd user service. This causes `ollama launch openclaw` to abort even though the gateway can be started as a foreground child process. Only pass --install-daemon when systemd user services are reachable (Linux with /run/systemd/system present and XDG_RUNTIME_DIR set). On all other platforms the flag is still included by default. --- cmd/launch/openclaw.go | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/cmd/launch/openclaw.go b/cmd/launch/openclaw.go index f2315ed4c..9d6812c8a 100644 --- a/cmd/launch/openclaw.go +++ b/cmd/launch/openclaw.go @@ -66,16 +66,20 @@ func (c *Openclaw) Run(model string, args []string) error { fmt.Fprintf(os.Stderr, "\n%sSetting up OpenClaw with Ollama...%s\n", ansiGreen, ansiReset) fmt.Fprintf(os.Stderr, "%s Model: %s%s\n\n", ansiGray, model, ansiReset) - cmd := exec.Command(bin, "onboard", + onboardArgs := []string{ + "onboard", "--non-interactive", "--accept-risk", "--auth-choice", "ollama", "--custom-base-url", envconfig.Host().String(), "--custom-model-id", model, - "--install-daemon", "--skip-channels", "--skip-skills", - ) + } + if canInstallDaemon() { + onboardArgs = append(onboardArgs, "--install-daemon") + } + cmd := exec.Command(bin, onboardArgs...) cmd.Stdin = os.Stdin cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr @@ -398,6 +402,25 @@ func patchScopes(obj map[string]any, key string, required []string) bool { return added } +// canInstallDaemon reports whether the openclaw daemon can be installed as a +// background service. Returns false on Linux when systemd is absent (e.g. +// containers) so that --install-daemon is omitted and the gateway is started +// as a foreground child process instead. Returns true in all other cases. +func canInstallDaemon() bool { + if runtime.GOOS != "linux" { + return true + } + // /run/systemd/system exists as a directory when systemd is the init system. + // This is absent in most containers. + fi, err := os.Stat("/run/systemd/system") + if err != nil || !fi.IsDir() { + return false + } + // Even when systemd is the init system, user services require a user + // manager instance. XDG_RUNTIME_DIR being set is a prerequisite. + return os.Getenv("XDG_RUNTIME_DIR") != "" +} + func ensureOpenclawInstalled() (string, error) { if _, err := exec.LookPath("openclaw"); err == nil { return "openclaw", nil