OpenClaw Build and Operations (3/5) — Production Ops: launchd, systemd, Log Rotation

How --install-daemon works, the /tmp log path trap, openclaw.json hot reload, multi-agent routing in practice


ํ•ต์‹ฌ ์š”์•ฝ

  • Audience: Past desktop testing — you want to run OpenClaw 24/7 on a home server or a small VPS.
  • What you'll get: What --install-daemon actually creates (launchd / systemd user service), the default log path (/tmp/openclaw/), how ~/.openclaw/openclaw.json hot-reloads, multi-channel coexistence as JSON5, group-chat mention gating, and the 3-tier log-level precedence.
  • Prerequisite: #9 install + Discord in 30 minutes done. Basic familiarity with Linux/macOS process managers.

1. What the daemon actually is

Per the official README:

"OpenClaw Onboard installs the Gateway daemon (launchd/systemd user service)"

  • macOS: launchd user agent (not system)
  • Linux: systemd user service

Both are user scope — no root required. Works fine on shared machines inside your home directory.

openclaw onboard --install-daemon

The README doesn't pin the exact plist/service file paths. Conventional locations:

  • macOS: ~/Library/LaunchAgents/com.openclaw.gateway.plist
  • Linux: ~/.config/systemd/user/openclaw.service

Verify on your system:

launchctl list | grep openclaw
ls ~/Library/LaunchAgents/ | grep openclaw

systemctl --user list-units | grep openclaw
systemctl --user status openclaw

2. Manual daemon management — restart, disable, remove

2.1 macOS (launchd)

launchctl unload ~/Library/LaunchAgents/com.openclaw.gateway.plist

launchctl unload ~/Library/LaunchAgents/com.openclaw.gateway.plist
launchctl load ~/Library/LaunchAgents/com.openclaw.gateway.plist

launchctl unload ~/Library/LaunchAgents/com.openclaw.gateway.plist
rm ~/Library/LaunchAgents/com.openclaw.gateway.plist

2.2 Linux (systemd user)

systemctl --user stop openclaw
systemctl --user restart openclaw
systemctl --user status openclaw

systemctl --user disable openclaw

systemctl --user stop openclaw
systemctl --user disable openclaw
rm ~/.config/systemd/user/openclaw.service
systemctl --user daemon-reload

2.3 In-session chat commands (not the daemon)

The README lists agent-session commands: /status, /restart, /reset, /compact, /think <level>, /verbose on|off, /trace on|off, /usage off|tokens|full, /activation mention|always.

These are session-level commands, not daemon management. To actually bounce the daemon, use 2.1 / 2.2 above.


3. Logs — location, level, subcommands

3.1 Default path

Per the official docs:

"The Gateway writes logs to /tmp/openclaw/openclaw-YYYY-MM-DD.log by default, using the gateway host's local timezone."

/tmp is wiped at reboot. Move the path if you want retention.

3.2 Override the path

~/.openclaw/openclaw.json:

{
  logging: {
    file: "/var/log/openclaw/gateway.log"
  }
}

The target directory must be writable. Prep system paths:

sudo mkdir -p /var/log/openclaw
sudo chown $USER /var/log/openclaw

3.3 Log level — 3-tier precedence

Official: env var > CLI flag > config.

export OPENCLAW_LOG_LEVEL=debug
openclaw gateway

openclaw gateway --log-level trace

Config example:

{
  logging: {
    level: "info",         // file log level
    consoleLevel: "warn"   // console output level
  }
}

Levels: trace > debug > info > warn > error.

3.4 Log subcommands

openclaw logs --follow

openclaw channels logs --channel discord

openclaw logs --follow --local-time --json
openclaw logs --follow --plain --no-color

For a remote gateway, combine --url + --token.


4. Log rotation — not built in

The docs only mention daily file naming (YYYY-MM-DD). No explicit rotation policy (size-based, retention, compression) is provided. Use OS-level logrotate.

4.1 Linux — /etc/logrotate.d/openclaw

/var/log/openclaw/*.log {
    daily
    rotate 14
    compress
    delaycompress
    missingok
    notifempty
    create 0644 myuser myuser
    postrotate
        systemctl --user reload openclaw 2>/dev/null || true
    endscript
}

14-day retention, compression, postrotate reload so the gateway reopens file handles.

4.2 macOS — newsyslog.d

macOS uses newsyslog, not logrotate. /etc/newsyslog.d/openclaw.conf:

/var/log/openclaw/gateway.log    myuser:wheel    644    14    *    $D0    J

14 rotations, daily, gzip compression.


5. Hot reload — edit config, no restart

Per the official docs:

"The gateway automatically monitors openclaw.json for changes and applies safe updates without restart. Configuration must pass strict schema validation before loading — unknown keys or malformed types cause startup failure."

Practical implications:

  • Safe changes apply live (adding channels, adjusting log level, reconfiguring bindings).
  • Schema failure is a startup failure — existing gateway keeps running with the old config.
  • Validate with:
openclaw doctor

Edit-apply pattern:

vim ~/.openclaw/openclaw.json
openclaw doctor
openclaw logs --follow

Changes that can't hot-reload (e.g., the gateway port itself) need a daemon restart.


6. Multi-channel coexistence — one gateway, many messengers

Per the docs, 22+ channels can run concurrently. Each under channels.<provider>.

6.1 JSON5 example (Discord + Telegram + Slack)

{
  channels: {
    discord: {
      enabled: true,
      token: { ref: { provider: "default", source: "env", id: "DISCORD_BOT_TOKEN" } },
      dmPolicy: "pairing",
      allowFrom: ["discord:123456789"]
    },
    telegram: {
      enabled: true,
      botToken: { ref: { provider: "default", source: "env", id: "TELEGRAM_BOT_TOKEN" } },
      dmPolicy: "allowlist",
      allowFrom: ["tg:123"]
    },
    slack: {
      enabled: true,
      token: { ref: { provider: "default", source: "env", id: "SLACK_BOT_TOKEN" } },
      dmPolicy: "pairing"
    }
  }
}

6.2 DM Policy — four options

Official:

Value Behavior
"pairing" (default) Unknown senders receive one-time approval codes
"allowlist" Only entries in allowFrom allowed
"open" All DMs accepted (risky — requires allowFrom: ["*"])
"disabled" All DMs ignored

For public-server bots, "allowlist" is safest. Avoid "open" outside automated testing.


7. Multi-agent routing — one gateway, multiple bots

7.1 Per-agent workspaces

{
  agents: {
    list: [
      { id: "home", default: true, workspace: "~/.openclaw/workspace-home" },
      { id: "work", workspace: "~/.openclaw/workspace-work" }
    ]
  },
  bindings: [
    { agentId: "home", match: { channel: "whatsapp", accountId: "personal" } },
    { agentId: "work", match: { channel: "whatsapp", accountId: "biz" } }
  ]
}

Each inbound message resolves to an agent via bindings. Each agent gets its own workspace / skills / memory.

7.2 Default agent

{
  agents: {
    defaults: {
      workspace: "~/.openclaw/workspace",
      sandbox: { mode: "non-main" }   // mandatory if you share channels
    }
  }
}

The README's security rule: default main session runs tools on the host with full access. When channels are shared, sandbox.mode: "non-main" is the safety line.


8. Group chat — mention gating

A bot that replies to every message floods the group. Gate with mentions.

{
  agents: {
    list: [{
      id: "main",
      groupChat: {
        mentionPatterns: ["@openclaw", "openclaw", "hey claw"]
      }
    }]
  },
  channels: {
    whatsapp: {
      groups: { "*": { requireMention: true } }
    },
    discord: {
      groups: { "*": { requireMention: true } }
    }
  }
}
  • mentionPatterns: supports native @-mentions plus regex text patterns.
  • requireMention: true: only replies when mentioned in groups. DMs unaffected.

9. Config file structure — six top-level sections

~/.openclaw/openclaw.json (JSON5 format) key sections:

{
  gateway: { port: 18789 /* server, auth, health */ },
  agents:  { /* model, skills, sandbox */ },
  channels: { /* per-provider settings */ },
  session: { /* conversation scope, reset policy */ },
  cron:    { /* scheduled jobs */ },
  hooks:   { /* webhooks */ }
}

Knowing these six makes reference-doc navigation fast.

9.1 Why JSON5

  • Allows comments (//, /* */)
  • Trailing commas OK
  • Single quotes OK

More maintainable than plain JSON. For editor highlighting, using .json5 extension helps on GitHub.


10. Monitoring — minimum observability set

For a personal production deployment, don't skip:

10.1 openclaw doctor

openclaw doctor

Checks Node version, gateway state, channel connectivity, token validity, config schema. Automate with cron and alert on failure:

*/10 * * * * /usr/local/bin/openclaw doctor > /tmp/openclaw-doctor.log 2>&1 || osascript -e 'display notification "OpenClaw doctor FAIL" with title "OpenClaw"'

10.2 openclaw channels status --probe

Actively probes each channel's connection.

10.3 Keyword-filtered log watch

openclaw logs --follow | grep -Ei 'error|fatal|panic|disconnected'

11. Resource consumption — observable bounds

Official docs don't publish hard numbers. From observation:

  • Memory: scales with gateway + connected channels + active sessions. Common range: 100–400 MB.
  • Disk: /tmp/openclaw/*.log grows fast over time. Move path + logrotate are mandatory.
  • Network: each messenger's persistent connection + API calls. Running 24/7 often consumes several GB/month.
  • Restart cadence: no official guidance, but weekly restarts are prudent against memory leaks.
0 4 * * 0 systemctl --user restart openclaw

12. Counter-scenarios — don't go to production if…

  • Desktop-only use → Skip the daemon; run openclaw gateway manually. Easier to cycle.
  • You already use PM2 or similar → Wrapping OpenClaw with PM2 works, but don't collide with --install-daemon.
  • You want Docker isolation → No official Docker image in the README. Custom Dockerfile needed, with PTY and channel credential mounts — high complexity.
  • You need strict audit retention → OpenClaw's built-in logging is weak. Stream into journald + an external SIEM.

13. Production checklist

  • [ ] --install-daemon installed launchd / systemd user service
  • [ ] Log path moved out of /tmp/ via logging.file
  • [ ] logrotate / newsyslog configured (14 days, compress)
  • [ ] Default OPENCLAW_LOG_LEVEL=info; raise to debug/trace only while debugging
  • [ ] Shared channels have agents.defaults.sandbox.mode = "non-main"
  • [ ] Group chats set requireMention: true + mentionPatterns
  • [ ] DM Policy defaults to "allowlist" (new senders need explicit approval)
  • [ ] openclaw doctor cron every 10 min with failure alerting
  • [ ] Weekly restart cron (memory leak hedge)
  • [ ] Env vars (tokens) split into systemd Environment= or .env.local

14. What's next

With production stable:

  1. OpenClaw ↔ Claude Code bridge — channel trigger → code execution (coming soon)
  2. OpenClaw install + Discord in 30 min — foundation.
  3. Claude Code hooks complete guide — for code-automation hook patterns.

References


This is post 10/15 in the "AI Coding CLI Entry Guide" series.
last verified: 2026-04-25 (per openclaw/openclaw README + docs.openclaw.ai).

Series overview: Series index

๋Œ“๊ธ€