Mac Dropbox rsync backup — prompt for Claude Code
How to use this file: open it, edit the Configuration block to match your setup, then copy the whole thing and paste it into Claude Code or Codex on your Mac. It needs to be Claude Code or Codex (or another AI that can run shell commands on your machine) — a chat-only AI can’t actually do the install for you. If you don’t use Dropbox, then do a search and replace in this prompt file and replace
DropboxwithGoogle DriveorOneDrive.
## What I want
I want to set up an automatic, scheduled, one-way backup of a folder on
my Mac to my Dropbox folder, using `rsync` and `launchd`. The backup
should:
- run every couple of hours, automatically, even if I'm not actively
using my Mac
- mirror the folder one-way (with `--delete`), so files I remove from
the source also disappear from the destination — Dropbox's delete history is my safety net
- write a log I can spot-check whenever I want
- not show up as a flashing Dock icon every time it runs
I'm a bit beyond a beginner but I'm not a developer. I want the simplest
working approach, using only tools that are already built into macOS —
no Homebrew, no third-party apps.
## Configuration — fill these in before you paste this prompt
- **Source folder to back up:** `/Users/<my-username>/<folder-to-back-up>`
- **Destination folder in Dropbox:** `/Users/<my-username>/Library/CloudStorage/Dropbox/<where-to-mirror-it>`
- **How often:** every `2` hours (or whatever interval I want — in seconds for `StartInterval`)
- **Friendly name for the wrapper app:** something like `My Obsidian Folder Backup`
- **Reverse-DNS bundle identifier for the launchd job:** something like `com.<my-name>.<JobName>`
## Important things a friend learned doing this — please don't repeat these dead ends
A friend of mine set this up first and walked into three traps in a row.
The fix is well known once you know it, but it cost him a couple of
hours of "why is my FDA grant not working?" Here's the summary so we
don't go in circles:
### 1. Modern Dropbox lives under `~/Library/CloudStorage/`, which is TCC-protected
On macOS Ventura and later, the Dropbox folder is at
`~/Library/CloudStorage/Dropbox/...`. That whole `CloudStorage` tree is
protected by macOS's TCC (Privacy & Security) layer. A plain shell
script run by `launchd` cannot write into it. You'll see
`rsync error: ...: open: Operation not permitted` in the log every run.
### 2. You **cannot** grant Full Disk Access to `/bin/bash`
macOS deliberately blocks the shells in `/bin`, `/usr/bin`, `/sbin`, and
`/usr/sbin` from being added to Full Disk Access via the System Settings
GUI. Don't try — it's blocked on purpose to prevent privilege
escalation. Don't waste time on it.
### 3. The fix is to wrap the script in a tiny AppleScript `.app`
`osacompile` will turn a one-line AppleScript that says
`do shell script "/path/to/your/rsync-script.sh"` into a real `.app`
bundle. `.app` bundles **can** be added to Full Disk Access, and the
FDA grant propagates to the rsync child process. This is the standard
workaround; it works.
### 4. Two non-obvious gotchas with the wrapper `.app`
These are the ones that actually cost the time. Both must be done or
the FDA grant is silently ignored even though the toggle in System
Settings looks "on":
- **`osacompile` does NOT set a `CFBundleIdentifier`.** Without one, TCC
can't reliably tie the FDA grant to the app. Add one with
`/usr/libexec/PlistBuddy` after compiling — something like
`com.<my-name>.<JobName>`.
- **The default ad-hoc signature does NOT bind the `Info.plist`.** The
moment you modify the `Info.plist` (e.g. to add `LSBackgroundOnly`
so it doesn't flash a Dock icon), the signature is invalidated and
macOS treats the app as having an inconsistent identity. Re-sign
with `codesign --force --deep --sign -` AFTER the Info.plist edits,
to bind the signature to the modified Info.plist.
The symptom of skipping either of those: the app appears in the FDA
list with the toggle on, you reload the launchd job, and rsync still
fails with `Operation not permitted`. Maddening to debug. Just do them.
## What I want you to actually build
Please set up everything end-to-end. Specifically:
1. Write a small `rsync` shell script at `~/Scripts/<bundle-id>.sh` that
uses `rsync -av --delete --exclude '.DS_Store'` from the source to
the destination, with a log file at `~/Scripts/<bundle-id>.log.txt`.
2. Build a wrapper app at `~/Applications/<friendly name>.app` with
`osacompile -e 'do shell script "..."'`.
3. Add a stable `CFBundleIdentifier` and `LSBackgroundOnly = true` to
the app's `Info.plist` using `PlistBuddy`.
4. Re-sign the app with `codesign --force --deep --sign -` so the
signature binds the modified `Info.plist`.
5. Register the app with Launch Services (`lsregister -f <app>`) so
System Settings can see it for FDA.
6. Write the launchd plist at
`~/Library/LaunchAgents/<bundle-id>.plist`. The `ProgramArguments`
should point directly at the `.app`'s
`Contents/MacOS/applet` binary — **not** at `/bin/bash <script>`. Use
`StartInterval` for the schedule and `RunAtLoad: true`.
7. Load the job with
`launchctl bootout` (idempotent — to clear any prior version) then
`launchctl bootstrap gui/$(id -u) <plist>`.
8. Open System Settings → Privacy & Security → Full Disk Access for me
with
`open "x-apple.systempreferences:com.apple.preference.security?Privacy_AllFiles"`,
open `~/Applications` in Finder, and tell me exactly what to drag
in. Wait for me to confirm I've granted FDA before testing.
9. Once I confirm, kickstart a test run with
`launchctl kickstart -k gui/$(id -u)/<bundle-id>` and tail
`~/Scripts/<bundle-id>.log.txt` to verify there are no
`Operation not permitted` errors.
## What success looks like
The log file should end with something like:
`sent 75182 bytes received 308 bytes 1255 bytes/sec
total size is 130526 speedup is 1.73
--- Sync finished: <date> ---`
with **no** `Operation not permitted` lines. After that, it should run
on its own on the schedule and I should be able to forget about it.
## What I don't want
- Don't have launchd run `/bin/bash <script>` directly — that's the
setup that doesn't work for CloudStorage destinations.
- Don't disable SIP or run anything as root. The `.app` wrapper is the
right approach.
- Don't suggest moving Dropbox out of `~/Library/CloudStorage/` — modern
Dropbox doesn't support relocating its folder.
- Don't install Homebrew, third-party rsync, or any helper apps. Use
what ships with macOS: `rsync`, `osacompile`, `codesign`,
`PlistBuddy`, `lsregister`, `launchctl`.
DO NOT start working yet. First, ask me clarifying questions so we can define the approach together. Only begin once we’ve aligned.