@mmerterden/multi-agent-pipeline 20.7.0 → 20.8.1

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