Claude Code Session Data Loss: Backup Script for Windows & Mac

Multiple users on r/ClaudeAI report that Claude Code silently loses session data — the session title remains in the sidebar, but clicking it reveals an empty transcript. No warning, no error, no recovery. This appears to happen during context compression, unexpected exits, or storage-layer issues.
The Backup Solution
A community-written script backs up all Claude Code data (sessions, projects, plans, drafts, memory) from ~/.claude to a separate folder, runs daily via Task Scheduler (Windows) or launchd (Mac), and retains 7 days of rolling backups.
Windows (PowerShell + Task Scheduler)
Create the backup folder:
mkdir C:\Users\%USERNAME%\ClaudeBackupsSave the following as backup-claude-sessions.ps1 in that folder:
$ErrorActionPreference = "Stop"
$source = "$env:USERPROFILE\.claude"
$backupRoot = "$env:USERPROFILE\ClaudeBackups"
$logFile = Join-Path $backupRoot "backup.log"
$keepDays = 7
$timestamp = Get-Date -Format "yyyy-MM-dd_HHmmss"
$backupDir = Join-Path $backupRoot $timestamp
$dirs = @("sessions", "projects", "plans", "drafts", "memory")
function Write-Log($msg) {
$line = "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') - $msg"
Add-Content -Path $logFile -Value $line -Encoding utf8
}
try {
Write-Log "=== Backup started ==="
New-Item -ItemType Directory -Path $backupDir -Force | Out-Null
foreach ($d in $dirs) {
$src = Join-Path $source $d
if (Test-Path $src) {
$dst = Join-Path $backupDir $d
Copy-Item -Path $src -Destination $dst -Recurse -Force
$count = (Get-ChildItem $dst -Recurse -File -ErrorAction SilentlyContinue | Measure-Object).Count
Write-Log " Copied $d ($count files)"
} else {
Write-Log " Skipped $d (not found)"
}
}
$size = (Get-ChildItem $backupDir -Recurse -File | Measure-Object -Property Length -Sum).Sum
Write-Log " Total backup size: $([math]::Round($size/1MB, 2)) MB"
$cutoff = (Get-Date).AddDays(-$keepDays)
Get-ChildItem $backupRoot -Directory | Where-Object { $.Name -match '^\d{4}-\d{2}-\d{2}\d{6}$' -and $.CreationTime -lt $cutoff } | ForEach-Object {
Remove-Item $.FullName -Recurse -Force -Confirm:$false
Write-Log " Rotated old backup: $($.Name)"
}
Write-Log "=== Backup completed successfully ==="
} catch {
Write-Log "!!! BACKUP FAILED: $"
exit 1
}
Create install-schedule.ps1 and run as Administrator once:
$action = New-ScheduledTaskAction -Execute "powershell.exe"
-Argument "-ExecutionPolicy Bypass -WindowStyle Hidden -File "$env:USERPROFILE\ClaudeBackups\backup-claude-sessions.ps1""
$trigger = New-ScheduledTaskTrigger -Daily -At 8:00AM
$settings = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries
-DontStopIfGoingOnBatteries -StartWhenAvailable Register-ScheduledTask
-TaskName "ClaudeSessionsBackup" -Action $action
-Trigger $trigger -Settings $settings
-Description "Daily backup of Claude Code sessions" `
-RunLevel Limited
Write-Host "Done! Runs daily at 8:00 AM." -ForegroundColor GreenRun the installer:
powershell -ExecutionPolicy Bypass -File "C:\Users%USERNAME%\ClaudeBackups\install-schedule.ps1"Mac (launchd + shell script)
Create the backup folder:
mkdir -p /ClaudeBackupsSave as /ClaudeBackups/backup-claude-sessions.sh:
#!/bin/bash
set -euo pipefail
SOURCE="$HOME/.claude"
BACKUP_ROOT="$HOME/ClaudeBackups"
LOG_FILE="$BACKUP_ROOT/backup.log"
KEEP_DAYS=7
TIMESTAMP=$(date +"%Y-%m-%d_%H%M%S")
BACKUP_DIR="$BACKUP_ROOT/$TIMESTAMP"
DIRS=("sessions" "projects" "plans" "drafts" "memory")
log() { echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" >> "$LOG_FILE"; }
log "=== Backup started ==="
mkdir -p "$BACKUP_DIR"
for d in "${DIRS[@]}"; do
src="$SOURCE/$d"
if [ -d "$src" ]; then
cp -R "$src" "$BACKUP_DIR/$d"
count=$(find "$BACKUP_DIR/$d" -type f | wc -l | tr -d ' ')
log " Copied $d ($count files)"
else
log " Skipped $d (not found)"
fi
done
size=$(du -sb "$BACKUP_DIR" | cut -f1)
log " Total backup size: $(echo "scale=2; $size/1048576" | bc) MB"
find "$BACKUP_ROOT" -maxdepth 1 -type d -name "????-??-??_??????" -mtime +$KEEP_DAYS -exec rm -rf {} + -exec log " Rotated old backup: {}" ;
log "=== Backup completed successfully ==="Make executable and schedule via launchd (see original post for plist setup).
The script runs completely independently of Claude Code, so even if Claude crashes or loses data, backups are preserved. It logs each run to backup.log for verification.
📖 Read the full source: r/ClaudeAI
👀 See Also

Claude Code Memory Leak Fix for Linux Homelabs
A developer discovered Claude Code has a severe memory leak in glibc malloc that consumed 400GB RAM and crashed their Proxmox homelab, then created a two-tier guard solution with LD_PRELOAD shim and watchdog.

Claude-Code v2.1.111 adds Opus 4.7 xhigh effort, /ultrareview, and PowerShell tool
Claude-Code v2.1.111 introduces the Opus 4.7 xhigh effort level between high and max, adds the /ultrareview command for cloud-based multi-agent code reviews, and begins rolling out PowerShell tool support on Windows. The update also includes interactive /effort controls, auto theme matching, and numerous bug fixes.

Ssemble MCP Server Enables Claude to Generate Short-Form Videos from YouTube
A new MCP server for Ssemble AI Clipping allows Claude to create TikTok/Reels/Shorts-style videos from YouTube URLs with AI-generated clips, caption templates, music tracks, and overlays. Setup involves adding configuration to Claude Desktop or using a hosted endpoint.

Claude Cowork mode explained: file-level task execution vs chat and code modes
Claude's Cowork mode operates inside a chosen folder to perform file-level tasks like organizing messy folders, extracting structured data from screenshots, and combining scattered notes into structured documents.