@mmerterden/multi-agent-pipeline 20.7.0 → 20.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (284) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/LICENSE +0 -10
  3. package/docs/facts.json +1 -1
  4. package/manifest.json +285 -285
  5. package/package.json +3 -3
  6. package/pipeline/lib/redact.mjs +3 -2
  7. package/pipeline/scripts/_notices.mjs +1 -1
  8. package/pipeline/scripts/gen-skills-index.mjs +13 -1
  9. package/pipeline/scripts/pre-commit-check.sh +4 -0
  10. package/pipeline/skills/.skill-manifest.json +69 -69
  11. package/pipeline/skills/shared/README.md +70 -70
  12. package/pipeline/skills/shared/external/alarmkit/SKILL.md +373 -381
  13. package/pipeline/skills/shared/external/alarmkit/evals/evals.json +23 -18
  14. package/pipeline/skills/shared/external/alarmkit/references/alarmkit-patterns.md +328 -378
  15. package/pipeline/skills/shared/external/app-clips/SKILL.md +260 -160
  16. package/pipeline/skills/shared/external/app-clips/evals/evals.json +27 -27
  17. package/pipeline/skills/shared/external/app-clips/references/data-handoff-notifications-location.md +150 -83
  18. package/pipeline/skills/shared/external/app-clips/references/routing-and-experiences.md +135 -83
  19. package/pipeline/skills/shared/external/app-clips/references/size-capabilities-and-promotion.md +143 -85
  20. package/pipeline/skills/shared/external/app-intents/SKILL.md +302 -304
  21. package/pipeline/skills/shared/external/app-intents/evals/evals.json +21 -21
  22. package/pipeline/skills/shared/external/app-intents/references/appintents-advanced.md +594 -894
  23. package/pipeline/skills/shared/external/app-store-optimization/SKILL.md +345 -277
  24. package/pipeline/skills/shared/external/app-store-optimization/evals/evals.json +27 -23
  25. package/pipeline/skills/shared/external/app-store-optimization/references/keyword-research-methodology.md +107 -121
  26. package/pipeline/skills/shared/external/app-store-optimization/references/product-page-variants.md +145 -165
  27. package/pipeline/skills/shared/external/app-store-review/SKILL.md +306 -326
  28. package/pipeline/skills/shared/external/app-store-review/evals/evals.json +21 -21
  29. package/pipeline/skills/shared/external/app-store-review/references/privacy-manifest.md +105 -67
  30. package/pipeline/skills/shared/external/app-store-review/references/review-checklists.md +114 -101
  31. package/pipeline/skills/shared/external/apple-on-device-ai/SKILL.md +335 -360
  32. package/pipeline/skills/shared/external/apple-on-device-ai/evals/evals.json +24 -27
  33. package/pipeline/skills/shared/external/apple-on-device-ai/references/coreml-conversion.md +215 -322
  34. package/pipeline/skills/shared/external/apple-on-device-ai/references/coreml-optimization.md +161 -256
  35. package/pipeline/skills/shared/external/apple-on-device-ai/references/foundation-models.md +277 -387
  36. package/pipeline/skills/shared/external/apple-on-device-ai/references/mlx-swift.md +196 -210
  37. package/pipeline/skills/shared/external/authentication/SKILL.md +277 -381
  38. package/pipeline/skills/shared/external/authentication/evals/evals.json +25 -25
  39. package/pipeline/skills/shared/external/authentication/references/keychain-biometric.md +135 -178
  40. package/pipeline/skills/shared/external/authentication/references/passkeys.md +111 -147
  41. package/pipeline/skills/shared/external/avkit/SKILL.md +267 -364
  42. package/pipeline/skills/shared/external/avkit/evals/evals.json +26 -26
  43. package/pipeline/skills/shared/external/avkit/references/avkit-patterns.md +375 -493
  44. package/pipeline/skills/shared/external/background-processing/SKILL.md +274 -384
  45. package/pipeline/skills/shared/external/background-processing/evals/evals.json +22 -22
  46. package/pipeline/skills/shared/external/background-processing/references/background-task-patterns.md +173 -321
  47. package/pipeline/skills/shared/external/callkit-voip/SKILL.md +290 -371
  48. package/pipeline/skills/shared/external/callkit-voip/evals/evals.json +24 -24
  49. package/pipeline/skills/shared/external/callkit-voip/references/callkit-patterns.md +175 -343
  50. package/pipeline/skills/shared/external/cloudkit-sync/SKILL.md +292 -381
  51. package/pipeline/skills/shared/external/cloudkit-sync/evals/evals.json +33 -30
  52. package/pipeline/skills/shared/external/cloudkit-sync/references/cloudkit-patterns.md +227 -355
  53. package/pipeline/skills/shared/external/contacts-framework/SKILL.md +197 -346
  54. package/pipeline/skills/shared/external/contacts-framework/evals/evals.json +19 -21
  55. package/pipeline/skills/shared/external/contacts-framework/references/contacts-patterns.md +169 -308
  56. package/pipeline/skills/shared/external/core-bluetooth/SKILL.md +228 -376
  57. package/pipeline/skills/shared/external/core-bluetooth/evals/evals.json +25 -22
  58. package/pipeline/skills/shared/external/core-bluetooth/references/ble-patterns.md +257 -337
  59. package/pipeline/skills/shared/external/core-data/SKILL.md +302 -368
  60. package/pipeline/skills/shared/external/core-data/evals/evals.json +30 -27
  61. package/pipeline/skills/shared/external/core-motion/SKILL.md +235 -324
  62. package/pipeline/skills/shared/external/core-motion/evals/evals.json +31 -27
  63. package/pipeline/skills/shared/external/core-motion/references/motion-patterns.md +210 -310
  64. package/pipeline/skills/shared/external/core-nfc/SKILL.md +292 -366
  65. package/pipeline/skills/shared/external/core-nfc/evals/evals.json +22 -24
  66. package/pipeline/skills/shared/external/core-nfc/references/nfc-patterns.md +233 -329
  67. package/pipeline/skills/shared/external/coreml/SKILL.md +323 -367
  68. package/pipeline/skills/shared/external/coreml/evals/evals.json +24 -21
  69. package/pipeline/skills/shared/external/coreml/references/coreml-swift-integration.md +562 -565
  70. package/pipeline/skills/shared/external/cryptokit/SKILL.md +253 -394
  71. package/pipeline/skills/shared/external/cryptokit/evals/evals.json +20 -18
  72. package/pipeline/skills/shared/external/cryptokit/references/cryptokit-patterns.md +299 -488
  73. package/pipeline/skills/shared/external/debugging-instruments/SKILL.md +270 -323
  74. package/pipeline/skills/shared/external/debugging-instruments/evals/evals.json +27 -30
  75. package/pipeline/skills/shared/external/debugging-instruments/references/instruments-guide.md +167 -315
  76. package/pipeline/skills/shared/external/debugging-instruments/references/lldb-patterns.md +140 -193
  77. package/pipeline/skills/shared/external/device-integrity/SKILL.md +236 -353
  78. package/pipeline/skills/shared/external/device-integrity/evals/evals.json +25 -21
  79. package/pipeline/skills/shared/external/device-integrity/references/device-integrity-patterns.md +159 -197
  80. package/pipeline/skills/shared/external/energykit/SKILL.md +225 -392
  81. package/pipeline/skills/shared/external/energykit/evals/evals.json +29 -28
  82. package/pipeline/skills/shared/external/energykit/references/energykit-patterns.md +174 -470
  83. package/pipeline/skills/shared/external/eventkit-calendar/SKILL.md +261 -383
  84. package/pipeline/skills/shared/external/eventkit-calendar/evals/evals.json +25 -22
  85. package/pipeline/skills/shared/external/eventkit-calendar/references/eventkit-patterns.md +165 -268
  86. package/pipeline/skills/shared/external/healthkit/SKILL.md +252 -303
  87. package/pipeline/skills/shared/external/healthkit/evals/evals.json +24 -23
  88. package/pipeline/skills/shared/external/healthkit/references/healthkit-patterns.md +369 -523
  89. package/pipeline/skills/shared/external/homekit-matter/SKILL.md +233 -348
  90. package/pipeline/skills/shared/external/homekit-matter/evals/evals.json +27 -22
  91. package/pipeline/skills/shared/external/homekit-matter/references/matter-commissioning.md +199 -305
  92. package/pipeline/skills/shared/external/ios-accessibility/SKILL.md +368 -340
  93. package/pipeline/skills/shared/external/ios-accessibility/evals/evals.json +28 -27
  94. package/pipeline/skills/shared/external/ios-accessibility/references/a11y-patterns.md +314 -260
  95. package/pipeline/skills/shared/external/ios-accessibility/references/media-accessibility.md +97 -67
  96. package/pipeline/skills/shared/external/ios-accessibility/references/nutrition-labels.md +165 -101
  97. package/pipeline/skills/shared/external/ios-localization/SKILL.md +258 -371
  98. package/pipeline/skills/shared/external/ios-localization/evals/evals.json +23 -23
  99. package/pipeline/skills/shared/external/ios-localization/references/formatstyle-locale.md +283 -491
  100. package/pipeline/skills/shared/external/ios-localization/references/string-catalogs.md +313 -440
  101. package/pipeline/skills/shared/external/ios-networking/SKILL.md +265 -341
  102. package/pipeline/skills/shared/external/ios-networking/evals/evals.json +24 -24
  103. package/pipeline/skills/shared/external/ios-networking/references/background-websocket.md +425 -652
  104. package/pipeline/skills/shared/external/ios-networking/references/file-storage-patterns.md +143 -285
  105. package/pipeline/skills/shared/external/ios-networking/references/lightweight-clients.md +93 -53
  106. package/pipeline/skills/shared/external/ios-networking/references/network-framework.md +231 -456
  107. package/pipeline/skills/shared/external/ios-networking/references/urlsession-patterns.md +517 -784
  108. package/pipeline/skills/shared/external/ios-simulator/SKILL.md +265 -393
  109. package/pipeline/skills/shared/external/ios-simulator/evals/evals.json +21 -21
  110. package/pipeline/skills/shared/external/ios-simulator/references/simctl-commands.md +177 -270
  111. package/pipeline/skills/shared/external/live-activities/SKILL.md +318 -360
  112. package/pipeline/skills/shared/external/live-activities/evals/evals.json +21 -21
  113. package/pipeline/skills/shared/external/live-activities/references/activitykit-patterns.md +478 -710
  114. package/pipeline/skills/shared/external/localization-reuse-map/SKILL.md +3 -3
  115. package/pipeline/skills/shared/external/localization-reuse-map/example-mapping.json +1 -1
  116. package/pipeline/skills/shared/external/localization-reuse-map/reference/format-and-output.md +8 -7
  117. package/pipeline/skills/shared/external/localization-reuse-map/reference/publish-and-snapshot.md +2 -2
  118. package/pipeline/skills/shared/external/localization-reuse-map/reference/sources-and-recipes.md +5 -2
  119. package/pipeline/skills/shared/external/localization-reuse-map/scripts/_shared.py +100 -0
  120. package/pipeline/skills/shared/external/localization-reuse-map/scripts/build-artifact.py +45 -26
  121. package/pipeline/skills/shared/external/localization-reuse-map/scripts/build-spreadsheet.py +14 -16
  122. package/pipeline/skills/shared/external/localization-reuse-map/scripts/fetch-annotations.py +12 -5
  123. package/pipeline/skills/shared/external/localization-reuse-map/scripts/fetch-legacy-labels.py +2 -1
  124. package/pipeline/skills/shared/external/localization-reuse-map/scripts/publish-confluence.py +6 -5
  125. package/pipeline/skills/shared/external/localization-reuse-map/scripts/render-overlay.py +44 -18
  126. package/pipeline/skills/shared/external/localization-reuse-map/scripts/resolve-legacy-values.py +5 -2
  127. package/pipeline/skills/shared/external/localization-reuse-map/scripts/resolve-new-values.py +10 -11
  128. package/pipeline/skills/shared/external/localization-reuse-map/scripts/scan-screen-keys.py +4 -33
  129. package/pipeline/skills/shared/external/localization-reuse-map/scripts/verify-map.py +12 -59
  130. package/pipeline/skills/shared/external/mapkit-location/SKILL.md +297 -267
  131. package/pipeline/skills/shared/external/mapkit-location/evals/evals.json +28 -24
  132. package/pipeline/skills/shared/external/mapkit-location/references/mapkit-corelocation-patterns.md +378 -532
  133. package/pipeline/skills/shared/external/mapkit-location/references/mapkit-patterns.md +397 -499
  134. package/pipeline/skills/shared/external/metrickit-diagnostics/SKILL.md +165 -348
  135. package/pipeline/skills/shared/external/metrickit-diagnostics/evals/evals.json +26 -23
  136. package/pipeline/skills/shared/external/metrickit-diagnostics/references/metrickit-patterns.md +123 -130
  137. package/pipeline/skills/shared/external/musickit-audio/SKILL.md +189 -315
  138. package/pipeline/skills/shared/external/musickit-audio/evals/evals.json +22 -21
  139. package/pipeline/skills/shared/external/musickit-audio/references/musickit-patterns.md +181 -270
  140. package/pipeline/skills/shared/external/natural-language/SKILL.md +188 -340
  141. package/pipeline/skills/shared/external/natural-language/evals/evals.json +21 -21
  142. package/pipeline/skills/shared/external/natural-language/references/translation-patterns.md +171 -225
  143. package/pipeline/skills/shared/external/passkit-wallet/SKILL.md +258 -392
  144. package/pipeline/skills/shared/external/passkit-wallet/evals/evals.json +30 -29
  145. package/pipeline/skills/shared/external/passkit-wallet/references/wallet-passes.md +164 -231
  146. package/pipeline/skills/shared/external/pdfkit/SKILL.md +312 -344
  147. package/pipeline/skills/shared/external/pdfkit/evals/evals.json +19 -19
  148. package/pipeline/skills/shared/external/pdfkit/references/pdfkit-patterns.md +413 -624
  149. package/pipeline/skills/shared/external/pencilkit-drawing/SKILL.md +242 -358
  150. package/pipeline/skills/shared/external/pencilkit-drawing/evals/evals.json +25 -21
  151. package/pipeline/skills/shared/external/pencilkit-drawing/references/pencilkit-patterns.md +161 -226
  152. package/pipeline/skills/shared/external/permissionkit/SKILL.md +282 -400
  153. package/pipeline/skills/shared/external/permissionkit/evals/evals.json +27 -30
  154. package/pipeline/skills/shared/external/permissionkit/references/permissionkit-patterns.md +237 -350
  155. package/pipeline/skills/shared/external/photos-camera-media/SKILL.md +276 -325
  156. package/pipeline/skills/shared/external/photos-camera-media/references/av-playback.md +299 -545
  157. package/pipeline/skills/shared/external/photos-camera-media/references/camera-capture.md +344 -588
  158. package/pipeline/skills/shared/external/photos-camera-media/references/image-loading-caching.md +316 -660
  159. package/pipeline/skills/shared/external/photos-camera-media/references/photokit-patterns.md +270 -416
  160. package/pipeline/skills/shared/external/push-notifications/SKILL.md +312 -340
  161. package/pipeline/skills/shared/external/push-notifications/evals/evals.json +27 -26
  162. package/pipeline/skills/shared/external/push-notifications/references/notification-patterns.md +328 -485
  163. package/pipeline/skills/shared/external/push-notifications/references/rich-notifications.md +327 -560
  164. package/pipeline/skills/shared/external/realitykit-ar/SKILL.md +218 -410
  165. package/pipeline/skills/shared/external/realitykit-ar/evals/evals.json +24 -27
  166. package/pipeline/skills/shared/external/realitykit-ar/references/realitykit-patterns.md +221 -348
  167. package/pipeline/skills/shared/external/shareplay-activities/SKILL.md +222 -393
  168. package/pipeline/skills/shared/external/shareplay-activities/evals/evals.json +23 -24
  169. package/pipeline/skills/shared/external/shareplay-activities/references/shareplay-patterns.md +280 -420
  170. package/pipeline/skills/shared/external/skill-creator/template.md +7 -1
  171. package/pipeline/skills/shared/external/speech-recognition/SKILL.md +217 -421
  172. package/pipeline/skills/shared/external/speech-recognition/evals/evals.json +23 -26
  173. package/pipeline/skills/shared/external/speech-recognition/references/speechanalyzer-patterns.md +133 -125
  174. package/pipeline/skills/shared/external/storekit/SKILL.md +228 -204
  175. package/pipeline/skills/shared/external/storekit/evals/evals.json +27 -24
  176. package/pipeline/skills/shared/external/storekit/references/app-review-guidelines.md +98 -109
  177. package/pipeline/skills/shared/external/storekit/references/core-patterns.md +302 -241
  178. package/pipeline/skills/shared/external/storekit/references/storekit-advanced.md +356 -649
  179. package/pipeline/skills/shared/external/swift-api-design-guidelines/SKILL.md +274 -399
  180. package/pipeline/skills/shared/external/swift-api-design-guidelines/evals/evals.json +22 -24
  181. package/pipeline/skills/shared/external/swift-api-design-guidelines/references/argument-labels-and-parameters.md +107 -108
  182. package/pipeline/skills/shared/external/swift-api-design-guidelines/references/conventions-and-special-rules.md +93 -165
  183. package/pipeline/skills/shared/external/swift-api-design-guidelines/references/naming-and-clarity.md +99 -137
  184. package/pipeline/skills/shared/external/swift-api-design-guidelines/references/side-effects-and-mutating-pairs.md +77 -120
  185. package/pipeline/skills/shared/external/swift-architecture/SKILL.md +334 -350
  186. package/pipeline/skills/shared/external/swift-architecture/evals/evals.json +22 -22
  187. package/pipeline/skills/shared/external/swift-charts/SKILL.md +208 -394
  188. package/pipeline/skills/shared/external/swift-charts/evals/evals.json +27 -30
  189. package/pipeline/skills/shared/external/swift-charts/references/charts-patterns.md +351 -762
  190. package/pipeline/skills/shared/external/swift-codable/SKILL.md +339 -343
  191. package/pipeline/skills/shared/external/swift-codable/evals/evals.json +20 -20
  192. package/pipeline/skills/shared/external/swift-concurrency/SKILL.md +304 -351
  193. package/pipeline/skills/shared/external/swift-concurrency/evals/evals.json +27 -24
  194. package/pipeline/skills/shared/external/swift-concurrency/references/approachable-concurrency.md +65 -80
  195. package/pipeline/skills/shared/external/swift-concurrency/references/async-algorithms.md +48 -84
  196. package/pipeline/skills/shared/external/swift-concurrency/references/bridging-interop.md +134 -79
  197. package/pipeline/skills/shared/external/swift-concurrency/references/concurrency-patterns.md +145 -167
  198. package/pipeline/skills/shared/external/swift-concurrency/references/diagnostics.md +62 -50
  199. package/pipeline/skills/shared/external/swift-concurrency/references/swiftui-concurrency.md +92 -121
  200. package/pipeline/skills/shared/external/swift-concurrency/references/synchronization-primitives.md +177 -241
  201. package/pipeline/skills/shared/external/swift-formatstyle/SKILL.md +258 -234
  202. package/pipeline/skills/shared/external/swift-language/SKILL.md +342 -382
  203. package/pipeline/skills/shared/external/swift-language/evals/evals.json +24 -27
  204. package/pipeline/skills/shared/external/swift-language/references/swift-attributes-interop.md +79 -56
  205. package/pipeline/skills/shared/external/swift-language/references/swift-patterns-extended.md +297 -340
  206. package/pipeline/skills/shared/external/swift-security/SKILL.md +183 -162
  207. package/pipeline/skills/shared/external/swift-security/evals/evals.json +25 -25
  208. package/pipeline/skills/shared/external/swift-security/references/biometric-authentication.md +314 -469
  209. package/pipeline/skills/shared/external/swift-security/references/certificate-trust.md +411 -476
  210. package/pipeline/skills/shared/external/swift-security/references/common-anti-patterns.md +260 -530
  211. package/pipeline/skills/shared/external/swift-security/references/compliance-owasp-mapping.md +270 -477
  212. package/pipeline/skills/shared/external/swift-security/references/credential-storage-patterns.md +573 -571
  213. package/pipeline/skills/shared/external/swift-security/references/cryptokit-public-key.md +370 -441
  214. package/pipeline/skills/shared/external/swift-security/references/cryptokit-symmetric.md +332 -433
  215. package/pipeline/skills/shared/external/swift-security/references/keychain-access-control.md +346 -468
  216. package/pipeline/skills/shared/external/swift-security/references/keychain-fundamentals.md +375 -491
  217. package/pipeline/skills/shared/external/swift-security/references/keychain-item-classes.md +431 -432
  218. package/pipeline/skills/shared/external/swift-security/references/keychain-sharing.md +328 -425
  219. package/pipeline/skills/shared/external/swift-security/references/migration-legacy-stores.md +341 -579
  220. package/pipeline/skills/shared/external/swift-security/references/secure-enclave.md +397 -457
  221. package/pipeline/skills/shared/external/swift-security/references/testing-security-code.md +354 -614
  222. package/pipeline/skills/shared/external/swift-testing/SKILL.md +191 -175
  223. package/pipeline/skills/shared/external/swift-testing/evals/evals.json +26 -24
  224. package/pipeline/skills/shared/external/swift-testing/references/testing-advanced.md +81 -84
  225. package/pipeline/skills/shared/external/swift-testing/references/testing-patterns.md +317 -433
  226. package/pipeline/skills/shared/external/swiftdata/SKILL.md +394 -256
  227. package/pipeline/skills/shared/external/swiftdata/evals/evals.json +24 -24
  228. package/pipeline/skills/shared/external/swiftdata/references/core-data-coexistence.md +206 -402
  229. package/pipeline/skills/shared/external/swiftdata/references/indexing.md +59 -52
  230. package/pipeline/skills/shared/external/swiftdata/references/predicate-pitfalls.md +57 -33
  231. package/pipeline/skills/shared/external/swiftdata/references/swiftdata-advanced.md +354 -747
  232. package/pipeline/skills/shared/external/swiftdata/references/swiftdata-queries.md +300 -508
  233. package/pipeline/skills/shared/external/swiftlint/SKILL.md +175 -226
  234. package/pipeline/skills/shared/external/swiftlint/references/adoption-and-configuration.md +141 -208
  235. package/pipeline/skills/shared/external/swiftlint/references/custom-rules-and-analyze.md +100 -109
  236. package/pipeline/skills/shared/external/swiftlint/references/plugins-run-scripts-and-integrations.md +159 -179
  237. package/pipeline/skills/shared/external/swiftlint/references/rule-reference.md +383 -18
  238. package/pipeline/skills/shared/external/swiftlint/references/rules-suppressions-and-baselines.md +143 -229
  239. package/pipeline/skills/shared/external/swiftui-animation/SKILL.md +283 -366
  240. package/pipeline/skills/shared/external/swiftui-animation/references/animation-advanced.md +396 -608
  241. package/pipeline/skills/shared/external/swiftui-animation/references/core-animation-bridge.md +336 -385
  242. package/pipeline/skills/shared/external/swiftui-gestures/SKILL.md +239 -349
  243. package/pipeline/skills/shared/external/swiftui-gestures/references/gesture-patterns.md +228 -310
  244. package/pipeline/skills/shared/external/swiftui-layout-components/SKILL.md +260 -249
  245. package/pipeline/skills/shared/external/swiftui-layout-components/references/form.md +92 -74
  246. package/pipeline/skills/shared/external/swiftui-layout-components/references/grids.md +112 -177
  247. package/pipeline/skills/shared/external/swiftui-layout-components/references/list.md +61 -64
  248. package/pipeline/skills/shared/external/swiftui-layout-components/references/scrollview.md +94 -134
  249. package/pipeline/skills/shared/external/swiftui-liquid-glass/SKILL.md +193 -225
  250. package/pipeline/skills/shared/external/swiftui-liquid-glass/references/liquid-glass.md +173 -327
  251. package/pipeline/skills/shared/external/swiftui-navigation/SKILL.md +201 -168
  252. package/pipeline/skills/shared/external/swiftui-navigation/references/deeplinks.md +127 -150
  253. package/pipeline/skills/shared/external/swiftui-navigation/references/navigationstack.md +134 -133
  254. package/pipeline/skills/shared/external/swiftui-navigation/references/sheets.md +152 -117
  255. package/pipeline/skills/shared/external/swiftui-navigation/references/tabview.md +111 -138
  256. package/pipeline/skills/shared/external/swiftui-patterns/SKILL.md +316 -252
  257. package/pipeline/skills/shared/external/swiftui-patterns/references/architecture-patterns.md +341 -332
  258. package/pipeline/skills/shared/external/swiftui-patterns/references/deprecated-migration.md +547 -854
  259. package/pipeline/skills/shared/external/swiftui-patterns/references/design-polish.md +485 -537
  260. package/pipeline/skills/shared/external/swiftui-patterns/references/platform-and-sharing.md +417 -499
  261. package/pipeline/skills/shared/external/swiftui-performance/SKILL.md +213 -376
  262. package/pipeline/skills/shared/external/swiftui-performance/references/demystify-swiftui-performance-wwdc23.md +86 -175
  263. package/pipeline/skills/shared/external/swiftui-performance/references/optimizing-swiftui-performance-instruments.md +89 -195
  264. package/pipeline/skills/shared/external/swiftui-performance/references/understanding-hangs-in-your-app.md +95 -182
  265. package/pipeline/skills/shared/external/swiftui-performance/references/understanding-improving-swiftui-performance.md +71 -149
  266. package/pipeline/skills/shared/external/swiftui-performance/references/wwdc-session-sources.md +21 -27
  267. package/pipeline/skills/shared/external/swiftui-uikit-interop/SKILL.md +303 -295
  268. package/pipeline/skills/shared/external/swiftui-uikit-interop/references/hosting-migration.md +204 -387
  269. package/pipeline/skills/shared/external/swiftui-uikit-interop/references/representable-recipes.md +469 -683
  270. package/pipeline/skills/shared/external/swiftui-webkit/SKILL.md +140 -186
  271. package/pipeline/skills/shared/external/swiftui-webkit/references/loading-and-observation.md +75 -86
  272. package/pipeline/skills/shared/external/swiftui-webkit/references/local-content-and-custom-schemes.md +63 -60
  273. package/pipeline/skills/shared/external/swiftui-webkit/references/migration-and-fallbacks.md +69 -137
  274. package/pipeline/skills/shared/external/swiftui-webkit/references/navigation-and-javascript.md +95 -67
  275. package/pipeline/skills/shared/external/tipkit/SKILL.md +220 -335
  276. package/pipeline/skills/shared/external/tipkit/references/tipkit-patterns.md +356 -494
  277. package/pipeline/skills/shared/external/vision-framework/SKILL.md +260 -375
  278. package/pipeline/skills/shared/external/vision-framework/references/vision-requests.md +393 -515
  279. package/pipeline/skills/shared/external/vision-framework/references/visionkit-scanner.md +363 -539
  280. package/pipeline/skills/shared/external/weatherkit/SKILL.md +160 -315
  281. package/pipeline/skills/shared/external/weatherkit/references/weatherkit-patterns.md +288 -407
  282. package/pipeline/skills/shared/external/widgetkit/SKILL.md +224 -288
  283. package/pipeline/skills/shared/external/widgetkit/references/widgetkit-advanced.md +416 -719
  284. package/pipeline/skills/shared/external/NOTICE-swift-ios-skills.md +0 -39
@@ -1,499 +1,377 @@
1
1
  ---
2
2
  name: eventkit-calendar
3
- description: "Create, read, and manage calendar events and reminders using EventKit and EventKitUI. Use when adding events to the user's calendar, creating reminders, setting recurrence rules, requesting calendar or reminders access, presenting event editors, choosing calendars, handling alarms, observing calendar changes, or working with EKEventStore, EKEvent, EKReminder, EKCalendar, EKRecurrenceRule, EKEventEditViewController, EKCalendarChooser, or EventKitUI views."
3
+ description: "EventKit and EventKitUI: adding events to the user's calendar, creating reminders, recurrence rules, calendar or reminders access, event editors, calendar choosers, alarms, change observation, with EKEventStore, EKEvent, EKReminder, EKCalendar, EKRecurrenceRule, EKEventEditViewController, EKCalendarChooser. Use when an app reads or writes the user's calendars or reminders. Not for app-owned local or push notifications (push-notifications)."
4
4
  metadata:
5
- source: "dpearson2699/swift-ios-skills (PolyForm Perimeter 1.0.0)"
5
+ source: multi-agent-pipeline
6
6
  ---
7
7
 
8
- # EventKit
8
+ # EventKit: Calendars and Reminders
9
9
 
10
- Create, read, and manage calendar events and reminders. Covers authorization,
11
- event and reminder CRUD, recurrence rules, alarms, and EventKitUI editors.
12
- Targets Swift 6.3 / iOS 26+.
10
+ EventKit reads and writes the same calendars and reminder lists the user sees
11
+ in Calendar and Reminders. EventKitUI adds system screens for editing, viewing
12
+ and choosing calendars. Examples assume Swift 6.3 and iOS 26.
13
13
 
14
- ## Contents
15
-
16
- - [Setup](#setup)
17
- - [Authorization](#authorization)
18
- - [Creating Events](#creating-events)
19
- - [Fetching Events](#fetching-events)
20
- - [Reminders](#reminders)
21
- - [Recurrence Rules](#recurrence-rules)
22
- - [Alarms](#alarms)
23
- - [EventKitUI Controllers](#eventkitui-controllers)
24
- - [Observing Changes](#observing-changes)
25
- - [Common Mistakes](#common-mistakes)
26
- - [Review Checklist](#review-checklist)
27
- - [References](#references)
14
+ Alerts the app itself sends (local notifications, pushes) are not EventKit;
15
+ use `UNUserNotificationCenter` and the `push-notifications` skill for those.
28
16
 
29
17
  ## Setup
30
18
 
31
- ### Info.plist Keys
19
+ ### Usage descriptions
32
20
 
33
- Add the required usage description strings based on what access level you need:
21
+ | Key | When |
22
+ |-----|------|
23
+ | `NSCalendarsFullAccessUsageDescription` | The app reads and writes events |
24
+ | `NSCalendarsWriteOnlyAccessUsageDescription` | The app writes events directly but never reads them |
25
+ | `NSRemindersFullAccessUsageDescription` | The app reads or writes reminders |
34
26
 
35
- | Key | Access Level |
36
- |---|---|
37
- | `NSCalendarsFullAccessUsageDescription` | Read + write events |
38
- | `NSCalendarsWriteOnlyAccessUsageDescription` | Direct write-only event creation |
39
- | `NSRemindersFullAccessUsageDescription` | Read + write reminders |
27
+ - Since iOS 17, creating events solely through
28
+ `EKEventEditViewController` requires no calendar permission and no calendar
29
+ usage string.
30
+ - Writing events with EventKit directly needs write-only or full access.
31
+ Reading or fetching events needs full access.
32
+ - Reminders have a single level: full access.
33
+ - If the app also runs on iOS 10 through 16, add the older
34
+ `NSCalendarsUsageDescription` and `NSRemindersUsageDescription` too. When
35
+ EventKitUI on those versions may show contact names or photos, add
36
+ `NSContactsUsageDescription` as well.
40
37
 
41
- On iOS 17+, an app that only presents `EKEventEditViewController` to let the
42
- person create an event does not need calendar authorization or calendar usage
43
- strings. Direct EventKit writes need write-only or full calendar access; any
44
- event read/fetch needs full calendar access. Reminders have only full access.
38
+ ### One store
45
39
 
46
- > For apps also running on iOS 10 through iOS 16, include the legacy
47
- > `NSCalendarsUsageDescription` / `NSRemindersUsageDescription` keys. If using
48
- > EventKitUI on those systems, also include `NSContactsUsageDescription` when the
49
- > UI may need contact display names or avatars.
40
+ Create a single `EKEventStore` and share it. Events, reminders and calendars
41
+ belong to the store that produced them; passing an object from one store to
42
+ another is undefined behaviour.
50
43
 
51
- ### Event Store
44
+ ## Asking for access
52
45
 
53
- Create a single `EKEventStore` instance and reuse it. Do not mix objects from
54
- different event stores.
46
+ iOS 17 split calendar access into levels. Ask for the smallest one the feature
47
+ needs.
55
48
 
56
49
  ```swift
57
50
  import EventKit
58
51
 
59
- let eventStore = EKEventStore()
60
- ```
61
-
62
- ## Authorization
63
-
64
- iOS 17+ introduced granular access levels. Request the narrowest access that
65
- matches the feature. If the deployment target includes earlier OS versions,
66
- availability-guard the iOS 17+ methods and fall back to `requestAccess(to:)`
67
- only before iOS 17.
68
-
69
- ### Full Access to Events
70
-
71
- Call `try await eventStore.requestFullAccessToEvents()` when the app needs to
72
- read, edit, delete, or fetch calendar events.
52
+ @MainActor
53
+ final class Planner {
54
+ let store = EKEventStore()
73
55
 
74
- ### Write-Only Access to Events
75
-
76
- Use when your app only creates events (e.g., saving an appointment) and does not
77
- need to read existing events.
78
-
79
- Call `try await eventStore.requestWriteOnlyAccessToEvents()` before direct
80
- EventKit writes that do not use `EKEventEditViewController`.
81
-
82
- With write-only access, EventKit can create events but cannot read calendars or
83
- events, including events the app created. Calendar reads return a virtual
84
- calendar and event fetches return no events.
56
+ func allowReadingSchedule() async throws -> Bool {
57
+ try await store.requestFullAccessToEvents()
58
+ }
85
59
 
86
- Use full access instead of write-only if the app must later query, verify,
87
- modify, or sync saved events.
60
+ func allowAddingEvents() async throws -> Bool {
61
+ try await store.requestWriteOnlyAccessToEvents()
62
+ }
88
63
 
89
- ### Full Access to Reminders
64
+ func allowReminders() async throws -> Bool {
65
+ try await store.requestFullAccessToReminders()
66
+ }
67
+ }
68
+ ```
90
69
 
91
- Call `try await eventStore.requestFullAccessToReminders()` before reading,
92
- creating, editing, or deleting reminders.
70
+ `Planner` owns the app's one store. `EKEventStore` is not `Sendable`, so
71
+ Swift 6 rejects it as a plain global; keeping it on a `@MainActor` type is the
72
+ simple fix. Later functions that use `store` are `Planner` methods; the
73
+ EventKitUI snippets run inside a view controller that can reach the same store.
93
74
 
94
- ### Checking Authorization Status
75
+ - **Full event access**: required to read, change, delete or fetch
76
+ events.
77
+ - **Write-only event access**: enough to save events directly without the
78
+ system editor. It cannot read anything, not even events the app itself
79
+ saved: calendar lookups return a single virtual calendar and event fetches
80
+ come back empty. If the app will later need to check, edit or sync what it
81
+ saved, ask for full access instead.
82
+ - **Full access to reminders**: required for any reminder work.
95
83
 
96
- Use `EKEventStore.authorizationStatus(for: .event)` or `.reminder` before work.
97
- Handle `.notDetermined`, `.fullAccess`, `.writeOnly`, `.restricted`, `.denied`,
98
- and `@unknown default`; only `.fullAccess` supports event/reminder reads.
84
+ When the deployment target is below iOS 17, wrap these calls in
85
+ `if #available(iOS 17.0, *)` and use `requestAccess(to:)` only in the `else`
86
+ branch.
99
87
 
100
- ## Creating Events
88
+ ### Checking the current status
101
89
 
102
90
  ```swift
103
- func createEvent(
104
- title: String,
105
- startDate: Date,
106
- endDate: Date,
107
- calendar: EKCalendar? = nil
108
- ) throws {
109
- let event = EKEvent(eventStore: eventStore)
110
- event.title = title
111
- event.startDate = startDate
112
- event.endDate = endDate
113
- event.calendar = calendar ?? eventStore.defaultCalendarForNewEvents
114
-
115
- try eventStore.save(event, span: .thisEvent)
91
+ func canReadEvents() -> Bool {
92
+ switch EKEventStore.authorizationStatus(for: .event) {
93
+ case .fullAccess:
94
+ return true
95
+ case .writeOnly, .notDetermined, .restricted, .denied:
96
+ return false
97
+ @unknown default:
98
+ return false
99
+ }
116
100
  }
117
101
  ```
118
102
 
119
- ### Setting a Specific Calendar
103
+ Only `.fullAccess` allows reads. The same call with `.reminder` covers
104
+ reminders.
120
105
 
121
- ```swift
122
- // List writable calendars
123
- let calendars = eventStore.calendars(for: .event)
124
- .filter { $0.allowsContentModifications }
125
-
126
- // Use the first writable calendar, or the default
127
- let targetCalendar = calendars.first ?? eventStore.defaultCalendarForNewEvents
128
- event.calendar = targetCalendar
129
- ```
106
+ ## Events
130
107
 
131
- ### Adding Structured Location
108
+ ### Saving an event
132
109
 
133
110
  ```swift
134
- import CoreLocation
135
-
136
- let location = EKStructuredLocation(title: "Apple Park")
137
- location.geoLocation = CLLocation(latitude: 37.3349, longitude: -122.0090)
138
- event.structuredLocation = location
111
+ func addRehearsal(start: Date) throws {
112
+ let rehearsal = EKEvent(eventStore: store)
113
+ rehearsal.title = "Choir Rehearsal"
114
+ rehearsal.startDate = start
115
+ rehearsal.endDate = start.addingTimeInterval(90 * 60)
116
+ rehearsal.calendar = store.defaultCalendarForNewEvents
117
+ rehearsal.timeZone = TimeZone(identifier: "Europe/Lisbon")
118
+
119
+ let hall = EKStructuredLocation(title: "Parish Hall")
120
+ hall.geoLocation = CLLocation(latitude: 38.7139, longitude: -9.1334)
121
+ rehearsal.structuredLocation = hall
122
+
123
+ try store.save(rehearsal, span: .thisEvent)
124
+ }
139
125
  ```
140
126
 
141
- ## Fetching Events
142
-
143
- Use a date-range predicate to query events. The `events(matching:)` method
144
- returns occurrences of recurring events expanded within the range. Fetching
145
- events requires full calendar access; write-only access returns no events.
146
- Event predicates are capped to a four-year span, and `events(matching:)` /
147
- `enumerateEvents(matching:using:)` are synchronous and return only committed
148
- events.
127
+ Before saving into a calendar other than the default, make sure it accepts
128
+ changes:
149
129
 
150
130
  ```swift
151
- func fetchEvents(from start: Date, to end: Date) -> [EKEvent] {
152
- let predicate = eventStore.predicateForEvents(
153
- withStart: start,
154
- end: end,
155
- calendars: nil // nil = all calendars
156
- )
157
- return eventStore.events(matching: predicate)
158
- .sorted { $0.startDate < $1.startDate }
159
- }
131
+ let writable = store.calendars(for: .event).filter(\.allowsContentModifications)
160
132
  ```
161
133
 
162
- ### Fetching a Single Event by Identifier
134
+ Setting `timeZone` matters for events tied to a place; without it, a traveller
135
+ sees the wrong local time.
136
+
137
+ ### Fetching events
163
138
 
164
139
  ```swift
165
- if let event = eventStore.event(withIdentifier: savedEventID) {
166
- print(event.title ?? "No title")
140
+ func upcoming(days: Int) -> [EKEvent] {
141
+ let today = Calendar.current.startOfDay(for: .now)
142
+ let horizon = today.addingTimeInterval(TimeInterval(days) * 86_400)
143
+ let window = store.predicateForEvents(withStart: today, end: horizon, calendars: nil)
144
+ return store.events(matching: window).sorted { $0.startDate < $1.startDate }
167
145
  }
168
146
  ```
169
147
 
170
- ## Reminders
148
+ - `calendars: nil` means every calendar.
149
+ - Recurring events come back as individual occurrences inside the range.
150
+ - Fetching needs full access; under write-only the result is empty.
151
+ - A predicate can span at most four years.
152
+ - Both `events(matching:)` and `enumerateEvents(matching:using:)` run
153
+ synchronously, and neither sees uncommitted changes.
154
+ - One event by id: `store.event(withIdentifier:)`.
171
155
 
172
- ### Creating a Reminder
156
+ ## Reminders
173
157
 
174
158
  ```swift
175
- func createReminder(title: String, dueDate: Date) throws {
176
- let reminder = EKReminder(eventStore: eventStore)
177
- reminder.title = title
178
- reminder.calendar = eventStore.defaultCalendarForNewReminders()
179
-
180
- let dueDateComponents = Calendar.current.dateComponents(
181
- [.year, .month, .day, .hour, .minute],
182
- from: dueDate
183
- )
184
- reminder.dueDateComponents = dueDateComponents
185
-
186
- try eventStore.save(reminder, commit: true)
159
+ func remindToWater(at due: Date) throws {
160
+ guard let list = store.defaultCalendarForNewReminders() else { throw PlannerError.noReminderList }
161
+ let reminder = EKReminder(eventStore: store)
162
+ reminder.title = "Water the tomatoes"
163
+ reminder.calendar = list
164
+ let parts: Set<Calendar.Component> = [.year, .month, .day, .hour, .minute]
165
+ reminder.dueDateComponents = Calendar.current.dateComponents(parts, from: due)
166
+ try store.save(reminder, commit: true)
187
167
  }
188
168
  ```
189
169
 
190
- ### Fetching Reminders
191
-
192
- Reminder fetches are asynchronous and return through a completion handler.
170
+ Reminder fetches use a completion handler that runs on a background queue.
171
+ `EKReminder` is not `Sendable`, so Swift 6 refuses to pass the array through a
172
+ continuation into a main-actor method. Copy what the caller needs into a
173
+ `Sendable` value inside the callback and keep the identifier for a later
174
+ `store.calendarItem(withIdentifier:)` lookup:
193
175
 
194
176
  ```swift
195
- func fetchIncompleteReminders() async -> [EKReminder] {
196
- let predicate = eventStore.predicateForIncompleteReminders(
177
+ struct ReminderRow: Sendable {
178
+ let id: String
179
+ let title: String
180
+ let due: DateComponents?
181
+ }
182
+
183
+ func openReminders(until end: Date) async -> [ReminderRow] {
184
+ let query = store.predicateForIncompleteReminders(
197
185
  withDueDateStarting: nil,
198
- ending: nil,
186
+ ending: end,
199
187
  calendars: nil
200
188
  )
201
-
202
- return await withCheckedContinuation { continuation in
203
- eventStore.fetchReminders(matching: predicate) { reminders in
204
- continuation.resume(returning: reminders ?? [])
189
+ return await withCheckedContinuation { resume in
190
+ store.fetchReminders(matching: query) { found in
191
+ let rows = (found ?? []).map {
192
+ ReminderRow(id: $0.calendarItemIdentifier, title: $0.title, due: $0.dueDateComponents)
193
+ }
194
+ resume.resume(returning: rows)
205
195
  }
206
196
  }
207
197
  }
208
198
  ```
209
199
 
210
- ### Completing a Reminder
211
-
212
- ```swift
213
- func completeReminder(_ reminder: EKReminder) throws {
214
- reminder.isCompleted = true
215
- try eventStore.save(reminder, commit: true)
216
- }
217
- ```
218
-
219
- ## Recurrence Rules
200
+ To tick a reminder off, set `isCompleted = true` and save it with
201
+ `commit: true`.
220
202
 
221
- Use `EKRecurrenceRule` to create repeating events or reminders.
222
-
223
- ### Simple Recurrence
203
+ ## Recurrence
224
204
 
225
205
  ```swift
226
- // Every week, indefinitely
227
- let weeklyRule = EKRecurrenceRule(
228
- recurrenceWith: .weekly,
229
- interval: 1,
230
- end: nil
231
- )
232
- event.addRecurrenceRule(weeklyRule)
206
+ let everyWeek = EKRecurrenceRule(recurrenceWith: .weekly, interval: 1, end: nil)
207
+ standup.addRecurrenceRule(everyWeek)
233
208
 
234
- // Every 2 weeks, ending after 10 occurrences
235
- let biweeklyRule = EKRecurrenceRule(
236
- recurrenceWith: .weekly,
237
- interval: 2,
238
- end: EKRecurrenceEnd(occurrenceCount: 10)
239
- )
240
-
241
- // Monthly, ending on a specific date
242
- let monthlyRule = EKRecurrenceRule(
243
- recurrenceWith: .monthly,
244
- interval: 1,
245
- end: EKRecurrenceEnd(end: endDate)
246
- )
209
+ let tenTimes = EKRecurrenceEnd(occurrenceCount: 10)
210
+ let untilSummer = EKRecurrenceEnd(end: summerStart)
247
211
  ```
248
212
 
249
- ### Complex Recurrence
213
+ `end: nil` repeats forever; `EKRecurrenceEnd` stops after a count or on a
214
+ date. For richer patterns, the full initializer takes `daysOfTheWeek`,
215
+ `daysOfTheMonth`, `monthsOfTheYear`, `weeksOfTheYear`, `daysOfTheYear`,
216
+ `setPositions` and `end`:
250
217
 
251
218
  ```swift
252
- // Every Monday and Wednesday
253
- let days = [
254
- EKRecurrenceDayOfWeek(.monday),
255
- EKRecurrenceDayOfWeek(.wednesday)
256
- ]
257
-
258
- let complexRule = EKRecurrenceRule(
259
- recurrenceWith: .weekly,
219
+ let lastFridayMonthly = EKRecurrenceRule(
220
+ recurrenceWith: .monthly,
260
221
  interval: 1,
261
- daysOfTheWeek: days,
222
+ daysOfTheWeek: [EKRecurrenceDayOfWeek(.friday)],
262
223
  daysOfTheMonth: nil,
263
224
  monthsOfTheYear: nil,
264
225
  weeksOfTheYear: nil,
265
226
  daysOfTheYear: nil,
266
- setPositions: nil,
267
- end: nil
227
+ setPositions: [-1],
228
+ end: tenTimes
268
229
  )
269
- event.addRecurrenceRule(complexRule)
270
230
  ```
271
231
 
272
- ### Editing Recurring Events
273
-
274
- When saving changes to a recurring event, specify the span:
275
-
276
- ```swift
277
- // Change only this occurrence
278
- try eventStore.save(event, span: .thisEvent)
279
-
280
- // Change this and all future occurrences
281
- try eventStore.save(event, span: .futureEvents)
282
- ```
232
+ Saving a recurring event needs an `EKSpan`: `.thisEvent` changes one
233
+ occurrence, `.futureEvents` changes it and every later one.
283
234
 
284
235
  ## Alarms
285
236
 
286
- Attach alarms to events or reminders to trigger notifications.
287
-
288
237
  ```swift
289
- // 15 minutes before
290
- let alarm = EKAlarm(relativeOffset: -15 * 60)
291
- event.addAlarm(alarm)
292
-
293
- // At an absolute date
294
- let absoluteAlarm = EKAlarm(absoluteDate: alertDate)
295
- event.addAlarm(absoluteAlarm)
238
+ rehearsal.addAlarm(EKAlarm(relativeOffset: -30 * 60))
239
+ rehearsal.addAlarm(EKAlarm(absoluteDate: dayBefore))
296
240
  ```
297
241
 
298
- For reminder geofences, put an `EKStructuredLocation` and `.enter` / `.leave`
299
- proximity on an `EKAlarm`, then add it to the reminder. See
300
- [references/eventkit-patterns.md](references/eventkit-patterns.md) for the full
301
- location-based reminder pattern.
242
+ A relative offset is in seconds from the start (negative means before). An
243
+ absolute alarm fires at a fixed moment. These alarms belong to the user's
244
+ calendar data; the system delivers them, and they do not need the app's
245
+ notification permission.
302
246
 
303
- ## EventKitUI Controllers
247
+ Reminders can also fire on arrival or departure: an `EKAlarm` carrying an
248
+ `EKStructuredLocation` and a `.enter` or `.leave` proximity. The full recipe,
249
+ including radius and priority, is in the
250
+ [patterns reference](references/eventkit-patterns.md).
304
251
 
305
- ### EKEventEditViewController - Create/Edit Events
252
+ ## EventKitUI
306
253
 
307
- Present the system event editor for creating or editing events.
254
+ ### Event editor
308
255
 
309
- On iOS 17+, `EKEventEditViewController` can let someone create an event without
310
- the app requesting calendar access. The editor runs out of process with its own
311
- calendar access, so do not inspect the dismissed controller to learn what was
312
- saved; refetch only if the app separately has full access.
256
+ `EKEventEditViewController` is the system editor for creating and changing
257
+ events. From iOS 17 it runs in a separate process with its own access, so the
258
+ app can use it without asking for calendar permission. The flip side: the app
259
+ cannot see what the user saved. Reading properties off the dismissed editor
260
+ tells you nothing reliable; a fresh fetch works only when the app has its own
261
+ full access.
313
262
 
314
263
  ```swift
315
- import EventKitUI
316
-
317
- class EventEditorCoordinator: NSObject, EKEventEditViewDelegate {
318
- let eventStore = EKEventStore()
264
+ func presentEditor(from host: UIViewController, delegate: any EKEventEditViewDelegate) {
265
+ let editor = EKEventEditViewController()
266
+ editor.eventStore = store
267
+ editor.editViewDelegate = delegate
268
+ host.present(editor, animated: true)
269
+ }
319
270
 
320
- func presentEditor(from viewController: UIViewController) {
321
- let editor = EKEventEditViewController()
322
- editor.eventStore = eventStore
323
- editor.editViewDelegate = self
324
- viewController.present(editor, animated: true)
325
- }
271
+ final class TripViewController: UIViewController, @preconcurrency EKEventEditViewDelegate {
272
+ private var lastEditorOutcome: EKEventEditViewAction?
326
273
 
327
- func eventEditViewController(
328
- _ controller: EKEventEditViewController,
329
- didCompleteWith action: EKEventEditViewAction
330
- ) {
331
- switch action {
332
- case .saved:
333
- // Event saved
334
- break
335
- case .canceled:
336
- break
337
- case .deleted:
338
- break
339
- @unknown default:
340
- break
341
- }
342
- controller.dismiss(animated: true)
274
+ func eventEditViewController(_ editor: EKEventEditViewController,
275
+ didCompleteWith outcome: EKEventEditViewAction) {
276
+ lastEditorOutcome = outcome
277
+ editor.dismiss(animated: true)
343
278
  }
344
279
  }
345
280
  ```
346
281
 
347
- ### EKEventViewController - View an Event
348
-
349
- ```swift
350
- import EventKitUI
351
-
352
- let viewer = EKEventViewController()
353
- viewer.event = existingEvent
354
- viewer.allowsEditing = true
355
- navigationController?.pushViewController(viewer, animated: true)
356
- ```
357
-
358
- ### EKCalendarChooser - Select Calendars
282
+ The outcome is `.saved`, `.canceled` or `.deleted`; a `switch` over it needs
283
+ an `@unknown default`. Whatever the outcome, the delegate dismisses the editor.
284
+ `EKEventEditViewDelegate` has no actor annotation, so a view controller, which
285
+ is main-actor isolated, adopts it with `@preconcurrency`. The editor calls the
286
+ delegate on the main thread, which is what that conformance checks at run time.
359
287
 
360
- `EKCalendarChooser` requires write-only or full calendar access. In write-only
361
- apps, the chooser behaves as writable-calendars-only and only allows a single
362
- writable calendar selection.
288
+ ### Viewer and calendar chooser
363
289
 
364
290
  ```swift
365
- let chooser = EKCalendarChooser(
291
+ let detail = EKEventViewController()
292
+ detail.event = selectedEvent
293
+ detail.allowsEditing = true
294
+ navigationController?.pushViewController(detail, animated: true)
295
+
296
+ let picker = EKCalendarChooser(
366
297
  selectionStyle: .multiple,
367
298
  displayStyle: .allCalendars,
368
299
  entityType: .event,
369
- eventStore: eventStore
300
+ eventStore: store
370
301
  )
371
- chooser.showsDoneButton = true
372
- chooser.showsCancelButton = true
373
- chooser.delegate = self
374
- present(UINavigationController(rootViewController: chooser), animated: true)
375
- ```
376
-
377
- ## Observing Changes
378
-
379
- Register for `EKEventStoreChanged` notifications to keep your UI in sync when
380
- events are modified outside your app (e.g., by the Calendar app or a sync).
381
-
382
- ```swift
383
- NotificationCenter.default.addObserver(
384
- forName: .EKEventStoreChanged,
385
- object: eventStore,
386
- queue: .main
387
- ) { [weak self] _ in
388
- self?.refreshEvents()
389
- }
302
+ picker.showsCancelButton = true
303
+ picker.showsDoneButton = true
304
+ picker.delegate = self
305
+ let wrapper = UINavigationController(rootViewController: picker)
306
+ present(wrapper, animated: true)
390
307
  ```
391
308
 
392
- Always re-fetch events after receiving this notification. Previously fetched
393
- `EKEvent`, `EKReminder`, and `EKCalendar` objects may be stale. The notification
394
- is posted on the main actor.
395
-
396
- On iOS 26+, you can also use the typed `EKEventStore.EventStoreChanged` /
397
- `.changed` notification message behind availability checks.
309
+ `EKCalendarChooser` needs write-only or full access. Under write-only it lists
310
+ only writable calendars and allows one selection.
398
311
 
399
- ## Common Mistakes
312
+ ## Staying in sync
400
313
 
401
- ### DON'T: Use the deprecated requestAccess(to:) method
314
+ Other apps and sync services change calendars all the time. Listen for
315
+ `.EKEventStoreChanged` and refetch:
402
316
 
403
317
  ```swift
404
- // WRONG: Deprecated in iOS 17
405
- eventStore.requestAccess(to: .event) { granted, error in }
406
-
407
- // CORRECT: Use the granular async methods
408
- let granted = try await eventStore.requestFullAccessToEvents()
409
- ```
410
-
411
- On iOS 17+, `requestAccess(to: .event)` does not prompt and throws. Keep it only
412
- as an availability-guarded fallback for apps that still run on earlier systems.
413
-
414
- ### DON'T: Save events to a read-only calendar
415
-
416
- ```swift
417
- // WRONG: No check -- will throw if calendar is read-only
418
- event.calendar = someCalendar
419
- try eventStore.save(event, span: .thisEvent)
420
-
421
- // CORRECT: Verify the calendar allows modifications
422
- guard someCalendar.allowsContentModifications else {
423
- event.calendar = eventStore.defaultCalendarForNewEvents
424
- return
318
+ let center = NotificationCenter.default
319
+ changeToken = center.addObserver(forName: .EKEventStoreChanged, object: store, queue: .main) { [weak self] _ in
320
+ Task { @MainActor in self?.reload() }
425
321
  }
426
- event.calendar = someCalendar
427
- try eventStore.save(event, span: .thisEvent)
428
- ```
429
-
430
- ### DON'T: Ignore timezone when creating events
431
-
432
- ```swift
433
- // WRONG: Event appears at wrong time for traveling users
434
- event.startDate = Date()
435
- event.endDate = Date().addingTimeInterval(3600)
436
-
437
- // CORRECT: Set the timezone explicitly for location-specific events
438
- event.timeZone = TimeZone(identifier: "America/New_York")
439
- event.startDate = startDate
440
- event.endDate = endDate
441
- ```
442
-
443
- ### DON'T: Forget to commit batched saves
444
-
445
- ```swift
446
- // WRONG: Changes never persisted
447
- try eventStore.save(event1, span: .thisEvent, commit: false)
448
- try eventStore.save(event2, span: .thisEvent, commit: false)
449
- // Missing commit!
450
-
451
- // CORRECT: Commit after batching
452
- try eventStore.save(event1, span: .thisEvent, commit: false)
453
- try eventStore.save(event2, span: .thisEvent, commit: false)
454
- try eventStore.commit()
455
- ```
456
-
457
- ### DON'T: Mix EKObjects from different event stores
458
-
459
- ```swift
460
- // WRONG: Event fetched from storeA, saved to storeB
461
- let event = storeA.event(withIdentifier: id)!
462
- try storeB.save(event, span: .thisEvent) // Undefined behavior
463
-
464
- // CORRECT: Use the same store throughout
465
- let event = eventStore.event(withIdentifier: id)!
466
- try eventStore.save(event, span: .thisEvent)
467
322
  ```
468
323
 
469
- ## Review Checklist
470
-
471
- - [ ] Correct `Info.plist` usage description keys added for calendars and/or reminders
472
- - [ ] Authorization requested with iOS 17+ granular methods, with `requestAccess(to:)` only as a pre-iOS 17 fallback
473
- - [ ] Write-only calendar access used only for direct event creation, not event/calendar reads
474
- - [ ] Authorization status checked before fetching or saving
475
- - [ ] Full access required before any event or reminder fetch
476
- - [ ] Single `EKEventStore` instance reused across the app
477
- - [ ] Events saved to a writable calendar (`allowsContentModifications` checked)
478
- - [ ] Recurring event saves specify correct `EKSpan` (`.thisEvent` vs `.futureEvents`)
479
- - [ ] Batched saves followed by explicit `commit()`
480
- - [ ] `EKEventStoreChanged` notification observed to refresh stale data
481
- - [ ] iOS 26 typed `.changed` notification used only behind availability checks
482
- - [ ] Timezone set explicitly for location-specific events
483
- - [ ] EKObjects not shared across different event store instances
484
- - [ ] EventKitUI delegates dismiss controllers in completion callbacks
324
+ After the notification, treat every `EKEvent`, `EKReminder` and `EKCalendar`
325
+ you hold as possibly stale and fetch again. EventKit posts this notification
326
+ on the main actor. iOS 26 adds a typed message, `EKEventStore.EventStoreChanged`
327
+ (used as `.changed`), for the new Foundation notification API; use it only
328
+ behind an availability check. See the reference for both forms.
329
+
330
+ ## Common mistakes
331
+
332
+ - **`requestAccess(to:)` on iOS 17 and later.** Deprecated from iOS 17; asking
333
+ for `.event` that way shows no prompt and fails with an error. It belongs in
334
+ the pre-17 branch only.
335
+ - **Saving into a read-only calendar.** The save throws. Check
336
+ `allowsContentModifications`, falling back to the default calendar.
337
+ - **No time zone on place-bound events.** Set `timeZone` explicitly, for
338
+ example `TimeZone(identifier: "Asia/Tokyo")`.
339
+ - **Batching without committing.** After saves with `commit: false`, call
340
+ `try store.commit()`, or nothing is stored.
341
+ - **Objects from two stores.** Fetching from one store and saving through
342
+ another is undefined behaviour.
343
+
344
+ ## Review checklist
345
+
346
+ - [ ] Usage keys match what the app touches (calendars, reminders or both)
347
+ - [ ] iOS 17 granular requests used; `requestAccess(to:)` only as pre-17 fallback
348
+ - [ ] Write-only used only for direct creation, never for reads
349
+ - [ ] Status is read before any fetch or save
350
+ - [ ] Fetching events or reminders only happens with full access
351
+ - [ ] One `EKEventStore` reused throughout
352
+ - [ ] Target calendar checked for `allowsContentModifications`
353
+ - [ ] Recurring saves pass the intended `EKSpan`
354
+ - [ ] `commit()` follows every batch
355
+ - [ ] `EKEventStoreChanged` observed and data refetched
356
+ - [ ] iOS 26 typed `.changed` message only behind availability checks
357
+ - [ ] Explicit time zone on location-specific events
358
+ - [ ] No EventKit object crosses between stores
359
+ - [ ] EventKitUI delegates dismiss their controllers
485
360
 
486
361
  ## References
487
362
 
488
- - Extended patterns (SwiftUI wrappers, predicate queries, batch operations): [references/eventkit-patterns.md](references/eventkit-patterns.md)
489
- - [EventKit framework](https://sosumi.ai/documentation/eventkit)
490
- - [EKEventStore](https://sosumi.ai/documentation/eventkit/ekeventstore)
491
- - [EKEvent](https://sosumi.ai/documentation/eventkit/ekevent)
492
- - [EKReminder](https://sosumi.ai/documentation/eventkit/ekreminder)
493
- - [EKRecurrenceRule](https://sosumi.ai/documentation/eventkit/ekrecurrencerule)
494
- - [EKCalendar](https://sosumi.ai/documentation/eventkit/ekcalendar)
495
- - [EventKit UI](https://sosumi.ai/documentation/eventkitui)
496
- - [EKEventEditViewController](https://sosumi.ai/documentation/eventkitui/ekeventeditviewcontroller)
497
- - [EKCalendarChooser](https://sosumi.ai/documentation/eventkitui/ekcalendarchooser)
498
- - [Accessing the event store](https://sosumi.ai/documentation/eventkit/accessing-the-event-store)
499
- - [Creating a recurring event](https://sosumi.ai/documentation/eventkit/creating-a-recurring-event)
363
+ - [EventKit patterns](references/eventkit-patterns.md): SwiftUI manager and
364
+ view, predicates and enumeration, batches, calendar creation, location and
365
+ priority reminders, SwiftUI editor wrapper, typed change notifications
366
+ - Apple documentation:
367
+ [EventKit](https://developer.apple.com/documentation/eventkit),
368
+ [event store](https://developer.apple.com/documentation/eventkit/ekeventstore),
369
+ [event](https://developer.apple.com/documentation/eventkit/ekevent),
370
+ [reminder](https://developer.apple.com/documentation/eventkit/ekreminder),
371
+ [recurrence rule](https://developer.apple.com/documentation/eventkit/ekrecurrencerule),
372
+ [calendar](https://developer.apple.com/documentation/eventkit/ekcalendar),
373
+ [EventKitUI framework](https://developer.apple.com/documentation/eventkitui),
374
+ [event editor](https://developer.apple.com/documentation/eventkitui/ekeventeditviewcontroller),
375
+ [calendar chooser](https://developer.apple.com/documentation/eventkitui/ekcalendarchooser),
376
+ [article on store access](https://developer.apple.com/documentation/eventkit/accessing-the-event-store),
377
+ [article on repeating events](https://developer.apple.com/documentation/eventkit/creating-a-recurring-event)