Back to Skills
    šŸ¦ž

    backup

    Backup and restore openclaw configuration, skills, commands, and settings.

    By @jordanprater
    View on GitHub
    SKILL.md
    ---
    name: backup
    description: Backup and restore openclaw configuration, skills, commands, and settings. Sync across devices, version control with git, automate backups, and migrate to new machines.
    metadata: {"openclaw":{"emoji":"šŸ’¾","requires":{"bins":["git","tar","rsync"],"env":[]}}}
    ---
    
    # OpenClaw Backup Skill
    
    Backup, restore, and sync your OpenClaw configuration across devices directly from openclaw.
    
    ## Overview
    
    This skill helps you:
    - Backup all openclaw data and settings
    - Restore from backups
    - Sync between multiple machines
    - Version control your configuration
    - Automate backup routines
    - Migrate to new devices
    
    ## openclaw Directory Structure
    
    ### Key Locations
    
    ```
    ~/.claude/                    # Main openclaw directory
    ā”œā”€ā”€ settings.json             # Global settings
    ā”œā”€ā”€ settings.local.json       # Local overrides (machine-specific)
    ā”œā”€ā”€ projects.json             # Project configurations
    ā”œā”€ā”€ skills/                   # Your custom skills
    │   ā”œā”€ā”€ skill-name/
    │   │   ā”œā”€ā”€ SKILL.md
    │   │   └── supporting-files/
    │   └── another-skill/
    ā”œā”€ā”€ commands/                 # Custom slash commands (legacy)
    │   └── command-name.md
    ā”œā”€ā”€ contexts/                 # Saved contexts
    ā”œā”€ā”€ templates/                # Response templates
    └── mcp/                      # MCP server configurations
        └── servers.json
    
    ~/projects/                   # Your projects (optional backup)
    ā”œā”€ā”€ project-1/
    │   └── .claude/              # Project-specific config
    │       ā”œā”€ā”€ settings.json
    │       └── skills/
    └── project-2/
    ```
    
    ### What to Backup
    
    ```
    ESSENTIAL (Always backup):
    āœ“ ~/.claude/skills/           # Custom skills
    āœ“ ~/.claude/commands/         # Custom commands
    āœ“ ~/.claude/settings.json     # Global settings
    āœ“ ~/.claude/mcp/              # MCP configurations
    
    RECOMMENDED (Usually backup):
    āœ“ ~/.claude/contexts/         # Saved contexts
    āœ“ ~/.claude/templates/        # Templates
    āœ“ Project .claude/ folders    # Project configs
    
    OPTIONAL (Case by case):
    ā—‹ ~/.claude/settings.local.json  # Machine-specific
    ā—‹ Cache directories              # Can be rebuilt
    ā—‹ Log files                      # Usually not needed
    ```
    
    ## Quick Backup Commands
    
    ### Full Backup
    
    ```bash
    # Create timestamped backup
    BACKUP_DIR="$HOME/openclaw-backups"
    TIMESTAMP=$(date +%Y%m%d_%H%M%S)
    BACKUP_NAME="openclaw_backup_$TIMESTAMP"
    
    mkdir -p "$BACKUP_DIR"
    
    tar -czvf "$BACKUP_DIR/$BACKUP_NAME.tar.gz" \
      -C "$HOME" \
      .claude/skills \
      .claude/commands \
      .claude/settings.json \
      .claude/mcp \
      .claude/contexts \
      .claude/templates \
      2>/dev/null
    
    echo "Backup created: $BACKUP_DIR/$BACKUP_NAME.tar.gz"
    ```
    
    ### Quick Skills-Only Backup
    
    ```bash
    # Backup just skills
    tar -czvf ~/openclaw_skills_$(date +%Y%m%d).tar.gz \
      -C "$HOME" .claude/skills .claude/commands
    ```
    
    ### Restore from Backup
    
    ```bash
    # Restore full backup
    BACKUP_FILE="$HOME/openclaw-backups/openclaw_backup_20260129.tar.gz"
    
    # Preview contents first
    tar -tzvf "$BACKUP_FILE"
    
    # Restore (will overwrite existing)
    tar -xzvf "$BACKUP_FILE" -C "$HOME"
    
    echo "Restore complete!"
    ```
    
    ## Backup Script
    
    ### Full-Featured Backup Script
    
    ```bash
    #!/bin/bash
    # openclaw-backup.sh - Comprehensive openclaw backup tool
    
    set -e
    
    # Configuration
    BACKUP_ROOT="${openclaw_BACKUP_DIR:-$HOME/openclaw-backups}"
    CLAUDE_DIR="$HOME/.claude"
    MAX_BACKUPS=10  # Keep last N backups
    TIMESTAMP=$(date +%Y%m%d_%H%M%S)
    
    # Colors
    RED='\033[0;31m'
    GREEN='\033[0;32m'
    YELLOW='\033[1;33m'
    NC='\033[0m'
    
    log_info() { echo -e "${GREEN}[INFO]${NC} $1"; }
    log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
    log_error() { echo -e "${RED}[ERROR]${NC} $1"; }
    
    # Check if openclaw directory exists
    check_claude_dir() {
        if [ ! -d "$CLAUDE_DIR" ]; then
            log_error "openclaw directory not found: $CLAUDE_DIR"
            exit 1
        fi
    }
    
    # Create backup
    create_backup() {
        local backup_type="${1:-full}"
        local backup_name="openclaw_${backup_type}_${TIMESTAMP}"
        local backup_path="$BACKUP_ROOT/$backup_name.tar.gz"
        
        mkdir -p "$BACKUP_ROOT"
        
        log_info "Creating $backup_type backup..."
        
        case $backup_type in
            full)
                tar -czvf "$backup_path" \
                    -C "$HOME" \
                    .claude/skills \
                    .claude/commands \
                    .claude/settings.json \
                    .claude/settings.local.json \
                    .claude/projects.json \
                    .claude/mcp \
                    .claude/contexts \
                    .claude/templates \
                    2>/dev/null || true
                ;;
            skills)
                tar -czvf "$backup_path" \
                    -C "$HOME" \
                    .claude/skills \
                    .claude/commands \
                    2>/dev/null || true
                ;;
            settings)
                tar -czvf "$backup_path" \
                    -C "$HOME" \
                    .claude/settings.json \
                    .claude/settings.local.json \
                    .claude/mcp \
                    2>/dev/null || true
                ;;
            *)
                log_error "Unknown backup type: $backup_type"
                exit 1
                ;;
        esac
        
        if [ -f "$backup_path" ]; then
            local size=$(du -h "$backup_path" | cut -f1)
            log_info "Backup created: $backup_path ($size)"
        else
            log_error "Backup failed!"
            exit 1
        fi
    }
    
    # List backups
    list_backups() {
        log_info "Available backups in $BACKUP_ROOT:"
        echo ""
        
        if [ -d "$BACKUP_ROOT" ]; then
            ls -lh "$BACKUP_ROOT"/*.tar.gz 2>/dev/null | \
                awk '{print $9, $5, $6, $7, $8}' || \
                echo "No backups found."
        else
            echo "Backup directory doesn't exist."
        fi
    }
    
    # Restore backup
    restore_backup() {
        local backup_file="$1"
        
        if [ -z "$backup_file" ]; then
            log_error "Please specify backup file"
            list_backups
            exit 1
        fi
        
        if [ ! -f "$backup_file" ]; then
            # Try relative path in backup dir
            backup_file="$BACKUP_ROOT/$backup_file"
        fi
        
        if [ ! -f "$backup_file" ]; then
            log_error "Backup file not found: $backup_file"
            exit 1
        fi
        
        log_warn "This will overwrite existing configuration!"
        read -p "Continue? (y/N) " confirm
        
        if [ "$confirm" != "y" ] && [ "$confirm" != "Y" ]; then
            log_info "Restore cancelled."
            exit 0
        fi
        
        log_info "Restoring from: $backup_file"
        tar -xzvf "$backup_file" -C "$HOME"
        log_info "Restore complete!"
    }
    
    # Clean old backups
    cleanup_backups() {
        log_info "Cleaning old backups (keeping last $MAX_BACKUPS)..."
        
        cd "$BACKUP_ROOT" 2>/dev/null || return
        
        local count=$(ls -1 *.tar.gz 2>/dev/null | wc -l)
        
        if [ "$count" -gt "$MAX_BACKUPS" ]; then
            local to_delete=$((count - MAX_BACKUPS))
            ls -1t *.tar.gz | tail -n "$to_delete" | xargs rm -v
            log_info "Removed $to_delete old backup(s)"
        else
            log_info "No cleanup needed ($count backups)"
        fi
    }
    
    # Show backup stats
    show_stats() {
        log_info "openclaw Backup Statistics"
        echo ""
        
        echo "=== Directory Sizes ==="
        du -sh "$CLAUDE_DIR"/skills 2>/dev/null || echo "Skills: N/A"
        du -sh "$CLAUDE_DIR"/commands 2>/dev/null || echo "Commands: N/A"
        du -sh "$CLAUDE_DIR"/mcp 2>/dev/null || echo "MCP: N/A"
        du -sh "$CLAUDE_DIR" 2>/dev/null || echo "Total: N/A"
        
        echo ""
        echo "=== Skills Count ==="
        find "$CLAUDE_DIR/skills" -name "SKILL.md" 2>/dev/null | wc -l | xargs echo "Skills:"
        find "$CLAUDE_DIR/commands" -name "*.md" 2>/dev/null | wc -l | xargs echo "Commands:"
        
        echo ""
        echo "=== Backup Directory ==="
        if [ -d "$BACKUP_ROOT" ]; then
            du -sh "$BACKUP_ROOT"
            ls -1 "$BACKUP_ROOT"/*.tar.gz 2>/dev/null | wc -l | xargs echo "Backup files:"
        else
            echo "No backups yet"
        fi
    }
    
    # Usage
    usage() {
        cat << EOF
    openclaw Backup Tool
    
    Usage: $(basename $0) <command> [options]
    
    Commands:
        backup [type]   Create backup (types: full, skills, settings)
        restore <file>  Restore from backup file
        list            List available backups
        cleanup         Remove old backups (keep last $MAX_BACKUPS)
        stats           Show backup statistics
        help            Show this help
    
    Examples:
        $(basename $0) backup              # Full backup
        $(basename $0) backup skills       # Skills only
        $(basename $0) restore latest.tar.gz
        $(basename $0) list
        $(basename $0) cleanup
    
    Environment:
        openclaw_BACKUP_DIR    Backup directory (default: ~/openclaw-backups)
    
    EOF
    }
    
    # Main
    main() {
        check_claude_dir
        
        case "${1:-help}" in
            backup)
                create_backup "${2:-full}"
                ;;
            restore)
                restore_backup "$2"
                ;;
            list)
                list_backups
                ;;
            cleanup)
                cleanup_backups
                ;;
            stats)
                show_stats
                ;;
            help|--help|-h)
                usage
                ;;
            *)
                log_error "Unknown command: $1"
                usage
                exit 1
                ;;
        esac
    }
    
    main "$@"
    ```
    
    ### Save and Use
    
    ```bash
    # Save script
    cat > ~/.local/bin/openclaw-backup << 'SCRIPT'
    # Paste script content here
    SCRIPT
    
    chmod +x ~/.local/bin/openclaw-backup
    
    # Usage
    openclaw-backup backup          # Full backup
    openclaw-backup backup skills   # Skills only
    openclaw-backup list            # List backups
    openclaw-backup restore <file>  # Restore
    ```
    
    ## Git Version Control
    
    ### Initialize Git Repo
    
    ```bash
    cd ~/.claude
    
    # Initialize git
    git init
    
    # Create .gitignore
    cat > .gitignore << 'EOF'
    # Machine-specific settings
    settings.local.json
    
    # Cache and temp files
    cache/
    *.tmp
    *.log
    
    # Large files
    *.tar.gz
    *.zip
    
    # Sensitive data (if any)
    *.pem
    *.key
    credentials/
    EOF
    
    # Initial commit
    git add .
    git commit -m "Initial openclaw configuration backup"
    ```
    
    ### Push to Remote
    
    ```bash
    # Add remote (GitHub, GitLab, etc)
    git remote add origin git@github.com:username/openclaw-config.git
    
    # Push
    git push -u origin main
    ```
    
    ### Daily
    
    ... (truncated)