Axiom axiom-audit-icloud

Use when the user mentions iCloud sync issues, CloudKit errors, ubiquitous container problems, or asks to audit cloud sync.

install
source · Clone the upstream repo
git clone https://github.com/CharlesWiltgen/Axiom
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/CharlesWiltgen/Axiom "$T" && mkdir -p ~/.claude/skills && cp -r "$T/axiom-codex/skills/axiom-audit-icloud" ~/.claude/skills/charleswiltgen-axiom-axiom-audit-icloud && rm -rf "$T"
manifest: axiom-codex/skills/axiom-audit-icloud/SKILL.md
source content

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 != nil
  • CKContainer.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
    NSFileVersion
    API

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:
    let 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:
    do {
        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:
    guard 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:
    // 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:
    let 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+):
    let 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

  1. Fix CRITICAL issues first - Data corruption risk
  2. Fix HIGH issues - Sync will fail without proper error handling
  3. Test offline scenarios - Turn off Wi-Fi, verify queue/retry logic
  4. Test quota exceeded - Fill iCloud storage, verify user prompt
  5. Test conflicts - Edit same file on two devices simultaneously

Related Skills

For comprehensive iCloud debugging:

  • Use
    /skill axiom:cloud-sync-diag
    for sync troubleshooting
  • Use
    /skill axiom:cloudkit-ref
    for modern CloudKit patterns
  • Use
    /skill axiom:icloud-drive-ref
    for 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