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