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.
In this repository8 other files it gives its agents.
- AGENTS.mdAGENTS.md
- CLAUDE.mdCLAUDE.md
- data-modelingSkill
- data-streamsSkill
- ditto-mesh-networkingSkill
- kotlin-sdkSkill
- sync-subscriptionsSkill
- write-dqlSkill
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
- Very specific: line 14
Use the shipping API: DittoIdentity, startSync() and collection APIs are deprecated on 4.14.x and removed in v5.
- Distinctive: line 18
Read only the reference sections needed for the task.
- Distinctive: line 37
Use for Swift Ditto integration and required permissions/entitlements.
- Distinctive: line 51
Read the relevant section of versions.md for package pins, platform minimums or version differences.
- Very specific: line 62
Read sdk-5.2.md when adopting 5.2.0 features or reviewing an upgrade: encryption, store deletion, startup configuration and behavior fixes.
- Distinctive: line 113
Read concurrency.md for callback delivery and the ordered observer→stream→consumer bridge.
- Very specific: line 116
Never assume main-actor delivery.
- Very specific: line 120
Use one stream consumer, not one unordered Task per delivery.
- Very specific: line 128
Keep one app-lived strong Ditto reference at the composition root.
- Distinctive: line 140
Read anti-patterns.md for wrong/right forms.
≈ “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.
Files
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:
| Question | Skill if installed | Otherwise |
| DQL syntax and semantics | write-dql | https://docs.ditto.live/dql/dql |
| CRDT selection, embed vs split, document size | data-modeling | https://docs.ditto.live/key-concepts |
| Subscription propagation | sync-subscriptions | https://docs.ditto.live/sdk/latest/sync/syncing-data |
| Radio selection and platform transport support | ditto-mesh-networking | https://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.
| ID | Capability | Support | Required caveat |
| CAP-03 | Connecting: config, opening, persistence directory | preview | 4.14.x config/open is preview, no opt-in; prefer it to the deprecated identity initializer. GA on v5. |
| CAP-04 | Authentication and identity | preview | 4.14.x provider/expirationHandler is preview; GA on v5. |
| CAP-13 | Presence graph and connection requests | partial | Graph, peer metadata and observe are available; connectionRequestHandler only takes effect with a second peer. |
| CAP-20 | Preview and platform-specific APIs | preview | passphrase 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.Dittois Sendable on v5; no actor wrapper/shim is needed. - On 4.14.x use
@preconcurrency import DittoSwiftfor Swift 6. - For
handlerWithSignalNext, callsignalNext()exactly once per delivery.auth.expirationHandleris 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
NSNumberor Codable instead of assuming Double. - Missing
signalNext()stops delivery forever without an error; usedefer { signalNext() }as the handler's first line. - Fresh
DittoTransportConfig()disables other P2P radios while sync stays active; useditto.updateTransportConfig { … }. - Dematerializing before
DittoDiffer.diffcrashes: diff → extract → dematerialize; preserve item positions withmap, notcompactMap. - A retroactive Sendable shim conflicts on v5; delete it (use preconcurrency on v4).
sync.isActivemeans 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.
| Task | Read |
| Install/package pin, platform minimums, Info.plist/entitlements | setup.md; keep signing enabled or the unsigned XCFramework aborts at launch |
| Open/authenticate, re-auth or logout | connect.md; install expirationHandler before sync.start(), await login; hold one instance and re-authenticate in place |
| Actor crossing or starting SwiftUI exactly once | concurrency.md; a guard alone does not prevent a double open |
| Retention/cancellation | lifetimes.md |
| Store observer, signalNext, UI diffing | observers.md; SELECT only, one stateful DittoDiffer per observer |
| Diagnose a symptom | anti-patterns.md, then errors.md if needed |
| Compare core versions | versions.md, only the relevant delta |
| Presence/Combine compatibility and patch fixes | api-compatibility.md |
| Run Swift tests | testing.md; unset NO_COLOR for swift test |
| Execute DQL, transact, index or evict | store.md |
| Subscribe, scope sync or track status | sync.md |
| Update radios/endpoints | transports.md |
| Create/fetch attachments | attachments.md; retain fetcher; token shape differs by version |
| Stream ephemeral bytes | data-streams.md; 5.2.0 SPI; concepts in data-streams |
| Presence/peer metadata | presence.md |
| Logging and disk usage | observability.md |
| On-disk upgrade/rollback | storage.md |
| Preview/platform APIs | preview.md |
| Architectural tradeoffs | best-practices.md, matching section |
| Run/configure the minimal example | minimal-app-running.md |
| Build a complete example | minimal-app.md (compiled/run) or swiftui-app.md (compile checked) |
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
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.

