CLAUDE.md#
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Project Overview#
AtProtoBackup is a multi-platform (iOS, macOS) SwiftUI application for backing up AT Protocol (Bluesky) accounts. It downloads repository snapshots (CAR files) and associated blobs (images, videos, etc.) from AT Protocol Personal Data Servers (PDS), storing them in the user's Documents/backups/ directory for safekeeping and portability.
Build Commands#
This project uses just (justfile) for build automation. The Justfile is located at the project root.
Common Commands#
# List all available commands
just
# Build for iOS Simulator (iPhone 16 Pro, iOS 18.6)
just build-ios-simulator
# Build for macOS
just build-mac
# Build for all platforms
just build-all
# Run tests on iOS Simulator
just test-ios
# Run tests on macOS
just test-mac
# Run all tests
just test-all
# Clean build artifacts
just clean
# Open project in Xcode
just xcode
Direct xcodebuild Commands#
If you need to customize build commands:
# Build for iOS Simulator
xcodebuild build \
-project AtProtoBackup.xcodeproj \
-scheme AtProtoBackup \
-destination 'platform=iOS Simulator,name=iPhone 16 Pro,OS=18.6' \
-configuration Debug
# Build for macOS
xcodebuild build \
-project AtProtoBackup.xcodeproj \
-scheme AtProtoBackup \
-destination 'platform=macOS' \
-configuration Debug
# Run tests
xcodebuild test \
-project AtProtoBackup.xcodeproj \
-scheme AtProtoBackup \
-destination 'platform=iOS Simulator,name=iPhone 16 Pro,OS=18.6'
Architecture Overview#
Data Flow#
- Account Discovery: Users add accounts by handle →
ATProtocolServiceresolves DID →Accountmodel created - Backup Discovery: On launch,
BackupDiscoveryscans Documents/backups/ for existing backups and auto-adds them to the account list - Download Process:
DownloadManagerorchestrates the backupBlobDownloaderhandles HTTP downloads using background URLSession- Downloads CAR file first (repository snapshot)
- Lists all blob CIDs via
listBlobsAPI - Downloads blobs concurrently with background-safe URLSession
BackupMetadatatracks completion and device info
- Progress Tracking (iOS only): Live Activities show real-time download progress via
BackgroundDownloadTracker
Core Components#
Data Layer#
- Account.swift: SwiftData model for account storage (DID, handle, PDS URL)
- BackupMetadata.swift: Codable struct tracking backup completion time, blob counts, device info, duration
- BackupDiscovery.swift: Discovers existing backups in Documents/backups/{did}/ directories
Service Layer#
- ATProtocolService.swift: Resolves handles to DIDs via slingshot.microcosm.blue API
- BlobDownloader.swift: Actor-based concurrent blob downloader using background URLSession for app suspension resilience. Implements retry logic, semaphore-based concurrency control, and skip-if-exists optimization.
- DownloadManager.swift: Orchestrates full backup process (CAR download → list blobs → download blobs → save metadata). Manages Live Activities on iOS.
UI Layer#
- ContentView.swift: Main account list with master-detail navigation
- AccountDetailView.swift: Shows account info and backup controls
- AccountListItemView.swift: Individual account row in list
- DownloadSection.swift: Download button and progress UI
Platform-Specific (iOS only)#
- LiveActivityManager.swift: Checks Live Activity permissions
- BackgroundDownloadTracker.swift: MainActor class that batches Live Activity updates (every 10 blobs) to reduce overhead
- DownloadActivityAttributes.swift: Defines Live Activity state and attributes
- AppDelegate.swift: Handles background URL session events
- WidgetExtension/: iOS Live Activity widget implementation
Multi-Platform Considerations#
The app uses #if os(iOS) preprocessor directives to conditionally compile iOS-specific features:
- Live Activities and ActivityKit
- UIKit-based device info (battery, device model)
- Background download event handling via AppDelegate
macOS builds exclude these features but share the core download and backup logic.
Dependencies#
Swift Package Manager dependencies (in Xcode project):
- ATProtoKit: AT Protocol Swift SDK for API interactions (repo syncing, blob listing)
- ZIPFoundation: (Currently unused but available for future archive compression)
File Storage Structure#
~/Documents/backups/
└── {did}/
├── backup-metadata.json # Backup completion info
├── {handle}-{timestamp}.car # Repository snapshot
└── {cid}.{ext} # Individual blobs (images, videos, etc.)
Background Download Strategy#
BlobDownloader uses URLSession.background with identifier com.app.atproto.backup.downloader. This allows:
- Downloads continue when app is suspended/backgrounded
- App wakes when downloads complete
- Automatic reconnection to in-progress downloads after app restart
Progress updates are batched (every 10 blobs) to minimize main thread overhead and Live Activity update frequency.
Error Handling#
- ATProtocolError: API and network errors (invalidURL, invalidResponse, decodingError)
- BlobDownloadError: HTTP errors, network failures, retry exhaustion
- BackupError: File system errors (documentsDirectoryNotFound)
- GenericIntentError: General error wrapper with custom messages
Blob downloads implement exponential backoff retry (up to 3 attempts by default) for transient network failures.
Key Implementation Details#
Concurrency Model#
BlobDownloaderis anactorfor thread-safe concurrent downloads- Uses async/await throughout for asynchronous operations
BackgroundDownloadTrackeris@MainActorto safely update Live Activities- TaskGroup pattern for managing concurrent blob downloads
SwiftData Usage#
Accountis a@Modelfor persistent storagemodelContainerconfigured with in-memory storage (Note: This means accounts don't persist between app launches!)- SwiftUI
@Queryused in ContentView for reactive account list
Security-Scoped Resources#
- Uses bookmark data to maintain access to user-selected save locations
- Properly calls
startAccessingSecurityScopedResource()/stopAccessingSecurityScopedResource()
Download Skipping#
- Before downloading each blob, checks if file with matching CID basename already exists
- Returns
wasNewDownload: Boolto track incremental vs full backups
Testing Notes#
- Unit tests: AtProtoBackupTests/
- UI tests: AtProtoBackupUITests/
- Tests currently minimal; expand coverage when modifying core download/backup logic