Install
openclaw skills install whatsapp-memoryMaintain separate memory contexts per WhatsApp conversation — both groups and direct messages (DMs). Use when: tracking what was discussed with a specific person or in a specific group, recalling past context before responding, logging decisions or key facts from a conversation, or preventing context bleed between different chats.
openclaw skills install whatsapp-memoryAny model. Memory management is file-based. No reasoning required. Use a medium+ model only when deciding what is worth logging.
Without conversation memory, context from one chat bleeds into another and you can't recall past decisions per group or person. This skill gives every group and DM its own context file.
memory/
whatsapp/
groups/
120363408613668489-g-us/ ← sanitized JID
meta.json ← group name, JID, participants
context.md ← running conversation context
decisions.md ← key decisions
people.md ← who participates and their role
dms/
972XXXXXXXXX/ ← sanitized phone number
meta.json ← name, phone, relationship
context.md ← running DM context
notes.md ← tasks, preferences, important facts
init_whatsapp_memory() {
TYPE="$1" # "group" or "dm"
ID="$2" # JID or phone number
NAME="$3" # Human-readable name
# Sanitize the ID for use as a directory name
SAFE_ID=$(echo "$ID" | tr '@.+' '---')
if [ "$TYPE" = "group" ]; then
DIR="$HOME/.openclaw/workspace/memory/whatsapp/groups/$SAFE_ID"
mkdir -p "$DIR"
# Write metadata file
cat > "$DIR/meta.json" << EOF
{"type": "group", "jid": "$ID", "name": "$NAME", "created": "$(date -u +%Y-%m-%dT%H:%M:%SZ)"}
EOF
# Create empty log files
touch "$DIR/context.md" "$DIR/decisions.md" "$DIR/people.md"
else
DIR="$HOME/.openclaw/workspace/memory/whatsapp/dms/$SAFE_ID"
mkdir -p "$DIR"
# Write metadata file
cat > "$DIR/meta.json" << EOF
{"type": "dm", "phone": "$ID", "name": "$NAME", "created": "$(date -u +%Y-%m-%dT%H:%M:%SZ)"}
EOF
# Create empty log files
touch "$DIR/context.md" "$DIR/notes.md"
fi
echo "Initialized WhatsApp memory: $NAME"
}
# Examples:
# init_whatsapp_memory "group" "120363422865795623@g.us" "PA Team"
# init_whatsapp_memory "dm" "+PHONE_NUMBER" "Contact Name"
wa_log() {
TYPE="$1" # "group" or "dm"
ID="$2" # JID or phone
CONTENT="$3" # what to log
FILE_NAME="${4:-context.md}" # context.md / decisions.md / notes.md
# Sanitize ID
SAFE_ID=$(echo "$ID" | tr '@.+' '---')
BASE="$HOME/.openclaw/workspace/memory/whatsapp"
# Pick the right directory
if [ "$TYPE" = "group" ]; then
FILE="$BASE/groups/$SAFE_ID/$FILE_NAME"
else
FILE="$BASE/dms/$SAFE_ID/$FILE_NAME"
fi
# Create file if missing
if [ ! -f "$FILE" ]; then
mkdir -p "$(dirname "$FILE")"
touch "$FILE"
fi
# Append timestamped entry
echo "[$(date -u +%Y-%m-%d\ %H:%M)] $CONTENT" >> "$FILE"
}
# Usage:
# wa_log "group" "XXXXXXXXXXX@g.us" "PA name: calendar connected ✅"
# wa_log "dm" "+PHONE_NUMBER" "Agreed to reschedule to Thursday" "notes.md"
wa_context() {
TYPE="$1"
ID="$2"
LINES="${3:-20}"
# Sanitize ID
SAFE_ID=$(echo "$ID" | tr '@.+' '---')
BASE="$HOME/.openclaw/workspace/memory/whatsapp"
# Pick directory
if [ "$TYPE" = "group" ]; then
DIR="$BASE/groups/$SAFE_ID"
else
DIR="$BASE/dms/$SAFE_ID"
fi
# Check if memory exists
if [ ! -d "$DIR" ]; then
echo "No memory for this conversation yet."
return
fi
# Read the conversation name from meta.json
NAME=$(python3 -c "
import json
with open('$DIR/meta.json') as f:
print(json.load(f).get('name', '?'))
" 2>/dev/null || echo "?")
echo "=== $NAME ==="
echo "--- Recent ---"
tail -"$LINES" "$DIR/context.md" 2>/dev/null || echo "(empty)"
echo "--- Notes/Decisions ---"
cat "$DIR/notes.md" "$DIR/decisions.md" 2>/dev/null | tail -10 || echo "(none)"
}
wa_search() {
QUERY="$1"
BASE="$HOME/.openclaw/workspace/memory/whatsapp"
echo "Searching WhatsApp memory for: '$QUERY'"
# Find all markdown files containing the query
grep -r "$QUERY" "$BASE" --include="*.md" -l 2>/dev/null | while read file; do
DIR=$(dirname "$file")
# Get conversation name from meta.json
NAME=$(python3 -c "
import json
with open('$DIR/meta.json') as f:
print(json.load(f).get('name', '?'))
" 2>/dev/null || echo "?")
echo "Found in: $NAME"
# Show matching lines with line numbers
grep -n "$QUERY" "$file" | head -3
echo ""
done
}
decisions.mdcontext.mdpeople.mdnotes.mdcontext.md| File | Use for |
|---|---|
| context.md | Ongoing conversation events |
| decisions.md | Agreed outcomes, group decisions |
| people.md | Who's in the group, their role/style |
| notes.md | DM tasks, owner preferences, follow-ups |
On every incoming message:
1. Extract JID or phone from inbound metadata
2. If group: run wa_context "group" "$JID" 10
If DM: run wa_context "dm" "$PHONE" 10
3. Use context to inform your response
4. After responding: log anything worth remembering
These rules prevent message loops and duplicate sends — learned from multi-PA group scenarios.
Before responding to ANY message, check sender_id from inbound metadata.
Before sending any message to a group or DM:
When multiple PA agents are active in the same group:
If another PA cannot send a message (pairing issues, gateway errors):
Before explaining, stepping in, or answering on behalf of another PA:
wa_weekly_digest() {
BASE="$HOME/.openclaw/workspace/memory/whatsapp"
# Get date from 7 days ago (works on Linux and macOS)
WEEK_AGO=$(date -u -d '7 days ago' +%Y-%m-%d 2>/dev/null \
|| date -u -v-7d +%Y-%m-%d)
echo "# WhatsApp Memory Digest — Week of $WEEK_AGO"
# Loop over all group and DM directories
for dir in "$BASE"/groups/*/ "$BASE"/dms/*/; do
[ -d "$dir" ] || continue
# Get the name
NAME=$(python3 -c "
import json
with open('${dir}meta.json') as f:
print(json.load(f).get('name', '?'))
" 2>/dev/null || echo "?")
# Show recent entries from this week
RECENT=$(grep "$WEEK_AGO\|$(date -u +%Y-%m-%d)" \
"${dir}context.md" "${dir}notes.md" 2>/dev/null | tail -5)
if [ -n "$RECENT" ]; then
echo "### $NAME"
echo "$RECENT"
echo ""
fi
done
}
tail -10 to limit tokens