# OpenClaw Upgrade Protection Strategy **Date:** 2026-02-16 22:30 **Context:** Protecting our WhatsApp monitoring system when OpenClaw gets updated via `docker compose pull` or version bumps ## Risk Map | Component | Location | Survives Update? | Risk | |-----------|----------|-----------------|------| | **handler.ts** (logger hook) | `~/.openclaw/hooks/whatsapp-logger/` | Yes — host volume mount | LOW: OpenClaw may change hook API | | **handler.ts** (context hook) | `~/.openclaw/hooks/whatsapp-context/` | Yes — host volume mount | LOW: same | | **wa-query.js** | `~/.openclaw/workspace/tools/` | Yes — host volume mount | NONE: pure Node.js, no OpenClaw deps | | **TOOLS.md** | `~/.openclaw/workspace/TOOLS.md` | Yes — host volume mount | NONE: documentation only | | **sidecar.py** | `~/.openclaw/whatsapp-monitor/` | Yes — runs on host, not in container | NONE: completely independent | | **PostgreSQL** | Coolify-managed container `akwgskos0woc4w0coc8ssks4` | Yes — separate container + volume | NONE: independent of OpenClaw | | **contacts.json** | `~/.openclaw/whatsapp-monitor/` | Yes — host filesystem | NONE | | **JSONL files** | `~/.openclaw/whatsapp-monitor/` | Yes — host filesystem | NONE | | **openclaw.json** | `~/.openclaw/openclaw.json` | Yes — host volume | MEDIUM: OpenClaw may add/remove keys on update | | **wa-policy.py** | `~/openclaw/wa-policy.py` | Yes — host filesystem | LOW: may need openclaw.json schema update | | **Cron jobs** | Stored in OpenClaw gateway internal DB | **MAYBE NOT** — depends on data persistence | HIGH: may be wiped on container recreation | | **systemd service** | `/etc/systemd/system/whatsapp-monitor.service` | Yes — system-level | NONE | | **Hook type imports** | `PluginHookMessageReceivedEvent` | Depends on API stability | HIGH: type may be renamed/restructured | ## What Can Break ### 1. Hook API Changes (HIGH risk) OpenClaw hooks import types from `openclaw/plugins`. If a new version: - Renames `PluginHookMessageReceivedEvent` → something else - Changes the event shape (e.g., `event.from` → `event.sender.id`) - Changes hook resolution (different events, different return types) **Mitigation:** ```typescript // Defensive handler.ts — no type import dependency export default function handler(event: any) { // Extract fields with fallbacks const from = event.from || event.sender?.id || event.sender || "unknown"; const content = event.content || event.body || event.message?.text || ""; const channel = event.channelId || event.channel || "unknown"; const senderName = event.metadata?.senderName || event.senderName || event.pushName || ""; // ... } ``` ### 2. Cron Jobs Lost on Recreate (HIGH risk) OpenClaw stores cron jobs in its internal state. If the container is recreated (not just restarted), crons may vanish. **Mitigation:** - Keep a cron recreation script on the host - Run it after every `docker compose up -d` or update ### 3. openclaw.json Schema Changes (MEDIUM risk) A new version might: - Reject unknown keys we added - Restructure `hooks.internal.entries` - Change `channels.whatsapp` shape **Mitigation:** - Keep a backup of our config additions separately - After update, run `openclaw doctor --fix` then re-apply our keys ### 4. Workspace Tool Execution (LOW risk) OpenClaw might change how workspace tools are discovered or executed. Currently `exec` runs commands in the workspace dir. **Mitigation:** - wa-query.js is self-contained Node.js — worst case, it's called by absolute path - The sidecar + index.json work regardless (host-side) ## Protection Artifacts ### Backup Script: `~/.openclaw/whatsapp-monitor/backup-config.sh` Run before any OpenClaw update: ```bash #!/bin/bash # Backup all WhatsApp monitoring config before OpenClaw update BACKUP_DIR="$HOME/.openclaw/whatsapp-monitor/backups/$(date +%Y%m%d-%H%M%S)" mkdir -p "$BACKUP_DIR" # Hooks cp -r ~/.openclaw/hooks/whatsapp-logger/ "$BACKUP_DIR/hook-logger/" cp -r ~/.openclaw/hooks/whatsapp-context/ "$BACKUP_DIR/hook-context/" # Config cp ~/.openclaw/openclaw.json "$BACKUP_DIR/openclaw.json" cp ~/.openclaw/whatsapp-monitor/contacts.json "$BACKUP_DIR/contacts.json" # Workspace tools cp ~/.openclaw/workspace/tools/wa-query.js "$BACKUP_DIR/wa-query.js" cp ~/.openclaw/workspace/TOOLS.md "$BACKUP_DIR/TOOLS.md" # Policy cp ~/openclaw/wa-policy.py "$BACKUP_DIR/wa-policy.py" # Cron snapshot docker exec openclaw-openclaw-gateway-1 node dist/index.js cron list \ --token 3547c3f2b7b4a33eb077cf804bcca446057f81ba1578b2045dbb3aa4e04346ee \ --url ws://127.0.0.1:18789 2>/dev/null > "$BACKUP_DIR/cron-jobs.txt" echo "Backed up to $BACKUP_DIR" ls -la "$BACKUP_DIR" ``` ### Restore Script: `~/.openclaw/whatsapp-monitor/restore-after-update.sh` Run after any OpenClaw update: ```bash #!/bin/bash # Restore WhatsApp monitoring after OpenClaw update TOKEN="3547c3f2b7b4a33eb077cf804bcca446057f81ba1578b2045dbb3aa4e04346ee" URL="ws://127.0.0.1:18789" echo "=== Verifying hooks ===" ls -la ~/.openclaw/hooks/whatsapp-logger/handler.ts ls -la ~/.openclaw/hooks/whatsapp-context/handler.ts echo "=== Verifying workspace tools ===" ls -la ~/.openclaw/workspace/tools/wa-query.js echo "=== Re-registering hooks in config ===" python3 -c " import json with open('$HOME/.openclaw/openclaw.json') as f: config = json.load(f) hooks = config.setdefault('hooks', {}).setdefault('internal', {}) hooks['enabled'] = True entries = hooks.setdefault('entries', {}) entries['WhatsApp Message Logger'] = {'enabled': True} entries['WhatsApp Context Injector'] = {'enabled': True} with open('$HOME/.openclaw/openclaw.json', 'w') as f: json.dump(config, f, indent=2) print('Hooks re-registered in config') " echo "=== Re-creating cron jobs ===" docker exec openclaw-openclaw-gateway-1 node dist/index.js cron add \ --name "WhatsApp Morning Digest" \ --schedule "cron 0 9 * * * @ UTC" \ --prompt 'Run node tools/wa-query.js summary 12 and node tools/wa-query.js unread. Create a digest. Send to +34678000075 via openclaw message send --channel whatsapp. Then mark-read all.' \ --target isolated --agent main \ --token "$TOKEN" --url "$URL" 2>/dev/null && echo "Morning digest cron added" docker exec openclaw-openclaw-gateway-1 node dist/index.js cron add \ --name "WhatsApp Evening Digest" \ --schedule "cron 0 21 * * * @ UTC" \ --prompt 'Run node tools/wa-query.js summary 12 and node tools/wa-query.js unread. Create a digest. Send to +34678000075 via openclaw message send --channel whatsapp. Then mark-read all.' \ --target isolated --agent main \ --token "$TOKEN" --url "$URL" 2>/dev/null && echo "Evening digest cron added" echo "=== Verifying sidecar ===" systemctl status whatsapp-monitor.service --no-pager | head -5 echo "=== Verifying PostgreSQL ===" docker exec akwgskos0woc4w0coc8ssks4 psql -U openclaw -d whatsapp_monitor -c "SELECT count(*) as messages FROM messages; SELECT count(*) as contacts FROM contacts;" echo "=== Restarting gateway ===" cd ~/openclaw && docker compose restart openclaw-gateway echo "=== Done ===" ``` ## Pre-Update Checklist Before running `docker compose pull` or updating OpenClaw: 1. **[ ]** Run backup script: `bash ~/.openclaw/whatsapp-monitor/backup-config.sh` 2. **[ ]** Note current cron job count: `docker exec openclaw-openclaw-gateway-1 node dist/index.js cron list --token TOKEN --url URL | grep -c WhatsApp` 3. **[ ]** Stop sidecar (optional, prevents stale writes): `sudo systemctl stop whatsapp-monitor` 4. **[ ]** Pull/update OpenClaw: `cd ~/openclaw && docker compose pull && docker compose up -d` 5. **[ ]** Wait for gateway to start: `docker logs -f openclaw-openclaw-gateway-1` 6. **[ ]** Run restore script: `bash ~/.openclaw/whatsapp-monitor/restore-after-update.sh` 7. **[ ]** Re-start sidecar: `sudo systemctl start whatsapp-monitor` 8. **[ ]** Verify everything: check hooks, crons, sidecar status, PG connection ## Why PostgreSQL Protects Us | SQLite (old) | PostgreSQL (new) | |---|---| | File inside `~/.openclaw/whatsapp-monitor/` — could be corrupted by concurrent access | Separate container, proper ACID transactions | | Gone if someone deletes the directory | Lives in Coolify-managed Docker volume — survives everything | | Not queryable from CloudBeaver | Visible in CloudBeaver at `127.0.0.1:5450` | | No backups | Can add Coolify backup schedule | | Single writer (file locking) | Concurrent readers + writers | ## PostgreSQL Connection Details | Property | Value | |----------|-------| | **Container** | `akwgskos0woc4w0coc8ssks4` | | **Image** | `postgres:16-alpine` | | **Host port** | `5450` | | **User** | `openclaw` | | **Password** | `OpenClaw2026!` | | **Database** | `whatsapp_monitor` | | **Coolify UUID** | `akwgskos0woc4w0coc8ssks4` | | **Internal URL** | `postgres://openclaw:OpenClaw2026%21@akwgskos0woc4w0coc8ssks4:5432/whatsapp_monitor` | | **Host URL** | `postgres://openclaw:OpenClaw2026!@127.0.0.1:5450/whatsapp_monitor` | ## Architecture After Migration ``` WhatsApp message → OpenClaw gateway (container) │ ├── Hook: whatsapp-logger/handler.ts │ └── writes JSONL to ~/.openclaw/whatsapp-monitor/ │ ├── Hook: whatsapp-context/handler.ts │ └── reads index.json → injects into agent context │ └── wa-query.js (reads JSONL + contacts.json) └── for quick queries inside the agent NUC Host: sidecar.py (systemd) ─── reads JSONL ──→ PostgreSQL (Coolify container :5450) │ │ └── writes ──→ index.json (summary for hooks + agent) │ CloudBeaver can query it ``` ## Related - Plan: `.artifacts/2026-02-16_22-00_whatsapp-monitoring-system-plan.md` - WhatsApp MCP: `.artifacts/2026-02-12_22-50_whatsapp-mcp-setup.md` - OpenClaw setup: `.artifacts/2026-02-12_02-30_openclaw-setup.md`