agentleFS
getdittogetditto/agent-skills/skills/swift-sdk/SKILL.md

swift-sdk

Skill4 starsChanged 9 days agoMITView on GitHub

Use ONLY for tasks that use the Ditto Swift SDK (not generic SwiftUI/Xcode work without Ditto): .swift, Package.swift or Xcode files touching import DittoSwift, DittoConfig, Ditto.open, observers, authentication, lifetimes and concurrency errors. Covers iOS, iPadOS, macOS/AppKit and Mac Catalyst on Ditto 4.14.x, 5.0.x, 5.1.x and 5.2.0. Other languages use their own Ditto SDK skill.

The file

We split this skill into the rules it gives an agent

10 rules. About 0 are common, 5 are distinctive, and 5 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈5

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 5

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    Use the shipping API: DittoIdentity, startSync() and collection APIs are deprecated on 4.14.x and removed in v5.

    line 14
  2. Distinctive:

    Read only the reference sections needed for the task.

    line 18
  3. Distinctive:

    Use for Swift Ditto integration and required permissions/entitlements.

    line 37
  4. Distinctive:

    Read the relevant section of versions.md for package pins, platform minimums or version differences.

    line 51
  5. Very specific:

    Read sdk-5.2.md when adopting 5.2.0 features or reviewing an upgrade: encryption, store deletion, startup configuration and behavior fixes.

    line 62
  6. Distinctive:

    Read concurrency.md for callback delivery and the ordered observer→stream→consumer bridge.

    line 113
  7. Very specific:

    Never assume main-actor delivery.

    line 116
  8. Very specific:

    Use one stream consumer, not one unordered Task per delivery.

    line 120
  9. Very specific:

    Keep one app-lived strong Ditto reference at the composition root.

    line 128
  10. Distinctive:

    Read anti-patterns.md for wrong/right forms.

    line 140

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Ditto Swift SDK

Use the shipping API: DittoIdentity, startSync() and collection APIs are deprecated on 4.14.x and removed in v5. Establish the package pin first; emit non-deprecated forms for that line, preferring forms that also exist in v5. Do not invent APIs from memory.

Read only the reference sections needed for the task. For long files, inspect the contents first and read the matching section. Do not preload all references or the README; the latter holds the capability/evidence map for coverage reviews.

What this skill does

Writes and reviews Ditto Swift code: initialization, authentication, store access, sync, lifetimes, threading and Xcode/SwiftPM configuration. Supports 4.14.x (LTS), 5.0.x, 5.1.x and 5.2.0, on iOS, iPadOS, macOS and Mac Catalyst with SwiftUI/UIKit/AppKit.

New apps and integration failures

For a new runnable Swift app, follow getting-started.md and project-deliverables.md. Use the bundled generator for a SwiftUI Xcode project; integrate existing apps in place. For failures, use troubleshooting.md. Load these only for that task.

When to use this skill

Use for Swift Ditto integration and required permissions/entitlements. Other topics have separate skills; load one only when the task needs its semantics:

QuestionSkill if installedOtherwise
DQL syntax and semanticswrite-dqlhttps://docs.ditto.live/dql/dql
CRDT selection, embed vs split, document sizedata-modelinghttps://docs.ditto.live/key-concepts
Subscription propagationsync-subscriptionshttps://docs.ditto.live/sdk/latest/sync/syncing-data
Radio selection and platform transport supportditto-mesh-networkinghttps://docs.ditto.live/sdk/latest/sync/customizing-transport-configurations
v4 → v5 migration procedure—https://docs.ditto.live/sdk/latest/migration-guides/swift-v4 and https://docs.ditto.live/sdk/latest/migration-guides/swift-dql

Supported versions and packages

SwiftPM: https://github.com/getditto/DittoSwiftPackage, product DittoSwift. Read the relevant section of versions.md for package pins, platform minimums or version differences.

For new apps and POCs, check the package manager for the latest stable release and use that resolved version. 5.2.0 is the latest version this skill knows about, not a permanent recommendation or claim about today’s latest release. Preserve an existing project’s selected version unless an upgrade is requested. If a newer release is found, read its release notes/API changes and validate the generated code. If lookup is unavailable, state that limitation; do not silently call 5.2.0 “latest”. The generator resolves the latest stable SwiftPM tag by default; see setup.md.

Read sdk-5.2.md when adopting 5.2.0 features or reviewing an upgrade: encryption, store deletion, startup configuration and behavior fixes. The 5.2.0 public Swift API lacks Ditto.close() despite the release notes; release all strong references before Ditto.deleteStore.

Capability exceptions

Full twenty-row evidence map: README.md, for capability reviews only.

IDCapabilitySupportRequired caveat
CAP-03Connecting: config, opening, persistence directorypreview4.14.x config/open is preview, no opt-in; prefer it to the deprecated identity initializer. GA on v5.
CAP-04Authentication and identitypreview4.14.x provider/expirationHandler is preview; GA on v5.
CAP-13Presence graph and connection requestspartialGraph, peer metadata and observe are available; connectionRequestHandler only takes effect with a second peer.
CAP-20Preview and platform-specific APIspreviewpassphrase is not for production; multicast beta is 5.1.0+, default off, restricted entitlement required. Data Streams: 5.2.0+, @_spi(PreviewDataStreams) import DittoSwift, executed on macOS. preview.md, data-streams.md

Minimum viable app

import DittoSwift
import Foundation  // v5 does not re-export Foundation

let ditto = try await Ditto.open(config: DittoConfig(   // `await`, not openSync
    databaseID: "REPLACE_ME_WITH_YOUR_DATABASE_ID",
    connect: .server(url: URL(string: "REPLACE_ME_WITH_YOUR_CONNECT_URL")!)))

// Install BEFORE sync.start(), and await the login inside it.
ditto.auth?.expirationHandler = { ditto, _ in await reauthenticate(ditto) }
try ditto.sync.start()

let query = "SELECT * FROM cars WHERE mileage > :min"
let arguments: [String: Any?] = ["min": 100]
let subscription = try ditto.sync.registerSubscription(query: query, arguments: arguments)
let observer = try ditto.store.registerObserver(query: query, arguments: arguments) { @Sendable result in
    for item in result.items {
        defer { item.dematerialize() }
        print(item.value["make"] as? String ?? "")      // [String: Any?] is not Sendable
    }
}
try await ditto.store.execute(query: "INSERT INTO cars DOCUMENTS (:car)",
                              arguments: ["car": ["make": "Toyota", "mileage": 120]])

Hold ditto, subscription and observer — see § Object lifetimes. Starting this once from SwiftUI and hopping to the main actor without losing ordering are both in references/concurrency.md. Complete runnable programs: examples/minimal-app.md and examples/swiftui-app.md.

Concurrency and threading model

Read concurrency.md for callback delivery and the ordered observer→stream→consumer bridge. Core constraints:

  • Never assume main-actor delivery. deliverOn: is ignored on 5.0.x; hop explicitly inside callbacks.
  • Extract Sendable values from [String: Any?] inside the callback. Do expensive conversion there; send only the final UI assignment to the main actor.
  • Use one stream consumer, not one unordered Task per delivery. .bufferingNewest(1) coalesces UI snapshots. Ditto is Sendable on v5; no actor wrapper/shim is needed.
  • On 4.14.x use @preconcurrency import DittoSwift for Swift 6.
  • For handlerWithSignalNext, call signalNext() exactly once per delivery. auth.expirationHandler is async, Sendable and off-main: it must not touch UI state.

Object lifetimes and retention

Keep one app-lived strong Ditto reference at the composition root. Its store, sync, presence, auth, smallPeerInfo and experimental hold weak parent references: retaining a child does not keep Ditto alive; using it after release can fatalError.

Dropping observer/subscription handles does not cancel them; work/captures remain until cancelled or Ditto is destroyed. Releasing AnyCancellable does cancel. Cancel at the owning scope's boundary (onDisappear/viewDidDisappear; deinit only where actor isolation permits). Do not cache computed sync.subscriptions or store.observers snapshots. Handle table/teardown: lifetimes.md.

Anti-patterns

Read anti-patterns.md for wrong/right forms.

  • Numeric casts can silently lose rows: CBOR chooses numeric widths by value; use NSNumber or Codable instead of assuming Double.
  • Missing signalNext() stops delivery forever without an error; use defer { signalNext() } as the handler's first line.
  • Fresh DittoTransportConfig() disables other P2P radios while sync stays active; use ditto.updateTransportConfig { … }.
  • Dematerializing before DittoDiffer.diff crashes: diff → extract → dematerialize; preserve item positions with map, not compactMap.
  • A retroactive Sendable shim conflicts on v5; delete it (use preconcurrency on v4).
  • sync.isActive means started, not connected; inspect presence server connectivity.
  • Copy the portal's Connect via SDK URL; deriving it from the database ID fails auth.

Version differences

versions.md owns deltas and upgrade/rollback results. On 4.14.x call try ditto.disableSyncWithV3() before mutating DQL. 5.1.0/5.2.0 are arm64-only; 4.14.x/5.0.x also ship x86_64. 4.14.6 throws for some use-after-release calls where v5 calls fatalError; preserve parent ownership on every line.

References

Choose the matching row and section; these are alternatives, not a reading checklist.

TaskRead
Install/package pin, platform minimums, Info.plist/entitlementssetup.md; keep signing enabled or the unsigned XCFramework aborts at launch
Open/authenticate, re-auth or logoutconnect.md; install expirationHandler before sync.start(), await login; hold one instance and re-authenticate in place
Actor crossing or starting SwiftUI exactly onceconcurrency.md; a guard alone does not prevent a double open
Retention/cancellationlifetimes.md
Store observer, signalNext, UI diffingobservers.md; SELECT only, one stateful DittoDiffer per observer
Diagnose a symptomanti-patterns.md, then errors.md if needed
Compare core versionsversions.md, only the relevant delta
Presence/Combine compatibility and patch fixesapi-compatibility.md
Run Swift teststesting.md; unset NO_COLOR for swift test
Execute DQL, transact, index or evictstore.md
Subscribe, scope sync or track statussync.md
Update radios/endpointstransports.md
Create/fetch attachmentsattachments.md; retain fetcher; token shape differs by version
Stream ephemeral bytesdata-streams.md; 5.2.0 SPI; concepts in data-streams
Presence/peer metadatapresence.md
Logging and disk usageobservability.md
On-disk upgrade/rollbackstorage.md
Preview/platform APIspreview.md
Architectural tradeoffsbest-practices.md, matching section
Run/configure the minimal exampleminimal-app-running.md
Build a complete exampleminimal-app.md (compiled/run) or swiftui-app.md (compile checked)

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.