Skip to main content
hooksSource-backedReview first Safety · Privacy ·

Auto Save Backup - Hooks

Automatically creates timestamped backups of files before modification to prevent data loss. This hook runs before file editing operations (Edit, Write, Multiedit) and creates versioned backups in a centralized .backups directory with ISO 8601-compliant timestamps including nanoseconds for collision prevention.

by JSONbored·added 2025-09-19·
Claude Code
HarnessClaude Code
Trigger:PreToolUse
Review first review before installing

Open the source and read safety notes before installing.

Schema details

Install type
cli
Reading time
1 min
Difficulty score
0
Troubleshooting
Yes
Breaking changes
No
Runtime and command metadata
Trigger
PreToolUse
Script language
bash
Script body
#!/usr/bin/env bash

# Read the tool input from stdin
INPUT=$(cat)
TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name')
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // .tool_input.path // ""')

if [ -z "$FILE_PATH" ]; then
  exit 0
fi

# Check if file exists before backing up
if [ -f "$FILE_PATH" ]; then
  echo "💾 Creating backup for $FILE_PATH..." >&2
  
  # Create backups directory
  mkdir -p .backups
  
  # Generate timestamped backup filename
  BASENAME=$(basename "$FILE_PATH")
  TIMESTAMP=$(date +%Y%m%d_%H%M%S)
  BACKUP_NAME="${BASENAME%.*}_${TIMESTAMP}.${BASENAME##*.}"
  
  # Create backup
  cp "$FILE_PATH" ".backups/$BACKUP_NAME" 2>/dev/null || true
  
  if [ $? -eq 0 ]; then
    echo "✅ Backup created: .backups/$BACKUP_NAME" >&2
  else
    echo "⚠️ Backup failed for $FILE_PATH" >&2
  fi
else
  echo "📝 Creating new file $FILE_PATH (no backup needed)" >&2
fi

exit 0
Full copyable content
{
  "hooks": {
    "preToolUse": {
      "script": "./.claude/hooks/auto-save-backup.sh",
      "matchers": [
        "edit",
        "write",
        "multiedit"
      ]
    }
  }
}

About this resource

Features

  • Automatic timestamped backups before file modification using ISO 8601 format with nanosecond precision for collision prevention
  • Organized backup storage in .backups directory with hierarchical structure and configurable retention policies
  • Filename format: filename_YYYYMMDD_HHMMSS_NS.ext supporting rapid file edits without timestamp collisions
  • Support for all file editing operations including Edit, Write, and Multiedit with batch backup creation
  • Version history maintenance with automatic cleanup of old backups based on age or count limits
  • Silent failure handling to prevent workflow interruption with graceful error recovery and logging
  • Disk space management with pre-backup checks and automatic cleanup of oldest backups when space is limited
  • Efficient file copying using optimized cp commands with preservation of file permissions, timestamps, and metadata

Use Cases

  • Automatic version control for critical configuration files ensuring recovery from accidental modifications
  • Safety net during development and debugging sessions providing rollback capability for experimental changes
  • Recovery from accidental file modifications with easy restoration from timestamped backup files
  • Maintaining edit history without git commits for files not tracked in version control
  • Protection during bulk file operations ensuring all modified files have backups before changes
  • Development workflow safety net for rapid prototyping and experimentation with automatic backup creation

Installation

  1. Create hooks directory: mkdir -p .claude/hooks
  2. Create hook file: touch .claude/hooks/auto-save-backup.sh
  3. Make executable: chmod +x .claude/hooks/auto-save-backup.sh
  4. Add configuration from Hook Configuration section above to .claude/settings.json or ~/.claude/settings.json
  5. Alternative: Use the interactive /hooks command in Claude Code

Config paths

  • Local (not committed): .claude/settings.local.json
  • User settings (global): ~/.claude/settings.json
  • Project-wide (committed): .claude/settings.json

Requirements

  • Claude Code CLI installed
  • Project directory initialized
  • Bash shell available
  • jq installed (for JSON parsing)
  • Standard Unix utilities: cp, date, find, mkdir (built into most Unix-like systems)
  • Sufficient disk space for backup storage (backups stored in .claude/backups/ directory)

Hook Configuration

{
  "hooks": {
    "preToolUse": {
      "script": "./.claude/hooks/auto-save-backup.sh",
      "matchers": ["edit", "write", "multiedit"]
    }
  }
}

Hook Script

#!/usr/bin/env bash

# Read the tool input from stdin
INPUT=$(cat)
TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name')
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // .tool_input.path // ""')

if [ -z "$FILE_PATH" ]; then
  exit 0
fi

# Check if file exists before backing up
if [ -f "$FILE_PATH" ]; then
  echo "💾 Creating backup for $FILE_PATH..." >&2

  # Create backups directory
  mkdir -p .backups

  # Generate timestamped backup filename
  BASENAME=$(basename "$FILE_PATH")
  TIMESTAMP=$(date +%Y%m%d_%H%M%S)
  BACKUP_NAME="${BASENAME%.*}_${TIMESTAMP}.${BASENAME##*.}"

  # Create backup
  cp "$FILE_PATH" ".backups/$BACKUP_NAME" 2>/dev/null || true

  if [ $? -eq 0 ]; then
    echo "✅ Backup created: .backups/$BACKUP_NAME" >&2
  else
    echo "⚠️ Backup failed for $FILE_PATH" >&2
  fi
else
  echo "📝 Creating new file $FILE_PATH (no backup needed)" >&2
fi

exit 0

Examples

Auto Save Backup Hook Script

Complete hook script that creates timestamped backups before file modifications with nanosecond precision

#!/usr/bin/env bash
INPUT=$(cat)
FILE_PATH=$(echo "$INPUT" | jq -r ".tool_input.file_path // .tool_input.path // \"\"")
if [ -z "$FILE_PATH" ]; then exit 0; fi
if [ -f "$FILE_PATH" ]; then
  mkdir -p .backups
  BASENAME=$(basename "$FILE_PATH")
  TIMESTAMP=$(date +%Y%m%d_%H%M%S_%N)
  BACKUP_NAME="${BASENAME%.*}_${TIMESTAMP}.${BASENAME##*.}"
  cp "$FILE_PATH" ".backups/$BACKUP_NAME" 2>/dev/null || true
  if [ $? -eq 0 ]; then
    echo "Backup created: .backups/$BACKUP_NAME" >&2
  fi
fi
exit 0

Hook Configuration

Complete hook configuration for .claude/settings.json to enable automatic backups before file edits, writes, and multiedits

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Edit|Write|Multiedit",
        "hooks": [
          {
            "type": "command",
            "command": "./.claude/hooks/auto-save-backup.sh"
          }
        ]
      }
    ]
  }
}

Backup with Disk Space Management

Enhanced hook script with automatic cleanup of old backups when disk space is limited

#!/usr/bin/env bash
INPUT=$(cat)
FILE_PATH=$(echo "$INPUT" | jq -r ".tool_input.file_path")
if [ -f "$FILE_PATH" ]; then
  mkdir -p .backups
  BASENAME=$(basename "$FILE_PATH")
  TIMESTAMP=$(date +%Y%m%d_%H%M%S_%N)
  BACKUP_NAME="${BASENAME%.*}_${TIMESTAMP}.${BASENAME##*.}"

  # Check disk space before backup
  AVAILABLE=$(df -BG .backups | tail -1 | awk '{print $4}' | sed 's/G//')
  if [ "$AVAILABLE" -lt 1 ]; then
    find .backups -type f -mtime +30 -delete 2>/dev/null
  fi

  cp "$FILE_PATH" ".backups/$BACKUP_NAME" 2>/dev/null || true
fi
exit 0

Multiedit Backup Support

Hook script that handles Multiedit operations by backing up all files in the edits array

#!/usr/bin/env bash
INPUT=$(cat)
if echo "$INPUT" | jq -e ".tool_input.edits" &> /dev/null; then
  mkdir -p .backups
  echo "$INPUT" | jq -r ".tool_input.edits[].file_path" | while read -r FILE_PATH; do
    if [ -f "$FILE_PATH" ]; then
      BASENAME=$(basename "$FILE_PATH")
      TIMESTAMP=$(date +%Y%m%d_%H%M%S_%N)
      BACKUP_NAME="${BASENAME%.*}_${TIMESTAMP}.${BASENAME##*.}"
      cp "$FILE_PATH" ".backups/$BACKUP_NAME" 2>/dev/null || true
    fi
  done
fi
exit 0

Backup with Retention Policy

Advanced hook script with automatic retention policy limiting backups to last 50 versions per file

#!/usr/bin/env bash
INPUT=$(cat)
FILE_PATH=$(echo "$INPUT" | jq -r ".tool_input.file_path")
if [ -f "$FILE_PATH" ]; then
  mkdir -p .backups

  # Retention policy: keep last 50 backups per file
  BASENAME=$(basename "$FILE_PATH")
  FILE_PREFIX="${BASENAME%.*}_"

  # Count existing backups for this file
  BACKUP_COUNT=$(find .backups -name "${FILE_PREFIX}*" | wc -l)

  if [ "$BACKUP_COUNT" -ge 50 ]; then
    find .backups -name "${FILE_PREFIX}*" -type f -printf '%T@ %p\n' | sort -n | head -n -50 | cut -d ' ' -f2- | xargs rm -f 2>/dev/null
  fi

  TIMESTAMP=$(date +%Y%m%d_%H%M%S_%N)
  BACKUP_NAME="${BASENAME%.*}_${TIMESTAMP}.${BASENAME##*.}"
  cp "$FILE_PATH" ".backups/$BACKUP_NAME" 2>/dev/null || true
fi
exit 0

Troubleshooting

PreToolUse hook runs but backup directory not created

Verify mkdir permissions in project root. Check disk space: df -h. Ensure script runs with correct CWD: pwd >&2 in hook. Create .backups manually if needed: mkdir -p .backups. Check filesystem permissions on project directory.

Backup created but original file modification fails after

PreToolUse only creates backup, doesn't block edits. Check subsequent tool execution logs. Verify hook exits with 0 (non-blocking). Review tool output for actual edit errors. Ensure backup operation completes before file modification.

Timestamp collisions when editing same file rapidly

Add nanoseconds to timestamp: date +%Y%m%d*%H%M%S*%N. Or use hash suffix: ${TIMESTAMP}_$(md5sum file | cut -c1-8). Implement collision detection and retry logic. Use ISO 8601 format with nanoseconds for better precision.

Hook backs up new files that don't exist yet on Write

Verify [ -f "$FILE_PATH" ] check works correctly. Check TOOL_NAME to distinguish edit vs write: if [["$TOOL_NAME" == "edit"]]. Skip backup for new file creation. Use PreToolUse only for Edit operations, not Write.

Backup directory grows unbounded filling disk space

Add retention policy: find .backups -mtime +30 -delete. Implement backup rotation script. Use git for versioning instead. Add size limit checks before creating backups. Limit backups per file: find .backups -name "file_*" | tail -n +50 | xargs rm.

Backup operation takes too long on large files

Add file size check before backup: [ $(stat -f%z file) -lt 10000000 ]. Use rsync for large files: rsync -a file .backups/backup_name. Consider excluding large files from backup. Add timeout wrapper: timeout 10s cp file backup.

Backup files have wrong permissions or ownership

Use cp -p to preserve permissions: cp -p file backup. Check umask settings. Verify backup directory permissions: chmod 700 .backups. Use rsync -a for better metadata preservation: rsync -a file backup.

Multiedit operations only backup first file

Check if FILE_PATH is array in multiedit context. Parse all paths: jq -r '.tool_input.edits[].file_path'. Loop through each file for backup. Verify jq parsing handles arrays correctly. Test with multiple files in edits array.

#backup#safety#file-management#data-protection

Source citations

Signals

Loading live community signals…

More like this, weekly

A short, calm digest of reviewed Claude resources. Unsubscribe any time.