Skill: zencrust-ai/minimal-memory (version 1.0.0)

--- name: minimal-memory description: Maintain clean, efficient memory files with GOOD/BAD/NEUTRAL categorization and semantic search. Use when managing agent memory, deciding what to store, searching past memories, or organizing knowledge. Triggers on: memory cleanup requests, "remember this", "search memory", memory organization discussions, or when MEMORY.md grows too large. --- # Minimal Memory Management Keep agent memory lean, searchable, and actionable through structured categorization and two-tier storage. ## Core Principle **MEMORY.md = Long-term essentials (GOOD/BAD learnings only)** **memory/YYYY-MM-DD.md = Daily operations (GOOD/BAD/NEUTRAL tagged)** ## Information Categorization Tag every memory entry with its value: | Tag | Meaning | Keep in MEMORY.md? | Example | |-----|---------|-------------------|---------| | `[GOOD]` | Worked well, repeat | ✅ Yes | `[GOOD] CSV batch format prevents duplicates` | | `[BAD]` | Failed, avoid | ✅ Yes | `[BAD] Bird CLI blocked by X anti-automation` | | `[NEUTRAL]` | Facts, context, state | ❌ No | `[NEUTRAL] Day 5 of 30-day media plan` | ### Writing Rules 1. **Always tag** new entries in daily files 2. **Be specific**: What worked/failed and why 3. **One tag per entry** - pick the strongest category 4. **NEUTRAL expires**: Archive after 30 days unless promoted to GOOD/BAD ## What Goes Where ### MEMORY.md (Categorized Learnings) Keep under 150 lines. Only GOOD and BAD entries: ```markdown ## GOOD - What Works - `[GOOD]` Cron jobs with CSV batching = zero duplicates - `[GOOD]` Browser tool > CLI for X.com automation - `[GOOD]` Moltbook "crypto" submolt for token posts ## BAD - What to Avoid - `[BAD]` Never use bird CLI for X (anti-bot blocks it) - `[BAD]` Don't post identical content across platforms ``` ### memory/YYYY-MM-DD.md (Daily Log) All three categories with full context: ```markdown # 2026-02-15 ## [GOOD] - Fixed duplicate posting with 4-batch CSV structure - Created 10 cron jobs for complete automation ## [BAD] - Old CSV format caused content duplication (now deprecated) ## [NEUTRAL] - Day 5 of 30-day media plan - Posted $ZEN token shill at 07:00 batch ``` ## Quick Commands ### Search Memory ```bash # Search all memory files ~/.openclaw/skills/minimal-memory/scripts/search.sh "duplicate posting" # Search only GOOD learnings ~/.openclaw/skills/minimal-memory/scripts/search.sh --good "CSV" # Search only BAD learnings ~/.openclaw/skills/minimal-memory/scripts/search.sh --bad "CLI" # Recent entries only (last 7 days) ~/.openclaw/skills/minimal-memory/scripts/search.sh --recent "cron job" ``` ### Daily Memory ```bash # Create today's memory file with template ~/.openclaw/skills/minimal-memory/scripts/daily.sh # Add entry with auto-tagging ~/.openclaw/skills/minimal-memory/scripts/add.sh GOOD "Browser tool works better than CLI" ``` ### Cleanup ```bash # Review and migrate GOOD/BAD to MEMORY.md ~/.openclaw/skills/minimal-memory/scripts/cleanup.sh # Archive old NEUTRAL entries (>30 days) ~/.openclaw/skills/minimal-memory/scripts/archive.sh ``` ## Workflow ### When Writing a Memory 1. **Tag it**: Is this GOOD, BAD, or NEUTRAL? 2. **Write to daily file** with tag prefix 3. **Weekly review**: Promote GOOD/BAD to MEMORY.md 4. **Archive NEUTRAL** after 30 days ### When Searching 1. **Use search script** for fast grep across all files 2. **Check MEMORY.md first** for established patterns 3. **Fall back to daily files** for specific context 4. **Prefer recent entries** unless looking for historical ### Weekly Cleanup 1. Read last 7 days of daily files 2. Extract `[GOOD]` and `[BAD]` entries 3. Add to MEMORY.md "GOOD" and "BAD" sections 4. Remove duplicates, condense similar items 5. Ensure MEMORY.md < 150 lines ## Anti-Patterns ❌ **Don't** skip tagging - every entry needs a category ❌ **Don't** put NEUTRAL in MEMORY.md ❌ **Don't** let MEMORY.md grow past 200 lines ❌ **Don't** keep NEUTRAL entries forever (30 day max) ❌ **Don't** create topical files - use daily + search ✅ **Do** search before asking user "did we try this?" ✅ **Do** migrate GOOD/BAD weekly ✅ **Do** be specific in failure/success descriptions ✅ **Do** trust the search script to find context ## Migration from Old System If MEMORY.md has untagged content: 1. Read entire MEMORY.md 2. Categorize each entry: GOOD/BAD/NEUTRAL 3. Move NEUTRAL to appropriate daily file 4. Keep GOOD/BAD in MEMORY.md with tags 5. Future entries: always tag in daily files first

path: scripts/add.sh
content: #!/bin/bash
# Add a tagged entry to today's memory file

MEMORY_DIR="${MEMORY_DIR:-$HOME/.openclaw/workspace/memory}"
TODAY=$(date +%Y-%m-%d)
TODAY_FILE="$MEMORY_DIR/$TODAY.md"

usage() {
    echo "Usage: add.sh CATEGORY \"Entry text\""
    echo ""
    echo "Categories: GOOD, BAD, NEUTRAL"
    echo ""
    echo "Examples:"
    echo '  add.sh GOOD "CSV batching prevents duplicates"'
    echo '  add.sh BAD "Bird CLI blocked by X anti-bot"'
    echo '  add.sh NEUTRAL "Day 5 of media plan"'
}

if [[ $# -lt 2 ]]; then
    usage
    exit 1
fi

CATEGORY=$(echo "$1" | tr '[:lower:]' '[:upper:]')
ENTRY="$2"

# Validate category
if [[ "$CATEGORY" != "GOOD" && "$CATEGORY" != "BAD" && "$CATEGORY" != "NEUTRAL" ]]; then
    echo "Error: Category must be GOOD, BAD, or NEUTRAL"
    usage
    exit 1
fi

# Create daily file if needed
if [[ ! -f "$TODAY_FILE" ]]; then
    cat > "$TODAY_FILE" << EOF
# $TODAY - Daily Memory Log

## [GOOD]
- 

## [BAD]
- 

## [NEUTRAL]
- 
EOF
fi

# Check if file has the category sections
if ! grep -q "^## \[GOOD\]" "$TODAY_FILE" 2>/dev/null; then
    # Add category sections at the end
    echo "" >> "$TODAY_FILE"
    echo "## [GOOD]" >> "$TODAY_FILE"
    echo "- " >> "$TODAY_FILE"
    echo "" >> "$TODAY_FILE"
    echo "## [BAD]" >> "$TODAY_FILE"
    echo "- " >> "$TODAY_FILE"
    echo "" >> "$TODAY_FILE"
    echo "## [NEUTRAL]" >> "$TODAY_FILE"
    echo "- " >> "$TODAY_FILE"
fi

# Add entry to the file using sed
TEMP_FILE=$(mktemp)

# Find the section and add entry after the header
awk -v cat="$CATEGORY" -v entry="$ENTRY" '
    BEGIN { in_section = 0 }
    /^## \['"$CATEGORY"'\]/ {
        print
        in_section = 1
        next
    }
    in_section && /^## / {
        in_section = 0
    }
    in_section && /^- $/ {
        print "- ["cat"] "entry
        in_section = 0
        next
    }
    { print }
' "$TODAY_FILE" > "$TEMP_FILE"

mv "$TEMP_FILE" "$TODAY_FILE"

case "$CATEGORY" in
    GOOD)  echo "✅ [GOOD] Added: $ENTRY" ;;
    BAD)   echo "❌ [BAD] Added: $ENTRY" ;;
    NEUTRAL) echo "⚪ [NEUTRAL] Added: $ENTRY" ;;
esac


path: scripts/archive.sh
content: #!/bin/bash
# Archive old NEUTRAL entries (older than 30 days)

MEMORY_DIR="${MEMORY_DIR:-$HOME/.openclaw/workspace/memory}"
ARCHIVE_DIR="$MEMORY_DIR/archive"

CUTOFF_DAYS=30

echo "📦 Memory Archival"
echo "=================="
echo ""
echo "Archiving NEUTRAL entries older than $CUTOFF_DAYS days..."
echo ""

mkdir -p "$ARCHIVE_DIR"

ARCHIVED_COUNT=0

for FILE in "$MEMORY_DIR"/*.md; do
    if [[ ! -f "$FILE" ]]; then
        continue
    fi
    
    FILENAME=$(basename "$FILE")
    
    # Skip archive directory
    if [[ "$FILE" == *"/archive/"* ]]; then
        continue
    fi
    
    # Extract date from filename
    FILE_DATE=$(echo "$FILENAME" | grep -oE '^[0-9]{4}-[0-9]{2}-[0-9]{2}')
    
    if [[ -z "$FILE_DATE" ]]; then
        continue
    fi
    
    # Calculate age
    FILE_EPOCH=$(date -j -f "%Y-%m-%d" "$FILE_DATE" +%s 2>/dev/null || date -d "$FILE_DATE" +%s 2>/dev/null)
    TODAY_EPOCH=$(date +%s)
    AGE_DAYS=$(( (TODAY_EPOCH - FILE_EPOCH) / 86400 ))
    
    if [[ $AGE_DAYS -gt $CUTOFF_DAYS ]]; then
        # Check if file has only NEUTRAL entries (no GOOD/BAD worth keeping)
        HAS_GOOD=$(grep -c "\[GOOD\]" "$FILE" 2>/dev/null || echo "0")
        HAS_BAD=$(grep -c "\[BAD\]" "$FILE" 2>/dev/null || echo "0")
        
        if [[ "$HAS_GOOD" == "0" && "$HAS_BAD" == "0" ]]; then
            mv "$FILE" "$ARCHIVE_DIR/"
            echo "   Archived: $FILENAME ($AGE_DAYS days old)"
            ((ARCHIVED_COUNT++))
        else
            echo "   Kept: $FILENAME (contains GOOD/BAD entries)"
        fi
    fi
done

echo ""
if [[ $ARCHIVED_COUNT -gt 0 ]]; then
    echo "✅ Archived $ARCHIVED_COUNT files to $ARCHIVE_DIR"
else
    echo "ℹ️  No files needed archiving"
fi


path: scripts/cleanup.sh
content: #!/bin/bash
# Cleanup: migrate GOOD/BAD entries from daily files to MEMORY.md

MEMORY_DIR="${MEMORY_DIR:-$HOME/.openclaw/workspace/memory}"
WORKSPACE="${WORKSPACE:-$HOME/.openclaw/workspace}"
MEMORY_FILE="$WORKSPACE/MEMORY.md"

echo "🧹 Memory Cleanup"
echo "================"
echo ""

# Find recent entries (last 14 days)
echo "Checking last 14 days of daily files..."
echo ""

GOOD_ENTRIES=""
BAD_ENTRIES=""

for i in $(seq 0 13); do
    DATE=$(date -v-${i}d +%Y-%m-%d 2>/dev/null || date -d "-$i days" +%Y-%m-%d 2>/dev/null)
    FILE="$MEMORY_DIR/$DATE.md"
    
    if [[ -f "$FILE" ]]; then
        # Extract GOOD entries
        FILE_GOOD=$(grep "\[GOOD\]" "$FILE" 2>/dev/null | sed 's/^[[:space:]]*- //' | sed 's/^[[:space:]]*//')
        if [[ -n "$FILE_GOOD" ]]; then
            GOOD_ENTRIES="$GOOD_ENTRIES
# From $DATE:
$FILE_GOOD"
        fi
        
        # Extract BAD entries
        FILE_BAD=$(grep "\[BAD\]" "$FILE" 2>/dev/null | sed 's/^[[:space:]]*- //' | sed 's/^[[:space:]]*//')
        if [[ -n "$FILE_BAD" ]]; then
            BAD_ENTRIES="$BAD_ENTRIES
# From $DATE:
$FILE_BAD"
        fi
    fi
done

# Display findings
echo "📈 [GOOD] entries found:"
if [[ -n "$GOOD_ENTRIES" ]]; then
    echo "$GOOD_ENTRIES" | head -20
else
    echo "   None found"
fi

echo ""
echo "📉 [BAD] entries found:"
if [[ -n "$BAD_ENTRIES" ]]; then
    echo "$BAD_ENTRIES" | head -20
else
    echo "   None found"
fi

echo ""
echo "💡 Next steps:"
echo "   1. Review entries above"
echo "   2. Add condensed GOOD/BAD sections to MEMORY.md"
echo "   3. Remove duplicates and similar items"
echo "   4. Ensure MEMORY.md stays under 150 lines"
echo ""
echo "   To auto-migrate (use with caution):"
echo "   $(dirname $0)/cleanup.sh --apply"

# If --apply flag, actually modify MEMORY.md
if [[ "$1" == "--apply" ]]; then
    echo ""
    echo "⚠️  Auto-migration not yet implemented - manual review recommended"
    echo "   Please manually update MEMORY.md based on entries above"
fi


path: scripts/daily.sh
content: #!/bin/bash
# Create or open today's memory file

MEMORY_DIR="${MEMORY_DIR:-$HOME/.openclaw/workspace/memory}"
TODAY=$(date +%Y-%m-%d)
TODAY_FILE="$MEMORY_DIR/$TODAY.md"

# Create memory directory if needed
mkdir -p "$MEMORY_DIR"

# If file doesn't exist, create with template
if [[ ! -f "$TODAY_FILE" ]]; then
    cat > "$TODAY_FILE" << EOF
# $TODAY - Daily Memory Log

## [GOOD]
- 

## [BAD]
- 

## [NEUTRAL]
- 

## Notes
- 
EOF
    echo "✅ Created: $TODAY_FILE"
else
    echo "📄 Exists: $TODAY_FILE"
fi

echo ""
echo "File location: $TODAY_FILE"


path: scripts/search.sh
content: #!/bin/bash
# Search through all memory files with categorization filters

MEMORY_DIR="${MEMORY_DIR:-$HOME/.openclaw/workspace/memory}"
WORKSPACE="${WORKSPACE:-$HOME/.openclaw/workspace}"

usage() {
    echo "Usage: search.sh [OPTIONS] QUERY"
    echo ""
    echo "Search memory files with categorization"
    echo ""
    echo "Options:"
    echo "  --good       Search only [GOOD] entries"
    echo "  --bad        Search only [BAD] entries"
    echo "  --neutral    Search only [NEUTRAL] entries"
    echo "  --recent N   Search only last N days (default: 7)"
    echo "  --all        Search all memory (default)"
    echo "  -h, --help   Show this help"
    echo ""
    echo "Examples:"
    echo "  search.sh \"duplicate posting\""
    echo "  search.sh --good \"CSV format\""
    echo "  search.sh --recent 3 \"cron job\""
}

# Parse arguments
CATEGORY=""
RECENT_DAYS=""
QUERY=""

while [[ $# -gt 0 ]]; do
    case $1 in
        --good)
            CATEGORY="GOOD"
            shift
            ;;
        --bad)
            CATEGORY="BAD"
            shift
            ;;
        --neutral)
            CATEGORY="NEUTRAL"
            shift
            ;;
        --recent)
            RECENT_DAYS="${2:-7}"
            shift 2
            ;;
        --all)
            CATEGORY=""
            shift
            ;;
        -h|--help)
            usage
            exit 0
            ;;
        *)
            QUERY="$1"
            shift
            ;;
    esac
done

if [[ -z "$QUERY" ]]; then
    echo "Error: No search query provided"
    usage
    exit 1
fi

echo "🔍 Searching memory for: $QUERY"
if [[ -n "$CATEGORY" ]]; then
    echo "   Category: [$CATEGORY]"
fi
if [[ -n "$RECENT_DAYS" ]]; then
    echo "   Time range: last $RECENT_DAYS days"
fi
echo ""

# Build grep pattern
if [[ -n "$CATEGORY" ]]; then
    PATTERN="\[$CATEGORY\]"
else
    PATTERN=".*"
fi

# Find files to search
FILES_TO_SEARCH=""

# Always include MEMORY.md
if [[ -f "$WORKSPACE/MEMORY.md" ]]; then
    FILES_TO_SEARCH="$WORKSPACE/MEMORY.md"
fi

# Add daily files
if [[ -n "$RECENT_DAYS" ]]; then
    # Recent files only
    for i in $(seq 0 $((RECENT_DAYS - 1))); do
        DATE=$(date -v-${i}d +%Y-%m-%d 2>/dev/null || date -d "-$i days" +%Y-%m-%d 2>/dev/null)
        FILE="$MEMORY_DIR/$DATE.md"
        if [[ -f "$FILE" ]]; then
            FILES_TO_SEARCH="$FILES_TO_SEARCH $FILE"
        fi
    done
else
    # All daily files
    if [[ -d "$MEMORY_DIR" ]]; then
        FILES_TO_SEARCH="$FILES_TO_SEARCH $MEMORY_DIR/*.md"
    fi
fi

# Perform search
if [[ -n "$FILES_TO_SEARCH" ]]; then
    RESULTS=$(grep -r -i -n "$QUERY" $FILES_TO_SEARCH 2>/dev/null | grep -i "$PATTERN" | head -20)
    
    if [[ -n "$RESULTS" ]]; then
        echo "$RESULTS" | while read -r line; do
            # Extract category for color coding
            if echo "$line" | grep -q "\[GOOD\]"; then
                echo "✅ $line"
            elif echo "$line" | grep -q "\[BAD\]"; then
                echo "❌ $line"
            elif echo "$line" | grep -q "\[NEUTRAL\]"; then
                echo "⚪ $line"
            else
                echo "   $line"
            fi
        done
        echo ""
        echo "Found $(echo "$RESULTS" | wc -l | tr -d ' ') results"
    else
        echo "No results found"
    fi
else
    echo "No memory files found"
fi


Security scan verdicts — ClawScan: clean | static analysis: clean | VirusTotal: suspicious | SkillSpector: suspicious (MEDIUM)