Overview
The defenseclaw-gateway binary is the enforcement point. It connects to the OpenClaw gateway over WebSocket (device-key authenticated), inspects every tool_call / tool_result, optionally fronts LLM traffic through the guardrail proxy on port 4000, persists verdicts into the SQLite audit store, and exposes a local REST API on port 18970. The Python CLI manages scanners, policies, and config; the Go daemon does the actual live enforcement.
Lifecycle commands
| Command | What it does | Source |
|---|---|---|
defenseclaw-gateway start | Spawns the gateway as a background daemon, detaches from the terminal, writes PID to ~/.defenseclaw/gateway.pid, starts the watchdog if gateway.watchdog.enabled | daemon.go |
defenseclaw-gateway stop | Sends SIGTERM, then SIGKILL after 10s if unresponsive; stops the watchdog first | runStop |
defenseclaw-gateway restart | stop then start; preserves the PID file contract | runRestart |
defenseclaw-gateway status | Prints subsystem health (gateway, watcher, guardrail, api, telemetry, splunk, sandbox) | sidecar.go |
defenseclaw-gateway run | Runs in the foreground (no detach, no PID file). Useful for debugging. | gateway run |
On-boot supervision
systemd (Linux)
DefenseClaw does not install a generic systemd unit during init; install it with:
sudo tee /etc/systemd/system/defenseclaw-gateway@.service > /dev/null <<'EOF'
[Unit]
Description=DefenseClaw gateway sidecar
After=network-online.target
Wants=network-online.target
[Service]
Type=exec
User=%i
ExecStart=/usr/local/bin/defenseclaw-gateway run
Restart=on-failure
RestartSec=5
StandardOutput=journal
StandardError=journal
[Install]
WantedBy=default.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable --now defenseclaw-gateway@$USER.service
For sandbox standalone mode, init --sandbox generates openshell-sandbox.service and defenseclaw-sandbox.target under ~/.defenseclaw/systemd/ and installs them when run as root — see setup-sandbox.
launchd (macOS)
cat > ~/Library/LaunchAgents/ai.defenseclaw.gateway.plist <<EOF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key><string>ai.defenseclaw.gateway</string>
<key>ProgramArguments</key>
<array>
<string>/usr/local/bin/defenseclaw-gateway</string>
<string>run</string>
</array>
<key>RunAtLoad</key><true/>
<key>KeepAlive</key><true/>
<key>StandardOutPath</key><string>/tmp/defenseclaw-gateway.out.log</string>
<key>StandardErrorPath</key><string>/tmp/defenseclaw-gateway.err.log</string>
</dict>
</plist>
EOF
launchctl load ~/Library/LaunchAgents/ai.defenseclaw.gateway.plist
What the sidecar exposes
| Surface | Default | Purpose |
|---|---|---|
| REST API | 127.0.0.1:18970 | Health, status, alerts, policy reload, provider registry — consumed by the Python CLI, TUI, and IDE extensions |
| Guardrail proxy | 127.0.0.1:4000 | OpenAI-compatible / LiteLLM-friendly; only bound when guardrail.enabled=true |
| WebSocket client | Outbound to cfg.gateway.host:port | Attaches to OpenClaw; authenticates with OPENCLAW_GATEWAY_TOKEN + device key |
gateway.api_port and guardrail.port are configurable in config.yaml; the pinned values above are the shipped defaults.
Watchdog
The built-in watchdog is separate from systemd and designed for workstations where users don't run services under an init system. Enable it by setting gateway.watchdog.enabled=true in config.yaml; it auto-starts with start and auto-stops on stop. It polls /health, restarts the daemon on repeated failures, and logs to ~/.defenseclaw/watchdog.log.
Verify it worked
defenseclaw-gateway status
curl -s http://127.0.0.1:18970/health | jq .
curl -s http://127.0.0.1:18970/alerts | jq '.alerts | length'
ps -p $(cat ~/.defenseclaw/gateway.pid)
The /health endpoint returns a JSON map keyed by subsystem: gateway, watcher, guardrail, api, telemetry, splunk, sandbox. Each has state: running|healthy|disabled|stopped|<error>. init parses this and prints a summary.
Undo / reset
defenseclaw-gateway stop
rm -f ~/.defenseclaw/gateway.pid ~/.defenseclaw/gateway.log
Stopping the sidecar does not remove the guardrail's openclaw.json patch. Use defenseclaw setup guardrail --disable to revert OpenClaw to direct LLM mode. See setup-guardrail.
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
Gateway sidecar is already running (PID N) | PID file present, process alive | Expected — use restart to reload config |
start: FAILED: bind: address already in use | Another process on 18970 | lsof -i :18970 and kill it, or change gateway.api_port |
status shows guardrail: stopped but enabled=true | Upstream LLM path not reachable, or plugin not installed | defenseclaw doctor — probably a missing plugin or bad master_key |
PID file present but ps shows nothing | Crash without cleanup | rm ~/.defenseclaw/gateway.pid then start |