📖 DOC: feat(cli): enhance daemonless mode support for container/cloud environments

Refine the handling of the DENCHCLAW_DAEMONLESS=1 environment variable and --skip-daemon-install flag to ensure consistent behavior across all commands, including bootstrap, update, start, restart, and stop, in environments lacking systemd/launchd.
This commit is contained in:
kumarabhirup 2026-03-15 21:27:20 -07:00
parent 76f8838362
commit 3cd51759da
No known key found for this signature in database
GPG Key ID: DB7CA2289CAB0167

View File

@ -0,0 +1,121 @@
---
name: Daemonless environment support
overview: Add daemonless mode support across all CLI commands via a `DENCHCLAW_DAEMONLESS=1` environment variable (plus per-command `--skip-daemon-install` flags), and document it in the README.
todos:
- id: helper
content: Create isDaemonlessMode() helper that checks opts.skipDaemonInstall || DENCHCLAW_DAEMONLESS env var
status: pending
- id: bootstrap
content: "Update bootstrap-external.ts: env var fallback, skip post-onboard gateway restart entirely, skip attemptGatewayAutoFix entirely, skip gateway health probe"
status: pending
- id: web-runtime-cmd
content: "Update web-runtime-command.ts: add skipDaemonInstall to option types, skip restartGatewayDaemon entirely in daemonless mode, skip LaunchAgent in update/start/restart/stop"
status: pending
- id: register-flags
content: Add --skip-daemon-install flag to register.update.ts, register.start.ts, register.restart.ts, register.stop.ts
status: pending
- id: readme
content: Add Daemonless / Docker section to README.md
status: pending
- id: tests
content: Update existing tests if needed to cover daemonless codepaths
status: pending
isProject: false
---
# Daemonless Environment Support
## Problem
`--skip-daemon-install` currently only affects bootstrap's `openclaw onboard` call. Three other codepaths still attempt daemon/service registration and will fail or waste time in container environments:
1. `**restartGatewayDaemon()**` in `update`/`start`/`restart` runs `openclaw gateway install --force` (registers a system service)
2. `**installWebRuntimeLaunchAgent()**` on macOS writes a launchd plist and calls `launchctl load`
3. `**attemptGatewayAutoFix()**` in bootstrap runs `gateway install --force` as a repair step
## Approach
### Env var + CLI flag
- `**DENCHCLAW_DAEMONLESS=1**` env var — set once in Dockerfile, all commands respect it
- `**--skip-daemon-install**` CLI flag — per-command override, already exists on `bootstrap`
- Resolution: `opts.skipDaemonInstall || process.env.DENCHCLAW_DAEMONLESS === '1'`
A shared helper `isDaemonlessMode(opts?: { skipDaemonInstall?: boolean })` in a small utility avoids repeating this logic.
### What changes per command
`**bootstrap**` ([src/cli/bootstrap-external.ts](src/cli/bootstrap-external.ts)):
- Onboard `--install-daemon` and `--skip-health` already gated (current diff)
- **Skip** post-onboard `gateway restart` entirely (line 2421-2432) — no service to restart
- **Skip** `attemptGatewayAutoFix()` entirely (line 2450-2467) — stop/install/start all operate on a registered service
- **Skip** the gateway health probe loop (line 2440-2444) — no daemon to probe
- Read `DENCHCLAW_DAEMONLESS` env var as fallback for `opts.skipDaemonInstall`
`**update`** ([src/cli/web-runtime-command.ts](src/cli/web-runtime-command.ts) `updateWebRuntimeCommand`):
- **Skip** `restartGatewayDaemon()` entirely — `stop`/`install`/`start` all operate on a registered service that doesn't exist
- Skip `installWebRuntimeLaunchAgent` as `startFn` — let `ensureManagedWebRuntime` use its default `startManagedWebRuntime` (spawns child process, works everywhere)
- Skip `uninstallWebRuntimeLaunchAgent` call
`**start`/`restart`** ([src/cli/web-runtime-command.ts](src/cli/web-runtime-command.ts) `startWebRuntimeCommand`):
- Same as update: skip `restartGatewayDaemon` entirely, skip LaunchAgent, use `startManagedWebRuntime`
`**stop`** ([src/cli/web-runtime-command.ts](src/cli/web-runtime-command.ts) `stopWebRuntimeCommand`):
- Skip `uninstallWebRuntimeLaunchAgent` (avoids noisy `launchctl` errors in containers)
### Gateway behavior in daemonless mode
Per [OpenClaw docs](https://docs.openclaw.ai/start/getting-started), the gateway supports a foreground mode:
```
openclaw gateway --port 18789
```
This runs the gateway as a regular process (no service manager needed). In daemonless mode:
- **Skip ALL gateway daemon management**`gateway install`, `gateway start`, `gateway stop`, `gateway restart` all operate on a registered launchd/systemd service
- The gateway must be started separately by the user as a foreground process (e.g., in Docker `CMD` or a process supervisor like `supervisord`)
- DenchClaw commands only manage the **web runtime** (spawned as a child process via `startManagedWebRuntime`)
### Files to modify
- [src/cli/bootstrap-external.ts](src/cli/bootstrap-external.ts) — env var fallback, gate auto-fix install step, gate post-onboard restart
- [src/cli/web-runtime-command.ts](src/cli/web-runtime-command.ts) — add `skipDaemonInstall` to option types, thread through `restartGatewayDaemon`, `updateWebRuntimeCommand`, `startWebRuntimeCommand`, `stopWebRuntimeCommand`; skip LaunchAgent when daemonless
- [src/cli/program/register.update.ts](src/cli/program/register.update.ts) — add `--skip-daemon-install` flag
- [src/cli/program/register.start.ts](src/cli/program/register.start.ts) — add `--skip-daemon-install` flag
- [src/cli/program/register.restart.ts](src/cli/program/register.restart.ts) — add `--skip-daemon-install` flag
- [src/cli/program/register.stop.ts](src/cli/program/register.stop.ts) — add `--skip-daemon-install` flag
- [README.md](README.md) — add "Daemonless / Docker" section documenting the env var and flag
### README addition (under Commands section)
```markdown
### Daemonless / Docker
For containers or environments without systemd/launchd, set:
```bash
export DENCHCLAW_DAEMONLESS=1
```
This skips all gateway daemon management (install/start/stop/restart) and launchd LaunchAgent installation across all commands. You must start the gateway yourself as a foreground process:
```bash
openclaw --profile dench gateway --port 19001
```
Alternatively, pass `--skip-daemon-install` to individual commands:
```bash
npx denchclaw --skip-daemon-install
npx denchclaw update --skip-daemon-install
```
```
```