@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,497 +1,379 @@
1
1
  ---
2
2
  name: permissionkit
3
- description: "Create child communication safety experiences using PermissionKit to request parental permission for children. Use when building apps that involve child-to-contact communication, need to check communication limits, request parent/guardian approval, or handle permission responses for minors."
3
+ description: "PermissionKit parental approval for minors: CommunicationLimits handle checks, PermissionQuestion, AskCenter requests and responses, PermissionButton, AskError, pending or expired requests. Use when building child communication safety, a child asking to allow a contact, or handling approvals."
4
4
  metadata:
5
- source: "dpearson2699/swift-ios-skills (PolyForm Perimeter 1.0.0)"
5
+ source: multi-agent-pipeline
6
6
  ---
7
7
 
8
8
  # PermissionKit
9
9
 
10
- > **Note:** PermissionKit APIs span multiple 26.x releases. Verify signatures
11
- > and availability against the current Xcode 26 SDK before shipping.
12
-
13
- Request permission from a parent or guardian to modify a child's communication
14
- rules. PermissionKit creates communication safety experiences that let children
15
- ask for exceptions to communication limits set by their parents. Targets
16
- Swift 6.3 / iOS 26+.
17
-
18
- PermissionKit communication experiences are available only through iMessage.
19
- Use it for parent/guardian approval flows, not as a general in-app contact
20
- permission, moderation, or chat-safety framework.
21
-
22
- ## Contents
23
-
24
- - [Setup](#setup)
25
- - [Core Concepts](#core-concepts)
26
- - [Checking Communication Limits](#checking-communication-limits)
27
- - [Creating Permission Questions](#creating-permission-questions)
28
- - [Requesting Permission with AskCenter](#requesting-permission-with-askcenter)
29
- - [SwiftUI Integration with PermissionButton](#swiftui-integration-with-permissionbutton)
30
- - [Handling Responses](#handling-responses)
31
- - [Significant App Update Topic](#significant-app-update-topic)
32
- - [Common Mistakes](#common-mistakes)
33
- - [Review Checklist](#review-checklist)
34
- - [References](#references)
35
-
36
- ## Setup
10
+ PermissionKit lets a child ask a parent or guardian to change the child's
11
+ communication rules for your app. The typical case: a parent has set
12
+ communication limits, the child wants to talk to someone new, and your app
13
+ turns that wish into a question the parent can approve or decline. The same
14
+ machinery also covers asking a parent to approve a significant app update.
15
+
16
+ What it is not:
17
+
18
+ - It is not a way to ask for in-app contact permission in general, and it is
19
+ not a moderation or chat-safety framework. Use it only when the answer has
20
+ to come from a parent or guardian.
21
+ - The request travels through iMessage and nothing else. Your own chat, DM or
22
+ notification channel cannot carry it.
23
+ - It does not tell you what counts legally as a significant update in a given
24
+ country. That call belongs to the developer, with qualified legal counsel.
25
+
26
+ Examples use Swift 6.3 against the iOS 26 SDK family. The API surface grew
27
+ across three point releases, so check every signature and `@available` line
28
+ against the Xcode 26 SDK you ship with before relying on it.
29
+
30
+ ## Setup and availability
31
+
32
+ Add `@preconcurrency import PermissionKit`. The SwiftUI and UIKit/AppKit
33
+ pieces (`PermissionButton`, `AskCenter.ask(_:in:)`) come in through
34
+ cross-import overlays, so importing SwiftUI or UIKit next to PermissionKit is
35
+ enough. The framework's types carry no `Sendable` annotations, so under Swift 6
36
+ a plain import turns every `ask(_:in:)` call from the main actor into a
37
+ "sending 'question' risks causing data races" error; `@preconcurrency` is what
38
+ lets the examples below compile.
39
+
40
+ Do not add made-up entitlement keys for PermissionKit. If a signing
41
+ requirement exists, it will be in Apple's documentation and in the Xcode
42
+ capabilities list; confirm it there first.
43
+
44
+ When you review code or write guidance, name the exact tier instead of saying
45
+ "iOS 26+". Platforms for every tier: iOS, iPadOS, Mac Catalyst, macOS and
46
+ visionOS.
47
+
48
+ | Tier | What becomes available |
49
+ |---|---|
50
+ | 26.0 | `CommunicationTopic`, `CommunicationHandle`, `PermissionQuestion`, `PermissionResponse`, `PermissionChoice`, `CommunicationLimits` |
51
+ | 26.1 | `AskError` |
52
+ | 26.2 | `AskCenter`, `AskCenter.ask(_:in:)`, `AskCenter.responses(for:)`, `PermissionButton`, `SignificantAppUpdateTopic` (and the `AskError.notAvailable` case) |
37
53
 
38
- Import `PermissionKit`. Do not invent PermissionKit entitlement keys; verify
39
- current Apple documentation and Xcode capabilities before adding signing
40
- requirements.
54
+ Gate the 26.2 path explicitly:
41
55
 
42
56
  ```swift
43
- import PermissionKit
57
+ if #available(iOS 26.2, macOS 26.2, visionOS 26.2, *) {
58
+ try await AskCenter.shared.ask(question, in: hostController)
59
+ } else {
60
+ showUpdateRequiredNotice()
61
+ }
44
62
  ```
45
63
 
46
- **Platform availability:**
47
-
48
- When reviewing or correcting code, state these exact tiers instead of collapsing
49
- PermissionKit to "iOS 26+":
50
-
51
- - Core topic, handle, question, response, choice, and `CommunicationLimits`
52
- APIs: iOS 26.0+, iPadOS 26.0+, Mac Catalyst 26.0+, macOS 26.0+,
53
- visionOS 26.0+.
54
- - `AskError`: iOS 26.1+, iPadOS 26.1+, Mac Catalyst 26.1+, macOS 26.1+,
55
- visionOS 26.1+.
56
- - `AskCenter`, `AskCenter.ask(_:in:)`, `AskCenter.responses(for:)`,
57
- `PermissionButton`, and `SignificantAppUpdateTopic`: iOS/iPadOS/
58
- Mac Catalyst/macOS/visionOS 26.2+.
59
-
60
- ## Core Concepts
61
-
62
- PermissionKit manages a flow where:
64
+ ## How a request flows
63
65
 
64
- 1. A child encounters a communication limit in your app
65
- 2. Your app creates a `PermissionQuestion` describing the request
66
- 3. The system presents the question to the child for them to send to their parent
67
- 4. The parent reviews and approves or denies the request
68
- 5. Your app receives a `PermissionResponse` with the parent's decision
66
+ 1. Inside your app, the child runs into a communication limit (for example,
67
+ tries to message a player they have not been allowed to contact).
68
+ 2. Your app builds a `PermissionQuestion`.
69
+ 3. The system shows the question to the child, who can send it to a parent.
70
+ 4. The parent approves or declines.
71
+ 5. Your app later receives a `PermissionResponse` carrying that decision.
69
72
 
70
- ### Key Types
73
+ Types involved:
71
74
 
72
75
  | Type | Role |
73
76
  |---|---|
74
- | `AskCenter` | Singleton that manages permission requests and responses |
75
- | `PermissionQuestion` | Describes the permission being requested |
76
- | `PermissionResponse` | The parent's decision (approval or denial) |
77
- | `PermissionChoice` | The specific answer (approve/decline) |
78
- | `PermissionButton` | SwiftUI button that triggers the permission flow |
79
- | `CommunicationTopic` | Topic for communication-related permission requests |
80
- | `CommunicationHandle` | A phone number, email, or custom identifier |
81
- | `CommunicationLimits` | Checks which communication handles are known to the system |
82
- | `SignificantAppUpdateTopic` | Topic for significant app update permission requests |
83
-
84
- ## Checking Communication Limits
85
-
86
- Use `CommunicationLimits.current` to check whether the system already knows a
87
- communication handle for your app. This is not an "are communication limits
88
- enabled?" probe. If limits are not enabled, `AskCenter.shared.ask(_:in:)`
89
- throws `AskError.communicationLimitsNotEnabled`; handle that path when asking.
90
-
91
- `knownHandles(in:)` also requires the calling app to have a non-nil, nonempty
92
- bundle identifier. Corrected code should guard `Bundle.main.bundleIdentifier`
93
- before calling it.
77
+ | `AskCenter` | Shared object (`AskCenter.shared`) that sends questions and delivers answers |
78
+ | `PermissionQuestion<Topic>` | What is being asked; has a `UUID` `id` |
79
+ | `PermissionResponse<Topic>` | The parent's decision, with `question` and `choice` |
80
+ | `PermissionChoice` | The concrete answer: approve or decline |
81
+ | `PermissionButton` | SwiftUI control that starts the ask flow when tapped |
82
+ | `CommunicationTopic` | Topic for communication requests |
83
+ | `CommunicationHandle` | Phone number, email address or custom identifier of a contact |
84
+ | `CommunicationLimits` | Tells you which handles the system already knows for your app |
85
+ | `SignificantAppUpdateTopic` | Topic for approving a significant app update |
86
+
87
+ ## Known handles are not a limits check
88
+
89
+ `CommunicationLimits.current` answers one narrow question: does the system
90
+ already know this handle for my app? It does not tell you whether the parent
91
+ has turned communication limits on. The only reliable signal for "limits are
92
+ off" is `AskError.communicationLimitsNotEnabled`, thrown by
93
+ `AskCenter.shared.ask(_:in:)`, so that path always needs handling.
94
+
95
+ `knownHandles(in:)` needs a bundle identifier that is present and not empty.
96
+ Guard `Bundle.main.bundleIdentifier` before you call it.
94
97
 
95
98
  ```swift
96
- import PermissionKit
99
+ @preconcurrency import PermissionKit
97
100
 
98
- func needsPermissionPrompt(for handle: CommunicationHandle) async -> Bool {
99
- let limits = CommunicationLimits.current
100
- let isKnown = await limits.isKnownHandle(handle)
101
- return !isKnown
101
+ func unknownPlayers(_ ids: [String]) async -> Set<CommunicationHandle> {
102
+ guard let bundleID = Bundle.main.bundleIdentifier, !bundleID.isEmpty else {
103
+ return []
104
+ }
105
+ let handles = Set(ids.map { CommunicationHandle(value: $0, kind: .custom) })
106
+ let known = await CommunicationLimits.current.knownHandles(in: handles)
107
+ return handles.subtracting(known)
102
108
  }
103
109
 
104
- // Check multiple handles at once.
105
- func filterKnownHandles(_ handles: Set<CommunicationHandle>) async -> Set<CommunicationHandle> {
106
- guard Bundle.main.bundleIdentifier?.isEmpty == false else { return [] }
107
-
108
- let limits = CommunicationLimits.current
109
- return await limits.knownHandles(in: handles)
110
+ func isAlreadyKnown(email: String) async -> Bool {
111
+ let handle = CommunicationHandle(value: email, kind: .emailAddress)
112
+ return await CommunicationLimits.current.isKnownHandle(handle)
110
113
  }
111
114
  ```
112
115
 
113
- ### Creating Communication Handles
116
+ - `isKnownHandle(_:)` is async and returns `Bool` for one handle.
117
+ - `knownHandles(in:)` takes a `Set<CommunicationHandle>` and returns the
118
+ subset the system knows.
119
+ - `CommunicationHandle(value:kind:)` kinds: `.phoneNumber`, `.emailAddress`,
120
+ `.custom` (your own account or player id). Pick the kind that matches the
121
+ value.
114
122
 
115
- ```swift
116
- let phoneHandle = CommunicationHandle(
117
- value: "+1234567890",
118
- kind: .phoneNumber
119
- )
123
+ ## Building a question
120
124
 
121
- let emailHandle = CommunicationHandle(
122
- value: "friend@example.com",
123
- kind: .emailAddress
124
- )
125
+ Quick forms, when a handle is all you have:
125
126
 
126
- let customHandle = CommunicationHandle(
127
- value: "user123",
128
- kind: .custom
127
+ ```swift
128
+ let single = PermissionQuestion<CommunicationTopic>(
129
+ handle: CommunicationHandle(value: "+15550100", kind: .phoneNumber)
129
130
  )
131
+ let group = PermissionQuestion<CommunicationTopic>(handles: [
132
+ CommunicationHandle(value: "coach-17", kind: .custom),
133
+ CommunicationHandle(value: "coach-18", kind: .custom),
134
+ ])
130
135
  ```
131
136
 
132
- ## Creating Permission Questions
133
-
134
- Build a `PermissionQuestion` with the contact information and communication
135
- action type.
137
+ A richer prompt shows the parent a name and, optionally, an avatar
138
+ (`CGImage`). Wrap each contact in `CommunicationTopic.PersonInformation`,
139
+ list the actions you actually support, then build the question from the
140
+ topic:
136
141
 
137
142
  ```swift
138
- // Question for a single contact
139
- let handle = CommunicationHandle(value: "+1234567890", kind: .phoneNumber)
140
- let question = PermissionQuestion<CommunicationTopic>(handle: handle)
141
-
142
- // Question for multiple contacts
143
- let handles = [
144
- CommunicationHandle(value: "+1234567890", kind: .phoneNumber),
145
- CommunicationHandle(value: "friend@example.com", kind: .emailAddress)
146
- ]
147
- let multiQuestion = PermissionQuestion<CommunicationTopic>(handles: handles)
148
- ```
149
-
150
- ### Using CommunicationTopic with Person Information
143
+ var name = PersonNameComponents()
144
+ name.givenName = "Rosa"
145
+ name.familyName = "Lindqvist"
151
146
 
152
- Provide display names and avatars for a richer permission prompt.
153
-
154
- ```swift
155
- let personInfo = CommunicationTopic.PersonInformation(
156
- handle: CommunicationHandle(value: "+1234567890", kind: .phoneNumber),
157
- nameComponents: {
158
- var name = PersonNameComponents()
159
- name.givenName = "Alex"
160
- name.familyName = "Smith"
161
- return name
162
- }(),
147
+ let rosa = CommunicationTopic.PersonInformation(
148
+ handle: CommunicationHandle(value: "player-4410", kind: .custom),
149
+ nameComponents: name,
163
150
  avatarImage: nil
164
151
  )
165
-
166
- let topic = CommunicationTopic(
167
- personInformation: [personInfo],
168
- actions: [.message, .audioCall]
169
- )
170
-
152
+ let topic = CommunicationTopic(personInformation: [rosa], actions: [.chat, .friend])
171
153
  let question = PermissionQuestion<CommunicationTopic>(communicationTopic: topic)
172
154
  ```
173
155
 
174
- ### Communication Actions
156
+ `CommunicationTopic.Action` values:
175
157
 
176
- | Action | Description |
158
+ | Action | Meaning |
177
159
  |---|---|
178
160
  | `.message` | Text messaging |
179
161
  | `.audioCall` | Voice call |
180
162
  | `.videoCall` | Video call |
181
- | `.call` | Generic call |
182
- | `.chat` | Chat communication |
183
- | `.follow` | Follow a user |
184
- | `.beFollowed` | Allow being followed |
163
+ | `.call` | A call of unspecified type |
164
+ | `.chat` | Chat |
165
+ | `.follow` | Follow someone |
166
+ | `.beFollowed` | Let someone follow the child |
185
167
  | `.friend` | Friend request |
186
168
  | `.connect` | Connection request |
187
- | `.communicate` | Generic communication |
169
+ | `.communicate` | Communication in general |
188
170
 
189
- ## Requesting Permission with AskCenter
171
+ Only list actions your app really offers; the parent is approving exactly
172
+ those.
190
173
 
191
- Use `AskCenter.shared` to request that the child send the permission question
192
- to their parent or guardian. The async `ask` call starts the send flow; parent
193
- decisions arrive later through `responses(for:)`. If the child cancels the send
194
- flow, the system does not deliver a `PermissionResponse` for that question.
174
+ ## Asking through AskCenter
195
175
 
196
- ```swift
197
- import PermissionKit
176
+ `AskCenter.shared.ask(_:in:)` is `async throws`. It presents the system flow
177
+ in which the child sends the question; it does not return the parent's
178
+ answer. Decisions arrive later on `responses(for:)`. If the child backs out of
179
+ the send sheet, no `PermissionResponse` ever arrives, so a pending request
180
+ needs its own expiry or retry.
198
181
 
199
- func requestPermission(
200
- for question: PermissionQuestion<CommunicationTopic>,
201
- in viewController: UIViewController
202
- ) async {
182
+ ```swift
183
+ @available(iOS 26.2, *)
184
+ @MainActor
185
+ func requestContact(_ question: PermissionQuestion<CommunicationTopic>,
186
+ from host: UIViewController) async {
203
187
  do {
204
- try await AskCenter.shared.ask(question, in: viewController)
205
- // Question send flow was started; wait for responses(for:) separately.
188
+ try await AskCenter.shared.ask(question, in: host)
189
+ pending.markPending(question.id)
206
190
  } catch let error as AskError {
207
191
  switch error {
208
192
  case .communicationLimitsNotEnabled:
209
- // Communication limits not active -- continue with normal app flow.
210
- break
193
+ unlockChat() // no limits: carry on normally
211
194
  case .contactSyncNotSetup:
212
- // Contact sync not configured
213
- break
195
+ promptForContactSync()
214
196
  case .invalidQuestion:
215
- // Question is malformed
216
- break
197
+ reportBrokenQuestion() // e.g. no handles at all
217
198
  case .notAvailable:
218
- // PermissionKit not available on this device
219
- break
199
+ explainUnavailableOnDevice()
220
200
  case .systemError(let underlying):
221
- print("System error: \(underlying)")
201
+ showFailure(underlying.localizedDescription)
222
202
  case .unknown:
223
- break
203
+ showRetryLater()
224
204
  @unknown default:
225
- break
205
+ showRetryLater()
226
206
  }
207
+ } catch {
208
+ showFailure(error.localizedDescription)
227
209
  }
228
210
  }
229
211
  ```
230
212
 
231
- ## SwiftUI Integration with PermissionButton
213
+ In the 26.2 SDK `.systemError` is deprecated because the underlying error is
214
+ now thrown directly; keep the generic `catch` for that reason.
232
215
 
233
- `PermissionButton` is a SwiftUI view that triggers the permission flow when
234
- tapped. It uses the same response model as `AskCenter`: observe responses and
235
- model a pending/canceled state instead of assuming every tap produces a parent
236
- decision.
216
+ ## PermissionButton in SwiftUI
237
217
 
238
- ```swift
239
- import SwiftUI
240
- import PermissionKit
218
+ `PermissionButton(question:label:)` starts the same flow when tapped:
241
219
 
242
- struct ContactPermissionView: View {
243
- let handle = CommunicationHandle(value: "+1234567890", kind: .phoneNumber)
244
-
245
- var body: some View {
246
- let question = PermissionQuestion<CommunicationTopic>(handle: handle)
247
-
248
- PermissionButton(question: question) {
249
- Label("Ask to Message", systemImage: "message")
250
- }
251
- }
220
+ ```swift
221
+ PermissionButton(question: question) {
222
+ Label("Ask to play with Rosa", systemImage: "person.badge.plus")
252
223
  }
253
224
  ```
254
225
 
255
- For richer SwiftUI flows, custom topics, and long-lived managers, read
256
- [references/permissionkit-patterns.md](references/permissionkit-patterns.md).
226
+ It uses the same response model as `AskCenter`. Keep observing
227
+ `responses(for:)`, and keep pending and cancelled states in your model,
228
+ because a tap does not guarantee that any decision comes back. Full screen
229
+ examples are in the
230
+ [patterns reference](references/permissionkit-patterns.md#swiftui-full-flow).
257
231
 
258
- ## Handling Responses
232
+ ## Handling responses
259
233
 
260
- Listen for permission responses asynchronously. Track pending questions by
261
- `question.id`, and give the UI a retry or expiration path because a child can
262
- cancel the iMessage send flow without producing a response.
263
- When combining known-handle checks with response handling, carry forward the
264
- bundle-identifier guard from `knownHandles(in:)`.
234
+ Track each question by `question.id` (a `UUID`). Since a cancelled send
235
+ produces nothing, give every pending entry a way out: a retry, an expiry, or
236
+ both. When a flow combines known-handle checks with responses, keep the
237
+ bundle-identifier guard from the section above.
265
238
 
266
239
  ```swift
267
- enum PermissionRequestState {
268
- case pending, approved, denied, expired
269
- }
240
+ enum RequestState { case pending, approved, denied, expired }
270
241
 
271
- var requestStates: [UUID: PermissionRequestState] = [:]
242
+ @MainActor @Observable
243
+ final class ContactRequests {
244
+ private(set) var states: [UUID: RequestState] = [:]
272
245
 
273
- func expireIfStillPending(_ id: UUID) {
274
- guard requestStates[id] == .pending else { return }
275
- requestStates[id] = .expired
276
- // Re-enable asking or show retry/canceled UI.
277
- }
246
+ func markPending(_ id: UUID) { states[id] = .pending }
278
247
 
279
- func observeResponses() async {
280
- let responses = AskCenter.shared.responses(for: CommunicationTopic.self)
281
-
282
- for await response in responses {
283
- let choice = response.choice
284
- let question = response.question
285
-
286
- switch choice.answer {
287
- case .approval:
288
- // Parent approved -- enable communication
289
- requestStates[question.id] = .approved
290
- print("Approved for topic: \(question.topic)")
291
- case .denial:
292
- // Parent denied -- keep restriction
293
- requestStates[question.id] = .denied
294
- print("Denied")
295
- @unknown default:
296
- break
297
- }
248
+ func expire(_ id: UUID) {
249
+ guard states[id] == .pending else { return }
250
+ states[id] = .expired // lets the child ask again
298
251
  }
299
- }
300
- ```
301
-
302
- ### PermissionChoice Properties
303
-
304
- ```swift
305
- let choice: PermissionChoice = response.choice
306
- print("Answer: \(choice.answer)") // .approval or .denial
307
- print("Choice ID: \(choice.id)")
308
- print("Title: \(choice.title)")
309
-
310
- // Convenience statics
311
- let approved = PermissionChoice.approve
312
- let declined = PermissionChoice.decline
313
- ```
314
-
315
- ## Significant App Update Topic
316
-
317
- Request permission for significant app updates that require parental approval.
318
- Your app determines what counts as significant based on applicable regulations
319
- and should consult qualified legal counsel for compliance interpretation.
320
- Use concise, understandable descriptions that state the concrete change parents
321
- are approving.
322
-
323
- ```swift
324
- let updateTopic = SignificantAppUpdateTopic(
325
- description: "This update adds multiplayer chat features"
326
- )
327
252
 
328
- let question = PermissionQuestion<SignificantAppUpdateTopic>(
329
- significantAppUpdateTopic: updateTopic
330
- )
331
-
332
- // Present the question
333
- try await AskCenter.shared.ask(question, in: viewController)
334
- requestStates[question.id] = .pending
335
- scheduleExpiration(for: question.id)
336
-
337
- // Listen for responses
338
- for await response in AskCenter.shared.responses(for: SignificantAppUpdateTopic.self) {
339
- switch response.choice.answer {
340
- case .approval:
341
- // Proceed with update
342
- requestStates[response.question.id] = .approved
343
- case .denial:
344
- // Skip update
345
- requestStates[response.question.id] = .denied
346
- @unknown default:
347
- break
253
+ @available(iOS 26.2, *)
254
+ func listen() async {
255
+ for await response in AskCenter.shared.responses(for: CommunicationTopic.self) {
256
+ let id = response.question.id
257
+ switch response.choice.answer {
258
+ case .approval: states[id] = .approved
259
+ case .denial: states[id] = .denied
260
+ @unknown default: states[id] = .denied
261
+ }
262
+ let people = response.question.topic.personInformation
263
+ refreshContacts(people.map(\.handle))
264
+ }
348
265
  }
349
- }
350
-
351
- // If no response arrives before your pending window expires, keep the update
352
- // blocked or offer a retry. Child cancellation produces no denial response.
353
- ```
354
-
355
- ## Common Mistakes
356
-
357
- ### DON'T: Treat known-handle checks as enabled-limits checks
358
266
 
359
- `isKnownHandle(_:)` and `knownHandles(in:)` only classify handles. They do not
360
- replace handling `.communicationLimitsNotEnabled` from `ask(_:in:)`.
361
-
362
- ```swift
363
- // WRONG: Assuming a handle lookup proves active limits
364
- let isKnown = await CommunicationLimits.current.isKnownHandle(handle)
365
- if !isKnown {
366
- try await AskCenter.shared.ask(question, in: viewController)
367
- }
368
-
369
- // CORRECT: Handle the case where limits are not enabled
370
- do {
371
- try await AskCenter.shared.ask(question, in: viewController)
372
- } catch AskError.communicationLimitsNotEnabled {
373
- // Communication limits not active -- continue with normal app flow.
374
- allowCommunication()
375
- } catch {
376
- handleError(error)
267
+ private func refreshContacts(_ handles: [CommunicationHandle]) {}
377
268
  }
378
269
  ```
379
270
 
380
- ### DON'T: Ignore AskError cases
271
+ - `responses(for:)` is an async sequence of `PermissionResponse<Topic>`; each
272
+ element has `.question` and `.choice`.
273
+ - `response.question.topic` gives back the topic you asked about.
274
+ - `choice.answer` is `.approval` (allow the communication) or `.denial` (keep
275
+ the restriction).
276
+ - `PermissionChoice` also exposes `id` and `title`, and the statics
277
+ `PermissionChoice.approve` and `PermissionChoice.decline`.
381
278
 
382
- Each error case requires different handling.
279
+ ## Significant app updates
383
280
 
384
- ```swift
385
- // WRONG: Catch-all with no user feedback
386
- do {
387
- try await AskCenter.shared.ask(question, in: viewController)
388
- } catch {
389
- print(error)
390
- }
391
-
392
- // CORRECT: Handle each case
393
- do {
394
- try await AskCenter.shared.ask(question, in: viewController)
395
- } catch let error as AskError {
396
- switch error {
397
- case .communicationLimitsNotEnabled:
398
- allowCommunication()
399
- case .contactSyncNotSetup:
400
- showContactSyncPrompt()
401
- case .invalidQuestion:
402
- showInvalidQuestionAlert()
403
- case .notAvailable:
404
- showUnavailableMessage()
405
- case .systemError(let underlying):
406
- showSystemError(underlying)
407
- case .unknown:
408
- showGenericError()
409
- @unknown default:
410
- break
411
- }
412
- }
413
- ```
414
-
415
- ### DON'T: Create questions with empty handles
416
-
417
- A question with no handles or person information is invalid.
281
+ `SignificantAppUpdateTopic` asks a parent to approve a significant change to
282
+ the app. You decide what is significant according to the regulations that
283
+ apply to you; get interpretation from qualified legal counsel, not from this
284
+ skill. The description should be short and name the concrete change the
285
+ parent is agreeing to, for example "Adds voice chat with players outside
286
+ your child's friend list", not "We updated our app".
418
287
 
419
288
  ```swift
420
- // WRONG: Empty handles array
421
- let question = PermissionQuestion<CommunicationTopic>(handles: []) // Invalid
422
-
423
- // CORRECT: Provide at least one handle
424
- let handle = CommunicationHandle(value: "+1234567890", kind: .phoneNumber)
425
- let question = PermissionQuestion<CommunicationTopic>(handle: handle)
426
- ```
427
-
428
- ### DON'T: Forget to observe responses and pending states
429
-
430
- Presenting a question without listening for the response means you never know
431
- if the parent approved. A child can also cancel the send flow, so do not wait
432
- forever for a response to every question.
433
-
434
- ```swift
435
- // WRONG: Fire and forget
436
- try await AskCenter.shared.ask(question, in: viewController)
437
-
438
- // CORRECT: Observe responses
439
- Task {
440
- for await response in AskCenter.shared.responses(for: CommunicationTopic.self) {
441
- handleResponse(response)
442
- }
443
- }
444
- try await AskCenter.shared.ask(question, in: viewController)
445
- ```
446
-
447
- ### DON'T: Use deprecated CommunicationLimitsButton
448
-
449
- Use `PermissionButton` instead of the deprecated `CommunicationLimitsButton`.
450
-
451
- ```swift
452
- // WRONG: Deprecated
453
- CommunicationLimitsButton(question: question) {
454
- Text("Ask Permission")
289
+ @available(iOS 26.2, *)
290
+ @MainActor
291
+ func askAboutVoiceChat(from host: UIViewController) async throws {
292
+ let topic = SignificantAppUpdateTopic(
293
+ description: "Adds voice chat with players outside your child's friend list."
294
+ )
295
+ let question = PermissionQuestion<SignificantAppUpdateTopic>(significantAppUpdateTopic: topic)
296
+ try await AskCenter.shared.ask(question, in: host)
297
+ updateGate.markPending(question.id)
298
+ updateGate.scheduleExpiry(for: question.id, after: .seconds(72 * 3600))
455
299
  }
456
300
 
457
- // CORRECT: Use PermissionButton
458
- PermissionButton(question: question) {
459
- Text("Ask Permission")
301
+ @available(iOS 26.2, *)
302
+ @MainActor
303
+ func watchUpdateDecisions() async {
304
+ for await response in AskCenter.shared.responses(for: SignificantAppUpdateTopic.self) {
305
+ switch response.choice.answer {
306
+ case .approval: updateGate.enableVoiceChat()
307
+ case .denial: updateGate.keepVoiceChatOff()
308
+ @unknown default: updateGate.keepVoiceChatOff()
309
+ }
310
+ }
460
311
  }
461
312
  ```
462
313
 
463
- ## Review Checklist
464
-
465
- - [ ] iMessage-only routing understood before choosing PermissionKit
466
- - [ ] Corrected guidance states exact availability tiers: core communication
467
- types/limits 26.0+, `AskError` 26.1+, and `AskCenter`/`PermissionButton`/
468
- responses/significant-update topics 26.2+
469
- - [ ] `AskError.communicationLimitsNotEnabled` handled to allow fallback
470
- - [ ] `AskError` cases handled individually with appropriate user feedback
471
- - [ ] `CommunicationHandle` created with correct `Kind` (phone, email, custom)
472
- - [ ] Known-handle examples guard a non-nil, nonempty bundle identifier before
473
- `knownHandles(in:)`
474
- - [ ] Known-handle checks are not treated as active-limits checks
475
- - [ ] `PermissionQuestion` includes at least one handle or person information
476
- - [ ] `AskCenter.shared.responses(for:)` observed to receive parent decisions
477
- - [ ] `PermissionButton` used instead of deprecated `CommunicationLimitsButton`
478
- - [ ] Person information includes name components for a clear permission prompt
479
- - [ ] Communication actions match the app's actual communication capabilities
480
- - [ ] Pending/canceled/expired question states handled when no response arrives
481
- - [ ] Response handling updates UI on the main actor
482
- - [ ] Error states provide clear guidance to the user
314
+ If the pending window closes with no answer, keep the update blocked or offer
315
+ another request. A child cancelling the send flow is not a denial; it simply
316
+ produces no response.
317
+
318
+ ## Common mistakes
319
+
320
+ - Reading `isKnownHandle(_:)` or `knownHandles(in:)` as "limits are on".
321
+ Those calls only classify handles. Still catch the limits-off case:
322
+
323
+ ```swift
324
+ do { try await AskCenter.shared.ask(question, in: host) }
325
+ catch AskError.communicationLimitsNotEnabled { unlockChat() }
326
+ ```
327
+
328
+ - One catch-all that shows nothing. Give each `AskError` case its own
329
+ outcome: allow communication, prompt for contact sync, flag an invalid
330
+ question, explain that the device cannot do it, surface a system error, or
331
+ show a generic retry message.
332
+ - Empty handles. `PermissionQuestion(handles: [])` is an invalid question.
333
+ Provide at least one handle or one `PersonInformation`.
334
+ - Fire-and-forget asking. Start the task that observes `responses(for:)`
335
+ before or next to the `ask` call, and never wait forever: the child can
336
+ cancel.
337
+ - Using `CommunicationLimitsButton`, or the `CommunicationLimits` ask and
338
+ `updates` APIs. They are deprecated; use `PermissionButton`,
339
+ `AskCenter.ask(_:in:)` and `AskCenter.responses(for:)`.
340
+
341
+ ## Review checklist
342
+
343
+ - [ ] The team knows the request goes through iMessage only before picking
344
+ PermissionKit.
345
+ - [ ] Availability is stated per tier: 26.0 core types and limits, 26.1
346
+ `AskError`, 26.2 `AskCenter`, `PermissionButton`, responses and
347
+ `SignificantAppUpdateTopic`.
348
+ - [ ] `.communicationLimitsNotEnabled` falls back to normal communication;
349
+ every other `AskError` case has its own user feedback.
350
+ - [ ] Each `CommunicationHandle` uses the right `Kind`.
351
+ - [ ] Known-handle code guards a nonempty bundle identifier and is not used
352
+ as a limits-enabled check.
353
+ - [ ] Every question has at least one handle or person information, and
354
+ person information carries name components.
355
+ - [ ] `responses(for:)` is observed; `PermissionButton` is used, not the
356
+ deprecated button.
357
+ - [ ] Listed actions match what the app really lets people do.
358
+ - [ ] Pending, cancelled and expired requests are handled when no answer
359
+ arrives.
360
+ - [ ] Response handling updates UI on the main actor and errors tell the user
361
+ what to do next.
483
362
 
484
363
  ## References
485
364
 
486
- - Extended patterns (response handling, multi-topic, UIKit): [references/permissionkit-patterns.md](references/permissionkit-patterns.md)
487
- - [PermissionKit framework](https://sosumi.ai/documentation/permissionkit)
488
- - [AskCenter](https://sosumi.ai/documentation/permissionkit/askcenter)
489
- - [PermissionQuestion](https://sosumi.ai/documentation/permissionkit/permissionquestion)
490
- - [PermissionButton](https://sosumi.ai/documentation/permissionkit/permissionbutton)
491
- - [PermissionResponse](https://sosumi.ai/documentation/permissionkit/permissionresponse)
492
- - [CommunicationTopic](https://sosumi.ai/documentation/permissionkit/communicationtopic)
493
- - [CommunicationHandle](https://sosumi.ai/documentation/permissionkit/communicationhandle)
494
- - [CommunicationLimits](https://sosumi.ai/documentation/permissionkit/communicationlimits)
495
- - [SignificantAppUpdateTopic](https://sosumi.ai/documentation/permissionkit/significantappupdatetopic)
496
- - [AskError](https://sosumi.ai/documentation/permissionkit/askerror)
497
- - [Creating a communication experience](https://sosumi.ai/documentation/permissionkit/creating-a-communication-experience)
365
+ - [Patterns reference](references/permissionkit-patterns.md): UIKit
366
+ controller, response manager, multi-contact questions, limits-check view
367
+ model, SwiftUI full flow, macOS, error recovery.
368
+ - Apple documentation:
369
+ - https://developer.apple.com/documentation/permissionkit
370
+ - https://developer.apple.com/documentation/permissionkit/askcenter
371
+ - https://developer.apple.com/documentation/permissionkit/permissionquestion
372
+ - https://developer.apple.com/documentation/permissionkit/permissionbutton
373
+ - https://developer.apple.com/documentation/permissionkit/permissionresponse
374
+ - https://developer.apple.com/documentation/permissionkit/communicationtopic
375
+ - https://developer.apple.com/documentation/permissionkit/communicationhandle
376
+ - https://developer.apple.com/documentation/permissionkit/communicationlimits
377
+ - https://developer.apple.com/documentation/permissionkit/significantappupdatetopic
378
+ - https://developer.apple.com/documentation/permissionkit/askerror
379
+ - https://developer.apple.com/documentation/permissionkit/creating-a-communication-experience