Files
claude-code-skills-reference/macos-cleaner/references/safety_rules.md
2026-02-23 16:16:58 +08:00

13 KiB

Safety Rules for macOS Cleanup

Critical safety guidelines to prevent data loss and system damage.

Golden Rules

Rule 1: Never Delete Without Confirmation

ALWAYS ask user before deleting ANY file or directory.

Bad:

shutil.rmtree(cache_dir)  # Immediately deletes

Good:

if confirm_delete(cache_dir, size, description):
    shutil.rmtree(cache_dir)
else:
    print("Skipped")

Rule 2: Explain Before Deleting

Users should understand:

  • What is being deleted
  • Why it's safe (or not safe)
  • Impact of deletion
  • Recoverability (can it be restored?)

Rule 3: When in Doubt, Don't Delete

If uncertain about safety: DON'T DELETE.

Ask user to verify instead.

Rule 4: Suggest Backups for Large Deletions

Before deleting >10 GB, recommend Time Machine backup.

Rule 5: Docker Prune Prohibition

NEVER use any Docker prune command. This includes:

  • docker image prune / docker image prune -a
  • docker container prune
  • docker volume prune / docker volume prune -f
  • docker system prune / docker system prune -a --volumes

Why: Prune commands operate on categories, not specific objects. They can silently destroy database volumes, user uploads, and container state that the user intended to keep. A user who loses their MySQL data because of a prune command will never trust this tool again.

Correct approach: Always specify exact object IDs or names:

# Images: delete by specific ID
docker rmi a02c40cc28df 555434521374

# Containers: delete by specific name
docker rm container-name-1 container-name-2

# Volumes: delete by specific name
docker volume rm project-mysql-data project-redis-data

Rule 6: Double-Check Verification Protocol

Before deleting ANY Docker object, perform independent cross-verification. This applies to images, volumes, and containers.

Key requirements:

  • For images: verify no container (running or stopped) references the image
  • For volumes: verify no container mounts the volume
  • For database volumes (name contains mysql, postgres, redis, mongo, mariadb): MANDATORY content inspection with a temporary container
  • Even if Docker reports a volume as "dangling", the data inside may be valuable

See SKILL.md Step 4 for the complete verification commands and database volume inspection workflow.

Rule 7: Use Trash When Possible

Prefer moving to Trash over permanent deletion:

# Recoverable
osascript -e 'tell app "Finder" to move POSIX file "/path/to/file" to trash'

# Permanent (use only when confirmed safe)
rm -rf /path/to/file

Never Delete These

System Directories

Path Why Impact if Deleted
/System macOS core System unbootable
/Library/Apple Apple frameworks Apps won't launch
/private/etc System config System unstable
/private/var/db System databases System unstable
/usr Unix utilities Commands won't work
/bin, /sbin System binaries System unusable

User Data

Path Why Impact if Deleted
~/Documents User documents Data loss
~/Desktop User files Data loss
~/Pictures Photos Data loss
~/Movies Videos Data loss
~/Music Music library Data loss
~/Downloads May contain important files Potential data loss

Security & Credentials

Path Why Impact if Deleted
~/.ssh SSH keys Cannot access servers
~/Library/Keychains Passwords, certificates Cannot access accounts/services
Any file with "credential", "password", "key" in name Security data Cannot authenticate

Active Databases

Pattern Why Impact if Deleted
*.db, *.sqlite, *.sqlite3 Application databases App data loss
Any database file for running app Active data Data corruption

Running Applications

Path Why Impact if Deleted
/Applications Installed apps Apps won't launch
~/Applications User-installed apps Apps won't launch
Files in use (check with lsof) Currently open App crash, data corruption

Require Extra Confirmation

Large Deletions

Threshold: >10 GB

Action: Warn user and suggest Time Machine backup

Example:

⚠️ This operation will delete 45 GB of data.

💡 Recommendation:
   Create a Time Machine backup first.

   Check last backup:
     tmutil latestbackup

   Create backup now:
     tmutil startbackup

Proceed without backup? [y/N]:

System-Wide Caches

Paths: /Library/Caches, /var/log

Action: Require manual sudo command (don't execute directly)

Example:

⚠️ This operation requires administrator privileges.

Please run this command manually:
  sudo rm -rf /Library/Caches/*

⚠️ You will be asked for your password.

Reason:

  • Requires elevated privileges
  • User should be aware of system-wide impact
  • Audit trail (user types password)

Docker Objects (Images, Containers, Volumes)

Action: List every object individually. Use precision deletion only (see Rule 5 and Rule 6).

NEVER use prune commands. Always specify exact IDs/names.

Example for volumes:

Docker volumes found:
  postgres_data    (1.2 GB)  - Contains PostgreSQL database
  redis_data       (500 MB)  - Contains Redis cache data
  app_uploads      (3 GB)    - Contains user-uploaded files

Database volumes inspected with temporary container:
  postgres_data: 8 databases, 45 tables, last modified 2 days ago
  redis_data: 12 MB dump.rdb

Confirm EACH volume individually:
  Delete postgres_data? [y/N]:
  Delete redis_data? [y/N]:
  Delete app_uploads? [y/N]:

Deletion commands (after confirmation):
  docker volume rm postgres_data redis_data

Application Preferences

Path: ~/Library/Preferences/*.plist

Action: Warn that app will reset to defaults

Example:

⚠️ Deleting preferences will reset the app to defaults.

Impact:
- All settings will be lost
- Custom configurations will be reset
- May need to re-enter license keys

Only delete if:
- App is misbehaving (troubleshooting)
- App is confirmed uninstalled

Proceed? [y/N]:

Safety Checks Before Deletion

Check 1: Path Exists

if not os.path.exists(path):
    print(f"❌ Path does not exist: {path}")
    return False

Check 2: Not a System Path

system_paths = [
    '/System', '/Library/Apple', '/private/etc',
    '/usr', '/bin', '/sbin', '/private/var/db'
]

for sys_path in system_paths:
    if path.startswith(sys_path):
        print(f"❌ Cannot delete system path: {path}")
        return False

Check 3: Not User Data

user_data_paths = [
    '~/Documents', '~/Desktop', '~/Pictures',
    '~/Movies', '~/Music', '~/.ssh'
]

expanded_path = os.path.expanduser(path)
for data_path in user_data_paths:
    if expanded_path.startswith(os.path.expanduser(data_path)):
        print(f"⚠️ This is a user data directory: {path}")
        print("   Are you ABSOLUTELY sure? [type 'DELETE' to confirm]:")
        response = input().strip()
        if response != 'DELETE':
            return False

Check 4: Not in Use

def is_in_use(path):
    """Check if file/directory is in use."""
    try:
        result = subprocess.run(
            ['lsof', path],
            capture_output=True,
            text=True
        )
        # If lsof finds processes using the file, returncode is 0
        if result.returncode == 0:
            return True
        return False
    except:
        return False  # Assume not in use if check fails

if is_in_use(path):
    print(f"⚠️ Warning: {path} is currently in use")
    print("   Close the application first, then try again.")
    return False

Check 5: Permissions

def can_delete(path):
    """Check if we have permission to delete."""
    try:
        # Check parent directory write permission
        parent = os.path.dirname(path)
        return os.access(parent, os.W_OK)
    except:
        return False

if not can_delete(path):
    print(f"❌ No permission to delete: {path}")
    print("   You may need sudo, but be careful!")
    return False

Safe Deletion Workflow

def safe_delete(path, size, description):
    """
    Safe deletion workflow with all checks.

    Args:
        path: Path to delete
        size: Size in bytes
        description: Human-readable description

    Returns:
        (success, message)
    """
    # Safety checks
    if not os.path.exists(path):
        return (False, "Path does not exist")

    if is_system_path(path):
        return (False, "Cannot delete system path")

    if is_user_data(path):
        if not extra_confirm(path):
            return (False, "User cancelled")

    if is_in_use(path):
        return (False, "Path is in use")

    if not can_delete(path):
        return (False, "No permission")

    # Backup warning for large deletions
    if size > 10 * 1024 * 1024 * 1024:  # 10 GB
        if not confirm_large_deletion(size):
            return (False, "User cancelled")

    # Final confirmation
    if not confirm_delete(path, size, description):
        return (False, "User cancelled")

    # Execute deletion
    try:
        if os.path.isfile(path):
            os.unlink(path)
        else:
            shutil.rmtree(path)
        return (True, f"Deleted successfully ({format_size(size)} freed)")
    except Exception as e:
        return (False, f"Deletion failed: {str(e)}")

Error Handling

Permission Denied

except PermissionError:
    print(f"❌ Permission denied: {path}")
    print("   Try running with sudo (use caution!)")

Operation Not Permitted (SIP)

# macOS System Integrity Protection blocks some deletions
except OSError as e:
    if e.errno == 1:  # Operation not permitted
        print(f"❌ System Integrity Protection prevents deletion: {path}")
        print("   This is a protected system file.")
        print("   Do NOT attempt to bypass SIP unless you know what you're doing.")

Path Too Long

except OSError as e:
    if e.errno == 63:  # File name too long
        print(f"⚠️ Path too long, trying alternative method...")
        # Try using find + rm

Recovery Options

If User Accidentally Confirmed

Immediate action: Check Trash first

# Files may be in Trash
ls -lh ~/.Trash

Next: Time Machine

# Open Time Machine to date before deletion
tmutil browse

Last resort: File recovery tools

  • Disk Drill (commercial)
  • PhotoRec (free)
  • TestDisk (free)

Note: Success rate depends on:

  • How recently deleted
  • How much disk activity since deletion
  • Whether SSD (TRIM) or HDD

Preventing Accidents

  1. Use Trash instead of rm when possible
  2. Require Time Machine backup for >10 GB deletions
  3. Test on small items first before batch operations
  4. Show dry-run results before actual deletion

Red Flags to Watch For

User Requests

If user asks to:

  • "Delete everything in ~/Library"
  • "Clear all caches including system"
  • "Delete all .log files on the entire system"
  • "Remove all databases"

Response:

⚠️ This request is too broad and risky.

Let me help you with a safer approach:
1. Run analysis to identify specific targets
2. Review each category
3. Delete selectively with confirmation

This prevents accidental data loss.

Script Behavior

If script is about to:

  • Delete >100 GB at once
  • Delete entire directory trees without listing contents
  • Run rm -rf / or similar dangerous commands
  • Delete from system paths

Action: STOP and ask for confirmation

Testing Guidelines

Before Packaging

Test safety checks:

  1. Attempt to delete system path → Should reject
  2. Attempt to delete user data → Should require extra confirmation
  3. Attempt to delete in-use file → Should warn
  4. Attempt to delete without permission → Should fail gracefully
  5. Large deletion → Should suggest backup

In Production

Always:

  • Start with smallest items
  • Confirm results after each deletion
  • Monitor disk space before/after
  • Ask user to verify important apps still work

Summary

Conservative Approach

When implementing cleanup:

  1. Assume danger until proven safe
  2. Explain everything to user
  3. Confirm each step
  4. Suggest backups for large operations
  5. Use Trash when possible
  6. Test thoroughly before packaging

Remember

"It's better to leave 1 GB of unnecessary files than to delete 1 MB of important data."

User trust is fragile. One bad deletion loses it forever.

Final Checklist

Before any deletion:

  • Path is verified to exist
  • Path is not a system path
  • Path is not user data (or extra confirmed)
  • Path is not in use
  • User has been informed of impact
  • User has explicitly confirmed
  • Backup suggested for large deletions
  • Error handling in place
  • Recovery options documented

Only then: proceed with deletion.