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

TailClaude: Open Source Web UI for Accessing Claude Code Sessions from Mobile and Browser
TailClaude is an open source web UI that lets you access and continue Claude Code sessions from your phone or any browser in under a minute using Tailscale. The project was built with Claude Code assistance for scaffolding, SSE streaming backend, mobile-first chat UI, and QR code integration.

Context Mode MCP Server Cuts Claude Code Context Usage by 98%
Context Mode is an MCP server that reduces Claude Code context consumption from 315 KB to 5.4 KB by sandboxing tool outputs. It supports 10 language runtimes and includes a knowledge base with full-text search.

Developer Tests Qwen3.5 27B vs Larger Models for Local Coding Tasks
A developer tested multiple Qwen3.5 and Nemotron models, finding Qwen3.5-27B-GGUF:UD-Q6_K_XL performs well for development tasks on existing 2x RTX 3090 hardware, with 803 pp and 25 tg/s at 256k context on vast.ai.

SIDJUA v0.9.7: Open Source Multi-Agent AI with Pre-Action Governance Enforcement
SIDJUA v0.9.7 is a self-hosted, open source multi-agent AI framework that enforces governance rules before agents act, blocking unauthorized actions like budget overruns or scope violations. It supports multiple LLM providers, runs on 4GB RAM, and includes a desktop GUI built with Tauri v2.