A safe rm replacement that intercepts file deletions by AI coding assistants — Claude Code, Codex, Cursor, Copilot, and others — and moves them to a recoverable trash instead of permanently destroying them. Works transparently on macOS, Linux, and Windows with zero workflow changes.
AI coding agents delete the wrong file more often than you'd expect. By the time you notice, rm has already destroyed it and there's no undo. ai-trash intercepts every rm call at the system level so deleted files are always recoverable, without changing how you or your scripts use rm.
/usr/local/bin/rm(or/opt/homebrew/bin/rmon Apple Silicon) is replaced with a wrapper. Since that directory precedes/binin the default PATH, allrmcalls — from your shell, scripts, build tools, and AI agents — go through it automatically.- macOS: files on the boot volume go directly to
~/.Trash/viaFSMoveObjectToTrashSync(CoreServices), so Finder's Put Back works out of the box. They are tagged withcom.ai-trash.*extended attributes soai-trash list/restore/emptycan identify them. Files on external drives use<volume>/.Trashes/<uid>/ai-trash/. - Linux: files go to
~/.local/share/Trash/ai-trash/; other volumes use<mountpoint>/.Trash-<uid>/ai-trash/. - Windows: a PowerShell
Remove-Itemfunction is dot-sourced from$PROFILEand routes deleted files to the Windows Recycle Bin viaMicrosoft.VisualBasic.FileIO.FileSystem.DeleteFile. A JSON manifest at%USERPROFILE%\.config\ai-trash\manifest.jsontracks each deletion soai-trash list/restore/emptycan find and recover items. Explorer's native "Restore" also works, since the files are in the real Recycle Bin. - Each trashed item keeps its original filename. Name collisions are handled Finder-style:
file (2).txt,file (3).txt. - Metadata is stored as extended attributes on the file itself: original path, deletion time (UTC), who deleted it, and original size.
- A LaunchAgent runs every 6 hours and permanently purges items older than
RETENTION_DAYS(default: 30 days, configurable in~/.config/ai-trash/config.sh). - Daemon-safe: if
$HOMEis unset or points to/var/root(system launchd daemons), the wrapper falls through to realrm. Non-interactive contexts (pipes, cron) never hang on-i/-Iprompts.
ai-trash has three modes, configured in ~/.config/ai-trash/config.sh:
| Mode | Your rm calls |
AI tool rm calls |
|---|---|---|
selective (default) |
pass through to /bin/rm unchanged |
→ ai-trash |
safe |
→ system Trash (recoverable, with Put Back, tracked by ai-trash) | → ai-trash |
selective is the default — your own commands behave exactly as before, only AI tool deletions are intercepted. safe routes your own deletions to the system Trash and tags them with ai-trash metadata, so ai-trash list shows everything and nothing silently disappears.
Detection works by checking environment variables first (IDE terminals like Cursor and VS Code set TERM_PROGRAM), then walking the full process tree up to PID 1. Covered out of the box: Claude Code, Gemini CLI, Codex, Aider, Goose, OpenCode, Devin, Kiro CLI, OpenHands, GitHub Copilot CLI, Cursor, VS Code, Windsurf, and Warp. Add your own tools in the config file.
macOS
- macOS Monterey 12+ (Ventura 13+, Sonoma 14+ also tested)
- Bash 3.2+ (ships with macOS)
- Python 3 (for Put Back support via
FSMoveObjectToTrashSync— falls back to plain move without it) /usr/local/bin(Intel) or/opt/homebrew/bin(Apple Silicon) must precede/binin PATH
Linux
- Bash 4.0+
/usr/local/binin PATH before/bin
Windows
- PowerShell 5.1+ or PowerShell 7+
$PROFILEmust be loaded in your sessions (the installer handles this)
macOS / Linux
curl -fsSL https://raw.githubusercontent.com/forethought-studio/ai-trash/main/install.sh | bashOr if you prefer to inspect before running:
git clone https://github.com/forethought-studio/ai-trash.git
cd ai-trash && ./install.shThe installer copies rm_wrapper.sh, ai-trash, and ai-trash-cleanup to the bin directory, symlinks rm and rmdir to the wrapper, and sets up the cleanup scheduler (LaunchAgent on macOS, cron on Linux).
Windows (PowerShell)
git clone https://github.com/forethought-studio/ai-trash.git
cd ai-trash/windows
.\install.ps1The installer copies the scripts to $env:USERPROFILE\.ai-trash\, dot-sources the wrapper from your $PROFILE, and registers a scheduled task that runs every 6 hours to purge items older than 30 days.
rm works exactly as before — no change to your workflow.
rm myfile.txt # moves to ~/.Trash/ (macOS) or ~/.Trash/ai-trash/ (Linux) — recoverable
rm -rf build/ # same — whole directory is recoverable
find . -name "*.bak" | xargs rm # works correctly — files are trashed, no hanging$ ai-trash list
NAME DELETED (UTC) SIZE BY ORIGINAL PATH
------------------------------------ -------------------- ----- ---------- ------------------------------
config.json 2026-03-21 14:22:10 2.1K user /Users/user/dev/myapp/config.json
server.js 2026-03-21 14:22:11 18.4K claude /Users/user/dev/myapp/server.js
migrations/ 2026-03-20 09:15:33 dir cursor /Users/user/dev/myapp/db/migrations
3 item(s) in AI trash
$ ai-trash restore server.js
restored → /Users/user/dev/myapp/server.js
ai-trash list # show all trashed items
ai-trash restore myfile.txt # restore to original location
ai-trash empty # permanently delete all AI trash (confirms first)
ai-trash empty --force # skip confirmation
ai-trash empty --older-than 7 # delete only items older than 7 daysOn macOS and Linux, each trashed item carries com.ai-trash.* extended attributes you can inspect directly:
# macOS (top-level ~/.Trash/)
xattr -p com.ai-trash.original-path ~/.Trash/myfile.txt
xattr -p com.ai-trash.deleted-at ~/.Trash/myfile.txt
xattr -p com.ai-trash.deleted-by ~/.Trash/myfile.txt
xattr -p com.ai-trash.original-size ~/.Trash/myfile.txt
xattr -p com.ai-trash.deleted-by-process ~/.Trash/myfile.txt # e.g. "claude --resume abc123"
# Linux / external drives
xattr -p com.ai-trash.original-path ~/.local/share/Trash/ai-trash/myfile.txtOn Windows, metadata is stored in a JSON manifest instead:
Get-Content "$env:USERPROFILE\.config\ai-trash\manifest.json" | ConvertFrom-JsonThe config file at ~/.config/ai-trash/config.sh (installed automatically) controls the protection mode and which AI tools are recognised. It's well-commented — open it and everything is explained inline.
To add a tool not on the default list, find its process name with ps aux | grep <toolname> and add it to AI_PROCESSES or AI_PROCESS_ARGS in the config.
macOS / Linux
./uninstall.shWindows
.\windows\uninstall.ps1Both uninstallers remove all installed files and leave your trash contents intact. Delete them manually if you want.
- macOS App Sandbox blocks wrapper execution. Sandboxed apps (those with an
APP_SANDBOX_CONTAINER_IDentitlement) cannot execute binaries from/usr/local/bin/or/opt/homebrew/bin/. The OS rejects theexecbefore the wrapper script starts running. This is a macOS platform constraint, not an ai-trash bug. - Workaround for sandboxed apps: Use absolute paths (
/bin/rm,/usr/bin/find) instead of barerm/find. This bypasses the wrapper entirely. - Defense-in-depth: If a partial sandbox allows the script to start, the wrappers detect
APP_SANDBOX_CONTAINER_IDand pass through to the real binary immediately.
| Tool | Trashes files | Replaces rm |
AI-aware | Recovery CLI | Cross-platform |
|---|---|---|---|---|---|
| ai-trash | Yes | Yes | Yes | Yes | macOS, Linux, Windows |
| safe-rm | No (blocks deletion) | Yes | No | No | Linux |
| trash-cli | Yes | No | No | Yes | Linux |
| trash | Yes | No | No | No | macOS |
| rm-protection | No (blocks deletion) | Yes | No | No | macOS, Linux |
Claude Code / Cursor / Copilot deleted my files — can I get them back?
If ai-trash was installed before the deletion, run ai-trash list to see all recoverable files and ai-trash restore <filename> to put them back. If ai-trash wasn't installed yet, install it now to prevent future losses.
Does this slow down rm?
The overhead is a few milliseconds for the process-tree check. Build tools, CI pipelines, and interactive use are unaffected in practice.
Does it work with find -delete and git clean?
Yes. ai-trash also ships wrappers for find and git that intercept -delete, git clean, git checkout -- ., and git reset --hard when run by AI tools.
Can I use it as a general safe-rm for all deletions, not just AI?
Yes — set MODE=safe in ~/.config/ai-trash/config.sh and every rm call (yours included) will go to the system Trash instead of being permanent.
MIT — see LICENSE. Your copyright notice must be retained in any copy or fork.
If you use ai-trash in a commercial product, a mention in your documentation or credits would be appreciated.
