PhotosAtlas is a macOS command-line app that turns Apple Photos location metadata into country-first travel reports.
It is built in Swift with Apple-native APIs. It reads Photos metadata through PhotoKit, resolves places with CoreLocation reverse geocoding, caches geocode results locally, and writes Markdown, CSV, and JSON reports.
- scans your Apple Photos library metadata
- avoids requesting originals, thumbnails, or image data
- reports unique countries visited
- summarizes regions, cities, and geocoder-provided areas of interest
- writes human-readable Markdown, spreadsheet-friendly CSV, and canonical JSON
- records skipped/problem assets separately instead of failing the whole run
PhotosAtlas is not a Photos export tool, backup tool, cleanup app, or precise trip-reconstruction engine. It is a metadata-only reporting tool for understanding where your geotagged Photos assets say you have been.
- macOS
- Xcode command line tools or Xcode
- SwiftPM
- Photos permission for the Terminal app or shell environment running the command
- network access for uncached CoreLocation reverse-geocode requests
Build and show help:
swift build
swift run photos-atlas -- --helpRun a full-library scan:
swift run photos-atlas -- scan --output ./ReportsRun a bounded scan:
swift run photos-atlas -- scan --start-day 2024-01-01 --end-day 2024-12-31 --output ./Reports-2024Warm the geocode cache over several passes:
swift run photos-atlas -- scan --output ./Reports --geocode-passes 5 --geocode-pass-delay 60--geocode-passes retries only coordinate buckets that still need reverse geocoding. Already cached buckets are reused, so repeated runs usually get faster and make fewer calls to Apple's geocoding service. For very large libraries, a first full scan may need multiple passes, and occasional reruns of the same command, before the cache is fully warm.
--start-day and --end-day use local calendar days in YYYY-MM-DD format.
--start-day 2024-01-01 --end-day 2024-01-31scans January 2024.--start-day 2024-01-01scans from the start of that day through the current moment.--end-day 2024-01-31scans everything up to and including that day.
Default output files:
photos-atlas.md: human-readable country-first reportphotos-atlas.csv: country/region/city summary for spreadsheetsphotos-atlas-landmarks.csv: areas of interest and landmark labelsphotos-atlas.json: canonical detailed outputphotos-atlas-summary.json: scan and geocode countersphotos-atlas-problems.csv: anomaly/problem records
Generated report folders and default report file names are ignored by Git.
PhotosAtlas reverse geocodes coordinate buckets, not individual assets. Nearby GPS points are quantized to reduce duplicate calls, then cached locally at:
~/.photos-atlas/geocode-cache.json
First runs can hit CoreLocation service throttling. Use --geocode-passes to let the app wait and retry unresolved buckets without rescanning PhotoKit metadata. See docs/geocoding.md for details.
PhotosAtlas reports and caches can reveal sensitive location history. Do not publish real generated reports unless you have intentionally reviewed and sanitized them. See docs/privacy.md.
The package has a reusable core library and a thin CLI frontend:
PhotosAtlasCore: models, protocols, PhotoKit scanning, geocoding, cache, aggregation, renderersPhotosAtlasCLI: argument parsing, output paths, terminal progress, exit behavior
The core is structured so a future SwiftUI app can reuse the same services. See docs/architecture.md.
Synthetic sample reports are available in Examples/SampleReports. They show the output shape without exposing a real Photos library.
Run the default unit test suite:
swift testLive PhotoKit integration tests are opt-in because they require Photos permission and access to the current user's Photos library:
PHOTOS_ATLAS_RUN_PHOTOKIT_TESTS=1 swift test --filter PhotoKitIntegrationTestsThe PhotoKit integration tests check scanner invariants and date-range behavior, but they do not assert personal-library-specific counts.
MIT License. See LICENSE.