Skip to content

Instantly share code, notes, and snippets.

@hbt
Last active July 24, 2025 22:17
Show Gist options
  • Save hbt/af7fd4b18988cf3ed8277dc4611c5baf to your computer and use it in GitHub Desktop.
Save hbt/af7fd4b18988cf3ed8277dc4611c5baf to your computer and use it in GitHub Desktop.

Claude Code Conversation Backup Solution

⚠️ WARNING: Claude Code automatically deletes conversation files after 30 days!

This backup solution prevents permanent loss of your Claude Code conversations by automatically committing them to a git repository every hour.

🚨 The Problem

Claude Code stores conversation history in .jsonl files but automatically purges files after 30 days to manage disk space. This means:

  • All conversations older than 30 days are permanently deleted
  • No built-in backup mechanism exists
  • Years of valuable conversation history can be lost without warning

πŸ“… Timeline Discovery

Through git log analysis, we discovered:

  • June 17, 2025: Claude Code purchased and usage began
  • June 25, 2025: Initial backup system created (smart move!)
  • June 30, 2025: First file deletion detected (manual cleanup of fork experiments)
  • July 17, 2025: Mass automatic deletions began (exactly 30 days after initial usage)
  • Pattern: Claude Code automatically deletes files exactly 30 days after their git commit date

πŸ’‘ The Solution

This backup system:

  1. Runs every hour via cron
  2. Commits any changes to conversation files with timestamps
  3. Preserves complete history in git even after Claude Code deletes files
  4. Logs all activity for monitoring
  5. Requires minimal setup and maintenance

πŸ“ Files Included

  • backup-conversations.sh - The backup script
  • README.md - This documentation
  • Installation and monitoring instructions below

πŸ”§ Installation

1. Setup the backup directory

# Navigate to your Claude Code projects directory
cd ~/.claude/projects

# Initialize git repository if not already done
git init
git add .
git commit -m "Initial backup of Claude Code conversations"

2. Install the backup script

# Copy the backup script to your .claude directory
cp backup-conversations.sh ~/.claude/
chmod +x ~/.claude/backup-conversations.sh

3. Setup cron job

# Edit your crontab
crontab -e

# Add this line to run backup every hour
0 * * * * /home/yourusername/.claude/backup-conversations.sh >> /home/yourusername/.claude/backup.log 2>&1

Replace yourusername with your actual username!

4. Verify setup

# Check if cron job was added
crontab -l

# Test the script manually
~/.claude/backup-conversations.sh

# Check the log
tail -f ~/.claude/backup.log

πŸ“Š Monitoring & Verification

Check backup activity

# View recent backup log entries
tail -20 ~/.claude/backup.log

# See git commit history
cd ~/.claude/projects
git log --oneline -10

Verify files are being backed up

# Check if new conversation files are being committed
git status

# See what files were in recent commits
git show --name-only HEAD

Recovery verification

# List all backed up conversations (even deleted ones)
git log --name-status | grep "\.jsonl$" | head -20

# Restore a deleted conversation file
git show COMMIT_HASH:path/to/file.jsonl > restored-conversation.jsonl

πŸ” How It Works

The script:

  1. Changes to ~/.claude/projects directory
  2. Checks if there are uncommitted changes using git diff-index
  3. If changes exist:
    • Stages all files with git add -A
    • Creates commit with timestamp and file count
    • Logs successful backup
  4. If no changes, logs "no changes to backup"

πŸ“ˆ Expected Log Output

2025-07-24 17:00:01: Conversations backed up
2025-07-24 18:00:01: No changes to backup
2025-07-24 19:00:01: Conversations backed up

πŸ› οΈ Troubleshooting

Cron not running?

# Check if cron service is running
systemctl status cron

# Check cron logs
journalctl -u cron

Script not executing?

# Verify script permissions
ls -la ~/.claude/backup-conversations.sh

# Test script manually
bash -x ~/.claude/backup-conversations.sh

Git issues?

# Check git configuration
cd ~/.claude/projects
git config --list

# Initialize if needed
git init
git config user.email "[email protected]"
git config user.name "Your Name"

πŸ’Ύ Storage Considerations

  • Each conversation file is typically 1-50KB
  • Git compresses history efficiently
  • Expect ~1-10MB growth per month depending on usage
  • Old commits can be cleaned up if storage becomes an issue

πŸ”’ Security Notes

  • Backup files contain your conversation history
  • Ensure proper file permissions on backup directory
  • Consider encrypting backups if sharing systems
  • Never commit the backup repository to public repositories

🀝 Contributing

Found this helpful? Please share with other Claude Code users to prevent conversation loss!

πŸ“œ License

Feel free to use, modify, and share this backup solution.


Created by a Claude Code user who learned about the 30-day purge the hard way!

#!/bin/bash
# Backup script for Claude Code conversation files
# Automatically commits changes to git repository with timestamp
cd /home/hassen/.claude/projects
# Check if working directory has uncommitted changes
if ! git diff-index --quiet HEAD --; then
# Stage all modified and new files
git add -A
# Create commit with current timestamp and file count
git commit -m "Auto-backup: $(date '+%Y-%m-%d %H:%M:%S') - $(git status --porcelain | wc -l) files changed"
# Log successful backup
echo "$(date '+%Y-%m-%d %H:%M:%S'): Conversations backed up"
else
# Log when no backup needed
echo "$(date '+%Y-%m-%d %H:%M:%S'): No changes to backup"
fi
#!/bin/bash
# Claude Code Conversation Backup - Installation Script
# Automates the setup of hourly conversation backups
set -e
echo "πŸ”§ Claude Code Conversation Backup Installer"
echo "============================================="
# Check if we're in the right directory
if [[ ! -f "backup-conversations.sh" ]]; then
echo "❌ Error: backup-conversations.sh not found in current directory"
echo "Please run this script from the directory containing backup-conversations.sh"
exit 1
fi
# Get user's home directory
USER_HOME="${HOME}"
CLAUDE_DIR="${USER_HOME}/.claude"
PROJECTS_DIR="${CLAUDE_DIR}/projects"
BACKUP_SCRIPT="${CLAUDE_DIR}/backup-conversations.sh"
LOG_FILE="${CLAUDE_DIR}/backup.log"
echo "πŸ“ Setting up directories..."
# Create .claude directory if it doesn't exist
if [[ ! -d "$CLAUDE_DIR" ]]; then
echo "Creating $CLAUDE_DIR"
mkdir -p "$CLAUDE_DIR"
fi
# Check if projects directory exists
if [[ ! -d "$PROJECTS_DIR" ]]; then
echo "❌ Error: Claude Code projects directory not found at $PROJECTS_DIR"
echo "Please make sure Claude Code is installed and has been run at least once."
exit 1
fi
echo "πŸ“„ Installing backup script..."
# Copy backup script
cp backup-conversations.sh "$BACKUP_SCRIPT"
chmod +x "$BACKUP_SCRIPT"
echo "πŸ“¦ Initializing git repository..."
# Initialize git repo in projects directory
cd "$PROJECTS_DIR"
if [[ ! -d ".git" ]]; then
git init
# Set git config if not already set
if ! git config user.email > /dev/null 2>&1; then
echo "βš™οΈ Setting up git configuration..."
read -p "Enter your email for git commits: " email
read -p "Enter your name for git commits: " name
git config user.email "$email"
git config user.name "$name"
fi
# Initial commit
git add .
git commit -m "Initial backup of Claude Code conversations"
echo "βœ… Initial git repository created and committed"
else
echo "βœ… Git repository already exists"
fi
echo "⏰ Setting up cron job..."
# Create cron job entry
CRON_ENTRY="0 * * * * $BACKUP_SCRIPT >> $LOG_FILE 2>&1"
# Check if cron job already exists
if crontab -l 2>/dev/null | grep -q "$BACKUP_SCRIPT"; then
echo "βœ… Cron job already exists"
else
# Add cron job
(crontab -l 2>/dev/null; echo "$CRON_ENTRY") | crontab -
echo "βœ… Cron job added - backups will run every hour"
fi
echo "πŸ§ͺ Testing backup script..."
# Test the backup script
if "$BACKUP_SCRIPT"; then
echo "βœ… Backup script test successful"
else
echo "❌ Backup script test failed"
exit 1
fi
echo ""
echo "πŸŽ‰ Installation Complete!"
echo "========================"
echo ""
echo "πŸ“‹ Summary:"
echo " β€’ Backup script: $BACKUP_SCRIPT"
echo " β€’ Projects directory: $PROJECTS_DIR"
echo " β€’ Log file: $LOG_FILE"
echo " β€’ Cron schedule: Every hour at minute 0"
echo ""
echo "πŸ“Š Monitoring commands:"
echo " β€’ View recent logs: tail -20 $LOG_FILE"
echo " β€’ Check git history: cd $PROJECTS_DIR && git log --oneline -10"
echo " β€’ Verify cron job: crontab -l | grep backup-conversations"
echo ""
echo "⚠️ Remember: Your conversations are now being backed up every hour!"
echo "πŸ“ All conversation history will be preserved in git even after Claude Code's 30-day purge."
#!/bin/bash
# Claude Code Conversation Backup - Verification Script
# Helps verify that the backup system is working correctly
set -e
USER_HOME="${HOME}"
CLAUDE_DIR="${USER_HOME}/.claude"
PROJECTS_DIR="${CLAUDE_DIR}/projects"
BACKUP_SCRIPT="${CLAUDE_DIR}/backup-conversations.sh"
LOG_FILE="${CLAUDE_DIR}/backup.log"
echo "πŸ” Claude Code Backup Verification"
echo "=================================="
echo ""
# Check if backup script exists
echo "πŸ“„ Checking backup script..."
if [[ -f "$BACKUP_SCRIPT" ]]; then
echo "βœ… Backup script found: $BACKUP_SCRIPT"
if [[ -x "$BACKUP_SCRIPT" ]]; then
echo "βœ… Backup script is executable"
else
echo "❌ Backup script is not executable"
echo " Fix with: chmod +x $BACKUP_SCRIPT"
fi
else
echo "❌ Backup script not found at $BACKUP_SCRIPT"
echo " Please run the installer first"
exit 1
fi
echo ""
# Check projects directory and git
echo "πŸ“ Checking projects directory..."
if [[ -d "$PROJECTS_DIR" ]]; then
echo "βœ… Projects directory found: $PROJECTS_DIR"
cd "$PROJECTS_DIR"
if [[ -d ".git" ]]; then
echo "βœ… Git repository initialized"
# Check recent commits
commit_count=$(git rev-list --count HEAD 2>/dev/null || echo "0")
echo "πŸ“Š Total commits: $commit_count"
if [[ $commit_count -gt 0 ]]; then
echo "πŸ“… Recent commits:"
git log --oneline -5 | sed 's/^/ /'
fi
else
echo "❌ Git repository not initialized"
echo " Run: cd $PROJECTS_DIR && git init"
fi
else
echo "❌ Projects directory not found: $PROJECTS_DIR"
echo " Make sure Claude Code is installed and has been run"
exit 1
fi
echo ""
# Check cron job
echo "⏰ Checking cron job..."
if crontab -l 2>/dev/null | grep -q "$BACKUP_SCRIPT"; then
echo "βœ… Cron job found:"
crontab -l | grep "$BACKUP_SCRIPT" | sed 's/^/ /'
else
echo "❌ Cron job not found"
echo " Add with: (crontab -l 2>/dev/null; echo '0 * * * * $BACKUP_SCRIPT >> $LOG_FILE 2>&1') | crontab -"
fi
echo ""
# Check log file
echo "πŸ“ Checking backup logs..."
if [[ -f "$LOG_FILE" ]]; then
echo "βœ… Log file found: $LOG_FILE"
log_lines=$(wc -l < "$LOG_FILE" 2>/dev/null || echo "0")
echo "πŸ“Š Log entries: $log_lines"
if [[ $log_lines -gt 0 ]]; then
echo "πŸ“… Recent log entries:"
tail -5 "$LOG_FILE" | sed 's/^/ /'
# Check for recent activity
recent_backup=$(grep "Conversations backed up" "$LOG_FILE" | tail -1 || echo "")
if [[ -n "$recent_backup" ]]; then
echo "βœ… Recent backup activity detected"
else
recent_no_changes=$(grep "No changes to backup" "$LOG_FILE" | tail -1 || echo "")
if [[ -n "$recent_no_changes" ]]; then
echo "βœ… Recent backup check (no changes needed)"
else
echo "⚠️ No recent backup activity detected"
fi
fi
fi
else
echo "⚠️ Log file not found (may not have run yet): $LOG_FILE"
fi
echo ""
# Check conversation files
echo "πŸ’¬ Checking conversation files..."
cd "$PROJECTS_DIR"
jsonl_count=$(find . -name "*.jsonl" -type f | wc -l)
echo "πŸ“Š Current conversation files: $jsonl_count"
if [[ $jsonl_count -gt 0 ]]; then
echo "πŸ“… Newest conversation files:"
find . -name "*.jsonl" -type f -printf "%T@ %TY-%Tm-%Td %TH:%TM %p\n" | sort -nr | head -3 | sed 's/^[0-9.]* / /'
fi
echo ""
# Test backup manually
echo "πŸ§ͺ Testing backup script..."
if "$BACKUP_SCRIPT"; then
echo "βœ… Manual backup test successful"
else
echo "❌ Manual backup test failed"
exit 1
fi
echo ""
# Summary
echo "πŸ“‹ Verification Summary"
echo "======================"
# Count issues
issues=0
if [[ ! -x "$BACKUP_SCRIPT" ]]; then ((issues++)); fi
if [[ ! -d "$PROJECTS_DIR/.git" ]]; then ((issues++)); fi
if ! crontab -l 2>/dev/null | grep -q "$BACKUP_SCRIPT"; then ((issues++)); fi
if [[ $issues -eq 0 ]]; then
echo "βœ… All checks passed! Your backup system is working correctly."
echo ""
echo "πŸ”„ Your conversations are being backed up every hour."
echo "πŸ“ All history is preserved in git even after Claude Code's 30-day purge."
echo ""
echo "πŸ’‘ Monitoring tips:"
echo " β€’ Check logs: tail -f $LOG_FILE"
echo " β€’ View commits: cd $PROJECTS_DIR && git log --oneline"
echo " β€’ Check file count: find $PROJECTS_DIR -name '*.jsonl' | wc -l"
else
echo "⚠️ Found $issues issue(s) that need attention."
echo " Please review the output above and fix any ❌ items."
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment