@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,500 +1,329 @@
1
1
  ---
2
2
  name: shareplay-activities
3
- description: "Build shared real-time experiences using GroupActivities and SharePlay. Use when implementing shared media playback, collaborative app features, synchronized game state, or any FaceTime, Messages, AirDrop, or nearby visionOS group activity on iOS, macOS, tvOS, or visionOS."
3
+ description: "GroupActivities and SharePlay on iOS, macOS, tvOS and visionOS: GroupActivity, GroupSession lifecycle, messengers, playback sync, file transfer, late joiners. Use for shared media, collaboration or synced game state over FaceTime, Messages, AirDrop or nearby sharing."
4
4
  metadata:
5
- source: "dpearson2699/swift-ios-skills (PolyForm Perimeter 1.0.0)"
5
+ source: multi-agent-pipeline
6
6
  ---
7
- # GroupActivities / SharePlay
8
- Build shared real-time experiences using the GroupActivities framework. SharePlay
9
- connects people over FaceTime, Messages, AirDrop, and nearby visionOS sharing,
10
- synchronizing media playback, app state, or custom data. Targets Swift 6.3 / iOS 26+.
11
-
12
- ## Contents
13
-
14
- - [Setup](#setup)
15
- - [Defining a GroupActivity](#defining-a-groupactivity)
16
- - [Session Lifecycle](#session-lifecycle)
17
- - [Sending and Receiving Messages](#sending-and-receiving-messages)
18
- - [Coordinated Media Playback](#coordinated-media-playback)
19
- - [Starting SharePlay from Your App](#starting-shareplay-from-your-app)
20
- - [GroupSessionJournal: File Transfer](#groupsessionjournal-file-transfer)
21
- - [Common Mistakes](#common-mistakes)
22
- - [Review Checklist](#review-checklist)
23
- - [References](#references)
7
+
8
+ # SharePlay and Group Activities
9
+
10
+ SharePlay joins people in a FaceTime call, a Messages conversation, an AirDrop
11
+ exchange or, on visionOS, a room of nearby headsets, and keeps media, app state
12
+ or custom data in step between them. Code here is written for Swift 6.3 on
13
+ iOS 26 and newer.
24
14
 
25
15
  ## Setup
26
16
 
27
17
  ### Capability
28
18
 
29
- Add the **Group Activities** capability to the app target in Xcode. Xcode adds
30
- the required entitlement and updates the provisioning profile:
19
+ Add **Group Activities** to the app target under Signing & Capabilities. Xcode
20
+ then sets `com.apple.developer.group-session` to `true` in the entitlements
21
+ file and refreshes provisioning.
31
22
 
32
- ```xml
33
- <key>com.apple.developer.group-session</key>
34
- <true/>
35
- ```
23
+ Only app targets get it. Group Activities does not run in widgets, other
24
+ extensions or App Clips.
36
25
 
37
- Configure this only for app targets. Group Activities are not available in
38
- widgets, extensions, or App Clips.
26
+ ### Eligibility
39
27
 
40
- ### Checking Eligibility
28
+ `GroupStateObserver` reports whether a FaceTime call, or a Messages chat, is
29
+ currently able to host an activity. Use it to decide whether a
30
+ SharePlay button appears.
41
31
 
42
32
  ```swift
43
33
  import GroupActivities
44
34
 
45
- let observer = GroupStateObserver()
46
-
47
- // Check if a FaceTime call or Messages conversation is active
48
- if observer.isEligibleForGroupSession {
49
- showSharePlayButton()
50
- }
51
- ```
52
-
53
- Observe changes reactively:
54
-
55
- ```swift
56
- for await isEligible in observer.$isEligibleForGroupSession.values {
57
- showSharePlayButton(isEligible)
35
+ @MainActor
36
+ func watchEligibility(update: @escaping @MainActor (Bool) -> Void) async {
37
+ let observer = GroupStateObserver()
38
+ update(observer.isEligibleForGroupSession)
39
+ for await eligible in observer.$isEligibleForGroupSession.values {
40
+ update(eligible)
41
+ }
58
42
  }
59
43
  ```
60
44
 
61
- ## Defining a GroupActivity
62
-
63
- Conform to `GroupActivity` and provide metadata:
45
+ ## Defining an activity
64
46
 
65
47
  ```swift
66
- import GroupActivities
67
-
68
- struct WatchTogetherActivity: GroupActivity {
69
- let movieID: String
70
- let movieTitle: String
48
+ struct CookAlong: GroupActivity {
49
+ let recipeID: String
71
50
 
72
51
  var metadata: GroupActivityMetadata {
73
- var meta = GroupActivityMetadata()
74
- meta.title = movieTitle
75
- meta.type = .watchTogether
76
- meta.fallbackURL = URL(string: "https://example.com/movie/\(movieID)")
77
- return meta
52
+ var info = GroupActivityMetadata()
53
+ info.title = "Cook together"
54
+ info.type = .exploreTogether
55
+ info.fallbackURL = URL(string: "https://recipes.example/r/\(recipeID)")
56
+ return info
78
57
  }
79
58
  }
80
59
  ```
81
60
 
82
- ### Activity Types
61
+ ### Activity types
83
62
 
84
- | Type | Use Case |
85
- |---|---|
86
- | `.generic` | Default for custom activities |
87
- | `.watchTogether` | Video playback |
88
- | `.listenTogether` | Audio playback |
89
- | `.createTogether` | Collaborative creation (drawing, editing) |
90
- | `.exploreTogether` | Shared browsing, planning, or exploration |
91
- | `.learnTogether` | Shared learning or studying |
92
- | `.readTogether` | Shared reading |
93
- | `.shopTogether` | Shared shopping |
94
- | `.workoutTogether` | Shared fitness sessions |
63
+ | Type | Fits |
64
+ | --- | --- |
65
+ | `.generic` | The default for anything custom |
66
+ | `.watchTogether` | Video |
67
+ | `.listenTogether` | Audio |
68
+ | `.createTogether` | Drawing, editing, building something together |
69
+ | `.exploreTogether` | Browsing, planning, exploring |
70
+ | `.learnTogether` | Study sessions |
71
+ | `.readTogether` | Reading |
72
+ | `.shopTogether` | Shopping |
73
+ | `.workoutTogether` | Fitness |
95
74
 
96
- `GroupActivity` is `Codable`; stored activity data must be codable. Add
97
- `Transferable` only for SwiftUI `ShareLink`, SharePlay over AirDrop, or
98
- AppKit/UIKit share sheets. Keep payloads minimal: use identifiers or URLs
99
- instead of large data.
75
+ `GroupActivity` inherits `Codable`, so every stored property must be codable.
76
+ Keep the payload tiny: an identifier or a URL, never the content itself. Add
77
+ `Transferable` only when the activity is offered through a SwiftUI `ShareLink`,
78
+ an AirDrop hand-off, or a UIKit or AppKit share sheet.
100
79
 
101
- ## Session Lifecycle
80
+ ## Session lifecycle
102
81
 
103
- ### Listening for Sessions
82
+ ### Receiving sessions
104
83
 
105
- Set up a long-lived task to receive sessions when another participant starts
106
- the activity:
84
+ Sessions started by anyone arrive through `Activity.sessions()`. Iterate it in
85
+ a task owned by a long-lived object.
107
86
 
108
87
  ```swift
109
- @Observable
110
- @MainActor
111
- final class SharePlayManager {
112
- private var session: GroupSession<WatchTogetherActivity>?
88
+ import GroupActivities
89
+ import Observation
90
+
91
+ @MainActor @Observable
92
+ final class KitchenSession {
93
+ private(set) var people: Set<Participant> = []
94
+ private(set) var session: GroupSession<CookAlong>?
95
+ private var jobs: [Task<Void, Never>] = []
113
96
  private var messenger: GroupSessionMessenger?
114
- private var sessionTasks: [Task<Void, Never>] = []
115
97
 
116
- func observeSessions() {
117
- Task {
118
- for await session in WatchTogetherActivity.sessions() {
119
- self.configureSession(session)
120
- }
98
+ init() {
99
+ Task { @MainActor [weak self] in
100
+ for await incoming in CookAlong.sessions() { self?.attach(incoming) }
121
101
  }
122
102
  }
123
103
 
124
- private func configureSession(
125
- _ session: GroupSession<WatchTogetherActivity>
126
- ) {
127
- self.session = session
128
- self.messenger = GroupSessionMessenger(session: session)
129
-
130
- // Observe session state changes
131
- let stateTask = Task {
132
- for await state in session.$state.values {
133
- handleState(state)
134
- }
135
- }
136
- sessionTasks.append(stateTask)
104
+ private func attach(_ incoming: GroupSession<CookAlong>) {
105
+ session = incoming
106
+ messenger = GroupSessionMessenger(session: incoming)
107
+ let states = incoming.$state.values
108
+ let rosters = incoming.$activeParticipants.values
109
+ jobs.append(Task { @MainActor [weak self] in
110
+ for await phase in states { self?.handle(phase) }
111
+ })
112
+ jobs.append(Task { @MainActor [weak self] in
113
+ for await roster in rosters { self?.people = roster }
114
+ })
115
+ incoming.join()
116
+ }
137
117
 
138
- // Observe participant changes
139
- let participantTask = Task {
140
- for await participants in session.$activeParticipants.values {
141
- handleParticipants(participants)
142
- }
118
+ private func handle(_ state: GroupSession<CookAlong>.State) {
119
+ switch state {
120
+ case .waiting:
121
+ break
122
+ case .joined:
123
+ if let recipe = session?.activity.recipeID { RecipeStore.shared.open(recipe) }
124
+ case .invalidated:
125
+ teardown()
126
+ @unknown default:
127
+ break
143
128
  }
144
- sessionTasks.append(participantTask)
145
-
146
- // Join the session
147
- session.join()
148
129
  }
149
130
 
150
- private func cleanUp() {
151
- sessionTasks.forEach { $0.cancel() }
152
- sessionTasks.removeAll()
131
+ func teardown() {
132
+ for job in jobs { job.cancel() }
133
+ jobs = []
153
134
  session = nil
154
135
  messenger = nil
155
136
  }
156
137
  }
157
138
  ```
158
139
 
159
- ### Session States
160
-
161
- | State | Description |
162
- |---|---|
163
- | `.waiting` | Session exists but local participant has not joined |
164
- | `.joined` | Local participant is actively in the session |
165
- | `.invalidated(reason:)` | Session ended (check reason for details) |
166
-
167
- ### Handling State Changes
168
-
169
- ```swift
170
- private func handleState(_ state: GroupSession<WatchTogetherActivity>.State) {
171
- switch state {
172
- case .waiting:
173
- print("Waiting to join")
174
- case .joined:
175
- print("Joined session")
176
- loadActivity(session?.activity)
177
- case .invalidated(let reason):
178
- print("Session ended: \(reason)")
179
- cleanUp()
180
- @unknown default:
181
- break
182
- }
183
- }
184
-
185
- private func handleParticipants(_ participants: Set<Participant>) {
186
- print("Active participants: \(participants.count)")
187
- }
188
- ```
189
-
190
- ### Leaving and Ending
140
+ ### States
191
141
 
192
- ```swift
193
- // Leave the session (other participants continue)
194
- session?.leave()
142
+ | State | Meaning |
143
+ | --- | --- |
144
+ | `.waiting` | The session exists; the local person has not joined |
145
+ | `.joined` | The local person is in the session |
146
+ | `.invalidated(reason:)` | The session is over; the reason says why |
195
147
 
196
- // End the session for all participants
197
- session?.end()
198
- ```
148
+ Participants come as a `Set<Participant>`.
199
149
 
200
- ## Sending and Receiving Messages
150
+ ### Leaving and ending
201
151
 
202
- Use `GroupSessionMessenger` to sync small, time-sensitive app state between
203
- participants.
152
+ - `session?.leave()`: only this device leaves; everyone else carries on.
153
+ - `session?.end()`: the session ends for all participants.
204
154
 
205
- ### Defining Messages
155
+ ## Messages
206
156
 
207
- Messages must be `Codable`; keep each message under 256 KB.
157
+ `GroupSessionMessenger` carries small, time-sensitive app state. Each message
158
+ is `Codable` and must stay under 256 KB.
208
159
 
209
160
  ```swift
210
- struct SyncMessage: Codable {
211
- let action: String
212
- let timestamp: Date
213
- let data: [String: String]
161
+ struct StepChanged: Codable, Sendable {
162
+ let stepIndex: Int
214
163
  }
215
- ```
216
-
217
- ### Sending
218
-
219
- ```swift
220
- func sendSync(_ message: SyncMessage) async throws {
221
- guard let messenger else { return }
222
164
 
223
- try await messenger.send(message, to: .all)
165
+ func announce(step: Int, via messenger: GroupSessionMessenger) async throws {
166
+ try await messenger.send(StepChanged(stepIndex: step), to: .all)
224
167
  }
225
168
 
226
- // Send to specific participants
227
- try await messenger.send(message, to: .only(participant))
228
- ```
229
-
230
- ### Receiving
231
-
232
- ```swift
233
- func observeMessages() {
234
- guard let messenger else { return }
235
-
236
- Task {
237
- for await (message, context) in messenger.messages(of: SyncMessage.self) {
238
- let sender = context.source
239
- handleReceivedMessage(message, from: sender)
240
- }
169
+ func listen(on messenger: GroupSessionMessenger) async {
170
+ for await (change, context) in messenger.messages(of: StepChanged.self) {
171
+ RecipeStore.shared.show(step: change.stepIndex, from: context.source)
241
172
  }
242
173
  }
243
174
  ```
244
175
 
245
- ### Delivery Modes
176
+ Send to one person with `to: .only(participant)`; the sender of a received
177
+ message is `context.source`.
246
178
 
247
- ```swift
248
- // Reliable (default) -- checked and retried for crucial state
249
- let reliableMessenger = GroupSessionMessenger(
250
- session: session,
251
- deliveryMode: .reliable
252
- )
253
-
254
- // Unreliable -- lower latency, no delivery guarantee
255
- let unreliableMessenger = GroupSessionMessenger(
256
- session: session,
257
- deliveryMode: .unreliable
258
- )
259
- ```
179
+ Pick a delivery mode with `GroupSessionMessenger(session:deliveryMode:)`:
260
180
 
261
- Use `.reliable` for state-changing actions such as selections or turns. Use
262
- `.unreliable` for high-frequency ephemeral data such as cursor positions,
263
- drawing strokes, and reactions.
181
+ | Mode | Behaviour | Use for |
182
+ | --- | --- | --- |
183
+ | `.reliable` (default) | Delivery checked and retried | State changes: selections, turns |
184
+ | `.unreliable` | Lower latency, may drop | Frequent throwaway data: cursors, strokes, reactions |
264
185
 
265
- ## Coordinated Media Playback
186
+ ## Coordinated media playback
266
187
 
267
- For video/audio, use `AVPlaybackCoordinator` with `AVPlayer`:
188
+ For `AVPlayer` content, hand the session to the player's coordinator:
268
189
 
269
190
  ```swift
270
191
  import AVFoundation
271
- import GroupActivities
272
192
 
273
- func configurePlayback(
274
- session: GroupSession<WatchTogetherActivity>,
275
- player: AVPlayer
276
- ) {
277
- // Connect the player's coordinator to the session
278
- let coordinator = player.playbackCoordinator
279
- coordinator.coordinateWithSession(session)
193
+ func syncPlayback(_ player: AVPlayer, with session: GroupSession<MovieNight>) {
194
+ player.playbackCoordinator.coordinateWithSession(session)
280
195
  }
281
196
  ```
282
197
 
283
- Once connected, AVFoundation synchronizes play/pause, seeking, rate, playback speed,
284
- and time. Do not put AVPlayer transport fields in messenger messages or snapshots,
285
- including late-joiner snapshots; use custom messages only for state outside playback.
198
+ `AVPlaybackCoordinator` then keeps play, pause, seeks, rate and position in
199
+ step for everyone. Play state, position and rate never belong in your own
200
+ messages or state snapshots, late-joiner snapshots included. Custom messages are
201
+ for state that playback does not cover.
286
202
 
287
- ## Starting SharePlay from Your App
288
-
289
- ### Using GroupActivitySharingController (UIKit)
203
+ ## Starting SharePlay from the app
290
204
 
291
205
  ```swift
292
- import GroupActivities
293
- import UIKit
294
-
295
- func startSharePlay() async throws {
296
- let activity = WatchTogetherActivity(
297
- movieID: "123",
298
- movieTitle: "Great Movie"
299
- )
300
-
301
- switch await activity.prepareForActivation() {
302
- case .activationPreferred:
303
- // A conversation is active and the user chose to share.
304
- _ = try await activity.activate()
305
-
206
+ func startCooking(_ activity: CookAlong) async {
207
+ let choice = await activity.prepareForActivation()
208
+ switch choice {
306
209
  case .activationDisabled:
307
- // The user chose local playback, or sharing is unavailable.
308
- startLocalExperience()
309
-
210
+ RecipeStore.shared.open(activity.recipeID)
211
+ case .activationPreferred:
212
+ do { _ = try await activity.activate() } catch { Log.share.error("\(error)") }
310
213
  case .cancelled:
311
- break
312
-
214
+ return
313
215
  @unknown default:
314
- break
216
+ return
315
217
  }
316
218
  }
317
219
  ```
318
220
 
319
- When no conversation is active (i.e., `isEligibleForGroupSession` is false),
320
- use `GroupActivitySharingController` to let the user pick contacts first:
321
-
322
- ```swift
323
- let controller = try GroupActivitySharingController(activity)
324
- present(controller, animated: true)
325
- ```
326
-
327
- Use the `shareplay` SF Symbol for custom controls. Treat `GroupActivityMetadata`
328
- as discovery copy: concise title, subtitle, image, and type aligned with the
329
- entry point. Keep sibling domains out: GameKit owns auth, matchmaking,
330
- leaderboards, achievements, and voice/chat; TabletopKit owns seats, board
331
- equipment, spatial placement, turns, rules, and authoritative tabletop state;
332
- AVKit owns playback UI. SharePlay owns invitations, lifecycle, participants, and
333
- coordination handoffs. See [references/shareplay-patterns.md](references/shareplay-patterns.md) for SwiftUI `ShareLink`, AirDrop, and direct activation patterns.
334
-
335
- ## GroupSessionJournal: File Transfer
336
-
337
- For larger, non-time-sensitive attachments, use `GroupSessionJournal` instead
338
- of `GroupSessionMessenger`. Journal items must conform to `Transferable`, are
339
- available to late joiners, and are limited to 100 MB. It requires iOS/iPadOS/tvOS
340
- 17+, macOS 14+, or visionOS 1+. For larger/protected assets, share a pointer or manifest and use server storage or app-managed file transfer.
341
-
342
- ```swift
343
- import GroupActivities
344
-
345
- let journal = GroupSessionJournal(session: session)
346
-
347
- // Upload a Transferable file or data item
348
- let attachment = try await journal.add(sharedImageItem)
349
-
350
- // Observe incoming attachments
351
- Task {
352
- for await attachments in journal.attachments {
353
- for attachment in attachments {
354
- let data = try await attachment.load(Data.self)
355
- handleReceivedFile(data)
356
- }
357
- }
358
- }
359
- ```
360
-
361
- ## Common Mistakes
362
-
363
- ### DON'T: Forget to call session.join()
364
-
365
- ```swift
366
- // WRONG -- session is received but never joined
367
- for await session in MyActivity.sessions() {
368
- self.session = session
369
- // Session stays in .waiting state forever
370
- }
371
-
372
- // CORRECT -- join after configuring
373
- for await session in MyActivity.sessions() {
374
- self.session = session
375
- self.messenger = GroupSessionMessenger(session: session)
376
- session.join()
377
- }
378
- ```
379
-
380
- ### DON'T: Forget to leave or end sessions
221
+ - `.activationPreferred`: there is a live conversation and sharing was
222
+ chosen; call `activate()`.
223
+ - `.activationDisabled`: they chose to stay local, or sharing is not possible;
224
+ start the local experience.
225
+ - `.cancelled`: do nothing.
381
226
 
382
- ```swift
383
- // WRONG -- session stays alive after the user navigates away
384
- func viewDidDisappear() {
385
- // Nothing -- session leaks
386
- }
387
-
388
- // CORRECT -- leave when the view is dismissed
389
- func viewDidDisappear() {
390
- session?.leave()
391
- session = nil
392
- messenger = nil
393
- }
394
- ```
395
-
396
- ### DON'T: Assume all participants have the same state
227
+ With no conversation in progress (`isEligibleForGroupSession == false`),
228
+ present `GroupActivitySharingController` in UIKit so the person can pick
229
+ contacts:
397
230
 
398
231
  ```swift
399
- // WRONG -- broadcasting state without handling late joiners
400
- func onJoin() {
401
- // New participant has no idea what the current state is
402
- }
403
-
404
- // CORRECT -- send full state to new participants
405
- func handleParticipants(_ participants: Set<Participant>) {
406
- let newParticipants = participants.subtracting(knownParticipants)
407
- for participant in newParticipants {
408
- Task {
409
- try await messenger?.send(currentState, to: .only(participant))
410
- }
411
- }
412
- knownParticipants = participants
413
- }
232
+ let picker = try GroupActivitySharingController(CookAlong(recipeID: recipe.id))
233
+ hostViewController.present(picker, animated: true)
414
234
  ```
415
235
 
416
- ### DON'T: Use SharePlay transports for large/protected assets
417
-
418
- ```swift
419
- // WRONG -- messenger is small/time-sensitive; journal is Transferable and <=100 MB
420
- let imageData = try Data(contentsOf: imageURL) // 300 KB
421
- try await messenger.send(imageData, to: .all) // Too large
422
- // CORRECT -- journal attachments up to 100 MB; otherwise share a pointer/manifest
423
- let journal = GroupSessionJournal(session: session)
424
- try await journal.add(sharedImageItem)
425
- // Larger/protected assets: server storage or app-managed file transfer
426
- ```
236
+ Custom controls use the `shareplay` SF Symbol. Write
237
+ `GroupActivityMetadata` as discovery copy: a short title, a subtitle and image
238
+ where the surface shows them, and a type that matches where the activity was
239
+ started. SwiftUI buttons, `ShareLink` and AirDrop are covered in
240
+ [the patterns file](references/shareplay-patterns.md).
427
241
 
428
- ### DON'T: Send redundant messages for media playback
242
+ Boundaries with neighbouring frameworks:
429
243
 
430
- ```swift
431
- // WRONG -- manually syncing play/pause when using AVPlayer
432
- func play() {
433
- player.play()
434
- try await messenger.send(PlayMessage(), to: .all)
435
- }
244
+ - GameKit: sign-in, matchmaking, leaderboards, achievements, voice chat.
245
+ - TabletopKit: seating, pieces on the board, where things sit in space, turn
246
+ order, game rules, and which device holds the true table state.
247
+ - AVKit: playback UI.
248
+ - SharePlay (this skill): invitations, session lifecycle, participants and the
249
+ hand-off points to the others.
436
250
 
437
- // CORRECT -- let AVPlaybackCoordinator handle it
438
- player.playbackCoordinator.coordinateWithSession(session)
439
- player.play() // Automatically synced to all participants
440
- ```
251
+ ## GroupSessionJournal: sharing files
441
252
 
442
- ### DON'T: Observe sessions in a view that gets recreated
253
+ For bigger attachments that are not time-critical, use `GroupSessionJournal`
254
+ instead of the messenger. Items must be `Transferable`, attachments stay
255
+ available to people who join later, and each attachment may be up to 100 MB.
256
+ Available on iOS, iPadOS and tvOS 17+, macOS 14+ and visionOS 1+.
443
257
 
444
258
  ```swift
445
- // WRONG -- each time the view appears, a new listener is created
446
- struct MyView: View {
447
- var body: some View {
448
- Text("Hello")
449
- .task {
450
- for await session in MyActivity.sessions() { }
451
- }
452
- }
259
+ func sharePhoto(_ photo: DishPhoto, in session: GroupSession<CookAlong>) async throws {
260
+ let shelf = GroupSessionJournal(session: session)
261
+ _ = try await shelf.add(photo)
453
262
  }
454
263
 
455
- // CORRECT -- observe sessions in a long-lived manager
456
- @Observable
457
- final class ActivityManager {
458
- init() {
459
- Task {
460
- for await session in MyActivity.sessions() {
461
- configureSession(session)
462
- }
264
+ func collectPhotos(from shelf: GroupSessionJournal) async {
265
+ for await batch in shelf.attachments {
266
+ for item in batch {
267
+ guard let bytes = try? await item.load(Data.self) else { continue }
268
+ Gallery.shared.insert(bytes, id: item.id)
463
269
  }
464
270
  }
465
271
  }
466
272
  ```
467
273
 
468
- ## Review Checklist
469
-
470
- - [ ] Group Activities capability added to the app target only
471
- - [ ] `GroupActivity` struct is `Codable` with meaningful metadata
472
- - [ ] `Transferable` conformance added when using `ShareLink`, AirDrop, or share sheets
473
- - [ ] `sessions()` observed in a long-lived object (not a SwiftUI view body)
474
- - [ ] `session.join()` called after receiving and configuring the session
475
- - [ ] `session.leave()` called when the user navigates away or dismisses
476
- - [ ] `GroupSessionMessenger` messages stay under 256 KB with appropriate `deliveryMode`
477
- - [ ] Late-joining participants receive current state on connection
478
- - [ ] `$state` and `$activeParticipants` publishers observed for lifecycle changes
479
- - [ ] `GroupSessionJournal` used for non-time-sensitive `Transferable` attachments
480
- - [ ] `AVPlaybackCoordinator` used for media sync (not manual messages)
481
- - [ ] `GroupStateObserver.isEligibleForGroupSession` checked before showing SharePlay UI
482
- - [ ] `GroupActivitySharingController` used when no conversation is active
483
- - [ ] Session invalidation handled with cleanup of messenger, journal, and tasks
274
+ Anything larger, or anything that needs access control, goes to server storage
275
+ or an app-managed transfer; share only a pointer or manifest through SharePlay.
276
+
277
+ ## Common mistakes
278
+
279
+ - **No `join()`.** The session sits in `.waiting` forever. Join once the
280
+ messenger and observers are set up.
281
+ - **Never leaving.** Navigating away without `session?.leave()` leaks the
282
+ session. Leave on disappear and drop the session and messenger.
283
+ - **Assuming everyone has the same state.** A late joiner knows nothing.
284
+ Compare `activeParticipants` with the set you already know and send the full
285
+ state `to: .only(participant)` to each newcomer.
286
+ - **Pushing big payloads through the messenger.** A 300 KB `Data` blob already
287
+ exceeds its limit. Use the journal up to 100 MB, and server storage or your
288
+ own transfer beyond that.
289
+ - **Duplicating playback commands.** With `AVPlaybackCoordinator` in charge,
290
+ `player.play()` is already shared; extra play or pause messages fight it.
291
+ - **Listening to `sessions()` in a view's `.task`.** Each appearance starts
292
+ another listener. Observe from a long-lived manager, for example from its
293
+ `init`.
294
+
295
+ ## Review checklist
296
+
297
+ - [ ] Only the app target carries the capability
298
+ - [ ] `GroupActivity` is `Codable` and its metadata is meaningful
299
+ - [ ] `Transferable` added where `ShareLink`, AirDrop or share sheets are used
300
+ - [ ] A long-lived object, never a view body, iterates `sessions()`
301
+ - [ ] `join()` called after the session is received and configured
302
+ - [ ] `leave()` called when the person navigates away or dismisses
303
+ - [ ] Messenger payloads under 256 KB, with a suitable `deliveryMode`
304
+ - [ ] Late joiners receive the current state
305
+ - [ ] Both `$state` and `$activeParticipants` are observed
306
+ - [ ] Journal used for `Transferable` attachments that are not time-sensitive
307
+ - [ ] `AVPlaybackCoordinator` handles media sync
308
+ - [ ] `isEligibleForGroupSession` checked before SharePlay UI is shown
309
+ - [ ] `GroupActivitySharingController` offered when no conversation is active
310
+ - [ ] Invalidation tears down messenger, journal and tasks
484
311
 
485
312
  ## References
486
313
 
487
- - Extended patterns (SwiftUI sharing, collaborative canvas, spatial Personas): [references/shareplay-patterns.md](references/shareplay-patterns.md)
488
- - [Configuring Group Activities](https://sosumi.ai/documentation/xcode/configuring-group-activities)
489
- - [GroupActivities framework](https://sosumi.ai/documentation/groupactivities)
490
- - [GroupActivity protocol](https://sosumi.ai/documentation/groupactivities/groupactivity)
491
- - [GroupSession](https://sosumi.ai/documentation/groupactivities/groupsession)
492
- - [GroupSessionMessenger](https://sosumi.ai/documentation/groupactivities/groupsessionmessenger)
493
- - [GroupSessionJournal](https://sosumi.ai/documentation/groupactivities/groupsessionjournal)
494
- - [GroupStateObserver](https://sosumi.ai/documentation/groupactivities/groupstateobserver)
495
- - [GroupActivitySharingController](https://sosumi.ai/documentation/groupactivities/groupactivitysharingcontroller-ybcy)
496
- - [Defining your app's SharePlay activities](https://sosumi.ai/documentation/groupactivities/defining-your-apps-shareplay-activities)
497
- - [Presenting SharePlay activities from your app's UI](https://sosumi.ai/documentation/groupactivities/promoting-shareplay-activities-from-your-apps-ui)
498
- - [Synchronizing data during a SharePlay activity](https://sosumi.ai/documentation/groupactivities/synchronizing-data-during-a-shareplay-activity)
499
- - [Supporting coordinated media playback](https://sosumi.ai/documentation/avfoundation/supporting-coordinated-media-playback)
500
- - [SharePlay HIG](https://sosumi.ai/design/human-interface-guidelines/shareplay)
314
+ - [Pattern catalogue](references/shareplay-patterns.md): shared canvas,
315
+ generic manager, SwiftUI buttons and ShareLink, state sync for late joiners,
316
+ participant tracking, visionOS nearby
317
+ - Capability setup: [Group Activities in Xcode](https://developer.apple.com/documentation/xcode/configuring-group-activities)
318
+ - [GroupActivities](https://developer.apple.com/documentation/groupactivities)
319
+ - [GroupActivity](https://developer.apple.com/documentation/groupactivities/groupactivity)
320
+ - [GroupSession](https://developer.apple.com/documentation/groupactivities/groupsession)
321
+ - [GroupSessionMessenger](https://developer.apple.com/documentation/groupactivities/groupsessionmessenger)
322
+ - [GroupSessionJournal](https://developer.apple.com/documentation/groupactivities/groupsessionjournal)
323
+ - [GroupStateObserver](https://developer.apple.com/documentation/groupactivities/groupstateobserver)
324
+ - [GroupActivitySharingController](https://developer.apple.com/documentation/groupactivities/groupactivitysharingcontroller-ybcy)
325
+ - Article, activity definitions: [link](https://developer.apple.com/documentation/groupactivities/defining-your-apps-shareplay-activities)
326
+ - Article, starting activities from app UI: [link](https://developer.apple.com/documentation/groupactivities/promoting-shareplay-activities-from-your-apps-ui)
327
+ - Article, keeping data in sync: [link](https://developer.apple.com/documentation/groupactivities/synchronizing-data-during-a-shareplay-activity)
328
+ - Article, coordinated playback: [link](https://developer.apple.com/documentation/avfoundation/supporting-coordinated-media-playback)
329
+ - Design guidance: [SharePlay HIG page](https://developer.apple.com/design/human-interface-guidelines/shareplay)