# AI deleted the database: a 7-minute recovery plan

> What to do after data deletion: stop the agent, document the incident, use git reflog, PITR, snapshots, and file recovery. Examples and safeguards.

Source: https://ailoot.ai/blog/en/ai-deleted-database-recovery/
Canonical: https://ailoot.ai/blog/en/ai-deleted-database-recovery/
Language: en
Publisher: Ailoot (https://ailoot.ai/)
Translation: guide-032
Revision: sha256-9d8999227f33f840ffa9575196c18e6ae4f229cfd81a3fb5f2849897f3f2730d


<div class="aside" data-semantic="key-takeaway" role="note" aria-label="Key takeaways">

Key takeaways

An AI agent just deleted your database, files, or your entire production environment. The first 7 minutes determine whether you recover your data or lose it forever. This playbook gives you specific commands for each minute. First stop the agent, then document the incident, then recover. No panic—follow the checklist.

</div>



[Practical information about working with Ailoot is available in the documentation](https://ailoot.ai/docs/).

## What to do in the first minute: STOP, don't panic

<div class="aside" data-semantic="key-takeaway" role="note" aria-label="Key takeaways">

Key takeaways

Stop the destructive writer immediately, including any child process that continues after the agent stops. Do not reboot or terminate unrelated processes that may still hold deleted files open. Recoverability is not guaranteed: overwrites and SSD discard/TRIM can make recovery impossible. Preserve evidence and surviving data on a separate verified device before changing the damaged copy.

</div>



When this happens to you, the **first thing to do is stop the agent**. Don't try to undo its actions yourself, don't tell it to “restore everything,” and don't run new prompts. Each subsequent action by the agent could overwrite the disk blocks where your data may still be stored.

1.  ### Close the agent's terminal

    Interrupt the dangerous command immediately with Ctrl+C; do not wait for deletion to finish. Stopping the agent does not necessarily stop its child commands, remote jobs, or database queries. Identify the actual writer and stop or cancel that operation; escalate termination if it continues destroying data. Keep unrelated processes with potentially recoverable open files alive.

2.  ### Do NOT reboot your laptop

    Deleted data may remain recoverable, but storage, database behavior, SSD discard/TRIM, and subsequent writes determine that. Minimize writes to the affected volume; do not assume the bytes still exist.

3.  ### Do NOT close open processes

    Preserve unrelated processes that hold deleted files open, because recovery may be possible through their file descriptors. This does not apply to the destructive writer: stop that writer first. Do not keep a deletion running merely to preserve an open handle.

4.  ### Start screen recording

    Record the exact time, affected paths, and visible command output. If recording or copying logs, save to a separate verified device rather than the damaged volume. Preserve surviving tracked, untracked, ignored files and Git metadata there before attempting recovery.

Next, 6 minutes to recover. Let's go.

## Minutes 2–3: document exactly what went wrong

<div class="aside" data-semantic="key-takeaway" role="note" aria-label="Key takeaways">

Key takeaways

Diagnose before recovery. Without an exact understanding of “what was deleted, by whom, when, and with which commands,” you'll be recovering blindly and could destroy data that is still intact. Open a new terminal window (not the one where the agent is running), run `git status`, `git log --since`, and `ps aux | grep claude`. Immediately copy the `~/.claude/projects/` folder—it contains the agent's complete session log, which may help with recovery.

</div>

Open a new terminal window. Not the one where the agent is running—another one. Run these three commands in sequence.

**1. Record exactly what changed in the git repository:**

```bash
git status
git log --since="30 minutes ago" --all --oneline
```

A deleted tracked file may still exist in the index or a commit. Preserve the current working tree, including untracked and ignored files, before any restore operation; restoring in place can overwrite surviving edits. Inspect and recover in a separate copy.

**2. Check which agent processes are running:**

```bash
ps aux | grep -i claude
ps aux | grep -i cursor
```

Identify which process is still performing the dangerous writes; a name match alone is not enough. Stop that writer and verify it has stopped. Preserve unrelated processes with useful open files; if graceful termination fails and destruction continues, force termination may be necessary.

**3. Save the agent session log:**

Claude Code stores JSONL sessions in `~/.claude/projects/`. Cursor stores them in `~/.cursor/`. Make a copy **right now**:

```bash
cp -r ~/.claude/projects /external/incident-evidence/claude-projects
```

Replace `/external/incident-evidence/` with an existing evidence directory on a separate verified mounted device. Do not write the backup onto the affected volume or overwrite existing evidence. This folder contains the verbatim conversation with the agent—which commands it ran, what it replied, and in what order. It's your main source for investigating the incident and potentially recovering deleted files from its context (see step 4).

## Minute 4: git reflog—your best chance

<div class="aside" data-semantic="key-takeaway" role="note" aria-label="Key takeaways">

Key takeaways

Reflog can locate commits that disappeared from branch history, but it does not save uncommitted working-tree files. After preserving surviving data and Git metadata on a separate device, inspect the copied repository and recover a verified commit into a separate worktree. Never begin by resetting the damaged working tree.

</div>

`git reflog` records local reference movements while entries remain retained. Expiration and pruning vary, and unreachable objects can be removed; it is not a guaranteed archive of every past commit. Run the recovery steps below from a preserved repository copy on the separate device.

**Step 1. View the log:**

```bash
git reflog --all
```

You'll get a list like this:

```
1a2b3c4 HEAD@{0}: reset: moving to HEAD~3
9z8y7x6 HEAD@{1}: commit: working version of the dashboard
5w4v3u2 HEAD@{2}: commit: added admin panel
```

Look for the point **before** the agent caused the damage. Each entry is a “snapshot” of the repository state at that moment.

**Step 2. Recover into a separate working tree:**

After copying the repository and all surviving work to a separate device, run this from that preserved repository copy. Replace the value with the exact commit SHA you checked in reflog, and choose an unused branch and destination:

```bash
RECOVERY_COMMIT='replace-with-verified-commit-sha'
git worktree add -b recovery-check ../recovery-check "$RECOVERY_COMMIT"
```

Inspect the recovered files in `../recovery-check` and compare them with the preserved uncommitted files before copying anything back. The command checks out the selected commit separately; it does not reset the damaged working tree. Linked worktrees share the copied repository’s Git object store, so this is a recovery workspace, not an independent backup. See the [official git-worktree documentation](https://git-scm.com/docs/git-worktree).

**If reflog was also cleaned (the agent managed to run `git gc`):**

```bash
git fsck --lost-found
```

This command finds “lost” commits and blobs (file objects) that are no longer attached to any branch. They'll appear in `.git/lost-found/commit/` and `.git/lost-found/other/`. To restore a file from there:

```bash
git cat-file -p <SHA1-blob> > recovered-file.ext
```

**When git reflog does NOT help:**

- The file was only in the working tree, without a commit or stash → reflog can't see it
- More than 90 days have passed (the standard `gc.reflogExpire`) and `git gc` was run
- The entire repository was deleted (`rm -rf .git`)—then you need Time Machine or a snapshot

## Minute 5: restore the database from a backup

<div class="aside" data-semantic="key-takeaway" role="note" aria-label="Key takeaways">

Key takeaways

PostgreSQL Point-In-Time Recovery (PITR) restores a database to any second within a 7–35 day window. It works with Yandex Cloud Managed Postgres, AWS RDS, Supabase Pro, and through a local `pg_dump` cron job in Coolify. The key requirement is that PITR must have been enabled **before** the incident; you can't enable it retroactively. Always restore to a new instance, never on top of a live database, so the rollback doesn't destroy even more data. If PITR wasn't enabled, use the latest snapshot.

</div>

The database was deleted with `DROP DATABASE`, `DROP TABLE`, or `DELETE FROM ... WHERE ...` (without a WHERE clause). What should you do?

**Step 1. Find out whether your provider offers PITR:**

| Provider | PITR window | Restore command |
|----|----|----|
| AWS RDS | 1–35 days (configurable) | `aws rds restore-db-instance-to-point-in-time --restore-time 2026-05-28T14:30:00Z` |
| Yandex Cloud Managed Postgres | 7 days (by default) | Restore from backup in the console + specify the time |
| Supabase Pro | 7 days (Pro+ only) | UI: Database → Backups → Restore |
| Coolify + local pg_dump | According to cron schedule | `pg_restore -d new_db backup.dump` |

**Step 2. Restore to a new instance, not the old one:**

Never restore over a live database. Create a new instance from the backup, then switch the application to it. If something goes wrong, you can switch DNS back.

**Step 3. If PITR wasn't enabled, use the latest snapshot:**

```bash
# AWS RDS, list snapshots:
aws rds describe-db-snapshots --db-instance-identifier my-db

# Restore from a snapshot:
aws rds restore-db-instance-from-db-snapshot \
  --db-instance-identifier my-db-restored \
  --db-snapshot-identifier rds:my-db-2026-05-28-12-00
```

**Supabase caveat**, which caught many people in 2026: when PITR is enabled, daily backups **stop being created**. Counterintuitive behavior; you could end up with no backups at all. Check Dashboard → Database → Backups to make sure PITR is active AND that you have a snapshot to restore from.





## Minute 6: Time Machine, lsof, and disk snapshots

<div class="aside" data-semantic="key-takeaway" role="note" aria-label="Key takeaways">

Key takeaways

If files were deleted from disk—not from git or a database—there are three practical recovery methods. On macOS, use Time Machine with hourly snapshots (if the laptop was connected to a Time Capsule or external drive). On Linux, run `sudo lsof | grep deleted`—it can retrieve files that a process still has open (95% chance); copy them through `/proc/PID/fd/N`. For critical cases, create a snapshot of the whole partition with `dd`, then recover with `extundelete` or `photorec`.

</div>

**macOS—Time Machine:**

```bash
# List snapshots:
tmutil listbackups

# Restore a file from the latest backup:
tmutil restore /Volumes/Backup/.../my-project/file.tsx ~/projects/my-project/file.tsx
```

Time Machine makes snapshots every hour, keeps hourly snapshots for a day and daily snapshots for a week, and weekly snapshots indefinitely. If your laptop is connected to a Time Capsule or external drive, your project is there with hourly granularity.

**Linux—the file was deleted, but a process still has it open:**

```bash
# Find all “deleted” files that a process still has open:
sudo lsof | grep deleted

# You'll get lines like:
# node 12345 user 24w REG 8,1 4096 1234567 /path/to/deleted/file.txt (deleted)

# Copy the file directly from /proc/PID/fd/N:
sudo cp /proc/12345/fd/24 ~/recovered-file.txt
```

The chance of success is ~95% if the process wasn't closed. Works on ext4, xfs, btrfs.

**macOS—equivalent using `lsof`:**

```bash
lsof | grep deleted
```

Copying the file is harder (there's no `/proc/`), but you can do it with `lldb`:

```bash
lldb -p 12345
(lldb) memory read --outfile recovered.txt --binary 0xADDRESS 0xSIZE
```

**Snapshot of the entire disk (Linux, last resort):**

```bash
sudo dd if=/dev/sda1 of=/external/disk-image.img bs=4M status=progress
```

This saves the entire partition as an image. Then recover using `extundelete` or `photorec`. The chance of recovery depends on how much has been written to the disk since deletion. If nothing has been written, it's 80–90%. If it has already been running for an hour, it's 20–30%.

## Minute 7: what if there is no backup

<div class="aside" data-semantic="key-takeaway" role="note" aria-label="Key takeaways">

Key takeaways

No backup, empty git reflog, and the disk has already been overwritten with new data. Two last-resort options remain: contact your provider's support (AWS, Yandex Cloud, and Google Cloud periodically recover data from their internal storage) or restore through S3 versioning (if it was enabled, all versions are physically there).

</div>

**Option 1—provider support:**

AWS, Yandex Cloud, Google Cloud, and DigitalOcean periodically recover data from their internal storage, even after a customer disaster, especially on paid plans. Open a support ticket, give the exact time of the incident, and include screenshots of the state. This most often works with major providers that keep automatic backups on their end. The chance is 40–60%; the response window is 24–72 hours.

**Option 2—S3 versioning:**

If files were in S3 (or Yandex Object Storage) and versioning was enabled, all versions **physically exist**; they're simply marked as “deleted.”

```bash
# AWS—list versions:
aws s3api list-object-versions --bucket my-bucket --prefix files/

# Restore a version:
aws s3api copy-object \
  --bucket my-bucket \
  --copy-source my-bucket/files/data.json?versionId=ABC123 \
  --key files/data.json
```



**Critical caveat:** Claude Code doesn't keep sessions forever—old JSONL files are deleted automatically after several weeks. To ensure you have a month of JSONL history in case of a disaster, copy `~/.claude/projects/` to an external drive once a week with a simple cron job:

```bash
# In crontab, every Sunday at 03:00:
0 3 * * 0 rsync -av ~/.claude/projects/ /external/claude-history-backup/
```

It's free and saves you when “everything is gone, there's no backup, and reflog is empty.”









## 7 rules to make sure this never happens again

<div class="aside" data-semantic="key-takeaway" role="note" aria-label="Key takeaways">

Key takeaways

Seven rules that keep an AI agent from deleting your database or code. Use Plan Mode before destructive operations. Use tested hooks to detect selected dangerous command strings, alongside enforced permission limits. Give the agent a read-only database user. Auto-commit after every file edit. Use an isolated sandbox folder for experiments. Take disk snapshots with `restic` every hour. Archive JSONL sessions to an external drive.

</div>

**1. Plan Mode before any destructive operation.** In Claude Code:

```bash
claude --plan
```

The agent builds a plan **before** acting. You read it, see `DROP TABLE users`, and cancel. Without Plan Mode, the agent decides for itself and executes in milliseconds. Learn more in the [Plan Mode in Claude Code guide](https://ailoot.ai/blog/en/claude-code-plan-mode/).

**2. Hooks as an extra tripwire.** Use a tested PreToolUse hook that reads the event JSON from stdin and exits 2 for a detected high-risk action. The complete example below covers Bash, Write, and Edit; it is not a security boundary and can miss indirect operations. Keep database privileges and the sandbox restrictive.

**3. Read-only DB user for the agent.** Create a separate user for the agent that **does not** have `DROP`, `TRUNCATE`, or `DELETE` permissions:

```sql
CREATE USER claude_readonly WITH PASSWORD 'xxx';
GRANT CONNECT ON DATABASE myapp TO claude_readonly;
GRANT USAGE ON SCHEMA public TO claude_readonly;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO claude_readonly;
```

When the agent really needs to write, switch to a different user manually. A read-only user is sufficient for everyday tasks (data analysis, reports, dashboards).

**4. Keep reviewed changes in Git.** A `PostToolUse` hook in `.claude/settings.json` can print a reminder after `Write` and `Edit`:

```json
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "printf '%s\\n' 'Review the diff and manually commit only the agreed files.' >&2"
          }
        ]
      }
    ]
  }
}
```

This example only prints a reminder; it does not stage files or create commits. Review the diff, then manually commit only the agreed files. The reflog does not save uncommitted changes.

**5. Sandbox project for experiments.** Never let the agent work in a project that contains real customer data. Create a separate `~/sandbox-projects/` folder, with a copy of the project and synthetic data. Use it to try a new prompt, agent, or MCP server. If it breaks something, no harm done.

**6. Disk snapshots with `restic` every hour.**

```bash
# Install:
brew install restic  # macOS
sudo apt install restic  # Linux

# Create repository:
restic init --repo /external/backups

# Back up the current project:
restic --repo /external/backups backup ~/projects

# Schedule cron every hour:
crontab -e
# Add:
0 * * * * restic --repo /external/backups backup ~/projects
```

Seven days of hourly backups, four weeks of daily backups—and you can always roll back to any point in the past. It's free and takes 10 minutes to set up.

**7. Archive Claude Code JSONL sessions.** Already mentioned above, but repeating as a separate rule: schedule a weekly `rsync` of `~/.claude/projects/` to an external drive. It's free and takes one line in crontab.

## Claude Code hooks to block dangerous commands {#ready-made-hooks-to-block-dangerous-commands}

<div class="aside" data-semantic="key-takeaway" role="note" aria-label="Key takeaways">

Key takeaways

The example below is a PreToolUse tripwire for selected Bash command strings and sensitive Write/Edit paths. It reads stdin JSON and returns exit 2 for matches. It can miss indirect or obfuscated actions, so it supplements a sandbox and restricted credentials rather than replacing them. Merge the hook into the existing configuration and test its behavior before use.

</div>

Merge this entry into `.claude/settings.json` without replacing existing hooks:

```json
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash|Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "python3 \"$CLAUDE_PROJECT_DIR/.claude/hooks/check-risk.py\""
          }
        ]
      }
    ]
  }
}
```

Create `.claude/hooks/check-risk.py` with the following Python 3 script:

```python
import json
import re
import sys
from pathlib import Path

try:
    event = json.load(sys.stdin)
    tool = event["tool_name"]
    data = event["tool_input"]
    blocked = False
    if tool == "Bash":
        command = data["command"]
        blocked = bool(re.search(
            r"drop\s+(database|table)|truncate\s+table|"
            r"delete\s+from.*where\s+1|rm\s+-rf|"
            r"git\s+reset\s+--hard|git\s+push.*(--force|-f)|"
            r"chmod\s+-R\s+777",
            command, re.IGNORECASE | re.DOTALL))
    elif tool in ("Write", "Edit"):
        path = Path(data["file_path"]).resolve()
        blocked = (".git" in path.parts or path.name.startswith(
            (".env", "credentials", "secrets")))
except (ValueError, KeyError, TypeError, OSError):
    print("BLOCKED: invalid hook input", file=sys.stderr)
    sys.exit(2)

if blocked:
    print("BLOCKED: high-risk command or sensitive path", file=sys.stderr)
    sys.exit(2)
sys.exit(0)
```

The hook reads the documented JSON event from **stdin**, checks `tool_input.command` or `tool_input.file_path`, and exits 2 on a match. It checks both Write and Edit. Test a harmless allowed fixture and a blocked fixture before relying on it, and verify that Python and the configured script actually start.

This is a lexical tripwire: it can miss reordered flags, scripts, aliases, obfuscated commands, other tools, and indirect writes; it can also reject harmless quoted examples. It does not grant or remove OS/database permissions. Keep production credentials outside the agent environment, use a read-only database role and an enforced sandbox, and protect the hook configuration from modification. See the [official hook input and exit-code reference](https://code.claude.com/docs/en/hooks).

For an intentional exceptional operation, review it and run it outside the agent with the appropriate restricted account. A shell environment variable is not a documented hook-disable interface, and hooks do not govern ordinary terminal commands.

## When to give AI permissions (and when not to)

<div class="aside" data-semantic="key-takeaway" role="note" aria-label="Key takeaways">

Key takeaways

Categorically do NOT give an agent the `--dangerously-skip-permissions` flag for projects with real data. In this YOLO mode, all protections are disabled, the agent runs any Bash command and writes files without confirmation, and spawned subagents inherit YOLO with no way to override it. Use YOLO only in a sandbox folder for experiments with new MCP servers or prompts on dummy data. For everything else, use precision permissions through `.claude/settings.json` with explicit `allow` and `deny` rules.

</div>

Anthropic documents the `--dangerously-skip-permissions` flag (also known as YOLO mode) as an option for “trusted environments.” In the reality of 2026, it's a **direct path to disaster**. When an agent doesn't have to ask, it:

- Runs any Bash command without confirmation
- Writes files without asking
- Can invoke a subagent, which **inherits** YOLO with no way to undo it

The third point is the most insidious. If you start the main agent with YOLO, its subagents are YOLO too, and you can't override it. One prompt—and a cascade of 10 parallel agents can do anything to your system.

**Rule:**

| Situation                                         | Is YOLO acceptable? |
|--------------------------------------------------|--------------------|
| Experimenting with a new MCP server in a sandbox folder | ✅ Yes          |
| Testing a new prompt on dummy data                | ✅ Yes          |
| Working with real project files                   | ❌ No           |
| Any command that touches a database               | ❌ Never        |
| Deploying to production                            | ❌ Never        |
| Managing infrastructure (AWS, Yandex Cloud)       | ❌ Never        |

**Alternative—precision permissions.** In `.claude/settings.json`:

```json
{
  "permissions": {
    "allow": [
      "Bash(git status:*)",
      "Bash(git log:*)",
      "Bash(npm run build:*)",
      "Read(*)",
      "Edit(src/**)"
    ],
    "deny": [
      "Bash(rm:*)",
      "Bash(git push:*)",
      "Edit(.env)",
      "Edit(prisma/migrations/*)"
    ]
  }
}
```

The agent sees what is and isn't allowed. You don't have to click “yes” or “no” every time—the agent works quickly, and you control the perimeter.

## Next: a 7-minute checklist to bookmark

<div class="aside" data-semantic="key-takeaway" role="note" aria-label="Key takeaways">

Key takeaways

Bookmark this guide right now. When disaster strikes, open the page and follow the 10-point checklist in order. It will save you 30 minutes of panic and keep you from accidentally overwriting data that may still be recoverable. After you recover, come back and configure the 7 preventive rules so disaster doesn't strike again next week.

</div>

**Checklist: “AI deleted it—what do I do?”**

1.  Stop the actual destructive writer immediately; verify child or remote operations have stopped
2.  Do not reboot; preserve unrelated processes holding deleted files open
3.  Record incident time and command evidence on a separate verified device
4.  Copy surviving files, Git metadata, and relevant session logs to that separate device
5.  In the preserved repository copy, inspect `git reflog --all` and recover a verified commit into a separate worktree
6.  If git didn't help—`git fsck --lost-found`
7.  Database: PITR (AWS/Yandex/Supabase) or latest snapshot
8.  Files: Time Machine on Mac, lsof on Linux
9.  Last resort: provider support + S3 versioning
10. After recovery, configure the 7 preventive rules in this guide

**Next—systematic protection:**

- [Plan Mode in Claude Code](https://ailoot.ai/blog/en/claude-code-plan-mode/)—so the agent makes a plan **before** a destructive operation
- [Hooks in Claude Code](https://ailoot.ai/blog/en/claude-code-hooks/)—ready-made templates for blocking dangerous commands
- [How to roll back changes in Claude Code](https://ailoot.ai/blog/en/claude-code-undo-changes/)—a detailed guide to `/rewind`, git, and 5 standard rollback methods
- [Security review in Claude Code](https://ailoot.ai/blog/en/claude-code-security-review/)—regular code security checks

<div class="section" role="doc-bibliography" aria-label="Sources">

### Sources





- [Anthropic Claude Code Hooks documentation](https://code.claude.com/docs/en/hooks-guide)
- [Anthropic Claude Code Plan Mode documentation](https://code.claude.com/docs/en/common-workflows)
- [PostgreSQL Point-In-Time Recovery (PITR) docs](https://www.postgresql.org/docs/current/continuous-archiving.html)
- [AWS RDS—Restore DB instance to point in time](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_PIT.html)
- [Yandex Cloud Managed PostgreSQL—Backup and recovery](https://yandex.cloud/ru/docs/managed-postgresql/concepts/backup)
- [Git reflog documentation](https://git-scm.com/docs/git-reflog)
- [Git fsck—`--lost-found` mode](https://git-scm.com/docs/git-fsck)



</div>







[Open Ailoot](https://ailoot.ai/).

## Questions about AI deleted the database: a 7-minute recovery plan

### Should I wait for the agent’s current command to finish?

No. Stop the destructive writer immediately and verify that its child, remote, or database operation has stopped. Preserve unrelated processes that may hold recoverable deleted files; stopping the agent alone may leave another writer running.

### Can I start recovery with git reset --hard?

First preserve surviving tracked, untracked, and ignored files plus Git metadata on a separate device. Inspect the copied repository and recover a verified commit into a separate worktree; an in-place hard reset can destroy surviving uncommitted edits.


## Ailoot · The company and its project portfolio

Ailoot combines established operating experience, a large client base, stable service and ongoing KPI control.

The company and its project portfolio: millions of customers; monthly sales in the billions.

Ailoot brings that operating experience to API access for AI features in customer products, agents, applications and automations.
