🎁 Get the FREE AI Skills Starter Guide β€” Subscribe β†’
BytesAgainBytesAgain
πŸ¦€ ClawHub

OpenClaw macOS Always-On

by @happydog-intj

Run OpenClaw as a system-level LaunchDaemon on macOS for 24/7 operation, surviving screen lock, logout, and user switching. Uses caffeinate to prevent sleep....

Versionv1.0.1
Downloads1,412
Comments2
TERMINAL
clawhub install openclaw-macos-always-on

πŸ“– About This Skill


name: macos-launchdaemon description: Run OpenClaw as a system-level LaunchDaemon on macOS for 24/7 operation, surviving screen lock, logout, and user switching. Uses caffeinate to prevent sleep. Verified working for long-term locked screen scenarios.

macOS LaunchDaemon Setup for OpenClaw

Run OpenClaw as a system-level service (LaunchDaemon) with caffeinate to ensure 24/7 operation. This configuration has been tested and verified to work even after extended screen lock periods (30+ minutes).

Ensures OpenClaw continues running when:

  • πŸ”’ Screen is locked (short or long duration)
  • πŸ‘€ User is logged out
  • πŸ”„ Switching between user accounts
  • πŸ’€ Display sleeps (system stays awake)
  • When to Use This

    Use LaunchDaemon if:

  • You need 24/7 bot availability
  • You lock your Mac regularly but want messages to still work
  • Multiple users on the same Mac need to access the bot
  • Running on a home server/always-on Mac
  • Use LaunchAgent if:

  • Only need bot while logged in
  • Prefer simpler setup (no sudo)
  • Security-conscious about system-level services
  • Quick Setup

    One-Command Installation

    curl -fsSL https://raw.githubusercontent.com/YOUR_USERNAME/clawd/master/skills/macos-launchdaemon/install.sh | bash
    

    Or manual setup below ⬇️

    Manual Setup

    Step 1: Create LaunchDaemon Configuration

    Create the plist file with your actual username. This configuration uses caffeinate and has been tested and verified to work even after 30+ minutes of screen lock:

    cat > /tmp/ai.openclaw.gateway.plist << 'EOF'
    
    
    
      
        Label
        ai.openclaw.gateway
        
        Comment
        OpenClaw Gateway (System Daemon - Network Always On)
        
        RunAtLoad
        
        
        
        KeepAlive
        
          SuccessfulExit
          
          NetworkState
          
          Crashed
          
        
        
        
        ThrottleInterval
        0
        
        
        ProcessType
        Interactive
        
        
        EnableTransactions
        
        
        UserName
        YOUR_USERNAME
        
        GroupName
        staff
        
        
        ProgramArguments
        
          /usr/bin/caffeinate
          -s
          /opt/homebrew/bin/node
          /opt/homebrew/lib/node_modules/openclaw/dist/index.js
          gateway
          --port
          18789
        
        
        StandardOutPath
        /Users/YOUR_USERNAME/.openclaw/logs/gateway.log
        
        StandardErrorPath
        /Users/YOUR_USERNAME/.openclaw/logs/gateway.err.log
        
        EnvironmentVariables
        
          HOME
          /Users/YOUR_USERNAME
          PATH
          /opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin
        
      
    
    EOF

    Replace YOUR_USERNAME with your actual username

    sed -i '' "s/YOUR_USERNAME/$(whoami)/g" /tmp/ai.openclaw.gateway.plist

    πŸ”‘ Key Configuration for Lock Screen Persistence:

  • /usr/bin/caffeinate -s - Prevents system sleep (display can sleep, network stays active)
  • NetworkState: true - Ensures service stays active when network is available
  • ProcessType: Interactive - Prevents macOS from suspending the process
  • ThrottleInterval: 0 - Disables any throttling
  • Crashed: true - Auto-restarts on crashes
  • βœ… Verified working after 30+ minutes of screen lock on macOS 14.4

    Step 2: Stop Existing LaunchAgent

    # Stop user-level service
    launchctl bootout gui/$(id -u)/ai.openclaw.gateway 2>/dev/null

    Backup and disable LaunchAgent plist

    mv ~/Library/LaunchAgents/ai.openclaw.gateway.plist ~/Library/LaunchAgents/ai.openclaw.gateway.plist.disabled 2>/dev/null

    Step 3: Install LaunchDaemon (requires sudo)

    # Copy to system location
    sudo cp /tmp/ai.openclaw.gateway.plist /Library/LaunchDaemons/

    Set correct permissions

    sudo chown root:wheel /Library/LaunchDaemons/ai.openclaw.gateway.plist sudo chmod 644 /Library/LaunchDaemons/ai.openclaw.gateway.plist

    Load and start service

    sudo launchctl bootstrap system /Library/LaunchDaemons/ai.openclaw.gateway.plist

    Step 4: Verify Installation

    # Check process is running
    ps aux | grep openclaw-gateway | grep -v grep

    Verify PPID = 1 (launched by system launchd)

    ps -p $(pgrep -f openclaw-gateway) -o pid,ppid,user,command

    Check service status

    sudo launchctl print system/ai.openclaw.gateway | head -10

    Test with OpenClaw

    openclaw status

    Expected output:

    PID   PPID  USER       COMMAND
    12345 1     youruser   openclaw-gateway
    

    PPID=1 confirms it's running as LaunchDaemon (parent is system launchd).

    Testing Lock Screen Behavior

    Test Script

    #!/bin/bash
    echo "πŸ§ͺ Testing LaunchDaemon lock screen behavior..."
    echo ""
    echo "1. Lock your Mac in 5 seconds..."
    sleep 5
    pmset displaysleepnow

    echo "2. Use your phone to send 'ping' to your bot" echo "3. Bot should reply 'pong! πŸŽ‰' even while locked" echo "" echo "Unlock your Mac after testing."

    Manual Test Steps

    1. Lock your Mac: ⌘ + Control + Q 2. Send from phone: Message your bot (Telegram/Feishu/etc.) with "ping" 3. Expected: Bot replies "pong! πŸŽ‰" immediately 4. Unlock and verify logs show the message was processed

    Management Commands

    View Logs

    # Real-time logs
    tail -f ~/.openclaw/logs/gateway.log

    Error logs

    tail -f ~/.openclaw/logs/gateway.err.log

    Last 100 lines

    tail -100 ~/.openclaw/logs/gateway.log

    Restart Service

    # Unload and reload
    sudo launchctl bootout system/ai.openclaw.gateway
    sudo launchctl bootstrap system /Library/LaunchDaemons/ai.openclaw.gateway.plist

    Or use kickstart (restarts without unloading)

    sudo launchctl kickstart -k system/ai.openclaw.gateway

    Stop Service

    # Stop service
    sudo launchctl bootout system/ai.openclaw.gateway

    Prevent auto-start

    sudo launchctl disable system/ai.openclaw.gateway

    Start Service

    # Enable and start
    sudo launchctl enable system/ai.openclaw.gateway
    sudo launchctl bootstrap system /Library/LaunchDaemons/ai.openclaw.gateway.plist
    

    Check Status

    # Full service details
    sudo launchctl print system/ai.openclaw.gateway

    Quick status check

    sudo launchctl list | grep openclaw

    Process info

    ps aux | grep openclaw-gateway | grep -v grep

    Uninstallation

    Complete Removal

    # 1. Stop service
    sudo launchctl bootout system/ai.openclaw.gateway

    2. Remove plist

    sudo rm /Library/LaunchDaemons/ai.openclaw.gateway.plist

    3. Restore LaunchAgent (optional)

    mv ~/Library/LaunchAgents/ai.openclaw.gateway.plist.disabled ~/Library/LaunchAgents/ai.openclaw.gateway.plist 2>/dev/null launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/ai.openclaw.gateway.plist

    4. Verify

    ps aux | grep openclaw | grep -v grep

    Automated Install Script

    Save this as install-launchdaemon.sh:

    #!/bin/bash
    set -e

    echo "πŸš€ OpenClaw LaunchDaemon Installer" echo "==================================" echo ""

    Colors

    RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' NC='\033[0m' # No Color

    USERNAME=$(whoami) PLIST_PATH="/Library/LaunchDaemons/ai.openclaw.gateway.plist" TEMP_PLIST="/tmp/ai.openclaw.gateway.plist"

    Check if running as root

    if [ "$EUID" -eq 0 ]; then echo -e "${RED}❌ Don't run this script with sudo${NC}" echo "The script will ask for sudo password when needed." exit 1 fi

    Check if OpenClaw is installed

    if ! command -v openclaw &> /dev/null; then echo -e "${RED}❌ OpenClaw not found. Install it first:${NC}" echo " npm install -g openclaw" exit 1 fi

    echo -e "${YELLOW}πŸ“‹ Creating LaunchDaemon configuration...${NC}"

    Get OpenClaw gateway token

    GATEWAY_TOKEN=$(openclaw config get gateway.auth.token 2>/dev/null | tr -d '"' || echo "")

    cat > "$TEMP_PLIST" << EOF Label ai.openclaw.gateway Comment OpenClaw Gateway (System Daemon) RunAtLoad KeepAlive UserName $USERNAME GroupName staff ProgramArguments /opt/homebrew/bin/node /opt/homebrew/lib/node_modules/openclaw/dist/index.js gateway --port 18789 StandardOutPath /Users/$USERNAME/.openclaw/logs/gateway.log StandardErrorPath /Users/$USERNAME/.openclaw/logs/gateway.err.log EnvironmentVariables HOME /Users/$USERNAME PATH /opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin OPENCLAW_GATEWAY_PORT 18789 OPENCLAW_GATEWAY_TOKEN $GATEWAY_TOKEN EOF

    echo -e "${YELLOW}πŸ›‘ Stopping existing services...${NC}"

    Stop LaunchAgent

    launchctl bootout gui/$(id -u)/ai.openclaw.gateway 2>/dev/null || true

    Backup LaunchAgent plist

    if [ -f ~/Library/LaunchAgents/ai.openclaw.gateway.plist ]; then mv ~/Library/LaunchAgents/ai.openclaw.gateway.plist ~/Library/LaunchAgents/ai.openclaw.gateway.plist.backup echo -e "${GREEN}βœ… Backed up LaunchAgent plist${NC}" fi

    Stop existing LaunchDaemon

    sudo launchctl bootout system/ai.openclaw.gateway 2>/dev/null || true

    echo -e "${YELLOW}πŸ“¦ Installing LaunchDaemon...${NC}"

    Install plist

    sudo cp "$TEMP_PLIST" "$PLIST_PATH" sudo chown root:wheel "$PLIST_PATH" sudo chmod 644 "$PLIST_PATH"

    echo -e "${YELLOW}πŸš€ Starting service...${NC}"

    Start service

    sudo launchctl bootstrap system "$PLIST_PATH" sleep 3

    Verify

    if ps aux | grep -q "[o]penclaw-gateway"; then echo "" echo -e "${GREEN}βœ… LaunchDaemon installed successfully!${NC}" echo "" echo "πŸ“Š Service Status:" ps aux | grep "[o]penclaw-gateway" | awk '{print " PID: "$2", User: "$1}' echo "" echo "πŸ§ͺ Test it:" echo " 1. Lock your Mac: ⌘ + Control + Q" echo " 2. Send 'ping' from your phone" echo " 3. Bot should reply even while locked!" echo "" echo "πŸ“‹ Management:" echo " Logs: tail -f ~/.openclaw/logs/gateway.log" echo " Restart: sudo launchctl kickstart -k system/ai.openclaw.gateway" echo " Stop: sudo launchctl bootout system/ai.openclaw.gateway" echo " Status: sudo launchctl print system/ai.openclaw.gateway" else echo -e "${RED}❌ Service failed to start${NC}" echo "Check logs: tail -50 ~/.openclaw/logs/gateway.err.log" exit 1 fi

    Make it executable:

    chmod +x install-launchdaemon.sh
    ./install-launchdaemon.sh
    

    Troubleshooting

    Service Won't Start

    Check logs:

    tail -50 ~/.openclaw/logs/gateway.err.log
    

    Common issues:

    1. Wrong username in plist

       # Verify username matches
       grep UserName /Library/LaunchDaemons/ai.openclaw.gateway.plist
       whoami
       

    2. Wrong node path

       # Check node location
       which node
       
       # Update plist if needed (change /opt/homebrew/bin/node to your path)
       

    3. Permissions issues

       # Fix log directory permissions
       mkdir -p ~/.openclaw/logs
       chmod 755 ~/.openclaw/logs
       

    Still Suspends After Lock

    If using older macOS or specific hardware:

    # Prevent system sleep
    sudo pmset -a sleep 0
    sudo pmset -a disksleep 0
    sudo pmset -a displaysleep 10  # Screen off but system awake
    

    Or use caffeinate (not recommended for laptops):

    # Modify ProgramArguments in plist to wrap with caffeinate
    /usr/bin/caffeinate
    -s  
    /opt/homebrew/bin/node
    ...
    

    Port Already in Use

    # Find what's using port 18789
    lsof -i :18789

    Kill the process

    kill -9

    Or change port in config and plist

    openclaw config set gateway.port 18790

    Logs Not Writing

    # Create log directory
    mkdir -p ~/.openclaw/logs

    Test permissions

    touch ~/.openclaw/logs/test.log ls -la ~/.openclaw/logs/

    Check plist paths match

    grep Path /Library/LaunchDaemons/ai.openclaw.gateway.plist

    Security Considerations

    Running as User vs Root

    βœ… This setup runs as your user (specified in UserName)

  • Not running as root
  • Same permissions as when you run OpenClaw manually
  • Safer than true root daemons
  • File Permissions

    # LaunchDaemon plist should be owned by root
    ls -l /Library/LaunchDaemons/ai.openclaw.gateway.plist
    

    Should show: -rw-r--r-- 1 root wheel

    Log directory owned by you

    ls -ld ~/.openclaw/logs

    Should show: drwxr-xr-x ... youruser staff

    Token Security

    The Gateway token is stored in the plist environment variables. While readable only by root and your user, consider:

    # Check who can read the plist
    ls -l /Library/LaunchDaemons/ai.openclaw.gateway.plist

    More secure: use macOS Keychain (advanced)

    Store token in keychain and retrieve at runtime

    Performance Impact

    LaunchDaemon has minimal performance impact:

  • Same process as LaunchAgent
  • Runs only when needed (KeepAlive handles crashes)
  • Idle resource usage: ~50MB RAM, <1% CPU
  • Active (processing messages): ~100MB RAM, varies by task
  • macOS Version Compatibility

    Tested on:

  • βœ… macOS 10.15 (Catalina)
  • βœ… macOS 11 (Big Sur)
  • βœ… macOS 12 (Monterey)
  • βœ… macOS 13 (Ventura)
  • βœ… macOS 14 (Sonoma)
  • βœ… macOS 15 (Sequoia)
  • Note: LaunchDaemon syntax changed slightly in macOS 11+, but backwards compatible.

    Comparison: LaunchAgent vs LaunchDaemon

    | Feature | LaunchAgent | LaunchDaemon | |---------|-------------|--------------| | Runs when locked | ❌ May suspend | βœ… Always runs | | Runs when logged out | ❌ Stops | βœ… Continues | | Setup complexity | Simple | Requires sudo | | Requires sudo | ❌ No | βœ… Yes | | Best for | Personal use, logged-in only | 24/7 server, multi-user | | Security | User-level | System-level (still runs as user) | | Auto-start | At login | At boot |

    Migration

    From LaunchAgent to LaunchDaemon

    Use the install script above, or:

    # Automatic migration
    launchctl bootout gui/$(id -u)/ai.openclaw.gateway
    mv ~/Library/LaunchAgents/ai.openclaw.gateway.plist ~/Library/LaunchAgents/ai.openclaw.gateway.plist.backup
    

    Then follow installation steps

    From LaunchDaemon back to LaunchAgent

    # Stop daemon
    sudo launchctl bootout system/ai.openclaw.gateway
    sudo rm /Library/LaunchDaemons/ai.openclaw.gateway.plist

    Restore agent

    mv ~/Library/LaunchAgents/ai.openclaw.gateway.plist.backup ~/Library/LaunchAgents/ai.openclaw.gateway.plist launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/ai.openclaw.gateway.plist

    FAQ

    Q: Will this drain my battery? A: Minimal impact. OpenClaw idles at <1% CPU when not processing messages.

    Q: Can I still update OpenClaw? A: Yes. After updating, restart the service:

    sudo launchctl kickstart -k system/ai.openclaw.gateway
    

    Q: What if I upgrade macOS? A: LaunchDaemon survives OS upgrades. Verify it's still running after update:

    sudo launchctl print system/ai.openclaw.gateway
    

    Q: Can I run multiple instances? A: Not recommended. Use one LaunchDaemon with multiple channel accounts instead.

    Q: Does this work on M1/M2 Macs? A: Yes! Works on both Intel and Apple Silicon Macs.

    Related Skills

  • macos-lock-screen-fix - Alternative LaunchAgent fix (simpler but may not work on all Macs)
  • healthcheck - Monitor OpenClaw health and uptime
  • Contributing

    Found issues or improvements?

  • GitHub: https://github.com/openclaw/openclaw/issues
  • Pull requests welcome!

  • Quick Commands Reference:

    # Status
    sudo launchctl print system/ai.openclaw.gateway

    Restart

    sudo launchctl kickstart -k system/ai.openclaw.gateway

    Logs

    tail -f ~/.openclaw/logs/gateway.log

    Uninstall

    sudo launchctl bootout system/ai.openclaw.gateway sudo rm /Library/LaunchDaemons/ai.openclaw.gateway.plist

    πŸ“‹ Tips & Best Practices

    Service Won't Start

    Check logs:

    tail -50 ~/.openclaw/logs/gateway.err.log
    

    Common issues:

    1. Wrong username in plist

       # Verify username matches
       grep UserName /Library/LaunchDaemons/ai.openclaw.gateway.plist
       whoami
       

    2. Wrong node path

       # Check node location
       which node
       
       # Update plist if needed (change /opt/homebrew/bin/node to your path)
       

    3. Permissions issues

       # Fix log directory permissions
       mkdir -p ~/.openclaw/logs
       chmod 755 ~/.openclaw/logs
       

    Still Suspends After Lock

    If using older macOS or specific hardware:

    # Prevent system sleep
    sudo pmset -a sleep 0
    sudo pmset -a disksleep 0
    sudo pmset -a displaysleep 10  # Screen off but system awake
    

    Or use caffeinate (not recommended for laptops):

    # Modify ProgramArguments in plist to wrap with caffeinate
    /usr/bin/caffeinate
    -s  
    /opt/homebrew/bin/node
    ...
    

    Port Already in Use

    # Find what's using port 18789
    lsof -i :18789

    Kill the process

    kill -9

    Or change port in config and plist

    openclaw config set gateway.port 18790

    Logs Not Writing

    # Create log directory
    mkdir -p ~/.openclaw/logs

    Test permissions

    touch ~/.openclaw/logs/test.log ls -la ~/.openclaw/logs/

    Check plist paths match

    grep Path /Library/LaunchDaemons/ai.openclaw.gateway.plist