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

Repowise: Pre-computed codebase context for Claude Code cuts token usage and task time in half
Repowise indexes your codebase into four layers (dependency graph, git signals, doc wiki, ADRs) and exposes eight MCP tools to Claude Code, reducing a 30-file archaeology session to 5 MCP calls and 2 minutes.

Colony: A Local-First Coordination Layer That Cuts Multi-Agent Handoff Tokens from 30K to 400
Colony is a local-first coordination substrate that reduces multi-agent handoff costs from ~30,000 tokens to ~400 by replacing context replay with compact observations stored in SQLite.

How I built a 3D scroll website in 2 hours using Claude Code and Veo
A developer built a 3D scroll website in 2 hours using Claude Code, Veo video generation, and a custom 'video to website' skill. Full code and live demo shared.

Six open-source tools that address OpenClaw's security, cost, and complexity issues
A developer tested six community tools to solve OpenClaw's security gaps flagged by Cisco, spiraling costs, and complex setup. ClawSec provides security scanning and integrity verification, Antfarm enables deterministic multi-agent workflows, and LanceDB Pro improves memory retrieval with hybrid vector search.