![]()
Handee copies and moves files between my Mac and an iPhone or iPad. It replaces AnyTrans for iOS by iMobie, which I ran through Setapp: macOS app subsciption. Handee waits in the background without a Dock icon and opens its window when a device connects by cable. The Mac is on the left, the devices in the middle, and the device's camera roll or app folder on the right. I drag, or press ⌘↩, to copy in either direction.
25 Oct 2026
I built it overnight with Claude Code, on 25th October 2026. The name follows the -ee family of my tools, like my file manager, see Filee: my own file manager for macOS. "Handy" is also German for a mobile phone.
All screenshots on this page use dummy data: a demo iPhone and iPad, generated landscape images, a made-up trip folder and public-domain film titles. None of it comes from my devices.

Why I replaced AnyTrans
The agent read a copy of AnyTrans's own logs and data before the build. It was a bad experience, and the numbers say why:
| What I found | Value |
|---|---|
| Use on record | 2 days in 19 months, 4 launches |
| Connect to ready | 69 s with 420 photos, 5 min 47 s with 3,965 photos |
| Crashes | 7, caught by its own crash guard, in 4 launches |
| Transfers logged | 1: a music track, which took 15 min 15 s |
| Wireless backup helper | 0 backups since July 2022, 10,256 connection errors |
| Data it kept on my Mac | 470 MB, mostly copies of the devices' photo databases |
I need this kind of tool a few times a year. When I need it, I want it ready in seconds, not minutes, and I want to trust that a move doesn't lose a photo.
What Handee does
It does 2 jobs: photos off the device, and files in and out of app folders. The full list is in the next section.
Photos get a name that sorts: YYMMDD-HHMMSS-IMG_1234.heic, the capture time then the original name. A file with the same name and the same SHA-256 already in the folder is skipped, not copied twice. There is no automatic import. I copy by hand, on purpose.
App folders are where video players and document apps keep their files. The screenshot of an app folder is in the update at the end of this note.
Keys
| Key | Action |
|---|---|
| ⌘↩ | Copy the selection to the other side |
| ⌥⌘↩ | Move it: confirm, copy, verify, delete |
| Tab | Switch side |
| ⌘⌫, ⌘Z | Delete with a safety copy; undo the last delete |
| ⇧⌘N, ⌘R | New folder, rename |
| ⇧⌘A | AirDrop the Mac selection |
| ⌃⌘A/P/V/N | Photo filters: All, Photos, Videos, New |
| ⌘K | Command centre: every command with its shortcut |
| ⌘. | Cancel the running transfers |
No global hotkey. Handee opens on plug-in, by name from my launcher, or from the CLI.
All features
Devices
- Opens on plug-in. A device on USB opens the window with that device selected. Wi-Fi never does.
- Several devices. iPhones and iPads, each paired on its own, with a clear "Tap Trust on the device" step.
- Device details. Model, iOS version, USB or Wi-Fi, free space and trust state in the sidebar.
- No Dock icon. Handee waits in the background and costs 0% CPU when idle.
Photos
- Camera roll. A grid by month, newest first, with All, Photos, Videos and New filters.
- Originals. HEIC, HEVC, ProRAW, both files of a Live Photo and the edit files. No conversion.
- "New" filter. Photos never copied to this Mac, from Handee's own copy log.
- Names that sort.
YYMMDD-HHMMSS-IMG_1234.heic, and a file with the same SHA-256 is skipped, not copied twice. - Verified move. Copy, verify, then delete from the device. Refused when iCloud Photos is on.
- AirDrop. Sends Mac files to the device, the only public route into its Photos library.
App folders
- Copy both ways. The Documents folder of any app with file sharing, plus new folder and rename.
- Safe delete. A delete keeps a copy on the Mac for 30 days, and
⌘Zrestores it. - Partial files. A file gets its real name only when its size matches, so a pulled cable leaves no half file.
- Conflicts. Keep both, replace or skip when a name already exists.
Window
- 3 panes. The Mac on the left, devices in the middle, the camera roll or app folder on the right.
- Type badges. The extension in a pill coloured by family: video, audio, image, document, subtitles, archive, folder.
- Type filters. 1 pill per file type with its count, and type-to-filter by name.
- Transfer cards. 1 card per job with direction, progress, current file, speed and time left.
⌘.cancels. - Coloured notices. Green, blue, orange, red and grey cards, always on the main display.
- Keys.
⌘↩copy,⌥⌘↩move,⌘Kcommand centre, and photo filters on⌃⌘A/P/V/N/M/D. No global hotkey.
Agent interface
- CLI. 18 commands with
--json, fromstatus,devicesandphotos listtopull,pushandcancel, listed byhandee describe --json. - Safe by default. Every destructive command refuses without
--yes, and moves take--dry-run. - Filee link.
⌥⌘Rreveals Handee's Mac folder in my file manager.
A move that can't lose a photo
Reliability was goal 2: nothing leaves a device without a verified copy on the Mac. A move runs in 5 steps:
- Download the item and its sidecar files into a hidden folder next to the target.
- Check the size and Apple's fingerprint of the copy against the device's.
- Record the SHA-256 of the copy in a journal, state
verified. - Move the files to their real names.
- Delete the verified items from the device in batches of 50.
The edge cases are where the care goes:
- iCloud Photos on: Move is refused, even from the CLI with
--yes. There a delete reaches iCloud and every device, the Mac included. - A crash between steps 3 and 5: at the next launch, Handee marks those items
keptand says the move was interrupted. It never deletes them without a new check. - Cancel: stops the copies, never the deletes of items already verified.
- Never through AFC: deleting a photo file through the file protocol breaks the Photos library on the device. Photos are deleted only through ImageCaptureCore, after the checks.
- App folder files arrive under a hidden partial name and get their real name only when the size matches. A pulled cable never leaves a half file under a real name.
Speed
Goal 1 was the time from plug-in to the first copy. Nothing in Handee waits for the whole device to load. Measured with QA's fake device:
| Metric | Budget | Measured | AnyTrans |
|---|---|---|---|
| Cold launch to ready | < 400 ms | 143 to 258 ms | - |
| Window shown again | < 50 ms | 1 ms | - |
| Grid of 4,000 photos on screen | < 500 ms | 156 ms | - |
| Select all 4,000 | - | 25 ms | - |
| Memory with 4,000 thumbnails | < 200 MB | 67 MB | - |
| Memory after a 200 MB transfer | < 200 MB | 108 MB | - |
| Handee's own cost per MB | > 150 MB/s | 1,800 to 6,800 MB/s | - |
| Idle, no window | ~ 0% CPU | 0.0% CPU, 59 MB | - |
| Plug-in to ready, real device | < 15 s | not measured yet | 69 s to 5 min 47 s |
The last row is the one that matters most. I'll add the real number after the first big copy from a phone. The first real numbers are in the update below.
How it's built
Stack
- Swift 6.3 and AppKit, built with XcodeGen. The transfer rules live in a package without AppKit, so they're unit tested without a device.
- ImageCaptureCore for photos: Apple's public API behind Image Capture. It gives originals, sidecars, a fingerprint and a proper delete.
- MobileDevice.framework for device info and app folders, loaded with
dlopen. It's Apple's private framework that Finder and Xcode use, and AnyTrans too. It ships on every Mac and Apple updates it for each new iOS. - An own AFC client for the file protocol, plus an own usbmux fallback in case a macOS update breaks the framework.
- SQLite in WAL mode for the copy log, the move journal and the safety copies.
- Nothing to install. The agent rejected libimobiledevice and pymobiledevice3 (installs that follow new iOS versions late) and Xcode's
devicectl(it needs Developer Mode).
Rules that keep it from hanging
- The main thread never touches the disk, a device or the database.
- Each device has its own serial queue. Transfers use their own connection, so browsing stays quick during a copy.
- Every blocking wait has a timeout: 30 s on a device socket, 120 s plus 1 s per 4 MB for a photo download.
- Transfers stream in 1 MB chunks, each in its own autorelease pool. Without the pools, 200 MB in meant 200 MB of memory.
Gotchas worth knowing
- App folders open at the container, not the files. Only
/Documentsis readable, and listing/was refused on iOS 27. Handee shows Documents as the top. - Image Capture sees only what's on the device. With "Optimise iPhone Storage", older photos live in iCloud only and don't show up in Handee, Image Capture or Photos import.
- The Files app's "On My iPhone" folder has no documented route. Handee doesn't try.
- A background app that opens a window must insist. The resident app switches from accessory to regular, and a plain
activate()was declined: the window opened behind the front app. Handee now callsactivate(ignoringOtherApps:)twice, 0.1 s apart. - Return values from a private framework. MobileDevice functions return
intorlong. Declared asInt32, the low 32 bits are right for both.
The agent interface
Every command takes --json, so NicAI can use Handee inside a task (see What is NicAI). The CLI opens a handee:// URL in the background, which starts the app when needed, and reads the app's reply from a file:
handee status --json # devices, iCloud Photos, locked, running jobs
handee photos list --new --json # photos never copied to this Mac
handee photos copy --to ~/Pictures/Trip --since 2026-10-01 --wait --json
Destructive commands refuse without --yes. An agent never gets a dialog: --yes is the confirmation.
How it was built
Handee followed my appee process for apps:
- Usage review: AnyTrans's logs and data, Apple's device stack on my Mac, and the framework's exports, checked with
nm. - Questions: 35 in 1 round, each with a recommended answer. I changed 2: no automatic import, and open the window on plug-in.
- Spec and build in the same pass: 9 commits between 01:02 and 07:29 on 25th October 2026.
QA ran against fake devices: a folder that acts as a camera roll, and app folders served by an in-memory AFC server through the real client. At version 1.0:
- 26 unit tests.
- 81 end-to-end checks in 6 suites, 3 runs in a row.
- An independent review by another agent found 15 defects in the data paths, for example a Live Photo's second file not checked before a move. All 15 are fixed.
The screenshots in this note come from those QA runs, on test data.
Left for later
- Version 2: a local device backup, Messages export from that backup, HEIC to JPEG on export.
- Dropped: automatic import, writing to the Music library, contacts and calendars (iCloud does those).
Update: a real iPhone and a new design
25 Oct 2026 added after the first hours of use, the same day.
The first real device
The first test was my iPhone 13 Pro on iOS 27.0.1. Pairing, the device details, the list of 20 apps with file sharing and the camera roll worked on the first try. App folders didn't: opening VLC gave "the device refused". The cause is in the gotchas above: the app's folder opens at its container, and only Documents is readable. The fake test devices allowed the listing, so QA never saw it. They now refuse it the same way the iPhone does.
The same test found a 2nd bug: the CLI sent spaces in file names as +, so a file with a space in its name was "not found".
Measured on the real iPhone:
| Metric | Measured |
|---|---|
| App starts to iPhone ready, 20 apps listed | 1.5 to 1.7 s over Wi-Fi |
| Copy a 237 MB video from VLC's folder | 9.3 s, 25 MB/s over the cable |
The first number held in 2 of 3 runs: the 3rd run waited over 30 s for the iPhone to appear on Wi-Fi. The copy speed is close to the USB 2 limit of the iPhone 13 Pro's Lightning port.
It isn't the same test: AnyTrans loads everything up front, photos, music, contacts and calendars, and its numbers come from its own logs, on 2 iPads. Handee doesn't wait for the camera roll before the window and the app folders are ready.
A new design for files and transfers
After the first use I asked for 4 changes, and they shipped the same morning:
- File types you can see. A Type column shows the extension in a pill coloured by family: video purple, audio pink, image green, document blue, subtitles teal, archive amber, folder blue.
- Filters. Above each file list, 1 pill per file type in the folder, with its count. Typing filters by name, as in my file manager:
⌫deletes a letter,Escclears.⌃⌘Mand⌃⌘Djoin the photo keys for audio and documents. - Transfer cards. At the bottom of the window, 1 card per job: an icon for the direction, "4 of 12", a progress bar, the current file, and the bytes, speed and time left. The status bar shows the keys to press next.
- Colour-coded notifications, always on my main screen. Green for success, blue for work in progress, orange for a warning, red for an error, grey for information. They always appear at the bottom of the display with the menu bar, whichever window is in front.


One more fix came from that round: when Handee opened its window, macOS kept it behind the front app and the menu bar showed the other app's name. That's the activation gotcha above.
Further reading
The app Handee replaces:

Apple's framework for photos on a connected device:

The tool I built it with:

- see Filee: my own file manager for macOS, the file manager:
⌥⌘Rreveals Handee's Mac folder there - see The era of personal software is here, why I now build the apps I use
- All my apps: see My apps: everything I built for myself