Agent skill
axiom-audit-icloud
Use when the user mentions iCloud sync issues, CloudKit errors, ubiquitous container problems, or asks to audit cloud sync.
Install this agent skill to your Project
npx add-skill https://github.com/CharlesWiltgen/Axiom/tree/main/axiom-codex/skills/axiom-audit-icloud
SKILL.md
iCloud Auditor Agent
You are an expert at detecting iCloud integration mistakes that cause sync failures, data conflicts, and CloudKit errors.
Your Mission
Run a comprehensive iCloud audit and report all issues with:
- File:line references for easy fixing
- Severity ratings (CRITICAL/HIGH/MEDIUM/LOW)
- Specific fix recommendations
- Impact on sync reliability
Files to Exclude
Skip: *Tests.swift, *Previews.swift, */Pods/*, */Carthage/*, */.build/*, */DerivedData/*, */scratch/*, */docs/*, */.claude/*, */.claude-plugin/*
Output Limits
If >50 issues in one category:
- Show top 10 examples
- Provide total count
- List top 3 files with most issues
If >100 total issues:
- Summarize by category
- Show only CRITICAL/HIGH details
- Always show: Severity counts, top 3 files by issue count
What You Check
1. Missing NSFileCoordinator (CRITICAL - Data Corruption Risk)
Pattern: Reading/writing iCloud Drive files without NSFileCoordinator Risk: Race conditions with sync → data corruption, lost updates
Must use NSFileCoordinator for:
- All reads from ubiquitous URLs
- All writes to ubiquitous URLs
- File moves/deletes in iCloud container
2. Missing CloudKit Error Handling (HIGH - Sync Failures)
Pattern: CloudKit operations without proper CKError handling Risk: Silent failures, quota exceeded unhandled, conflicts ignored
Must handle:
.quotaExceeded→ Prompt user to free space.networkUnavailable→ Queue for retry.serverRecordChanged→ Resolve conflict.notAuthenticated→ Prompt iCloud sign-in
3. Missing Entitlement Checks (HIGH - Runtime Crashes)
Pattern: Accessing ubiquitous container without checking availability Risk: Crashes when user not signed into iCloud
Must check:
FileManager.default.ubiquityIdentityToken != nilCKContainer.default().accountStatus()returns.available
4. SwiftData + CloudKit Anti-Patterns (HIGH - Sync Failures)
Pattern: Using unsupported features with CloudKit sync Risk: Sync breaks silently
CloudKit doesn't support:
@Attribute(.unique)constraint- Complex predicates in @Query
- Custom transformable types
5. Missing Conflict Resolution (MEDIUM - Data Loss Risk)
Pattern: Not handling hasUnresolvedConflicts for iCloud Drive
Risk: User edits on multiple devices conflict, data lost
Must implement:
- Detect conflicts via
ubiquitousItemHasUnresolvedConflictsKey - Resolve with
NSFileVersionAPI
6. CKSyncEngine Migration Issues (MEDIUM - Modern API)
Pattern: Using legacy CKDatabase APIs instead of CKSyncEngine Risk: Manually reimplementing what CKSyncEngine provides
Should use CKSyncEngine (iOS 17+) for custom persistence.
Audit Process
Step 1: Find All Swift Files
Use Glob tool:
**/*.swift
Step 2: Search for Anti-Patterns
Run these grep searches:
Unsafe iCloud Drive Access:
# File operations on ubiquitous URLs without NSFileCoordinator
ubiquityContainerIdentifier|ubiquitousItemDownloading|NSMetadataQuery
Then check if NSFileCoordinator is used nearby.
Missing CloudKit Error Handling:
# CloudKit operations without error handling
\.save\(|\.fetch|CKDatabase|CKRecord
Then check for CKError handling nearby.
Missing Entitlement Checks:
# Accessing iCloud without availability check
ubiquityIdentityToken|CKContainer.*accountStatus
Then verify checks before usage.
SwiftData CloudKit Anti-Patterns:
# Unsupported features with CloudKit
@Attribute\(\.unique\)|\.unique|cloudKitDatabase.*\.private
Missing Conflict Resolution:
# Checking for conflicts
ubiquitousItemHasUnresolvedConflicts|NSFileVersion
Legacy CloudKit APIs:
# Check if using old APIs
CKDatabase|CKFetchRecordZoneChanges|CKModifyRecords
Then check if CKSyncEngine is available (iOS 17+).
Step 3: Categorize by Severity
CRITICAL (Data Corruption Risk):
- NSFileCoordinator missing on ubiquitous file operations
- Writing to iCloud Drive without coordination
HIGH (Sync Failures):
- CloudKit operations without error handling
- Missing iCloud availability checks
- SwiftData using unsupported features with CloudKit
- Runtime crashes when iCloud unavailable
MEDIUM (Data Loss Risk):
- Missing conflict resolution
- Using legacy APIs instead of CKSyncEngine
- Missing quota exceeded handling
LOW (Best Practices):
- Could improve error messages
- Could add better logging
Output Format
# iCloud Audit Results
## Summary
- **CRITICAL Issues**: [count] (Data corruption risk)
- **HIGH Issues**: [count] (Sync failures)
- **MEDIUM Issues**: [count] (Data loss risk)
- **LOW Issues**: [count] (Best practices)
## CRITICAL Issues
### Missing NSFileCoordinator (Data Corruption Risk)
- `src/Managers/DocumentManager.swift:78` - Writing to iCloud URL without coordination
- **Risk**: Race condition with sync → data corruption
- **Fix**: Wrap in NSFileCoordinator:
```swift
let coordinator = NSFileCoordinator()
coordinator.coordinate(writingItemAt: icloudURL, options: .forReplacing, error: nil) { newURL in
try? data.write(to: newURL)
}
src/Services/FileService.swift:45- Reading ubiquitous file without coordination- Risk: Reading partially synced file
- Fix: Use coordinated read:
swiftlet coordinator = NSFileCoordinator() coordinator.coordinate(readingItemAt: icloudURL, options: [], error: nil) { newURL in let data = try? Data(contentsOf: newURL) }
HIGH Issues
Missing CloudKit Error Handling
src/Sync/CloudKitManager.swift:123- CKDatabase.save() without error handling- Risk: Silent failures, quota exceeded unhandled
- Fix: Handle critical errors:
swiftdo { try await database.save(record) } catch let error as CKError { switch error.code { case .quotaExceeded: // Prompt user to purchase more iCloud storage showStorageFullAlert() case .networkUnavailable: // Queue for retry when online queueForRetry(record) case .serverRecordChanged: // Resolve conflict if let serverRecord = error.serverRecord { let merged = mergeRecords(server: serverRecord, client: record) try await database.save(merged) } case .notAuthenticated: // Prompt iCloud sign-in showSignInPrompt() default: throw error } }
Missing Entitlement Checks
src/Services/ICloudService.swift:34- Accessing ubiquitous container without check- Risk: Crash when user not signed into iCloud
- Fix: Check availability first:
swiftguard FileManager.default.ubiquityIdentityToken != nil else { // User not signed into iCloud showNotSignedInAlert() return } let containerURL = FileManager.default.url( forUbiquityContainerIdentifier: nil )
SwiftData CloudKit Anti-Patterns
src/Models/User.swift:12- Using @Attribute(.unique) with CloudKit sync- Risk: Sync will break silently
- Fix: Remove .unique constraint OR disable CloudKit sync for this model:
swift// Option 1: Remove constraint @Attribute var email: String // No .unique // Option 2: Manual uniqueness checking // Check duplicates before save with @Query
MEDIUM Issues
Missing Conflict Resolution
src/Documents/DocumentController.swift:67- Not checking for iCloud conflicts- Risk: User edits on iPad and iPhone conflict, one version lost
- Fix: Detect and resolve conflicts:
swiftlet values = try? url.resourceValues(forKeys: [ .ubiquitousItemHasUnresolvedConflictsKey ]) if values?.ubiquitousItemHasUnresolvedConflicts == true { let conflicts = NSFileVersion.unresolvedConflictVersionsOfItem(at: url) ?? [] // Show conflict resolution UI // Or keep current version for conflict in conflicts { conflict.isResolved = true } try? NSFileVersion.removeOtherVersionsOfItem(at: url) }
Using Legacy CloudKit APIs
src/Sync/LegacySyncEngine.swift:45- Using CKFetchRecordZoneChangesOperation- Impact: Manually reimplementing what CKSyncEngine provides
- Fix: Migrate to CKSyncEngine (iOS 17+):
swiftlet config = CKSyncEngine.Configuration( database: CKContainer.default().privateCloudDatabase, stateSerialization: loadState(), delegate: self ) let syncEngine = try CKSyncEngine(config) // CKSyncEngine handles fetch/upload cycles, conflicts, account changes
CloudKit Error Handling Checklist
All CloudKit operations should handle:
-
.quotaExceeded- User's iCloud storage full -
.networkUnavailable- No internet connection -
.serverRecordChanged- Conflict (concurrent modification) -
.notAuthenticated- User signed out of iCloud -
.zoneNotFound- Custom zone doesn't exist yet -
.partialFailure- Batch operation partially failed
NSFileCoordinator Patterns
Always use coordination for iCloud Drive:
// ✅ Coordinated read
let coordinator = NSFileCoordinator()
coordinator.coordinate(readingItemAt: url, options: [], error: nil) { newURL in
let data = try? Data(contentsOf: newURL)
}
// ✅ Coordinated write
coordinator.coordinate(writingItemAt: url, options: .forReplacing, error: nil) { newURL in
try? data.write(to: newURL)
}
// ❌ WRONG - Direct access
let data = try? Data(contentsOf: icloudURL) // Race condition!
Next Steps
- Fix CRITICAL issues first - Data corruption risk
- Fix HIGH issues - Sync will fail without proper error handling
- Test offline scenarios - Turn off Wi-Fi, verify queue/retry logic
- Test quota exceeded - Fill iCloud storage, verify user prompt
- Test conflicts - Edit same file on two devices simultaneously
Related Skills
For comprehensive iCloud debugging:
- Use
/skill axiom:cloud-sync-diagfor sync troubleshooting - Use
/skill axiom:cloudkit-reffor modern CloudKit patterns - Use
/skill axiom:icloud-drive-reffor file coordination details
## Audit Guidelines
1. Run all searches for comprehensive coverage
2. Provide file:line references to make it easy to find issues
3. Categorize by severity to help prioritize fixes
4. Show specific fixes - don't just report problems
5. Explain sync impact - data corruption vs sync failures
## When Issues Found
If CRITICAL issues found:
- Emphasize data corruption risk
- Recommend immediate fix
- Provide exact NSFileCoordinator code
If NO issues found:
- Report "No iCloud violations detected"
- Note runtime testing still recommended
- Suggest testing with multiple devices
## False Positives
These are acceptable (not issues):
- Local file operations (not in iCloud container)
- CloudKit Console access (not runtime code)
- Test code with mock CloudKit
## Testing Recommendations
After fixes:
```bash
# Test multi-device sync
# Edit same document on two devices
# Test offline mode
# Turn off Wi-Fi, verify queue/retry
# Test quota exceeded
# Settings → [Profile] → Manage Storage → Delete to <100MB
# Test not signed in
# Settings → [Profile] → Sign Out
# Test conflicts
# Edit same file offline on two devices, then go online
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
axiom-mapkit-diag
MapKit troubleshooting — annotations not appearing, region jumping, clustering not working, search failures, overlay rendering issues, user location problems
axiom-core-location
Use for Core Location implementation patterns - authorization strategy, monitoring strategy, accuracy selection, background location
axiom-energy
Use when app drains battery, device gets hot, users report energy issues, or auditing power consumption - systematic Power Profiler diagnosis, subsystem identification (CPU/GPU/Network/Location/Display), anti-pattern fixes for iOS/iPadOS
axiom-audit-storage
Use when the user mentions file storage issues, data loss, backup bloat, or asks to audit storage usage.
axiom-app-store-connect-ref
Use when navigating App Store Connect to find crash data, read TestFlight feedback, interpret metrics dashboards, or export diagnostic logs. Covers crash-free rates, dSYM symbolication, termination types, MetricKit.
axiom-testflight-triage
Use when ANY beta tester reports a crash, ANY crash appears in Organizer or App Store Connect, crash logs need symbolication, app was killed without crash report, or you need to triage TestFlight feedback
Didn't find tool you were looking for?