macOS only

Your entire iCloud,
from the terminal.

icloudcli reads your on-device data directly — Photos, Messages, Contacts, Notes, Reminders, Calendar, and Safari. No API token, no login, no cloud round-trip. Find storage hogs, search every conversation and note, audit your reminders, and pipe it all to jq or any AI agent with --agent JSON.

Quick Install

curl -fsSL https://icloudcli.com/install.sh | sh

Open Source · Apache-2.0

What you can do with icloudcli

Every command runs locally against your on-device databases — no network, no app launch. Pipe to jq or use --agent to wire it into any AI workflow.

Find your heaviest files
Every row includes the UUID — copy it straight into photos delete to free space without ever opening Photos.app.
Live
$ icloud-pp-cli photos top --limit 5
 
# Type Size Date Filename UUID
1 video 9.78 GB 2025-06-19 IMG_2898.MOV 6799AE02-EE45-4469-8AC9-1443582A828E
2 video 4.13 GB 2025-06-28 IMG_2901.MOV C625E37E-F406-435E-B274-67088D9ABF5E
3 video 3.96 GB 2026-05-01 IMG_3668.MOV 4D1C6E68-861D-4512-B09E-5E3D81571A1D
4 video 2.47 GB 2025-01-15 IMG_1262.MOV 02CB886E-51C1-4ED1-81E1-25F1EB275B0D
5 photo 0.84 GB 2024-08-03 RAW_2024-08-03.dng 1A2B3C4D-5E6F-7890-ABCD-EF1234567890
Delete by UUID — no Photos.app needed
Grab UUIDs from photos top, pass them to photos delete. Always a dry run until you add --confirm. Items stay in Recently Deleted for 30 days — fully recoverable.
Live
$ icloud-pp-cli photos delete \ 6799AE02-EE45-4469-8AC9-1443582A828E \ C625E37E-F406-435E-B274-67088D9ABF5E
 
2025-06-19 IMG_2898.MOV 9.78 GB
2025-06-28 Screen Recording 2025-06-28 at 4.30.51 PM.mov 4.13 GB
 
Dry run — 2 item(s) would be moved to Recently Deleted.
Add --confirm to proceed.
 
$ icloud-pp-cli photos delete --confirm \ 6799AE02-EE45-4469-8AC9-1443582A828E \ C625E37E-F406-435E-B274-67088D9ABF5E
 
✓ moved to Recently Deleted: IMG_2898.MOV
✓ moved to Recently Deleted: Screen Recording 2025-06-28 at 4.30.51 PM.mov
 
Done — 2 moved, 0 failed.
Open Photos.app → Recently Deleted → Empty to permanently free space.
Export originals from iCloud to a local folder
Downloads originals via Photos.app — even items stored only in iCloud (Optimize Mac Storage). Pipe UUIDs from any read command, or use --sensitive to batch-export nudity-flagged content (requires --confirm). Each file is renamed to its UUID for easy downstream scripting.
Live
$ icloud-pp-cli photos top --type video --limit 3 --json \ | jq -r '.[].uuid' \ | xargs icloud-pp-cli photos download --output ~/Desktop/export
 
Exporting 3 item(s) to /Users/matias/Desktop/export
 
→ IMG_2898.MOV 9.78 GB
→ IMG_2901.MOV 4.13 GB
→ IMG_3668.MOV 3.96 GB
 
[1/3] IMG_2898.MOV … ✓ → 6799AE02-EE45-4469-8AC9-1443582A828E.mov
[2/3] IMG_2901.MOV … ✓ → C625E37E-F406-435E-B274-67088D9ABF5E.mov
[3/3] IMG_3668.MOV … ✓ → 4D1C6E68-861D-4512-B09E-5E3D81571A1D.mov
 
Done — 3 exported, 0 failed.
Files saved to: /Users/matias/Desktop/export
Pick the right iCloud storage plan
Know your actual library size before upgrading. One number tells you whether you need 200 GB or 2 TB.
Live
$ icloud-pp-cli photos stats --agent | jq '{ items: .total_items, size_gb: .total_size_gb }'
{
"items": 129464,
"size_gb": 794.31
}
 
→ You need the 2 TB plan.
Find which years are eating the most space
Spot the year that ballooned your library — usually the year you got a new iPhone.
Live
$ icloud-pp-cli photos storage --agent | jq '.by_year | sort_by(-.size_gb) | .[0:5]'
[
{ "label": "2025", "count": 20438, "size_gb": 187.26 },
{ "label": "2024", "count": 18153, "size_gb": 151.17 },
{ "label": "2021", "count": 14559, "size_gb": 123.23 },
{ "label": "2022", "count": 15587, "size_gb": 115.47 },
{ "label": "2020", "count": 17957, "size_gb": 96.28 }
]
Find large videos from a specific time period
Narrow by year and month to target a trip or event. Combine with jq to filter by a size threshold.
Live
$ icloud-pp-cli photos videos --year 2024 --month 8 --agent \ | jq '[.[] | select(.size_gb > 0.5)]'
[
{
"rank": 1, "filename": "IMG_5820.MOV", "size_gb": 1.84,
"date": "2024-08-17", "uuid": "A1B2C3D4-E5F6-7890-ABCD-EF1234567890"
},
{
"rank": 2, "filename": "IMG_5741.MOV", "size_gb": 0.76,
"date": "2024-08-12", "uuid": "B2C3D4E5-F6A7-8901-BCDE-F12345678901"
}
]
Search by location
Find photos and videos shot near a coordinate — a bounding-box radius search straight over the GPS data in Photos.sqlite. Add --has-gps for everything with a location.
Live
$ icloud-pp-cli photos search --near 25.79,-80.13 --radius 5 --type video
 
# Type Size Date Filename UUID
1 video 0.04 GB 2025-07-08 IMG_3528.MOV 8F2A…
2 video 0.02 GB 2025-06-19 IMG_3401.MOV 1C7B…
3 video 0.01 GB 2025-05-30 IMG_3310.MOV A904…
Search by person
Find photos featuring a named person from your People album — read from on-device face detection, with no Photos.app launch. Pipe the UUIDs straight to download.
Live
$ icloud-pp-cli photos search --person "Mom" --year 2024 --json \ | jq -r '.[].uuid' \ | xargs icloud-pp-cli photos download --output ~/Desktop/mom
 
Exporting 42 item(s) to ~/Desktop/mom
✓ 42 exported, 0 failed.
Natural language queries
Ask in plain English. The one feature still on the roadmap — everything else here is live today.
Coming
$ icloud-pp-cli photos ask "vacation videos longer than 2 minutes from last summer" [ ... matching results ... ]
Audit your entire iMessage history
Reads chat.db directly and decodes the modern attributedBody blob so nothing post-2020 is missed. One command surfaces unique conversations, your longest threads, and who you talk to most.
Live
$ icloud-pp-cli messages audit --top 3
 
Conversations
1,284 unique · 1,032 DMs · 252 groups
 
Longest by message count
Mom dm 48,201 7.4 yrs
Weekend Crew group 31,544 5.1 yrs
Alex Rivera dm 22,910 6.8 yrs
 
Direction
from me: 312,887 (47.3%)
from others: 348,012 (52.7%)
Find and merge duplicate contacts
Syncs Contacts.app into a local cache, then finds likely duplicates by name, phone, or email — and hands you ready-to-paste merge commands. Merging dedupes phones, emails, and addresses, then syncs back to iCloud.
Live
$ icloud-pp-cli contacts duplicates
 
Likely duplicates (same name):
Danilo Gomes [a1b2c3d4] 2 phones, 1 email
Danilo Gomes SF [e5f6a7b8] 1 phone
→ icloud-pp-cli contacts merge a1b2c3d4 e5f6a7b8 --confirm
 
$ icloud-pp-cli contacts merge a1b2c3d4 e5f6a7b8 --confirm
✓ merged — 1 phone added, kept 1 contact
Full-text search your Notes
Pulls every note into a local FTS5 index (folders and accounts included). Search titles and bodies instantly. Password-protected notes stay private — only their metadata is read.
Live
$ icloud-pp-cli notes search "wifi password"
 
ID Title Folder Words Modified
p1842 House guide Home 412 2026-05-30
p0931 Airbnb checkout Travel 88 2026-04-12
See what's overdue across every list
Open reminders, soonest-due first, with overdue items flagged. Filter by list, by --upcoming N days, or get a full breakdown with analytics.
Live
$ icloud-pp-cli reminders list --overdue
 
Reminder List Due Pri
○ Renew passport Personal 2026-05-20 ⚠ high
○ Pay parking ticket Personal 2026-06-01 ⚠
○ Send invoice Work 2026-06-05 ⚠ ⚑ medium
Your week at a glance
A clean agenda grouped by day, pulled from every calendar. Search by keyword, list an explicit range, or run analytics for scheduled hours and your busiest weekday.
Live
$ icloud-pp-cli calendar agenda --days 3
 
Mon, Jun 8 2026
09:30–10:00 Standup [Work]
13:00–14:00 Lunch w/ Sam · Cafe Habana [Personal]
 
Tue, Jun 9 2026
all-day Flight to NYC [Travel]
See where your browsing time goes
Reads Safari's History.db read-only. Rank your most-visited domains, search history by URL or title, or list bookmarks with their folder path.
Live
$ icloud-pp-cli safari top-sites --limit 5
 
Domain Visits URLs
github.com 4,821 932
news.ycombinator 2,140 611
youtube.com 1,907 1,204
google.com 1,455 1,322
developer.apple 903 488

Paste into any AI agent

Copy a prompt, paste it into Claude, Cursor, Codex, or any agent with terminal access — it runs the commands and handles the rest.

Photos
Your best shots. Print-ready.
Curate a year into a photo book — sorted by month, RAW keepers first.
Photos
50 best dog shots. One folder.
Surface dedicated shoot sessions from date clusters and stage them automatically.
Storage
Drop a plan tier. Save $36/yr.
Calculate exactly what to delete to downgrade, with ready-to-run commands.
–2 TB
freed this session
Videos
All your clips. Organized by day.
Find footage from any recording window and stage it for editing.
Storage
3,847 screenshots. Gone.
Find every screenshot, show total wasted space, delete in one shot.
Photos
Your 2024. The 75 best.
Pull RAW and ProRAW keepers from a full year, grouped by quarter.
Messages
Your year in conversations.
Turn a decade of iMessage into a who-you-talk-to-most report — no data leaves your Mac.
661K
messages analyzed
Reminders · Calendar
Your Monday briefing.
Combine overdue reminders and the week ahead into one plain-English start-of-week digest.
7 days
planned for you
Notes
Find what you wrote down.
Surface stale, empty, and duplicate notes — and resurface the ones worth keeping.
💡
Community
Have a use case to share?
Write your own prompt and submit it as a pull request — it might end up right here in the slider.
Open GitHub issue

Leave a star on GitHub.

Open source lives on community support. A star takes one second and helps other developers find this tool.

Apache-2.0 · free forever · macOS only

icloudcli command reference

Every command accepts --json, --compact, --no-color, and --agent (sets all three). The Contacts, Notes, Reminders, and Calendar groups keep a local SQLite cache — run sync once, then every read is instant and offline. Photos, Messages, and Safari read their databases directly.

photos
photos top Top N heaviest files across all media types. Flags: --limit, --type all|photo|video Live
photos videos Largest videos sorted by file size. Flags: --limit, --year, --month Live
photos storage Storage breakdown by media type (photo/video) and by year Live
photos stats Total item count and total library size Live
photos delete Move items to Recently Deleted. Dry run by default; add --confirm to act. Requires Photos.app. Live
photos download Export originals to a local folder via Photos.app — downloads from iCloud automatically if needed. Flags: --output, --sensitive, --type all|photo|video, --limit. Files renamed to <UUID>.ext. Live
photos search Filter by person, date, type, favorite, or location — pipes straight into download/delete. Flags: --person, --year, --month, --type, --favorites, --has-gps, --near LAT,LON --radius, --keyword Live
photos ask Natural language query over your library Coming
messages
messages list-chats List conversations by most-recent activity — name, handle, participant count, message count, last preview. Flags: --limit, --since, --include-empty Live
messages search Search message bodies — decodes the modern attributedBody blob so post-2020 texts aren't missed. Flags: --chat, --handle, --from-me, --since, --until, --limit Live
messages stats Totals, by-year breakdown, and top handles by message count. Flags: --top-handles, --include-tapbacks Live
messages audit Deep analysis — unique conversations (DM vs group), longest threads by count and by date span, activity recency, per-chat distribution, from-me vs from-others. Flags: --top Live
messages export Export a chat (or --chat all) to JSON with attachment paths. Flags: --out, --since, --until Live
contacts
contacts sync Pull all contacts from Contacts.app via JXA into a local SQLite cache. Run once; re-run with --force. Live
contacts list / get / search List, show one (8-char UUID prefix lookup), or full-text search across name, org, phones, emails, and notes (FTS5). Live
contacts merge / duplicates Find likely duplicates (name / phone / email) and merge two contacts — dedupes phones, emails, URLs, addresses. Dry run until --confirm. Live
contacts create / update / delete Write back to Contacts.app safely (values passed as out-of-band AppleScript args — no injection). Syncs to iCloud automatically. Live
contacts analytics Group by country (E.164 dial-code resolution), email domain, and missing-field coverage. Live
notes
notes sync Pull all notes from Notes.app via JXA into a local SQLite cache with folder and account. Password-protected notes expose metadata only. Live
notes list / get / search List by most-recently modified, show a full body, or full-text search titles and bodies (FTS5). Flags: --limit Live
notes analytics Word/char totals, averages, shared/locked/empty counts, longest note, and a per-folder breakdown. Live
reminders
reminders sync Pull all reminders from Reminders.app via JXA into a local SQLite cache, with list, priority, due/remind dates. Live
reminders list Open by default, soonest-due first. Flags: --list, --completed, --all, --overdue, --upcoming N Live
reminders get / search Show one reminder, or full-text search across titles, notes, and lists (FTS5). Live
reminders analytics Open / done / overdue, due today and this week, high-priority and flagged, plus a per-list breakdown. Live
calendar  alias: cal
calendar sync Pull events within a date window via JXA. Flags: --back (days history, default 90), --forward (default 365) Live
calendar agenda Upcoming events grouped by day (next 7 by default). Flags: --days, --calendar Live
calendar list / search Events in an explicit range (--from/--to), or full-text search across titles, locations, and notes. Live
calendar analytics Total events and scheduled hours, per-calendar breakdown, and a busiest-weekday histogram. Live
safari
safari history Recently visited pages, most recent first. Reads History.db read-only. Flags: --limit, --domain, --since Live
safari search / top-sites Search history by URL and title, or rank the most-visited domains by visit count. Live
safari bookmarks List all bookmarks flattened with their folder path (parsed from Bookmarks.plist). Live
root
doctor Pre-flight check — verifies macOS, Photos library + schema, Messages and Safari Full Disk Access, and Automation for the Notes/Reminders/Calendar groups. Run this first. Live
photos ask Natural-language queries over your library — the one feature still on the roadmap. Coming

Install icloudcli on macOS

Requires macOS 13+. Run icloud-pp-cli doctor after installing to verify your setup.

Shell script (recommended)
$ curl -fsSL https://icloudcli.com/install.sh | sh
Go install
$ go install github.com/matysanchez/icloudcli/cmd/icloud-pp-cli@latest
Via Printing Press CLI
$ npx -y @mvanhorn/printing-press install icloud
Build from source
$ git clone https://github.com/matysanchez/icloudcli
$ cd icloudcli && make install
Verify — run this first
$ icloud-pp-cli doctor

System
✓ macOS required
macOS 15.4.1
✓ Photos.app installed

Library
✓ Library found · readable (read-only)
✓ Core schema valid (ZASSET + ZADDITIONALASSETATTRIBUTES)

Assets
✓ Can query assets
130,232 items · 802.12 GB (original sizes)

Messages · Safari
✓ chat.db & History.db readable (Full Disk Access granted)

Automation (Notes · Reminders · Calendar)
i Approved on first sync

All checks passed. Ready to use.
Permissions — grant once
Full Disk Access — for messages and safari (they read system SQLite databases).
System Settings → Privacy & Security → Full Disk Access →
add your terminal → quit & reopen it.


Automation — for notes, reminders, and calendar (read via JXA).
macOS prompts on first sync — click OK. Or pre-grant under
Privacy & Security → Automation → your terminal.


photos and contacts need no extra permission. Re-run doctor anytime.

icloudcli · early access

Be first when
new commands ship.

New iCloud databases unlock regularly. Get a short note when they do — no noise, no marketing.

One email per release. Unsubscribe any time.