@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,46 +1,35 @@
1
1
  ---
2
2
  name: authentication
3
- description: "Implement iOS authentication flows with AuthenticationServices and LocalAuthentication. Use when building Sign in with Apple, passkey/WebAuthn registration or sign-in with ASAuthorizationPlatformPublicKeyCredentialProvider, ASAuthorizationController credential state and revocation handling, ASWebAuthenticationSession OAuth or third-party login, Password AutoFill, identity-token server validation, or local biometric re-authentication with LAContext."
3
+ description: "iOS sign-in with AuthenticationServices and LocalAuthentication: Sign in with Apple, passkey (WebAuthn) registration and login via ASAuthorizationPlatformPublicKeyCredentialProvider, ASAuthorizationController credential state and revocation, ASWebAuthenticationSession OAuth and third-party login, Password AutoFill, server-side identity-token validation, LAContext biometric re-authentication. Use when adding or reviewing account flows."
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
  # Authentication
9
9
 
10
- Implement authentication flows on iOS using the AuthenticationServices
11
- framework, including Sign in with Apple, passkeys, OAuth/third-party web
12
- auth, Password AutoFill, and biometric re-authentication.
13
-
14
- ## Contents
15
-
16
- - [Sign in with Apple](#sign-in-with-apple)
17
- - [Credential Handling](#credential-handling)
18
- - [Credential State Checking](#credential-state-checking)
19
- - [Token Validation](#token-validation)
20
- - [Existing Account Setup Flows](#existing-account-setup-flows)
21
- - [Passkeys](#passkeys)
22
- - [ASWebAuthenticationSession (OAuth)](#aswebauthenticationsession-oauth)
23
- - [Password AutoFill Credentials](#password-autofill-credentials)
24
- - [Biometric Authentication](#biometric-authentication)
25
- - [Security Boundaries](#security-boundaries)
26
- - [SwiftUI SignInWithAppleButton](#swiftui-signinwithapplebutton)
27
- - [Common Mistakes](#common-mistakes)
28
- - [Review Checklist](#review-checklist)
29
- - [References](#references)
10
+ This skill owns the account-facing side of identity on iOS: Sign in with
11
+ Apple, passkeys, Password AutoFill, `ASAuthorizationController`, presenting an
12
+ OAuth session with `ASWebAuthenticationSession`, credential state, and local
13
+ biometric re-authentication. Code samples assume iOS 26 with Swift 6.3.
14
+
15
+ Deeper material:
16
+
17
+ - [Passkeys](references/passkeys.md) - prerequisites, registration, sign-in, AutoFill, security keys, failure modes
18
+ - [Keychain and biometrics](references/keychain-biometric.md) - token storage, `LAContext`, access-controlled items
30
19
 
31
20
  ## Sign in with Apple
32
21
 
33
- Add the "Sign in with Apple" capability in Xcode before using these APIs.
22
+ Before any code, add the Apple sign-in capability to the app target in Signing & Capabilities.
34
23
 
35
- ### UIKit: ASAuthorizationController Setup
24
+ ### Starting the request (UIKit)
36
25
 
37
26
  ```swift
38
27
  import AuthenticationServices
28
+ import UIKit
39
29
 
40
- final class LoginViewController: UIViewController {
41
- func startSignInWithApple() {
42
- let provider = ASAuthorizationAppleIDProvider()
43
- let request = provider.createRequest()
30
+ final class WelcomeViewController: UIViewController {
31
+ func beginAppleSignIn() {
32
+ let request = ASAuthorizationAppleIDProvider().createRequest()
44
33
  request.requestedScopes = [.fullName, .email]
45
34
 
46
35
  let controller = ASAuthorizationController(authorizationRequests: [request])
@@ -50,445 +39,340 @@ final class LoginViewController: UIViewController {
50
39
  }
51
40
  }
52
41
 
53
- extension LoginViewController: ASAuthorizationControllerPresentationContextProviding {
42
+ extension WelcomeViewController: ASAuthorizationControllerPresentationContextProviding {
54
43
  func presentationAnchor(for controller: ASAuthorizationController) -> ASPresentationAnchor {
55
- view.window!
44
+ guard let window = view.window else {
45
+ preconditionFailure("Start Sign in with Apple only while this screen is on screen")
46
+ }
47
+ return window // ASPresentationAnchor() with no scene is deprecated in iOS 26
56
48
  }
57
49
  }
58
50
  ```
59
51
 
60
- ### Delegate: Handling Success and Failure
52
+ ### Delegate callbacks
61
53
 
62
54
  ```swift
63
- extension LoginViewController: ASAuthorizationControllerDelegate {
64
- func authorizationController(
65
- controller: ASAuthorizationController,
66
- didCompleteWithAuthorization authorization: ASAuthorization
67
- ) {
68
- guard let credential = authorization.credential
69
- as? ASAuthorizationAppleIDCredential else { return }
70
-
71
- let userID = credential.user // Stable, unique, per-team identifier
72
- let email = credential.email // nil after first authorization
73
- let fullName = credential.fullName // nil after first authorization
74
- let identityToken = credential.identityToken // JWT for server validation
75
- let authCode = credential.authorizationCode // Short-lived code for server exchange
76
-
77
- // Save userID to Keychain for credential state checks
78
- // See references/keychain-biometric.md for Keychain patterns
79
- saveUserID(userID)
80
-
81
- // Send identityToken and authCode to your server
82
- authenticateWithServer(identityToken: identityToken, authCode: authCode)
55
+ extension WelcomeViewController: ASAuthorizationControllerDelegate {
56
+ func authorizationController(controller: ASAuthorizationController,
57
+ didCompleteWithAuthorization authorization: ASAuthorization) {
58
+ let credential = authorization.credential
59
+ guard let apple = credential as? ASAuthorizationAppleIDCredential else { return }
60
+ AccountVault.shared.rememberAppleUser(apple.user) // stable per-team ID
61
+ if let name = apple.fullName { ProfileDraft.shared.name = name } // first time only
62
+ if let mail = apple.email { ProfileDraft.shared.email = mail } // first time only
63
+ Task { try await SessionAPI.exchange(token: apple.identityToken, code: apple.authorizationCode) }
83
64
  }
84
65
 
85
- func authorizationController(
86
- controller: ASAuthorizationController,
87
- didCompleteWithError error: any Error
88
- ) {
89
- let authError = error as? ASAuthorizationError
90
- switch authError?.code {
91
- case .canceled:
92
- break // User dismissed
93
- case .failed:
94
- showError("Authorization failed")
95
- case .invalidResponse:
96
- showError("Invalid response")
97
- case .notHandled:
98
- showError("Not handled")
99
- case .notInteractive:
100
- break // Non-interactive request failed -- expected for silent checks
66
+ func authorizationController(controller: ASAuthorizationController,
67
+ didCompleteWithError error: Error) {
68
+ guard let authError = error as? ASAuthorizationError else { return }
69
+ switch authError.code {
70
+ case .canceled: break // user closed the sheet
71
+ case .notInteractive: break // silent check found nothing
72
+ case .failed, .invalidResponse, .notHandled:
73
+ showSignInProblem(authError)
101
74
  default:
102
- showError("Unknown error")
75
+ showSignInProblem(authError)
103
76
  }
104
77
  }
105
78
  }
106
79
  ```
107
80
 
108
- ## Credential Handling
109
-
110
- `ASAuthorizationAppleIDCredential` properties and their behavior:
81
+ `user` is a stable identifier scoped to your team; save it in the Keychain so
82
+ you can check credential state later. `identityToken` is a JWT for the server
83
+ and `authorizationCode` is a short-lived code the server exchanges; send both.
111
84
 
112
- | Property | Type | First Auth | Subsequent Auth |
113
- |---|---|---|---|
114
- | `user` | `String` | Always | Always |
115
- | `email` | `String?` | Provided if requested | `nil` |
116
- | `fullName` | `PersonNameComponents?` | Provided if requested | `nil` |
117
- | `identityToken` | `Data?` | JWT encoded as UTF-8 data | JWT encoded as UTF-8 data |
118
- | `authorizationCode` | `Data?` | Short-lived code | Short-lived code |
119
- | `realUserStatus` | `ASUserDetectionStatus` | Fraud-prevention signal | Do not rely on later attempts |
85
+ ### What the credential contains
120
86
 
121
- **Critical:** `email` and `fullName` are provided ONLY on the first
122
- authorization. Cache them immediately during the initial sign-up flow. If the
123
- user later deletes and re-adds the app, these values will not be returned.
87
+ | Property | Type | Availability |
88
+ |---|---|---|
89
+ | `user` | `String` | Every time |
90
+ | `email` | `String?` | First authorization only, if requested |
91
+ | `fullName` | `PersonNameComponents?` | First authorization only, if requested |
92
+ | `identityToken` | `Data?` | Every time, a UTF-8 JWT |
93
+ | `authorizationCode` | `Data?` | Every time, short-lived |
94
+ | `realUserStatus` | `ASUserDetectionStatus` | Anti-fraud hint; do not count on it after the first attempt |
124
95
 
125
- ```swift
126
- func handleCredential(_ credential: ASAuthorizationAppleIDCredential) {
127
- // Always persist the user identifier
128
- let userID = credential.user
129
-
130
- // Cache name and email IMMEDIATELY -- only available on first auth
131
- if let fullName = credential.fullName {
132
- let name = PersonNameComponentsFormatter().string(from: fullName)
133
- UserProfile.saveName(name) // Persist to your backend
134
- }
135
- if let email = credential.email {
136
- UserProfile.saveEmail(email) // Persist to your backend
137
- }
138
- }
139
- ```
96
+ Capture name and email the moment they arrive and send them to your backend.
97
+ Apple never sends them again, and deleting and reinstalling the app does not
98
+ bring them back. Format a name with
99
+ `PersonNameComponentsFormatter().string(from:)` before storing it.
140
100
 
141
- ## Credential State Checking
101
+ ### Credential state
142
102
 
143
- Check credential state on every app launch. The user may revoke access at
144
- any time via Settings > Apple Account > Sign-In & Security.
103
+ People can revoke the app at any time under Settings > Apple Account >
104
+ Sign-In & Security, so check on every launch:
145
105
 
146
106
  ```swift
147
- func checkCredentialState() {
107
+ func verifyAppleCredential(for userID: String) {
148
108
  let provider = ASAuthorizationAppleIDProvider()
149
- guard let userID = loadSavedUserID() else {
150
- showLoginScreen()
151
- return
152
- }
153
-
154
- provider.getCredentialState(forUserID: userID) { state, _ in
109
+ provider.getCredentialState(forUserID: userID) { credentialState, _ in
155
110
  DispatchQueue.main.async {
156
- switch state {
157
- case .authorized:
158
- proceedToMainApp()
159
- case .revoked:
160
- // User revoked -- sign out and clear local data
161
- signOut()
162
- showLoginScreen()
163
- case .notFound:
164
- showLoginScreen()
165
- case .transferred:
166
- // App transferred to new team -- migrate user identifier
167
- migrateUser()
168
- @unknown default:
169
- showLoginScreen()
111
+ switch credentialState {
112
+ case .authorized: SessionStore.shared.resume()
113
+ case .revoked: SessionStore.shared.signOutAndWipe()
114
+ case .notFound: SessionStore.shared.presentLogin()
115
+ case .transferred: SessionStore.shared.migrateTransferredUser(userID)
116
+ @unknown default: SessionStore.shared.presentLogin()
170
117
  }
171
118
  }
172
119
  }
173
120
  }
174
121
  ```
175
122
 
176
- ### Credential Revocation Notification
177
-
178
- ```swift
179
- NotificationCenter.default.addObserver(
180
- forName: ASAuthorizationAppleIDProvider.credentialRevokedNotification,
181
- object: nil,
182
- queue: .main
183
- ) { _ in
184
- // Sign out immediately
185
- AuthManager.shared.signOut()
186
- }
187
- ```
123
+ `.transferred` means the app moved to a different developer team and the user
124
+ identifier must be migrated. Also subscribe to
125
+ `ASAuthorizationAppleIDProvider.credentialRevokedNotification` and sign the
126
+ user out as soon as it fires.
188
127
 
189
- ## Token Validation
128
+ ### Server validation
190
129
 
191
- The `identityToken` is a JWT. Send it to your server for validation --
192
- never trust it client-side alone.
130
+ Never accept the identity token on the device alone. Hand both values to your
131
+ backend and keep only what it returns:
193
132
 
194
133
  ```swift
195
- func sendTokenToServer(credential: ASAuthorizationAppleIDCredential) async throws {
196
- guard let tokenData = credential.identityToken,
197
- let token = String(data: tokenData, encoding: .utf8),
198
- let authCodeData = credential.authorizationCode,
199
- let authCode = String(data: authCodeData, encoding: .utf8) else {
200
- throw AuthError.missingToken
134
+ enum SessionAPI {
135
+ struct Session: Decodable { let accessToken: String }
136
+
137
+ static func exchange(token: Data?, code: Data?) async throws {
138
+ guard let token, let code,
139
+ let jwt = String(data: token, encoding: .utf8),
140
+ let grant = String(data: code, encoding: .utf8) else { throw URLError(.badServerResponse) }
141
+
142
+ guard let endpoint = URL(string: "https://api.tasknest.app/auth/apple") else { throw URLError(.badURL) }
143
+ var call = URLRequest(url: endpoint)
144
+ call.httpMethod = "POST"
145
+ call.addValue("application/json", forHTTPHeaderField: "Content-Type")
146
+ let body = try JSONEncoder().encode(["identity_token": jwt, "authorization_code": grant])
147
+ let (bytes, reply) = try await URLSession(configuration: .ephemeral).upload(for: call, from: body)
148
+ let status = (reply as? HTTPURLResponse)?.statusCode ?? 0
149
+ if status != 200 { throw URLError(.userAuthenticationRequired) }
150
+
151
+ let session = try JSONDecoder().decode(Session.self, from: bytes)
152
+ try TokenVault(service: "auth").store(Data(session.accessToken.utf8), account: "access")
201
153
  }
202
-
203
- var request = URLRequest(url: URL(string: "https://api.example.com/auth/apple")!)
204
- request.httpMethod = "POST"
205
- request.setValue("application/json", forHTTPHeaderField: "Content-Type")
206
- request.httpBody = try JSONEncoder().encode(
207
- ["identityToken": token, "authorizationCode": authCode]
208
- )
209
-
210
- let (data, response) = try await URLSession.shared.data(for: request)
211
- guard (response as? HTTPURLResponse)?.statusCode == 200 else {
212
- throw AuthError.serverValidationFailed
213
- }
214
- let session = try JSONDecoder().decode(SessionResponse.self, from: data)
215
- // Store session token in Keychain -- see references/keychain-biometric.md
216
- try KeychainHelper.save(session.accessToken, forKey: "accessToken")
217
154
  }
218
155
  ```
219
156
 
220
- Server-side, validate the JWT against Apple's public keys at
221
- `https://appleid.apple.com/auth/keys` (JWKS). Verify: `iss` is
222
- `https://appleid.apple.com`, `aud` matches your bundle ID, `exp` not passed.
157
+ `TokenVault` is in the [Keychain reference](references/keychain-biometric.md). The
158
+ server verifies the JWT signature against Apple's published key set (the JWKS
159
+ document served from `appleid.apple.com` under `/auth/keys`) and checks that `iss` is
160
+ `https://appleid.apple.com`, `aud` is your bundle ID, and `exp` is in the future.
223
161
 
224
- ## Existing Account Setup Flows
162
+ ### Existing accounts first
225
163
 
226
- On launch, silently check for existing Sign in with Apple and password
227
- credentials before showing a login screen:
164
+ Before showing a login screen, quietly ask the system whether the person
165
+ already has an Apple ID credential or a saved password for the app:
228
166
 
229
167
  ```swift
230
- func performExistingAccountSetupFlows() {
231
- let appleIDRequest = ASAuthorizationAppleIDProvider().createRequest()
232
- let passwordRequest = ASAuthorizationPasswordProvider().createRequest()
233
-
234
- let controller = ASAuthorizationController(
235
- authorizationRequests: [appleIDRequest, passwordRequest]
236
- )
237
- controller.delegate = self
238
- controller.presentationContextProvider = self
239
- controller.performRequests(
240
- options: .preferImmediatelyAvailableCredentials
241
- )
168
+ extension WelcomeViewController {
169
+ func offerSavedCredentials() {
170
+ let requests: [ASAuthorizationRequest] = [
171
+ ASAuthorizationAppleIDProvider().createRequest(),
172
+ ASAuthorizationPasswordProvider().createRequest(),
173
+ ]
174
+ let controller = ASAuthorizationController(authorizationRequests: requests)
175
+ controller.delegate = self
176
+ controller.presentationContextProvider = self
177
+ controller.performRequests(options: .preferImmediatelyAvailableCredentials)
178
+ }
242
179
  }
243
180
  ```
244
181
 
245
- Call this in `viewDidAppear` or on app launch. If no existing credentials
246
- are found, the delegate receives a `.notInteractive` error -- handle it
247
- silently and show your normal login UI.
248
-
249
- ## Passkeys
250
-
251
- Use passkeys for passwordless WebAuthn-style registration and sign-in. The
252
- app must have an Associated Domains entitlement for the relying party domain
253
- using the `webcredentials:` service; passkey requests fail for services the app
254
- has not configured as associated domains.
182
+ Run it from `viewDidAppear` or during launch. When nothing is stored, the
183
+ delegate receives `.notInteractive`; treat that silently and show the usual
184
+ login.
255
185
 
256
- For platform passkeys synced through iCloud Keychain, request a server-provided
257
- challenge and create requests with `ASAuthorizationPlatformPublicKeyCredentialProvider`:
186
+ ### SwiftUI button
258
187
 
259
188
  ```swift
260
- let challenge: Data = try await server.registrationChallenge()
261
- let userID: Data = try await server.passkeyUserID()
262
- let provider = ASAuthorizationPlatformPublicKeyCredentialProvider(
263
- relyingPartyIdentifier: "example.com"
264
- )
265
- let request = provider.createCredentialRegistrationRequest(
266
- challenge: challenge,
267
- name: username,
268
- userID: userID
269
- )
270
-
271
- let controller = ASAuthorizationController(authorizationRequests: [request])
272
- controller.delegate = self
273
- controller.presentationContextProvider = self
274
- controller.performRequests()
275
- ```
276
-
277
- For sign-in, use `createCredentialAssertionRequest(challenge:)` with a fresh
278
- server challenge, then send the resulting registration or assertion object to
279
- the relying-party server for verification:
280
-
281
- ```swift
282
- let request = provider.createCredentialAssertionRequest(challenge: challenge)
283
-
284
- switch authorization.credential {
285
- case let registration as ASAuthorizationPlatformPublicKeyCredentialRegistration:
286
- try await server.finishPasskeyRegistration(registration)
287
- case let assertion as ASAuthorizationPlatformPublicKeyCredentialAssertion:
288
- try await server.finishPasskeySignIn(assertion)
289
- default:
290
- break
189
+ import AuthenticationServices
190
+ import SwiftUI
191
+
192
+ struct AppleSignInRow: View {
193
+ let model: LoginModel
194
+
195
+ var body: some View {
196
+ SignInWithAppleButton(.continue) { request in
197
+ request.requestedScopes = [.fullName, .email]
198
+ } onCompletion: { outcome in
199
+ switch outcome {
200
+ case .success(let auth):
201
+ if let apple = auth.credential as? ASAuthorizationAppleIDCredential {
202
+ model.completeAppleSignIn(apple) // same server validation as UIKit
203
+ }
204
+ case .failure(let error):
205
+ model.report(error)
206
+ }
207
+ }
208
+ .signInWithAppleButtonStyle(.whiteOutline)
209
+ .frame(height: 48)
210
+ }
291
211
  }
292
212
  ```
293
213
 
294
- For inline passkey suggestions, set the username field's `textContentType` to
295
- `.username`, include the passkey assertion request in the controller, and call
296
- `performAutoFillAssistedRequests()`. Use `ASAuthorizationSecurityKeyPublicKeyCredentialProvider`
297
- only when the user must authenticate with a physical security key. See
298
- [references/passkeys.md](references/passkeys.md) for complete registration,
299
- assertion, AutoFill, and security-key patterns.
214
+ The button lives in AuthenticationServices but needs SwiftUI imported in the
215
+ same file.
300
216
 
301
- ## ASWebAuthenticationSession (OAuth)
217
+ ## Passkeys
302
218
 
303
- Use `ASWebAuthenticationSession` for OAuth and third-party authentication
304
- (Google, GitHub, etc.). Never use `WKWebView` for auth flows.
219
+ Passkeys replace passwords with WebAuthn credentials for both account creation and login. They need
220
+ the Associated Domains entitlement with a `webcredentials:` entry for the
221
+ relying-party domain; requests for a domain that is not associated fail.
222
+ Platform passkeys sync through iCloud Keychain.
305
223
 
306
- ```swift
307
- import AuthenticationServices
224
+ - Create `ASAuthorizationPlatformPublicKeyCredentialProvider(relyingPartyIdentifier:)`.
225
+ - Register with `createCredentialRegistrationRequest(challenge:name:userID:)` using a
226
+ challenge and user ID `Data` from the server.
227
+ - Sign in with `createCredentialAssertionRequest(challenge:)` and a fresh server challenge.
228
+ - Results arrive as `ASAuthorizationPlatformPublicKeyCredentialRegistration` or
229
+ `ASAuthorizationPlatformPublicKeyCredentialAssertion`; the relying-party server verifies them.
230
+ - For inline suggestions, mark the username field `.username`, include an
231
+ assertion request, and call `performAutoFillAssistedRequests()`.
232
+ - Reach for `ASAuthorizationSecurityKeyPublicKeyCredentialProvider` only when a
233
+ physical security key is required.
308
234
 
309
- final class OAuthController: NSObject, ASWebAuthenticationPresentationContextProviding {
310
- private weak var presentationAnchor: ASPresentationAnchor?
235
+ Details and code: [passkeys reference](references/passkeys.md).
311
236
 
312
- init(presentationAnchor: ASPresentationAnchor) {
313
- self.presentationAnchor = presentationAnchor
314
- }
237
+ ## OAuth with `ASWebAuthenticationSession`
238
+
239
+ Third-party logins (Google, GitHub and similar) go through
240
+ `ASWebAuthenticationSession`, never an embedded `WKWebView`.
315
241
 
316
- func startOAuthFlow() {
317
- let authURL = URL(string:
318
- "https://provider.com/oauth/authorize?client_id=YOUR_ID&redirect_uri=myapp://callback&response_type=code"
319
- )!
320
- let session = ASWebAuthenticationSession(
321
- url: authURL, callback: .customScheme("myapp")
322
- ) { callbackURL, error in
323
- guard let callbackURL, error == nil,
324
- let code = URLComponents(url: callbackURL, resolvingAgainstBaseURL: false)?
325
- .queryItems?.first(where: { $0.name == "code" })?.value else { return }
326
- Task { await self.exchangeCodeForTokens(code) }
242
+ ```swift
243
+ final class GitHubLogin: NSObject, ASWebAuthenticationPresentationContextProviding {
244
+ private var session: ASWebAuthenticationSession?
245
+
246
+ func start(authorizeURL: URL) {
247
+ let session = ASWebAuthenticationSession(url: authorizeURL,
248
+ callback: .customScheme("tasknest")) { url, error in
249
+ guard error == nil, let url,
250
+ let items = URLComponents(url: url, resolvingAgainstBaseURL: false)?.queryItems,
251
+ let code = items.first(where: { $0.name == "code" })?.value else { return }
252
+ Task { try await OAuthBackend.redeem(code: code) }
327
253
  }
328
254
  session.presentationContextProvider = self
329
- session.prefersEphemeralWebBrowserSession = true // No shared cookies
255
+ session.prefersEphemeralWebBrowserSession = true // no shared browser cookies
330
256
  session.start()
257
+ self.session = session
331
258
  }
332
259
 
333
- func presentationAnchor(for session: ASWebAuthenticationSession) -> ASPresentationAnchor {
334
- guard let presentationAnchor else {
335
- fatalError("ASWebAuthenticationSession needs the active window")
336
- }
337
- return presentationAnchor
260
+ func presentationAnchor(for webSession: ASWebAuthenticationSession) -> ASPresentationAnchor {
261
+ let scenes = UIApplication.shared.connectedScenes.compactMap { $0 as? UIWindowScene }
262
+ if let key = scenes.compactMap(\.keyWindow).first { return key }
263
+ guard let scene = scenes.first else { preconditionFailure("No window scene to present from") }
264
+ return ASPresentationAnchor(windowScene: scene)
338
265
  }
339
266
  }
340
267
  ```
341
268
 
342
- In SwiftUI, use `@Environment(\.webAuthenticationSession)` and call
269
+ In SwiftUI, read `@Environment(\.webAuthenticationSession)` and call
343
270
  `authenticate(using:callback:preferredBrowserSession:additionalHeaderFields:)`
344
- with `.customScheme("myapp")` or `.https(host:path:)`; prefer `.ephemeral`
345
- only when the provider flow should avoid shared browser cookies.
271
+ with `.customScheme(...)` or `.https(host:path:)`. Ask for the `.ephemeral`
272
+ browser session only when the provider's flow should not share cookies.
346
273
 
347
- ## Password AutoFill Credentials
274
+ ## Password AutoFill
348
275
 
349
- Use `ASAuthorizationPasswordProvider` to offer saved keychain credentials
350
- alongside Sign in with Apple:
276
+ `ASAuthorizationPasswordProvider` puts saved Keychain passwords in the same
277
+ controller as Sign in with Apple. The delegate then branches on the credential:
351
278
 
352
279
  ```swift
353
- func performSignIn() {
354
- let appleIDRequest = ASAuthorizationAppleIDProvider().createRequest()
355
- appleIDRequest.requestedScopes = [.fullName, .email]
356
-
357
- let passwordRequest = ASAuthorizationPasswordProvider().createRequest()
358
-
359
- let controller = ASAuthorizationController(
360
- authorizationRequests: [appleIDRequest, passwordRequest]
361
- )
362
- controller.delegate = self
363
- controller.presentationContextProvider = self
364
- controller.performRequests()
365
- }
366
-
367
- // In delegate:
368
- func authorizationController(
369
- controller: ASAuthorizationController,
370
- didCompleteWithAuthorization authorization: ASAuthorization
371
- ) {
372
- switch authorization.credential {
373
- case let appleIDCredential as ASAuthorizationAppleIDCredential:
374
- handleAppleIDLogin(appleIDCredential)
375
- case let passwordCredential as ASPasswordCredential:
376
- // User selected a saved password from keychain
377
- signInWithPassword(
378
- username: passwordCredential.user,
379
- password: passwordCredential.password
380
- )
381
- default:
382
- break
383
- }
280
+ switch authorization.credential {
281
+ case let apple as ASAuthorizationAppleIDCredential:
282
+ finishApple(apple)
283
+ case let saved as ASPasswordCredential:
284
+ signIn(username: saved.user, password: saved.password)
285
+ default:
286
+ break
384
287
  }
385
288
  ```
386
289
 
387
- Set `textContentType` on text fields for AutoFill to work:
388
-
389
- ```swift
390
- usernameField.textContentType = .username
391
- passwordField.textContentType = .password
392
- ```
290
+ AutoFill only lights up when the text fields declare `textContentType`
291
+ `.username` and `.password`.
393
292
 
394
- ## Biometric Authentication
293
+ ## Biometric re-authentication
395
294
 
396
- Use `LAContext` from LocalAuthentication for local re-authentication before
397
- showing account settings or starting sensitive actions. Do not treat a returned
398
- `Bool` as proof to unlock a stored secret; protect secrets with Keychain access
399
- control instead. See [references/keychain-biometric.md](references/keychain-biometric.md)
400
- for `SecAccessControl` and `.biometryCurrentSet` patterns.
295
+ Use `LAContext` to confirm the device owner before opening account settings or
296
+ a sensitive action. The `Bool` it returns is a UI gate, not permission to read
297
+ a secret. Put Keychain access control on anything valuable (see
298
+ [Keychain and biometrics](references/keychain-biometric.md)).
401
299
 
402
300
  ```swift
403
301
  import LocalAuthentication
404
302
 
405
- func authenticateWithBiometrics() async throws -> Bool {
303
+ func confirmOwner() async -> Bool {
406
304
  let context = LAContext()
407
- var error: NSError?
408
-
409
- guard context.canEvaluatePolicy(
410
- .deviceOwnerAuthenticationWithBiometrics, error: &error
411
- ) else {
412
- throw AuthError.biometricsUnavailable
305
+ var problem: NSError?
306
+ guard context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &problem) else {
307
+ return false
413
308
  }
414
-
415
- return try await context.evaluatePolicy(
416
- .deviceOwnerAuthenticationWithBiometrics,
417
- localizedReason: "Sign in to your account"
418
- )
309
+ let reason = "Confirm it's you to change your email"
310
+ let passed = try? await context.evaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, localizedReason: reason)
311
+ return passed == true
419
312
  }
420
313
  ```
421
314
 
422
- **Required:** Add `NSFaceIDUsageDescription` to Info.plist. Missing this
423
- key crashes on Face ID devices.
424
-
425
- ## Security Boundaries
426
-
427
- This skill owns user-facing account authentication: Sign in with Apple,
428
- passkeys, Password AutoFill, ASAuthorizationController, OAuth session
429
- presentation, credential state, and local biometric re-authentication. Route
430
- deep security work to `swift-security`: Keychain architecture/migration,
431
- CryptoKit, Secure Enclave, certificate pinning/trust, keychain sharing, storage
432
- hardening, and OWASP MASVS/MASTG. Keep only the storage minimum here: tokens and
433
- secrets belong in Keychain; `LAContext.evaluatePolicy` alone must not release
434
- protected secrets.
435
-
436
- ## SwiftUI SignInWithAppleButton
437
-
438
- Use `SignInWithAppleButton` in SwiftUI views when the login surface is SwiftUI.
439
- Request `.fullName` and `.email`, handle `.success` and `.failure`, downcast to
440
- `ASAuthorizationAppleIDCredential`, and send the credential through the same
441
- server-validation flow as UIKit. Style with `.signInWithAppleButtonStyle(...)`.
442
-
443
- ## Common Mistakes
444
-
445
- - Assuming a saved local session means the Apple ID credential is still valid.
446
- Check credential state at launch and handle revocation notifications.
447
- - Showing a full login screen before trying existing account setup flows.
448
- Treat `.notInteractive` as the normal "no local credential" path.
449
- - Force-unwrapping `email` or `fullName`. Cache them on first authorization and
450
- handle `nil` later.
451
- - Creating an `ASAuthorizationController` without a presentation context
452
- provider. Authorization UI needs the active presentation anchor.
453
- - Storing identity tokens, authorization codes, access tokens, passwords, or
454
- passkey server state in `UserDefaults`, files, or Core Data. Store secrets in
455
- Keychain and keep relying-party passkey verification server-side.
456
- - Adding passkey requests without `webcredentials:` Associated Domains for the
457
- relying-party domain, or trying to use app-native passkeys for unrelated
458
- websites.
459
- - Expanding authentication work into CryptoKit, Secure Enclave, certificate
460
- pinning, or OWASP MASVS. Route those to `swift-security`.
461
-
462
- ## Review Checklist
463
-
464
- - [ ] "Sign in with Apple" capability added in Xcode project
315
+ Info.plist must include `NSFaceIDUsageDescription`; without it the app crashes
316
+ on Face ID hardware.
317
+
318
+ ## Security boundaries
319
+
320
+ This skill covers: Apple ID sign-in, passkeys, AutoFill of saved passwords, the
321
+ `ASAuthorizationController` flow, presenting OAuth web sessions, checking
322
+ credential state, and biometric re-authentication on the device.
323
+
324
+ The minimum storage rule stays here too: tokens and secrets live in the
325
+ Keychain, and `LAContext.evaluatePolicy` on its own must never unlock a
326
+ protected secret.
327
+
328
+ Hand off to `swift-security`: Keychain architecture and migration,
329
+ access-control policy design, CryptoKit, Secure Enclave, certificate pinning
330
+ and trust evaluation, sharing items between apps, hardening local storage, and
331
+ mapping against OWASP MASVS/MASTG. App and device attestation belongs to `device-integrity`.
332
+
333
+ ## Common mistakes
334
+
335
+ - Assuming a cached session means Apple has not revoked the link. Check state at launch and react to the revocation notification.
336
+ - Jumping straight to the login form without first asking for saved credentials;
337
+ `.notInteractive` is simply the "nothing saved" answer.
338
+ - Force-unwrapping `email` or `fullName`.
339
+ - Building an `ASAuthorizationController` with no presentation context provider.
340
+ - Writing JWTs from Apple, one-time codes, session tokens, passwords or
341
+ passkey server records into `UserDefaults`, plain files or Core Data. Use the
342
+ Keychain, and keep passkey verification on the server.
343
+ - Passkey requests without a `webcredentials:` Associated Domains entry, or
344
+ using app passkeys for an unrelated website.
345
+ - Drifting into CryptoKit, Secure Enclave, pinning or MASVS work instead of
346
+ routing it to `swift-security`.
347
+
348
+ ## Review checklist
349
+
350
+ - [ ] Sign in with Apple capability enabled
465
351
  - [ ] `ASAuthorizationControllerPresentationContextProviding` implemented
466
- - [ ] Credential state checked on every app launch (`getCredentialState(forUserID:completion:)`)
467
- - [ ] `credentialRevokedNotification` observer registered; sign-out handled
468
- - [ ] `email` and `fullName` cached on first authorization (not assumed available later)
469
- - [ ] `identityToken` sent to server for validation, not trusted client-side only
470
- - [ ] Tokens stored in Keychain, not UserDefaults or files
471
- - [ ] `performExistingAccountSetupFlows` called before showing login UI
472
- - [ ] Error cases handled: `.canceled`, `.failed`, `.notInteractive`
473
- - [ ] `NSFaceIDUsageDescription` in Info.plist for biometric auth
474
- - [ ] `ASWebAuthenticationSession` used for OAuth (not `WKWebView`)
475
- - [ ] `prefersEphemeralWebBrowserSession` set for OAuth when appropriate
476
- - [ ] `textContentType` set on username/password fields for AutoFill
477
- - [ ] Passkey relying party has `webcredentials:` Associated Domains configured
478
- - [ ] Passkey registration/assertion challenges come from the server and are verified server-side
479
- - [ ] Deep Keychain, CryptoKit, Secure Enclave, certificate pinning, and MASVS work routed to `swift-security`
352
+ - [ ] `getCredentialState(forUserID:completion:)` runs on every launch
353
+ - [ ] `credentialRevokedNotification` observed and signs the user out
354
+ - [ ] `email` and `fullName` saved on first authorization
355
+ - [ ] `identityToken` validated by the server
356
+ - [ ] Tokens kept in the Keychain
357
+ - [ ] Existing-account flows run before the login UI
358
+ - [ ] `.canceled`, `.failed` and `.notInteractive` handled
359
+ - [ ] `NSFaceIDUsageDescription` present
360
+ - [ ] OAuth uses `ASWebAuthenticationSession`, not `WKWebView`
361
+ - [ ] `prefersEphemeralWebBrowserSession` set where cookie isolation matters
362
+ - [ ] `textContentType` set on username and password fields
363
+ - [ ] Passkey relying party listed under `webcredentials:` Associated Domains
364
+ - [ ] Passkey challenges issued and verified by the server
365
+ - [ ] Deep Keychain, CryptoKit, Secure Enclave, pinning and MASVS questions routed to `swift-security`
480
366
 
481
367
  ## References
482
368
 
483
- - Keychain & biometric patterns: [references/keychain-biometric.md](references/keychain-biometric.md)
484
- - Passkey patterns: [references/passkeys.md](references/passkeys.md)
485
- - [AuthenticationServices](https://sosumi.ai/documentation/authenticationservices)
486
- - [ASAuthorizationAppleIDProvider](https://sosumi.ai/documentation/authenticationservices/asauthorizationappleidprovider)
487
- - [ASAuthorizationAppleIDCredential](https://sosumi.ai/documentation/authenticationservices/asauthorizationappleidcredential)
488
- - [ASAuthorizationController](https://sosumi.ai/documentation/authenticationservices/asauthorizationcontroller)
489
- - [ASWebAuthenticationSession](https://sosumi.ai/documentation/authenticationservices/aswebauthenticationsession)
490
- - [Supporting passkeys](https://sosumi.ai/documentation/authenticationservices/supporting-passkeys)
491
- - [ASAuthorizationPlatformPublicKeyCredentialProvider](https://sosumi.ai/documentation/authenticationservices/asauthorizationplatformpublickeycredentialprovider)
492
- - [ASAuthorizationPasswordProvider](https://sosumi.ai/documentation/authenticationservices/asauthorizationpasswordprovider)
493
- - [SignInWithAppleButton](https://sosumi.ai/documentation/authenticationservices/signinwithapplebutton)
494
- - [Implementing User Authentication with Sign in with Apple](https://sosumi.ai/documentation/authenticationservices/implementing-user-authentication-with-sign-in-with-apple)
369
+ - [AuthenticationServices](https://developer.apple.com/documentation/authenticationservices)
370
+ - [ASAuthorizationAppleIDProvider](https://developer.apple.com/documentation/authenticationservices/asauthorizationappleidprovider)
371
+ - [ASAuthorizationAppleIDCredential](https://developer.apple.com/documentation/authenticationservices/asauthorizationappleidcredential)
372
+ - [ASAuthorizationController](https://developer.apple.com/documentation/authenticationservices/asauthorizationcontroller)
373
+ - [ASWebAuthenticationSession](https://developer.apple.com/documentation/authenticationservices/aswebauthenticationsession)
374
+ - [Supporting passkeys](https://developer.apple.com/documentation/authenticationservices/supporting-passkeys)
375
+ - [ASAuthorizationPlatformPublicKeyCredentialProvider](https://developer.apple.com/documentation/authenticationservices/asauthorizationplatformpublickeycredentialprovider)
376
+ - [ASAuthorizationPasswordProvider](https://developer.apple.com/documentation/authenticationservices/asauthorizationpasswordprovider)
377
+ - [SignInWithAppleButton](https://developer.apple.com/documentation/authenticationservices/signinwithapplebutton)
378
+ - Sample code: the AuthenticationServices sample on implementing user authentication with Apple ID sign-in