@mmerterden/multi-agent-pipeline 20.7.0 → 20.8.0

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 (264) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/LICENSE +0 -10
  3. package/docs/facts.json +1 -1
  4. package/manifest.json +266 -267
  5. package/package.json +2 -2
  6. package/pipeline/scripts/_notices.mjs +1 -1
  7. package/pipeline/skills/.skill-manifest.json +68 -68
  8. package/pipeline/skills/shared/README.md +70 -70
  9. package/pipeline/skills/shared/external/alarmkit/SKILL.md +373 -381
  10. package/pipeline/skills/shared/external/alarmkit/evals/evals.json +23 -18
  11. package/pipeline/skills/shared/external/alarmkit/references/alarmkit-patterns.md +328 -378
  12. package/pipeline/skills/shared/external/app-clips/SKILL.md +260 -160
  13. package/pipeline/skills/shared/external/app-clips/evals/evals.json +27 -27
  14. package/pipeline/skills/shared/external/app-clips/references/data-handoff-notifications-location.md +150 -83
  15. package/pipeline/skills/shared/external/app-clips/references/routing-and-experiences.md +135 -83
  16. package/pipeline/skills/shared/external/app-clips/references/size-capabilities-and-promotion.md +143 -85
  17. package/pipeline/skills/shared/external/app-intents/SKILL.md +302 -304
  18. package/pipeline/skills/shared/external/app-intents/evals/evals.json +21 -21
  19. package/pipeline/skills/shared/external/app-intents/references/appintents-advanced.md +594 -894
  20. package/pipeline/skills/shared/external/app-store-optimization/SKILL.md +339 -277
  21. package/pipeline/skills/shared/external/app-store-optimization/evals/evals.json +27 -23
  22. package/pipeline/skills/shared/external/app-store-optimization/references/keyword-research-methodology.md +105 -122
  23. package/pipeline/skills/shared/external/app-store-optimization/references/product-page-variants.md +143 -166
  24. package/pipeline/skills/shared/external/app-store-review/SKILL.md +307 -326
  25. package/pipeline/skills/shared/external/app-store-review/evals/evals.json +21 -21
  26. package/pipeline/skills/shared/external/app-store-review/references/privacy-manifest.md +105 -67
  27. package/pipeline/skills/shared/external/app-store-review/references/review-checklists.md +114 -101
  28. package/pipeline/skills/shared/external/apple-on-device-ai/SKILL.md +333 -360
  29. package/pipeline/skills/shared/external/apple-on-device-ai/evals/evals.json +24 -27
  30. package/pipeline/skills/shared/external/apple-on-device-ai/references/coreml-conversion.md +215 -322
  31. package/pipeline/skills/shared/external/apple-on-device-ai/references/coreml-optimization.md +161 -256
  32. package/pipeline/skills/shared/external/apple-on-device-ai/references/foundation-models.md +277 -387
  33. package/pipeline/skills/shared/external/apple-on-device-ai/references/mlx-swift.md +196 -210
  34. package/pipeline/skills/shared/external/authentication/SKILL.md +265 -381
  35. package/pipeline/skills/shared/external/authentication/evals/evals.json +25 -25
  36. package/pipeline/skills/shared/external/authentication/references/keychain-biometric.md +133 -178
  37. package/pipeline/skills/shared/external/authentication/references/passkeys.md +111 -147
  38. package/pipeline/skills/shared/external/avkit/SKILL.md +267 -364
  39. package/pipeline/skills/shared/external/avkit/evals/evals.json +26 -26
  40. package/pipeline/skills/shared/external/avkit/references/avkit-patterns.md +375 -493
  41. package/pipeline/skills/shared/external/background-processing/SKILL.md +270 -382
  42. package/pipeline/skills/shared/external/background-processing/evals/evals.json +22 -22
  43. package/pipeline/skills/shared/external/background-processing/references/background-task-patterns.md +169 -317
  44. package/pipeline/skills/shared/external/callkit-voip/SKILL.md +290 -371
  45. package/pipeline/skills/shared/external/callkit-voip/evals/evals.json +24 -24
  46. package/pipeline/skills/shared/external/callkit-voip/references/callkit-patterns.md +175 -343
  47. package/pipeline/skills/shared/external/cloudkit-sync/SKILL.md +292 -381
  48. package/pipeline/skills/shared/external/cloudkit-sync/evals/evals.json +33 -30
  49. package/pipeline/skills/shared/external/cloudkit-sync/references/cloudkit-patterns.md +227 -355
  50. package/pipeline/skills/shared/external/contacts-framework/SKILL.md +197 -346
  51. package/pipeline/skills/shared/external/contacts-framework/evals/evals.json +19 -21
  52. package/pipeline/skills/shared/external/contacts-framework/references/contacts-patterns.md +169 -308
  53. package/pipeline/skills/shared/external/core-bluetooth/SKILL.md +226 -376
  54. package/pipeline/skills/shared/external/core-bluetooth/evals/evals.json +25 -22
  55. package/pipeline/skills/shared/external/core-bluetooth/references/ble-patterns.md +257 -337
  56. package/pipeline/skills/shared/external/core-data/SKILL.md +292 -368
  57. package/pipeline/skills/shared/external/core-data/evals/evals.json +30 -27
  58. package/pipeline/skills/shared/external/core-motion/SKILL.md +235 -324
  59. package/pipeline/skills/shared/external/core-motion/evals/evals.json +31 -27
  60. package/pipeline/skills/shared/external/core-motion/references/motion-patterns.md +210 -310
  61. package/pipeline/skills/shared/external/core-nfc/SKILL.md +292 -366
  62. package/pipeline/skills/shared/external/core-nfc/evals/evals.json +22 -24
  63. package/pipeline/skills/shared/external/core-nfc/references/nfc-patterns.md +233 -329
  64. package/pipeline/skills/shared/external/coreml/SKILL.md +323 -367
  65. package/pipeline/skills/shared/external/coreml/evals/evals.json +24 -21
  66. package/pipeline/skills/shared/external/coreml/references/coreml-swift-integration.md +562 -565
  67. package/pipeline/skills/shared/external/cryptokit/SKILL.md +253 -394
  68. package/pipeline/skills/shared/external/cryptokit/evals/evals.json +20 -18
  69. package/pipeline/skills/shared/external/cryptokit/references/cryptokit-patterns.md +299 -488
  70. package/pipeline/skills/shared/external/debugging-instruments/SKILL.md +270 -323
  71. package/pipeline/skills/shared/external/debugging-instruments/evals/evals.json +27 -30
  72. package/pipeline/skills/shared/external/debugging-instruments/references/instruments-guide.md +167 -315
  73. package/pipeline/skills/shared/external/debugging-instruments/references/lldb-patterns.md +140 -193
  74. package/pipeline/skills/shared/external/device-integrity/SKILL.md +230 -353
  75. package/pipeline/skills/shared/external/device-integrity/evals/evals.json +25 -21
  76. package/pipeline/skills/shared/external/device-integrity/references/device-integrity-patterns.md +159 -197
  77. package/pipeline/skills/shared/external/energykit/SKILL.md +225 -392
  78. package/pipeline/skills/shared/external/energykit/evals/evals.json +29 -28
  79. package/pipeline/skills/shared/external/energykit/references/energykit-patterns.md +174 -470
  80. package/pipeline/skills/shared/external/eventkit-calendar/SKILL.md +261 -383
  81. package/pipeline/skills/shared/external/eventkit-calendar/evals/evals.json +25 -22
  82. package/pipeline/skills/shared/external/eventkit-calendar/references/eventkit-patterns.md +165 -268
  83. package/pipeline/skills/shared/external/healthkit/SKILL.md +252 -303
  84. package/pipeline/skills/shared/external/healthkit/evals/evals.json +24 -23
  85. package/pipeline/skills/shared/external/healthkit/references/healthkit-patterns.md +369 -523
  86. package/pipeline/skills/shared/external/homekit-matter/SKILL.md +233 -348
  87. package/pipeline/skills/shared/external/homekit-matter/evals/evals.json +27 -22
  88. package/pipeline/skills/shared/external/homekit-matter/references/matter-commissioning.md +199 -305
  89. package/pipeline/skills/shared/external/ios-accessibility/SKILL.md +368 -340
  90. package/pipeline/skills/shared/external/ios-accessibility/evals/evals.json +28 -27
  91. package/pipeline/skills/shared/external/ios-accessibility/references/a11y-patterns.md +314 -260
  92. package/pipeline/skills/shared/external/ios-accessibility/references/media-accessibility.md +97 -67
  93. package/pipeline/skills/shared/external/ios-accessibility/references/nutrition-labels.md +165 -101
  94. package/pipeline/skills/shared/external/ios-localization/SKILL.md +258 -371
  95. package/pipeline/skills/shared/external/ios-localization/evals/evals.json +23 -23
  96. package/pipeline/skills/shared/external/ios-localization/references/formatstyle-locale.md +283 -491
  97. package/pipeline/skills/shared/external/ios-localization/references/string-catalogs.md +313 -440
  98. package/pipeline/skills/shared/external/ios-networking/SKILL.md +265 -341
  99. package/pipeline/skills/shared/external/ios-networking/evals/evals.json +24 -24
  100. package/pipeline/skills/shared/external/ios-networking/references/background-websocket.md +425 -652
  101. package/pipeline/skills/shared/external/ios-networking/references/file-storage-patterns.md +143 -285
  102. package/pipeline/skills/shared/external/ios-networking/references/lightweight-clients.md +93 -53
  103. package/pipeline/skills/shared/external/ios-networking/references/network-framework.md +231 -456
  104. package/pipeline/skills/shared/external/ios-networking/references/urlsession-patterns.md +517 -784
  105. package/pipeline/skills/shared/external/ios-simulator/SKILL.md +265 -393
  106. package/pipeline/skills/shared/external/ios-simulator/evals/evals.json +21 -21
  107. package/pipeline/skills/shared/external/ios-simulator/references/simctl-commands.md +177 -270
  108. package/pipeline/skills/shared/external/live-activities/SKILL.md +318 -360
  109. package/pipeline/skills/shared/external/live-activities/evals/evals.json +21 -21
  110. package/pipeline/skills/shared/external/live-activities/references/activitykit-patterns.md +478 -710
  111. package/pipeline/skills/shared/external/mapkit-location/SKILL.md +295 -267
  112. package/pipeline/skills/shared/external/mapkit-location/evals/evals.json +28 -24
  113. package/pipeline/skills/shared/external/mapkit-location/references/mapkit-corelocation-patterns.md +378 -532
  114. package/pipeline/skills/shared/external/mapkit-location/references/mapkit-patterns.md +397 -499
  115. package/pipeline/skills/shared/external/metrickit-diagnostics/SKILL.md +165 -348
  116. package/pipeline/skills/shared/external/metrickit-diagnostics/evals/evals.json +26 -23
  117. package/pipeline/skills/shared/external/metrickit-diagnostics/references/metrickit-patterns.md +123 -130
  118. package/pipeline/skills/shared/external/musickit-audio/SKILL.md +189 -315
  119. package/pipeline/skills/shared/external/musickit-audio/evals/evals.json +22 -21
  120. package/pipeline/skills/shared/external/musickit-audio/references/musickit-patterns.md +181 -270
  121. package/pipeline/skills/shared/external/natural-language/SKILL.md +188 -340
  122. package/pipeline/skills/shared/external/natural-language/evals/evals.json +21 -21
  123. package/pipeline/skills/shared/external/natural-language/references/translation-patterns.md +171 -225
  124. package/pipeline/skills/shared/external/passkit-wallet/SKILL.md +258 -392
  125. package/pipeline/skills/shared/external/passkit-wallet/evals/evals.json +30 -29
  126. package/pipeline/skills/shared/external/passkit-wallet/references/wallet-passes.md +164 -231
  127. package/pipeline/skills/shared/external/pdfkit/SKILL.md +312 -344
  128. package/pipeline/skills/shared/external/pdfkit/evals/evals.json +19 -19
  129. package/pipeline/skills/shared/external/pdfkit/references/pdfkit-patterns.md +413 -624
  130. package/pipeline/skills/shared/external/pencilkit-drawing/SKILL.md +242 -358
  131. package/pipeline/skills/shared/external/pencilkit-drawing/evals/evals.json +25 -21
  132. package/pipeline/skills/shared/external/pencilkit-drawing/references/pencilkit-patterns.md +161 -226
  133. package/pipeline/skills/shared/external/permissionkit/SKILL.md +282 -400
  134. package/pipeline/skills/shared/external/permissionkit/evals/evals.json +27 -30
  135. package/pipeline/skills/shared/external/permissionkit/references/permissionkit-patterns.md +237 -350
  136. package/pipeline/skills/shared/external/photos-camera-media/SKILL.md +276 -325
  137. package/pipeline/skills/shared/external/photos-camera-media/references/av-playback.md +299 -545
  138. package/pipeline/skills/shared/external/photos-camera-media/references/camera-capture.md +344 -588
  139. package/pipeline/skills/shared/external/photos-camera-media/references/image-loading-caching.md +316 -660
  140. package/pipeline/skills/shared/external/photos-camera-media/references/photokit-patterns.md +270 -416
  141. package/pipeline/skills/shared/external/push-notifications/SKILL.md +312 -340
  142. package/pipeline/skills/shared/external/push-notifications/evals/evals.json +27 -26
  143. package/pipeline/skills/shared/external/push-notifications/references/notification-patterns.md +328 -485
  144. package/pipeline/skills/shared/external/push-notifications/references/rich-notifications.md +327 -560
  145. package/pipeline/skills/shared/external/realitykit-ar/SKILL.md +218 -410
  146. package/pipeline/skills/shared/external/realitykit-ar/evals/evals.json +24 -27
  147. package/pipeline/skills/shared/external/realitykit-ar/references/realitykit-patterns.md +221 -348
  148. package/pipeline/skills/shared/external/shareplay-activities/SKILL.md +222 -393
  149. package/pipeline/skills/shared/external/shareplay-activities/evals/evals.json +23 -24
  150. package/pipeline/skills/shared/external/shareplay-activities/references/shareplay-patterns.md +280 -420
  151. package/pipeline/skills/shared/external/speech-recognition/SKILL.md +217 -421
  152. package/pipeline/skills/shared/external/speech-recognition/evals/evals.json +23 -26
  153. package/pipeline/skills/shared/external/speech-recognition/references/speechanalyzer-patterns.md +133 -125
  154. package/pipeline/skills/shared/external/storekit/SKILL.md +228 -204
  155. package/pipeline/skills/shared/external/storekit/evals/evals.json +27 -24
  156. package/pipeline/skills/shared/external/storekit/references/app-review-guidelines.md +98 -109
  157. package/pipeline/skills/shared/external/storekit/references/core-patterns.md +298 -242
  158. package/pipeline/skills/shared/external/storekit/references/storekit-advanced.md +356 -649
  159. package/pipeline/skills/shared/external/swift-api-design-guidelines/SKILL.md +274 -399
  160. package/pipeline/skills/shared/external/swift-api-design-guidelines/evals/evals.json +22 -24
  161. package/pipeline/skills/shared/external/swift-api-design-guidelines/references/argument-labels-and-parameters.md +107 -108
  162. package/pipeline/skills/shared/external/swift-api-design-guidelines/references/conventions-and-special-rules.md +93 -165
  163. package/pipeline/skills/shared/external/swift-api-design-guidelines/references/naming-and-clarity.md +99 -137
  164. package/pipeline/skills/shared/external/swift-api-design-guidelines/references/side-effects-and-mutating-pairs.md +77 -120
  165. package/pipeline/skills/shared/external/swift-architecture/SKILL.md +334 -350
  166. package/pipeline/skills/shared/external/swift-architecture/evals/evals.json +22 -22
  167. package/pipeline/skills/shared/external/swift-charts/SKILL.md +208 -394
  168. package/pipeline/skills/shared/external/swift-charts/evals/evals.json +27 -30
  169. package/pipeline/skills/shared/external/swift-charts/references/charts-patterns.md +351 -762
  170. package/pipeline/skills/shared/external/swift-codable/SKILL.md +339 -343
  171. package/pipeline/skills/shared/external/swift-codable/evals/evals.json +20 -20
  172. package/pipeline/skills/shared/external/swift-concurrency/SKILL.md +303 -351
  173. package/pipeline/skills/shared/external/swift-concurrency/evals/evals.json +27 -24
  174. package/pipeline/skills/shared/external/swift-concurrency/references/approachable-concurrency.md +65 -80
  175. package/pipeline/skills/shared/external/swift-concurrency/references/async-algorithms.md +48 -84
  176. package/pipeline/skills/shared/external/swift-concurrency/references/bridging-interop.md +134 -79
  177. package/pipeline/skills/shared/external/swift-concurrency/references/concurrency-patterns.md +145 -167
  178. package/pipeline/skills/shared/external/swift-concurrency/references/diagnostics.md +62 -50
  179. package/pipeline/skills/shared/external/swift-concurrency/references/swiftui-concurrency.md +92 -121
  180. package/pipeline/skills/shared/external/swift-concurrency/references/synchronization-primitives.md +177 -241
  181. package/pipeline/skills/shared/external/swift-formatstyle/SKILL.md +258 -234
  182. package/pipeline/skills/shared/external/swift-language/SKILL.md +342 -382
  183. package/pipeline/skills/shared/external/swift-language/evals/evals.json +24 -27
  184. package/pipeline/skills/shared/external/swift-language/references/swift-attributes-interop.md +79 -56
  185. package/pipeline/skills/shared/external/swift-language/references/swift-patterns-extended.md +297 -340
  186. package/pipeline/skills/shared/external/swift-security/SKILL.md +180 -161
  187. package/pipeline/skills/shared/external/swift-security/evals/evals.json +25 -25
  188. package/pipeline/skills/shared/external/swift-security/references/biometric-authentication.md +314 -469
  189. package/pipeline/skills/shared/external/swift-security/references/certificate-trust.md +408 -476
  190. package/pipeline/skills/shared/external/swift-security/references/common-anti-patterns.md +260 -530
  191. package/pipeline/skills/shared/external/swift-security/references/compliance-owasp-mapping.md +270 -477
  192. package/pipeline/skills/shared/external/swift-security/references/credential-storage-patterns.md +573 -571
  193. package/pipeline/skills/shared/external/swift-security/references/cryptokit-public-key.md +370 -441
  194. package/pipeline/skills/shared/external/swift-security/references/cryptokit-symmetric.md +332 -433
  195. package/pipeline/skills/shared/external/swift-security/references/keychain-access-control.md +346 -468
  196. package/pipeline/skills/shared/external/swift-security/references/keychain-fundamentals.md +352 -472
  197. package/pipeline/skills/shared/external/swift-security/references/keychain-item-classes.md +431 -432
  198. package/pipeline/skills/shared/external/swift-security/references/keychain-sharing.md +328 -425
  199. package/pipeline/skills/shared/external/swift-security/references/migration-legacy-stores.md +341 -579
  200. package/pipeline/skills/shared/external/swift-security/references/secure-enclave.md +396 -457
  201. package/pipeline/skills/shared/external/swift-security/references/testing-security-code.md +354 -614
  202. package/pipeline/skills/shared/external/swift-testing/SKILL.md +188 -175
  203. package/pipeline/skills/shared/external/swift-testing/evals/evals.json +26 -24
  204. package/pipeline/skills/shared/external/swift-testing/references/testing-advanced.md +80 -84
  205. package/pipeline/skills/shared/external/swift-testing/references/testing-patterns.md +317 -433
  206. package/pipeline/skills/shared/external/swiftdata/SKILL.md +392 -256
  207. package/pipeline/skills/shared/external/swiftdata/evals/evals.json +24 -24
  208. package/pipeline/skills/shared/external/swiftdata/references/core-data-coexistence.md +206 -402
  209. package/pipeline/skills/shared/external/swiftdata/references/indexing.md +59 -52
  210. package/pipeline/skills/shared/external/swiftdata/references/predicate-pitfalls.md +57 -33
  211. package/pipeline/skills/shared/external/swiftdata/references/swiftdata-advanced.md +354 -747
  212. package/pipeline/skills/shared/external/swiftdata/references/swiftdata-queries.md +300 -508
  213. package/pipeline/skills/shared/external/swiftlint/SKILL.md +175 -226
  214. package/pipeline/skills/shared/external/swiftlint/references/adoption-and-configuration.md +141 -208
  215. package/pipeline/skills/shared/external/swiftlint/references/custom-rules-and-analyze.md +100 -109
  216. package/pipeline/skills/shared/external/swiftlint/references/plugins-run-scripts-and-integrations.md +159 -179
  217. package/pipeline/skills/shared/external/swiftlint/references/rule-reference.md +383 -18
  218. package/pipeline/skills/shared/external/swiftlint/references/rules-suppressions-and-baselines.md +143 -229
  219. package/pipeline/skills/shared/external/swiftui-animation/SKILL.md +283 -366
  220. package/pipeline/skills/shared/external/swiftui-animation/references/animation-advanced.md +396 -608
  221. package/pipeline/skills/shared/external/swiftui-animation/references/core-animation-bridge.md +336 -385
  222. package/pipeline/skills/shared/external/swiftui-gestures/SKILL.md +239 -349
  223. package/pipeline/skills/shared/external/swiftui-gestures/references/gesture-patterns.md +228 -310
  224. package/pipeline/skills/shared/external/swiftui-layout-components/SKILL.md +260 -249
  225. package/pipeline/skills/shared/external/swiftui-layout-components/references/form.md +92 -74
  226. package/pipeline/skills/shared/external/swiftui-layout-components/references/grids.md +112 -177
  227. package/pipeline/skills/shared/external/swiftui-layout-components/references/list.md +61 -64
  228. package/pipeline/skills/shared/external/swiftui-layout-components/references/scrollview.md +94 -134
  229. package/pipeline/skills/shared/external/swiftui-liquid-glass/SKILL.md +193 -225
  230. package/pipeline/skills/shared/external/swiftui-liquid-glass/references/liquid-glass.md +173 -327
  231. package/pipeline/skills/shared/external/swiftui-navigation/SKILL.md +193 -168
  232. package/pipeline/skills/shared/external/swiftui-navigation/references/deeplinks.md +127 -150
  233. package/pipeline/skills/shared/external/swiftui-navigation/references/navigationstack.md +132 -133
  234. package/pipeline/skills/shared/external/swiftui-navigation/references/sheets.md +152 -117
  235. package/pipeline/skills/shared/external/swiftui-navigation/references/tabview.md +106 -140
  236. package/pipeline/skills/shared/external/swiftui-patterns/SKILL.md +316 -252
  237. package/pipeline/skills/shared/external/swiftui-patterns/references/architecture-patterns.md +341 -332
  238. package/pipeline/skills/shared/external/swiftui-patterns/references/deprecated-migration.md +547 -854
  239. package/pipeline/skills/shared/external/swiftui-patterns/references/design-polish.md +485 -537
  240. package/pipeline/skills/shared/external/swiftui-patterns/references/platform-and-sharing.md +417 -499
  241. package/pipeline/skills/shared/external/swiftui-performance/SKILL.md +213 -376
  242. package/pipeline/skills/shared/external/swiftui-performance/references/demystify-swiftui-performance-wwdc23.md +86 -175
  243. package/pipeline/skills/shared/external/swiftui-performance/references/optimizing-swiftui-performance-instruments.md +89 -195
  244. package/pipeline/skills/shared/external/swiftui-performance/references/understanding-hangs-in-your-app.md +95 -182
  245. package/pipeline/skills/shared/external/swiftui-performance/references/understanding-improving-swiftui-performance.md +71 -149
  246. package/pipeline/skills/shared/external/swiftui-performance/references/wwdc-session-sources.md +21 -27
  247. package/pipeline/skills/shared/external/swiftui-uikit-interop/SKILL.md +303 -295
  248. package/pipeline/skills/shared/external/swiftui-uikit-interop/references/hosting-migration.md +204 -387
  249. package/pipeline/skills/shared/external/swiftui-uikit-interop/references/representable-recipes.md +469 -683
  250. package/pipeline/skills/shared/external/swiftui-webkit/SKILL.md +140 -186
  251. package/pipeline/skills/shared/external/swiftui-webkit/references/loading-and-observation.md +75 -86
  252. package/pipeline/skills/shared/external/swiftui-webkit/references/local-content-and-custom-schemes.md +63 -60
  253. package/pipeline/skills/shared/external/swiftui-webkit/references/migration-and-fallbacks.md +69 -137
  254. package/pipeline/skills/shared/external/swiftui-webkit/references/navigation-and-javascript.md +95 -67
  255. package/pipeline/skills/shared/external/tipkit/SKILL.md +220 -335
  256. package/pipeline/skills/shared/external/tipkit/references/tipkit-patterns.md +356 -494
  257. package/pipeline/skills/shared/external/vision-framework/SKILL.md +260 -375
  258. package/pipeline/skills/shared/external/vision-framework/references/vision-requests.md +393 -515
  259. package/pipeline/skills/shared/external/vision-framework/references/visionkit-scanner.md +363 -539
  260. package/pipeline/skills/shared/external/weatherkit/SKILL.md +152 -310
  261. package/pipeline/skills/shared/external/weatherkit/references/weatherkit-patterns.md +288 -407
  262. package/pipeline/skills/shared/external/widgetkit/SKILL.md +216 -288
  263. package/pipeline/skills/shared/external/widgetkit/references/widgetkit-advanced.md +414 -719
  264. 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)