@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,486 +1,412 @@
1
1
  ---
2
2
  name: core-nfc
3
- description: "Read and write NFC tags using CoreNFC. Use when scanning NDEF tags, reading ISO7816/ISO15693/FeliCa/MIFARE tags, writing NDEF messages, handling NFC session lifecycle, configuring NFC entitlements, or implementing background tag reading in iOS apps."
3
+ description: "Core NFC on iPhone: reading and writing NDEF tags, ISO7816, ISO15693, FeliCa and MIFARE access, reader session lifecycle, NFC entitlement and Info.plist setup, background tag reading. Use when adding or reviewing NFC tag scanning or writing."
4
4
  metadata:
5
- source: "dpearson2699/swift-ios-skills (PolyForm Perimeter 1.0.0)"
5
+ source: multi-agent-pipeline
6
6
  ---
7
7
 
8
- # CoreNFC
9
-
10
- Read and write NFC tags on iPhone using the CoreNFC framework. Covers NDEF
11
- reader sessions, tag reader sessions, NDEF message construction, entitlements,
12
- and background tag reading. Targets Swift 6.3 / iOS 26+.
13
-
14
- ## Contents
15
-
16
- - [Setup](#setup)
17
- - [NDEF Reader Session](#ndef-reader-session)
18
- - [Tag Reader Session](#tag-reader-session)
19
- - [Writing NDEF Messages](#writing-ndef-messages)
20
- - [NDEF Payload Types](#ndef-payload-types)
21
- - [Background Tag Reading](#background-tag-reading)
22
- - [Common Mistakes](#common-mistakes)
23
- - [Review Checklist](#review-checklist)
24
- - [References](#references)
25
-
26
- ## Setup
27
-
28
- ### Project Configuration
29
-
30
- 1. Add the **Near Field Communication Tag Reading** capability in Xcode
31
- 2. Add `NFCReaderUsageDescription` to Info.plist with a user-facing reason string
32
- 3. Add the `com.apple.developer.nfc.readersession.formats` entitlement with the current `TAG` value; do not add legacy `NDEF`
33
- 4. For ISO 7816 tags, add supported application identifiers to `com.apple.developer.nfc.readersession.iso7816.select-identifiers` in Info.plist
34
- 5. For FeliCa tags, add supported system codes to `com.apple.developer.nfc.readersession.felica.systemcodes`; do not use wildcard system codes
35
-
36
- ### Device Requirements
8
+ # Core NFC
9
+
10
+ Core NFC lets an iPhone app read tags, write NDEF data and talk to a tag in its
11
+ own protocol. Everything happens inside a short-lived reader session that the
12
+ system presents as a scan sheet. Code here assumes Swift 6.3 with an iOS 26
13
+ deployment target, and only iPhone hardware reads tags.
14
+
15
+ ## Project setup
16
+
17
+ 1. In Signing & Capabilities, add **Near Field Communication Tag Reading**.
18
+ 2. Put a sentence the user will read into `NFCReaderUsageDescription` in Info.plist.
19
+ An empty value is a review problem.
20
+ 3. The capability writes the reader-session formats entitlement
21
+ (`...nfc.readersession.formats`) with the value `TAG`. Older samples add
22
+ `NDEF` as well; leave that out.
23
+ 4. For ISO 7816 cards, list every application identifier the app will select
24
+ in the Info.plist select-identifiers array (shown below).
25
+ 5. For FeliCa, list each system code in the Info.plist systemcodes array.
26
+ Wildcard codes are not accepted.
27
+
28
+ ```xml
29
+ <key>NFCReaderUsageDescription</key>
30
+ <string>Scanning lets you check in to the gym by tapping your member card.</string>
31
+ <key>com.apple.developer.nfc.readersession.iso7816.select-identifiers</key>
32
+ <array>
33
+ <string>F0010203040506</string>
34
+ </array>
35
+ <key>com.apple.developer.nfc.readersession.felica.systemcodes</key>
36
+ <array>
37
+ <string>12FC</string>
38
+ </array>
39
+ ```
37
40
 
38
- NFC reading requires iPhone 7 or later. Always check for reader session
39
- availability before creating NFC UI or sessions. Use the concrete reader
40
- session type you are about to create.
41
+ ### Hardware and availability
41
42
 
42
- ```swift
43
- import CoreNFC
43
+ Tag reading needs an iPhone 7 or newer. Before showing any NFC button or
44
+ creating a session, ask the session class you intend to use, for example
45
+ `NFCNDEFReaderSession.readingAvailable` or `NFCTagReaderSession.readingAvailable`.
46
+ `false` means the device lacks the hardware or NFC is restricted, so hide or
47
+ disable the feature instead of starting a session that will fail.
44
48
 
45
- guard NFCNDEFReaderSession.readingAvailable else {
46
- // Device does not support NFC or feature is restricted
47
- showUnsupportedMessage()
48
- return
49
- }
50
- ```
51
-
52
- ### Key Types
49
+ ### Types you will meet
53
50
 
54
51
  | Type | Role |
55
- |---|---|
56
- | `NFCNDEFReaderSession` | Scans for NDEF-formatted tags |
57
- | `NFCTagReaderSession` | Scans for ISO7816, ISO15693, FeliCa, MIFARE tags |
58
- | `NFCNDEFMessage` | Collection of NDEF payload records |
59
- | `NFCNDEFPayload` | Single record within an NDEF message |
60
- | `NFCNDEFTag` | Protocol for interacting with an NDEF-capable tag |
52
+ |------|------|
53
+ | `NFCNDEFReaderSession` | Session that scans NDEF-formatted tags |
54
+ | `NFCTagReaderSession` | Session with native access to ISO7816, ISO15693, FeliCa and MIFARE tags |
55
+ | `NFCNDEFMessage` | An NDEF message: an ordered list of records |
56
+ | `NFCNDEFPayload` | A single NDEF record |
57
+ | `NFCNDEFTag` | Protocol adopted by tags that can hold NDEF data |
61
58
 
62
- ## NDEF Reader Session
59
+ ## Reading NDEF data
63
60
 
64
- Use `NFCNDEFReaderSession` to read NDEF-formatted data from tags. This is the
65
- simplest path for reading standard tag content like URLs, text, and MIME data.
61
+ The NDEF session is the shortest path when all you need is a URL, some text or
62
+ a MIME blob.
66
63
 
67
64
  ```swift
68
65
  import CoreNFC
69
66
 
70
- final class NDEFReader: NSObject, NFCNDEFReaderSessionDelegate {
67
+ final class BadgeReader: NSObject, NFCNDEFReaderSessionDelegate {
71
68
  private var session: NFCNDEFReaderSession?
72
69
 
73
- func beginScanning() {
70
+ func scan() {
74
71
  guard NFCNDEFReaderSession.readingAvailable else { return }
75
-
76
72
  session = NFCNDEFReaderSession(
77
73
  delegate: self,
78
74
  queue: nil,
79
75
  invalidateAfterFirstRead: false
80
76
  )
81
- session?.alertMessage = "Hold your iPhone near an NFC tag."
77
+ session?.alertMessage = "Hold the top of your iPhone near the badge."
82
78
  session?.begin()
83
79
  }
84
80
 
85
- // MARK: - NFCNDEFReaderSessionDelegate
81
+ func readerSessionDidBecomeActive(_ session: NFCNDEFReaderSession) {}
86
82
 
87
- func readerSessionDidBecomeActive(_ session: NFCNDEFReaderSession) {
88
- // Session is scanning
89
- }
90
-
91
- func readerSession(
92
- _ session: NFCNDEFReaderSession,
93
- didDetectNDEFs messages: [NFCNDEFMessage]
94
- ) {
95
- for message in messages {
83
+ func readerSession(_ reader: NFCNDEFReaderSession, didDetectNDEFs found: [NFCNDEFMessage]) {
84
+ for message in found {
96
85
  for record in message.records {
97
- processRecord(record)
86
+ handle(record)
98
87
  }
99
88
  }
100
89
  }
101
90
 
102
- func readerSession(
103
- _ session: NFCNDEFReaderSession,
104
- didInvalidateWithError error: Error
105
- ) {
106
- let nfcError = error as? NFCReaderError
107
- if nfcError?.code != .readerSessionInvalidationErrorFirstNDEFTagRead,
108
- nfcError?.code != .readerSessionInvalidationErrorUserCanceled {
109
- print("Session invalidated: \(error.localizedDescription)")
91
+ func readerSession(_ reader: NFCNDEFReaderSession, didInvalidateWithError error: any Error) {
92
+ if let nfcError = error as? NFCReaderError,
93
+ nfcError.code == .readerSessionInvalidationErrorFirstNDEFTagRead
94
+ || nfcError.code == .readerSessionInvalidationErrorUserCanceled {
95
+ // Normal end of a scan, not a failure.
96
+ } else {
97
+ report(error)
110
98
  }
111
99
  self.session = nil
112
100
  }
101
+
102
+ private func handle(_ record: NFCNDEFPayload) {}
103
+ private func report(_ error: Error) {}
113
104
  }
114
105
  ```
115
106
 
116
- ### Reading with Tag Connection
107
+ The first-read and user-cancel codes are ordinary endings. Only other codes
108
+ deserve an alert, and the session reference is cleared in every case.
109
+
110
+ ### Connecting to the tag
117
111
 
118
- For read-write operations, use the tag-detection delegate method to connect
119
- to individual tags:
112
+ To read and then write, or to inspect capacity, implement
113
+ `readerSession(_:didDetect:)` with `[any NFCNDEFTag]`. When that method exists,
114
+ the system calls it instead of `didDetectNDEFs`.
120
115
 
121
116
  ```swift
122
- func readerSession(
123
- _ session: NFCNDEFReaderSession,
124
- didDetect tags: [any NFCNDEFTag]
125
- ) {
126
- guard let tag = tags.first else {
127
- session.restartPolling()
117
+ func readerSession(_ reader: NFCNDEFReaderSession, didDetect found: [any NFCNDEFTag]) {
118
+ if found.count > 1 {
119
+ retryAfterMultipleTags(reader)
128
120
  return
129
121
  }
130
-
131
- session.connect(to: tag) { error in
132
- if let error {
133
- session.invalidate(errorMessage: "Connection failed: \(error)")
134
- return
135
- }
136
-
137
- tag.queryNDEFStatus { status, capacity, error in
138
- guard error == nil else {
139
- session.invalidate(errorMessage: "Query failed.")
140
- return
141
- }
142
-
122
+ guard let first = found.first else {
123
+ reader.restartPolling()
124
+ return
125
+ }
126
+ nonisolated(unsafe) let reader = reader
127
+ nonisolated(unsafe) let tag = first
128
+ Task {
129
+ do {
130
+ try await reader.connect(to: tag)
131
+ let (status, _) = try await tag.queryNDEFStatus()
143
132
  switch status {
144
133
  case .notSupported:
145
- session.invalidate(errorMessage: "Tag is not NDEF compliant.")
146
- case .readOnly:
147
- tag.readNDEF { message, error in
148
- if let message {
149
- self.processMessage(message)
150
- }
151
- session.invalidate()
152
- }
153
- case .readWrite:
154
- tag.readNDEF { message, error in
155
- if let message {
156
- self.processMessage(message)
157
- }
158
- session.alertMessage = "Tag read successfully."
159
- session.invalidate()
160
- }
134
+ reader.invalidate(errorMessage: "No NDEF support on this tag.")
135
+ case .readOnly, .readWrite:
136
+ let badge = try await tag.readNDEF()
137
+ reader.alertMessage = "Badge read: \(badge.records.count) records."
138
+ reader.invalidate()
161
139
  @unknown default:
162
- session.invalidate()
140
+ reader.invalidate(errorMessage: "Unexpected tag status.")
163
141
  }
142
+ } catch {
143
+ reader.invalidate(errorMessage: "Could not read the tag: \(error.localizedDescription)")
164
144
  }
165
145
  }
166
146
  }
167
147
  ```
168
148
 
169
- ## Tag Reader Session
149
+ Every tag call also has a completion-handler form. Those handlers are
150
+ `@Sendable`, while sessions and tags are not `Sendable`, so capturing them there
151
+ draws Swift 6 warnings. The `async` forms, awaited inside one `Task`, keep the
152
+ steps in reading order, but the `Task` closure still captures the session and
153
+ the tag. Swift 6 rejects that in its region-isolation pass ("passing closure as
154
+ a 'sending' parameter risks causing data races"), so the callback hands them
155
+ over as `nonisolated(unsafe)` copies. After starting the task the callback
156
+ touches neither, which leaves the task as their only user.
157
+
158
+ An empty array means nothing usable was found yet: `restartPolling()` keeps
159
+ the sheet open and waits for the next tap.
160
+
161
+ ### More than one tag in the field
162
+
163
+ Both session types can report several tags at once. Talking to one of them
164
+ while another is in range is unreliable, so do not pick one at random. Tell the
165
+ user to take the extra tags away, pause briefly so they can do it, then resume
166
+ polling on the same session:
167
+
168
+ ```swift
169
+ func retryAfterMultipleTags(_ session: NFCNDEFReaderSession) {
170
+ session.alertMessage = "More than one tag found. Remove the extras and try again."
171
+ nonisolated(unsafe) let session = session
172
+ Task {
173
+ try? await Task.sleep(for: .milliseconds(500))
174
+ session.restartPolling()
175
+ }
176
+ }
177
+
178
+ func retryAfterMultipleTags(_ session: NFCTagReaderSession) {
179
+ session.alertMessage = "More than one tag found. Remove the extras and try again."
180
+ nonisolated(unsafe) let session = session
181
+ Task {
182
+ try? await Task.sleep(for: .milliseconds(500))
183
+ session.restartPolling()
184
+ }
185
+ }
186
+ ```
187
+
188
+ `restartPolling()` is declared separately on each session class rather than on
189
+ the shared base, hence the two overloads. A zero-length array gets the plain
190
+ `restartPolling()` call without the message.
191
+
192
+ ## Native tag access
193
+
194
+ `NFCTagReaderSession` exposes each tag family in its own protocol: ISO 7816,
195
+ ISO 15693, FeliCa and MIFARE. Pick polling options to match the tags you expect:
170
196
 
171
- Use `NFCTagReaderSession` when you need direct access to the native tag
172
- protocol (ISO 7816, ISO 15693, FeliCa, or MIFARE).
197
+ | Polling option | Finds |
198
+ |----------------|-------|
199
+ | `.iso14443` | ISO 7816 compatible cards and MIFARE |
200
+ | `.iso15693` | ISO 15693 vicinity tags |
201
+ | `.iso18092` | FeliCa |
173
202
 
174
- Polling options are protocol-specific: `.iso14443` detects ISO
175
- 7816-compatible and MIFARE tags, `.iso15693` detects ISO 15693 tags, and
176
- `.iso18092` detects FeliCa tags. Do not use `NFCTagReaderSession` for
177
- payment-related AIDs; Apple documents `NFCPaymentTagReaderSession` for
178
- eligible EU payment use cases.
203
+ Payment application identifiers are off limits for this session. For eligible
204
+ payment use cases in the EU, Apple documents a separate
205
+ `NFCPaymentTagReaderSession`.
179
206
 
180
207
  ```swift
181
- final class TagReader: NSObject, NFCTagReaderSessionDelegate {
208
+ final class CardReader: NSObject, NFCTagReaderSessionDelegate {
182
209
  private var session: NFCTagReaderSession?
183
210
 
184
- func beginScanning() {
211
+ func scan() {
185
212
  guard NFCTagReaderSession.readingAvailable else { return }
186
-
187
- session = NFCTagReaderSession(
188
- pollingOption: [.iso14443, .iso15693, .iso18092],
189
- delegate: self,
190
- queue: nil
191
- )
192
- session?.alertMessage = "Hold your iPhone near a tag."
213
+ session = NFCTagReaderSession(pollingOption: [.iso14443, .iso15693], delegate: self, queue: nil)
214
+ session?.alertMessage = "Hold your transit card near the phone."
193
215
  session?.begin()
194
216
  }
195
217
 
196
- func tagReaderSessionDidBecomeActive(
197
- _ session: NFCTagReaderSession
198
- ) { }
199
-
200
- func tagReaderSession(
201
- _ session: NFCTagReaderSession,
202
- didDetect tags: [NFCTag]
203
- ) {
204
- guard let tag = tags.first else { return }
205
-
206
- session.connect(to: tag) { error in
207
- guard error == nil else {
208
- session.invalidate(
209
- errorMessage: "Connection failed."
210
- )
218
+ func tagReaderSessionDidBecomeActive(_ session: NFCTagReaderSession) {}
219
+
220
+ func tagReaderSession(_ reader: NFCTagReaderSession, didDetect found: [NFCTag]) {
221
+ if found.count > 1 {
222
+ retryAfterMultipleTags(reader)
223
+ return
224
+ }
225
+ guard !found.isEmpty else {
226
+ reader.restartPolling()
227
+ return
228
+ }
229
+ nonisolated(unsafe) let reader = reader
230
+ nonisolated(unsafe) let tags = found
231
+ Task {
232
+ let tag = tags[0]
233
+ do {
234
+ try await reader.connect(to: tag)
235
+ } catch {
236
+ reader.invalidate(errorMessage: error.localizedDescription)
211
237
  return
212
238
  }
213
-
214
239
  switch tag {
215
- case .iso7816(let iso7816Tag):
216
- self.readISO7816(tag: iso7816Tag, session: session)
217
- case .miFare(let miFareTag):
218
- self.readMiFare(tag: miFareTag, session: session)
219
- case .iso15693(let iso15693Tag):
220
- self.readISO15693(tag: iso15693Tag, session: session)
221
- case .feliCa(let feliCaTag):
222
- self.readFeliCa(tag: feliCaTag, session: session)
223
- @unknown default:
224
- session.invalidate(errorMessage: "Unsupported tag type.")
240
+ case .iso7816(let card): await select(card, in: reader)
241
+ case .miFare(let chip): await inspect(chip, in: reader)
242
+ case .iso15693(let label): await readBlocks(label, in: reader)
243
+ case .feliCa(let card): await readSystemCodes(card, in: reader)
244
+ @unknown default: reader.invalidate(errorMessage: "This tag type is not handled.")
225
245
  }
226
246
  }
227
247
  }
228
248
 
229
- func tagReaderSession(
230
- _ session: NFCTagReaderSession,
231
- didInvalidateWithError error: Error
232
- ) {
233
- self.session = nil
249
+ func tagReaderSession(_ reader: NFCTagReaderSession, didInvalidateWithError error: any Error) {
250
+ session = nil
234
251
  }
235
252
  }
236
253
  ```
237
254
 
238
- ## Writing NDEF Messages
255
+ The task receives the whole `tags` array rather than a single `NFCTag`: with
256
+ the enum value itself as the `nonisolated(unsafe)` copy, Swift 6.3 still
257
+ rejects the capture. Always connect before sending any command. The `select`, `inspect`,
258
+ `readBlocks` and `readSystemCodes` helpers stand for per-family code (APDUs,
259
+ block reads, MIFARE and FeliCa calls), which is written out in the
260
+ [patterns reference](references/nfc-patterns.md).
239
261
 
240
- Write NDEF data to a connected tag. Always check `readWrite` status first.
262
+ ## Writing NDEF
263
+
264
+ Query the status first. Only `.readWrite` tags accept a write; anything else
265
+ ends the session with a clear message.
241
266
 
242
267
  ```swift
243
- func writeToTag(
244
- tag: any NFCNDEFTag,
245
- session: NFCNDEFReaderSession,
246
- url: URL
247
- ) {
248
- tag.queryNDEFStatus { status, capacity, error in
268
+ func store(_ link: URL, on tag: any NFCNDEFTag, session: NFCNDEFReaderSession) async {
269
+ do {
270
+ let (status, _) = try await tag.queryNDEFStatus()
249
271
  guard status == .readWrite else {
250
- session.invalidate(errorMessage: "Tag is read-only.")
272
+ session.invalidate(errorMessage: "This tag is read-only.")
251
273
  return
252
274
  }
253
-
254
- guard let payload = NFCNDEFPayload.wellKnownTypeURIPayload(
255
- url: url
256
- ) else {
257
- session.invalidate(errorMessage: "Invalid URL.")
275
+ guard let record = NFCNDEFPayload.wellKnownTypeURIPayload(url: link) else {
276
+ session.invalidate(errorMessage: "Could not encode the link.")
258
277
  return
259
278
  }
260
-
261
- let message = NFCNDEFMessage(records: [payload])
262
-
263
- tag.writeNDEF(message) { error in
264
- if let error {
265
- session.invalidate(
266
- errorMessage: "Write failed: \(error.localizedDescription)"
267
- )
268
- } else {
269
- session.alertMessage = "Tag written successfully."
270
- session.invalidate()
271
- }
272
- }
279
+ try await tag.writeNDEF(NFCNDEFMessage(records: [record]))
280
+ session.alertMessage = "Tag updated."
281
+ session.invalidate()
282
+ } catch {
283
+ session.invalidate(errorMessage: "Could not write: \(error.localizedDescription)")
273
284
  }
274
285
  }
275
286
  ```
276
287
 
277
- ## NDEF Payload Types
278
-
279
- ### Creating Common Payloads
288
+ Check capacity against the message size before large writes; see the reference
289
+ file for the comparison and for permanent locking.
280
290
 
281
- ```swift
282
- // URL payload
283
- let urlPayload = NFCNDEFPayload.wellKnownTypeURIPayload(
284
- url: URL(string: "https://example.com")!
285
- )
291
+ ## Building and parsing payloads
286
292
 
287
- // Text payload
288
- let textPayload = NFCNDEFPayload.wellKnownTypeTextPayload(
289
- string: "Hello NFC",
290
- locale: Locale(identifier: "en")
291
- )
293
+ | Record | Factory |
294
+ |--------|---------|
295
+ | URI | `NFCNDEFPayload.wellKnownTypeURIPayload(url:)` (optional result) |
296
+ | Text | `NFCNDEFPayload.wellKnownTypeTextPayload(string:locale:)` |
297
+ | App data | `NFCNDEFPayload(format: .nfcExternal, type:identifier:payload:)` with a `domain:type` type string |
292
298
 
293
- // Custom payload
294
- let customPayload = NFCNDEFPayload(
299
+ ```swift
300
+ let config = NFCNDEFPayload(
295
301
  format: .nfcExternal,
296
- type: "com.example:mytype".data(using: .utf8)!,
302
+ type: Data("example.com:shelf".utf8),
297
303
  identifier: Data(),
298
- payload: "custom-data".data(using: .utf8)!
304
+ payload: Data(#"{"aisle":7}"#.utf8)
299
305
  )
300
306
  ```
301
307
 
302
- ### Parsing Payload Content
308
+ When reading, branch on `typeNameFormat`:
303
309
 
304
310
  ```swift
305
- func processRecord(_ record: NFCNDEFPayload) {
311
+ func describe(_ record: NFCNDEFPayload) -> String? {
306
312
  switch record.typeNameFormat {
307
313
  case .nfcWellKnown:
308
- if let url = record.wellKnownTypeURIPayload() {
309
- print("URL: \(url)")
310
- } else if let (text, locale) = record.wellKnownTypeTextPayload() {
311
- print("Text (\(locale)): \(text)")
312
- }
314
+ if let url = record.wellKnownTypeURIPayload() { return url.absoluteString }
315
+ let (text, locale) = record.wellKnownTypeTextPayload()
316
+ return text.map { "\($0) [\(locale?.identifier ?? "?")]" }
313
317
  case .absoluteURI:
314
- if let uri = String(data: record.payload, encoding: .utf8) {
315
- print("Absolute URI: \(uri)")
316
- }
318
+ return utf8(record.payload)
317
319
  case .media:
318
- let mimeType = String(data: record.type, encoding: .utf8) ?? ""
319
- print("MIME type: \(mimeType), size: \(record.payload.count)")
320
+ return "\(utf8(record.type) ?? "unknown"), \(record.payload.count) bytes"
320
321
  case .nfcExternal:
321
- let type = String(data: record.type, encoding: .utf8) ?? ""
322
- print("External type: \(type)")
322
+ return utf8(record.type)
323
323
  case .empty, .unknown, .unchanged:
324
- break
324
+ return nil
325
325
  @unknown default:
326
- break
327
- }
328
- }
329
- ```
330
-
331
- ## Background Tag Reading
332
-
333
- On iPhone XS and later, iOS can read NFC tags in the background without
334
- opening your app. The NDEF message must contain a URI record
335
- (`typeNameFormat == .nfcWellKnown`, type `U`). If there are multiple URI
336
- records, the system uses the first one.
337
-
338
- For app-specific routing, write a universal link to the tag and configure the
339
- Associated Domains capability for that domain. Background tag reading also
340
- supports specific system URL schemes such as web, email, SMS, telephone,
341
- FaceTime, Maps, and HomeKit setup. It does not support custom URL schemes, and
342
- the system does not route by bundle ID or arbitrary NDEF content type.
343
-
344
- When a user taps a compatible tag, iOS displays a notification that opens
345
- your app. Handle the tag data via `NSUserActivity`:
346
-
347
- ```swift
348
- func scene(
349
- _ scene: UIScene,
350
- continue userActivity: NSUserActivity
351
- ) {
352
- guard userActivity.activityType ==
353
- NSUserActivityTypeBrowsingWeb else { return }
354
-
355
- let message = userActivity.ndefMessagePayload
356
- guard message.records.first?.typeNameFormat != .empty else { return }
357
-
358
- for record in message.records {
359
- processRecord(record)
326
+ return nil
360
327
  }
361
328
  }
362
- ```
363
-
364
- ## Common Mistakes
365
-
366
- ### DON'T: Use stale or missing NFC entitlements
367
-
368
- Without the `com.apple.developer.nfc.readersession.formats` entitlement,
369
- reader sessions cannot access NFC hardware. Use the current `TAG` value for
370
- Core NFC reader sessions; do not copy older examples that add `NDEF`.
371
-
372
- ### DON'T: Skip the readingAvailable check
373
-
374
- Creating an NFC session on an unsupported or restricted device fails before
375
- the scan UI can do useful work.
376
-
377
- Check `NFCNDEFReaderSession.readingAvailable` or
378
- `NFCTagReaderSession.readingAvailable` before creating the matching session.
379
-
380
- ### DON'T: Ignore session invalidation errors
381
-
382
- The session invalidates for multiple reasons. Distinguishing user cancellation
383
- from real errors prevents false error alerts.
384
-
385
- ```swift
386
- // WRONG -- shows error when user cancels
387
- func readerSession(
388
- _ session: NFCNDEFReaderSession,
389
- didInvalidateWithError error: Error
390
- ) {
391
- showAlert("NFC Error: \(error.localizedDescription)")
392
- }
393
329
 
394
- // CORRECT -- filter expected invalidation reasons
395
- func readerSession(
396
- _ session: NFCNDEFReaderSession,
397
- didInvalidateWithError error: Error
398
- ) {
399
- let nfcError = error as? NFCReaderError
400
- switch nfcError?.code {
401
- case .readerSessionInvalidationErrorUserCanceled,
402
- .readerSessionInvalidationErrorFirstNDEFTagRead:
403
- break // Normal termination
404
- default:
405
- showAlert("NFC Error: \(error.localizedDescription)")
406
- }
407
- self.session = nil
408
- }
330
+ func utf8(_ bytes: Data) -> String? { String(bytes: bytes, encoding: .utf8) }
409
331
  ```
410
332
 
411
- ### DON'T: Hold a strong reference to a stale session
333
+ ## Background tag reading
412
334
 
413
- Once a session is invalidated, it cannot be restarted. Nil out your reference
414
- and create a new session for the next scan.
335
+ iPhone XS and newer read tags without the app open. The rules:
415
336
 
416
- ```swift
417
- // WRONG -- reusing invalidated session
418
- func scanAgain() {
419
- session?.begin() // Does nothing, session is dead
420
- }
421
-
422
- // CORRECT -- create a new session
423
- func scanAgain() {
424
- session = NFCNDEFReaderSession(
425
- delegate: self, queue: nil, invalidateAfterFirstRead: false
426
- )
427
- session?.begin()
428
- }
429
- ```
337
+ - One record has to be a well-known URI record: `typeNameFormat` equal to
338
+ `.nfcWellKnown` and a record type of `U`. If there are several URI records, the first one wins.
339
+ - To route to your app, write a universal link and set up Associated Domains
340
+ for that domain.
341
+ - System schemes also work: web, mail, SMS, phone, FaceTime, Maps and HomeKit
342
+ setup.
343
+ - Custom URL schemes do nothing here. There is no routing by bundle identifier
344
+ or by arbitrary NDEF content type.
430
345
 
431
- ### DON'T: Write without checking tag status
432
-
433
- Writing to a read-only tag silently fails or produces confusing errors.
346
+ A matching tag posts a notification; tapping it launches the app with a
347
+ browsing-web activity:
434
348
 
435
349
  ```swift
436
- // WRONG -- writes without checking status
437
- tag.writeNDEF(message) { error in
438
- // May fail on read-only tags
439
- }
440
-
441
- // CORRECT -- check status first
442
- tag.queryNDEFStatus { status, capacity, error in
443
- guard status == .readWrite else {
444
- session.invalidate(errorMessage: "Tag is read-only.")
445
- return
446
- }
447
- tag.writeNDEF(message) { error in
448
- // Handle result
350
+ func scene(_ scene: UIScene, continue activity: NSUserActivity) {
351
+ guard activity.activityType == NSUserActivityTypeBrowsingWeb else { return }
352
+ let message = activity.ndefMessagePayload
353
+ guard let first = message.records.first, first.typeNameFormat != .empty else { return }
354
+ for record in message.records {
355
+ route(record)
449
356
  }
450
357
  }
451
358
  ```
452
359
 
453
- ## Review Checklist
454
-
455
- - [ ] NFC capability added in Signing & Capabilities
456
- - [ ] `NFCReaderUsageDescription` set in Info.plist
457
- - [ ] `com.apple.developer.nfc.readersession.formats` entitlement uses `TAG`, not legacy `NDEF`
458
- - [ ] `NFCNDEFReaderSession.readingAvailable` or `NFCTagReaderSession.readingAvailable` checked before creating sessions
459
- - [ ] Session delegate set before calling `begin()`
460
- - [ ] Session reference set to nil after invalidation
461
- - [ ] `didInvalidateWithError` distinguishes user cancellation from actual errors
462
- - [ ] NDEF status queried before write operations
463
- - [ ] Tag capacity checked before writing large messages
464
- - [ ] ISO 7816 application identifiers listed in Info.plist if using `NFCTagReaderSession`
465
- - [ ] FeliCa system codes listed in Info.plist when polling `.iso18092`
466
- - [ ] Background tag reading uses a URI NDEF record and universal links or supported system URL schemes
467
- - [ ] Custom URL schemes, bundle IDs, or arbitrary NDEF content types are not used for background routing
468
- - [ ] Payment-related AIDs are routed away from `NFCTagReaderSession`
469
- - [ ] Only one reader session active at a time
360
+ ## Mistakes that keep coming back
361
+
362
+ - **Wrong or missing formats entitlement.** Without it the session cannot reach
363
+ the NFC hardware. Use `TAG`; drop copied `NDEF` values.
364
+ - **No `readingAvailable` check.** Where NFC is missing or switched off by
365
+ policy, session creation fails before any scan sheet appears.
366
+ - **Every invalidation treated as an error.** Cancel and first-read are normal;
367
+ alerting on them trains users to ignore alerts.
368
+ - **Reusing a dead session.** An invalidated session cannot restart and
369
+ `begin()` on it does nothing. Clear the reference and create a new one.
370
+ - **Writing blind.** Without a status query, writes to read-only tags fail in
371
+ confusing ways.
372
+ - **Answering the first of several tags.** Ask the user to remove the extras
373
+ and restart polling.
374
+
375
+ ## Review checklist
376
+
377
+ - [ ] NFC Tag Reading capability is on
378
+ - [ ] `NFCReaderUsageDescription` has a real sentence
379
+ - [ ] Formats entitlement is `TAG`, with no `NDEF`
380
+ - [ ] `readingAvailable` is checked on the same session class that is created
381
+ - [ ] Delegate is supplied before `begin()`
382
+ - [ ] Session reference is cleared after invalidation
383
+ - [ ] `didInvalidateWithError` separates cancel and first-read from real errors
384
+ - [ ] Multiple detected tags lead to a remove-extras message and `restartPolling()`
385
+ - [ ] NDEF status is queried before any write
386
+ - [ ] Capacity is compared with message length before large writes
387
+ - [ ] ISO 7816 AIDs are listed when `NFCTagReaderSession` selects applications
388
+ - [ ] FeliCa system codes are listed when polling `.iso18092`
389
+ - [ ] Background tags carry a URI record with a universal link or supported system scheme
390
+ - [ ] No custom schemes, bundle IDs or content types relied on for background routing
391
+ - [ ] Payment AIDs are kept away from `NFCTagReaderSession`
392
+ - [ ] Only one reader session runs at a time
470
393
 
471
394
  ## References
472
395
 
473
- - Extended patterns (ISO 7816 commands, multi-tag scanning, NDEF locking): [references/nfc-patterns.md](references/nfc-patterns.md)
474
- - [Core NFC framework](https://sosumi.ai/documentation/corenfc)
475
- - [NFCNDEFReaderSession](https://sosumi.ai/documentation/corenfc/nfcndefreadersession)
476
- - [NFCTagReaderSession](https://sosumi.ai/documentation/corenfc/nfctagreadersession)
477
- - [NFCNDEFMessage](https://sosumi.ai/documentation/corenfc/nfcndefmessage)
478
- - [NFCNDEFPayload](https://sosumi.ai/documentation/corenfc/nfcndefpayload)
479
- - [NFCNDEFTag](https://sosumi.ai/documentation/corenfc/nfcndeftag)
480
- - [NFCNDEFReaderSessionDelegate](https://sosumi.ai/documentation/corenfc/nfcndefreadersessiondelegate)
481
- - [NFCTagReaderSessionDelegate](https://sosumi.ai/documentation/corenfc/nfctagreadersessiondelegate)
482
- - [Building an NFC Tag-Reader App](https://sosumi.ai/documentation/corenfc/building_an_nfc_tag-reader_app)
483
- - [Adding Support for Background Tag Reading](https://sosumi.ai/documentation/corenfc/adding-support-for-background-tag-reading)
484
- - [Near Field Communication Tag Reader Session Formats Entitlement](https://sosumi.ai/documentation/bundleresources/entitlements/com.apple.developer.nfc.readersession.formats)
485
- - [ISO7816 application identifiers for NFC Tag Reader Session](https://sosumi.ai/documentation/bundleresources/entitlements/com.apple.developer.nfc.readersession.iso7816.select-identifiers)
486
- - [ISO18092 system codes for NFC Tag Reader Session](https://sosumi.ai/documentation/bundleresources/entitlements/com.apple.developer.nfc.readersession.felica.systemcodes)
396
+ - [NFC patterns](references/nfc-patterns.md): ISO 7816 APDUs, ISO 15693
397
+ blocks, MIFARE and FeliCa commands, multi-tag handling, multi-record messages
398
+ and capacity, tag locking, a SwiftUI scanner, error codes
399
+ - Apple documentation, all under developer.apple.com/documentation:
400
+ - [framework overview](https://developer.apple.com/documentation/corenfc)
401
+ - session classes: [NDEF](https://developer.apple.com/documentation/corenfc/nfcndefreadersession),
402
+ [tag](https://developer.apple.com/documentation/corenfc/nfctagreadersession)
403
+ - delegates: [NDEF](https://developer.apple.com/documentation/corenfc/nfcndefreadersessiondelegate),
404
+ [tag](https://developer.apple.com/documentation/corenfc/nfctagreadersessiondelegate)
405
+ - data types: [message](https://developer.apple.com/documentation/corenfc/nfcndefmessage),
406
+ [payload](https://developer.apple.com/documentation/corenfc/nfcndefpayload),
407
+ [NDEF tag protocol](https://developer.apple.com/documentation/corenfc/nfcndeftag)
408
+ - articles: [tag-reader sample app](https://developer.apple.com/documentation/corenfc/building-an-nfc-tag-reader-app),
409
+ [background reading](https://developer.apple.com/documentation/corenfc/adding-support-for-background-tag-reading)
410
+ - keys: [formats entitlement](https://developer.apple.com/documentation/bundleresources/entitlements/com.apple.developer.nfc.readersession.formats),
411
+ [ISO 7816 AIDs](https://developer.apple.com/documentation/bundleresources/information-property-list/com.apple.developer.nfc.readersession.iso7816.select-identifiers),
412
+ [FeliCa system codes](https://developer.apple.com/documentation/bundleresources/information-property-list/com.apple.developer.nfc.readersession.felica.systemcodes)