@mmerterden/multi-agent-pipeline 20.6.0 → 20.8.0

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