I've built two-way sync between the deck and a folder in iCloud Drive, and before opening a ~2k-line PR I'd rather ask whether you want the feature at all.
The approach. Each note becomes one Markdown file in ~/Library/Mobile Documents/com~apple~CloudDocs/Noty/, with a small front-matter header carrying its identity, colour, dates and order. The folder opens in Files on a phone and the notes edit in any in-place Markdown editor. Edits travel both ways, files written on the phone are adopted as notes, deletions propagate.
Not CloudKit. CKContainer needs the com.apple.developer.icloud-container-identifiers entitlement, which needs a provisioning profile, an Xcode project and a paid developer account — the same wall that keeps the app unsandboxed — plus an iOS app that doesn't exist. The iCloud Drive folder is a plain path a non-sandboxed app may use, and the system daemon does the syncing. No account, no entitlements, no server.
The part I actually want your opinion on. The README promises, in its own section, that notes never leave the Mac. This makes that conditional. The feature is off by default and the local database stays AES-GCM encrypted either way, but the files written to iCloud Drive are plaintext — they have to be, or nothing on the phone could open them.
That's your call to make, not mine. If you'd rather Noty not offer this on those grounds, say so and I'll drop it — no hard feelings, and I'd rather hear it now than after you've read the diff.
If you do want it, the branch is ready: vasyakrg/noty:icloud-drive-sync, targeting dev. 20 files, +1979/−13, no new dependencies. SyncPlan.actions is a pure function so the decision table is unit-tested, and the runner talks to the filesystem through a protocol so it's tested against in-memory fakes — the destructive cases (evicted iCloud placeholders, failed reads, duplicate titles, renames and copies made on the phone, a lost index, a note open in an editor when a pull lands) each have a test pinning them.
It also carries one fix that's independent of sync and cherry-pickable on its own: Tasks.fromMarkdown/toMarkdown used String.replacingOccurrences(options: .regularExpression), which can't request .anchorsMatchLines, so importing a Markdown file with several tasks converted only the first one. Happy to send that as its own PR whichever way this goes.
Would also welcome a "yes, but differently" — e.g. if you'd rather the folder location, the file format or the conflict handling worked another way.
I've built two-way sync between the deck and a folder in iCloud Drive, and before opening a ~2k-line PR I'd rather ask whether you want the feature at all.
The approach. Each note becomes one Markdown file in
~/Library/Mobile Documents/com~apple~CloudDocs/Noty/, with a small front-matter header carrying its identity, colour, dates and order. The folder opens in Files on a phone and the notes edit in any in-place Markdown editor. Edits travel both ways, files written on the phone are adopted as notes, deletions propagate.Not CloudKit.
CKContainerneeds thecom.apple.developer.icloud-container-identifiersentitlement, which needs a provisioning profile, an Xcode project and a paid developer account — the same wall that keeps the app unsandboxed — plus an iOS app that doesn't exist. The iCloud Drive folder is a plain path a non-sandboxed app may use, and the system daemon does the syncing. No account, no entitlements, no server.The part I actually want your opinion on. The README promises, in its own section, that notes never leave the Mac. This makes that conditional. The feature is off by default and the local database stays AES-GCM encrypted either way, but the files written to iCloud Drive are plaintext — they have to be, or nothing on the phone could open them.
That's your call to make, not mine. If you'd rather Noty not offer this on those grounds, say so and I'll drop it — no hard feelings, and I'd rather hear it now than after you've read the diff.
If you do want it, the branch is ready:
vasyakrg/noty:icloud-drive-sync, targetingdev. 20 files, +1979/−13, no new dependencies.SyncPlan.actionsis a pure function so the decision table is unit-tested, and the runner talks to the filesystem through a protocol so it's tested against in-memory fakes — the destructive cases (evicted iCloud placeholders, failed reads, duplicate titles, renames and copies made on the phone, a lost index, a note open in an editor when a pull lands) each have a test pinning them.It also carries one fix that's independent of sync and cherry-pickable on its own:
Tasks.fromMarkdown/toMarkdownusedString.replacingOccurrences(options: .regularExpression), which can't request.anchorsMatchLines, so importing a Markdown file with several tasks converted only the first one. Happy to send that as its own PR whichever way this goes.Would also welcome a "yes, but differently" — e.g. if you'd rather the folder location, the file format or the conflict handling worked another way.