autoheic is intentionally small. Three files do the real work:
| File | Role |
|---|---|
~/Library/Scripts/Folder Action Scripts/autoheic-trigger.scpt |
AppleScript fired by macOS when files are added to a watched folder. Dispatches HEIC/HEIF files one at a time to the converter. |
~/.local/bin/heic-convert-one (or wherever you installed it) |
Shell script — receives one file path, converts via sips, deletes original. |
~/.config/autoheic/config |
Format / quality / keep-originals settings. Sourced on every conversion. |
The ~/.local/bin/autoheic CLI is purely management surface — it doesn't participate in the runtime conversion path.
1. iPhone AirDrops a photo, or anything else creates a file in ~/Downloads
│
2. macOS's System Events daemon sees the directory change and fires every
Folder Action attached to that directory
│
3. autoheic-trigger.scpt runs:
for each added item:
if extension is "heic" or "heif":
shell-out to heic-convert-one <file>
│
4. heic-convert-one:
- waits up to 5s for the file's size to stop changing (AirDrop chunks)
- computes output path (collision-safe)
- runs /usr/bin/sips to convert
- if output is non-empty, deletes the original
- appends a log line
Each step runs in the user's session, in the user's permission context. No daemons, no LaunchAgent, no Full Disk Access.
The "obvious" macOS way to react to files appearing in a folder is a launchd LaunchAgent with WatchPaths. We tried that first. It has two killer problems on modern macOS:
-
TCC denials.
launchd-spawned binaries trying to read~/Downloadsor~/DesktopgetOperation not permittedeven with Full Disk Access granted, unless the binary is properly Developer-ID signed. An ad-hoc-signed app bundle's FDA grant is silently dropped whenlaunchdre-spawns it. Re-signing the bundle invalidates the existing grant. -
Sledgehammer permissions. Even when FDA works, you've granted an automation tool the entire disk. That's wildly out of proportion to "convert HEICs in my Downloads."
Folder Actions sidestep both. They live in the AppleScript / Finder permission domain, which has per-folder TCC entries Apple maintains correctly. The user grants exactly what's needed — access to this folder — and autoheic never sees anything else.
Shortcuts.app has a "Folder" automation trigger as of macOS 26 (Tahoe). It would be nicer to share — a single iCloud link, one tap to add. We considered it. The tradeoffs:
- The Shortcuts folder trigger is younger and historically less reliable than Folder Actions, especially after sleep / reboot.
- Shortcuts'
Convert Imageaction exposes only a coarse quality slider, notsips's fineformatOptionsknob. - An imported Shortcut can't auto-create its own automation — recipients still need ~30 seconds of manual GUI setup.
- The shortcut runs through Shortcuts.app, which adds its own notification banner on every run unless suppressed in Settings.
For this tool's specific job — reliable, silent, quality-controllable HEIC conversion — Folder Actions win.
Folder Action attachments are stored in macOS's System Events database. autoheic manipulates them via osascript:
tell application "System Events"
set folder actions enabled to true
make new folder action at end of folder actions with properties \
{name: "/Users/you/Downloads", path: "/Users/you/Downloads", enabled: true}
tell folder action "/Users/you/Downloads"
make new script with properties {name: "autoheic-trigger.scpt"}
end tell
end tellThe name is set to the absolute path of the watched folder, guaranteeing uniqueness (two folders with the same basename in different paths don't collide). All autoheic add and autoheic remove operations check for existing attachments before mutating — they're safe to re-run.
When autoheic uninstall runs, it walks every Folder Action, removes the autoheic-trigger.scpt script, and deletes the parent Folder Action only if no other scripts remain attached (so it doesn't clobber unrelated Folder Action setups you may have).
heic-convert-one polls the source file's size up to five times at 1s intervals, returning as soon as it sees the same size twice in a row. This handles:
- AirDrop, which writes the file in chunks and may trigger the Folder Action before the last chunk lands
- Browser downloads that rename
.crdownload→.heicmid-write - Photos.app exports
If the file is gone before stabilization (e.g., another tool moved it), the converter logs a skip (vanished) and exits 0.
The config file is sourced fresh on every invocation of heic-convert-one. There's no daemon caching state. This means autoheic config set format=png takes effect for the next file dropped — no reload, no restart, no re-attach.
- No file watcher daemon. Folder Actions are the watcher.
- No log rotation. The log is plain text; users can
: > ~/Library/Logs/autoheic.logif it grows. Conversion lines are ~100 bytes; you'd need to AirDrop ten thousand photos to hit 1 MB. - No GUI. Everything is
autoheic <command>. Folks who want a GUI can use the Automator app to inspect the same Folder Action state. - No recursion. Each watched folder is independent. Per the Folder Actions API, subfolders are not included.
- No update mechanism. Re-run the installer to upgrade.