@mmerterden/multi-agent-pipeline 20.7.0 → 20.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (284) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/LICENSE +0 -10
  3. package/docs/facts.json +1 -1
  4. package/manifest.json +285 -285
  5. package/package.json +3 -3
  6. package/pipeline/lib/redact.mjs +3 -2
  7. package/pipeline/scripts/_notices.mjs +1 -1
  8. package/pipeline/scripts/gen-skills-index.mjs +13 -1
  9. package/pipeline/scripts/pre-commit-check.sh +4 -0
  10. package/pipeline/skills/.skill-manifest.json +69 -69
  11. package/pipeline/skills/shared/README.md +70 -70
  12. package/pipeline/skills/shared/external/alarmkit/SKILL.md +373 -381
  13. package/pipeline/skills/shared/external/alarmkit/evals/evals.json +23 -18
  14. package/pipeline/skills/shared/external/alarmkit/references/alarmkit-patterns.md +328 -378
  15. package/pipeline/skills/shared/external/app-clips/SKILL.md +260 -160
  16. package/pipeline/skills/shared/external/app-clips/evals/evals.json +27 -27
  17. package/pipeline/skills/shared/external/app-clips/references/data-handoff-notifications-location.md +150 -83
  18. package/pipeline/skills/shared/external/app-clips/references/routing-and-experiences.md +135 -83
  19. package/pipeline/skills/shared/external/app-clips/references/size-capabilities-and-promotion.md +143 -85
  20. package/pipeline/skills/shared/external/app-intents/SKILL.md +302 -304
  21. package/pipeline/skills/shared/external/app-intents/evals/evals.json +21 -21
  22. package/pipeline/skills/shared/external/app-intents/references/appintents-advanced.md +594 -894
  23. package/pipeline/skills/shared/external/app-store-optimization/SKILL.md +345 -277
  24. package/pipeline/skills/shared/external/app-store-optimization/evals/evals.json +27 -23
  25. package/pipeline/skills/shared/external/app-store-optimization/references/keyword-research-methodology.md +107 -121
  26. package/pipeline/skills/shared/external/app-store-optimization/references/product-page-variants.md +145 -165
  27. package/pipeline/skills/shared/external/app-store-review/SKILL.md +306 -326
  28. package/pipeline/skills/shared/external/app-store-review/evals/evals.json +21 -21
  29. package/pipeline/skills/shared/external/app-store-review/references/privacy-manifest.md +105 -67
  30. package/pipeline/skills/shared/external/app-store-review/references/review-checklists.md +114 -101
  31. package/pipeline/skills/shared/external/apple-on-device-ai/SKILL.md +335 -360
  32. package/pipeline/skills/shared/external/apple-on-device-ai/evals/evals.json +24 -27
  33. package/pipeline/skills/shared/external/apple-on-device-ai/references/coreml-conversion.md +215 -322
  34. package/pipeline/skills/shared/external/apple-on-device-ai/references/coreml-optimization.md +161 -256
  35. package/pipeline/skills/shared/external/apple-on-device-ai/references/foundation-models.md +277 -387
  36. package/pipeline/skills/shared/external/apple-on-device-ai/references/mlx-swift.md +196 -210
  37. package/pipeline/skills/shared/external/authentication/SKILL.md +277 -381
  38. package/pipeline/skills/shared/external/authentication/evals/evals.json +25 -25
  39. package/pipeline/skills/shared/external/authentication/references/keychain-biometric.md +135 -178
  40. package/pipeline/skills/shared/external/authentication/references/passkeys.md +111 -147
  41. package/pipeline/skills/shared/external/avkit/SKILL.md +267 -364
  42. package/pipeline/skills/shared/external/avkit/evals/evals.json +26 -26
  43. package/pipeline/skills/shared/external/avkit/references/avkit-patterns.md +375 -493
  44. package/pipeline/skills/shared/external/background-processing/SKILL.md +274 -384
  45. package/pipeline/skills/shared/external/background-processing/evals/evals.json +22 -22
  46. package/pipeline/skills/shared/external/background-processing/references/background-task-patterns.md +173 -321
  47. package/pipeline/skills/shared/external/callkit-voip/SKILL.md +290 -371
  48. package/pipeline/skills/shared/external/callkit-voip/evals/evals.json +24 -24
  49. package/pipeline/skills/shared/external/callkit-voip/references/callkit-patterns.md +175 -343
  50. package/pipeline/skills/shared/external/cloudkit-sync/SKILL.md +292 -381
  51. package/pipeline/skills/shared/external/cloudkit-sync/evals/evals.json +33 -30
  52. package/pipeline/skills/shared/external/cloudkit-sync/references/cloudkit-patterns.md +227 -355
  53. package/pipeline/skills/shared/external/contacts-framework/SKILL.md +197 -346
  54. package/pipeline/skills/shared/external/contacts-framework/evals/evals.json +19 -21
  55. package/pipeline/skills/shared/external/contacts-framework/references/contacts-patterns.md +169 -308
  56. package/pipeline/skills/shared/external/core-bluetooth/SKILL.md +228 -376
  57. package/pipeline/skills/shared/external/core-bluetooth/evals/evals.json +25 -22
  58. package/pipeline/skills/shared/external/core-bluetooth/references/ble-patterns.md +257 -337
  59. package/pipeline/skills/shared/external/core-data/SKILL.md +302 -368
  60. package/pipeline/skills/shared/external/core-data/evals/evals.json +30 -27
  61. package/pipeline/skills/shared/external/core-motion/SKILL.md +235 -324
  62. package/pipeline/skills/shared/external/core-motion/evals/evals.json +31 -27
  63. package/pipeline/skills/shared/external/core-motion/references/motion-patterns.md +210 -310
  64. package/pipeline/skills/shared/external/core-nfc/SKILL.md +292 -366
  65. package/pipeline/skills/shared/external/core-nfc/evals/evals.json +22 -24
  66. package/pipeline/skills/shared/external/core-nfc/references/nfc-patterns.md +233 -329
  67. package/pipeline/skills/shared/external/coreml/SKILL.md +323 -367
  68. package/pipeline/skills/shared/external/coreml/evals/evals.json +24 -21
  69. package/pipeline/skills/shared/external/coreml/references/coreml-swift-integration.md +562 -565
  70. package/pipeline/skills/shared/external/cryptokit/SKILL.md +253 -394
  71. package/pipeline/skills/shared/external/cryptokit/evals/evals.json +20 -18
  72. package/pipeline/skills/shared/external/cryptokit/references/cryptokit-patterns.md +299 -488
  73. package/pipeline/skills/shared/external/debugging-instruments/SKILL.md +270 -323
  74. package/pipeline/skills/shared/external/debugging-instruments/evals/evals.json +27 -30
  75. package/pipeline/skills/shared/external/debugging-instruments/references/instruments-guide.md +167 -315
  76. package/pipeline/skills/shared/external/debugging-instruments/references/lldb-patterns.md +140 -193
  77. package/pipeline/skills/shared/external/device-integrity/SKILL.md +236 -353
  78. package/pipeline/skills/shared/external/device-integrity/evals/evals.json +25 -21
  79. package/pipeline/skills/shared/external/device-integrity/references/device-integrity-patterns.md +159 -197
  80. package/pipeline/skills/shared/external/energykit/SKILL.md +225 -392
  81. package/pipeline/skills/shared/external/energykit/evals/evals.json +29 -28
  82. package/pipeline/skills/shared/external/energykit/references/energykit-patterns.md +174 -470
  83. package/pipeline/skills/shared/external/eventkit-calendar/SKILL.md +261 -383
  84. package/pipeline/skills/shared/external/eventkit-calendar/evals/evals.json +25 -22
  85. package/pipeline/skills/shared/external/eventkit-calendar/references/eventkit-patterns.md +165 -268
  86. package/pipeline/skills/shared/external/healthkit/SKILL.md +252 -303
  87. package/pipeline/skills/shared/external/healthkit/evals/evals.json +24 -23
  88. package/pipeline/skills/shared/external/healthkit/references/healthkit-patterns.md +369 -523
  89. package/pipeline/skills/shared/external/homekit-matter/SKILL.md +233 -348
  90. package/pipeline/skills/shared/external/homekit-matter/evals/evals.json +27 -22
  91. package/pipeline/skills/shared/external/homekit-matter/references/matter-commissioning.md +199 -305
  92. package/pipeline/skills/shared/external/ios-accessibility/SKILL.md +368 -340
  93. package/pipeline/skills/shared/external/ios-accessibility/evals/evals.json +28 -27
  94. package/pipeline/skills/shared/external/ios-accessibility/references/a11y-patterns.md +314 -260
  95. package/pipeline/skills/shared/external/ios-accessibility/references/media-accessibility.md +97 -67
  96. package/pipeline/skills/shared/external/ios-accessibility/references/nutrition-labels.md +165 -101
  97. package/pipeline/skills/shared/external/ios-localization/SKILL.md +258 -371
  98. package/pipeline/skills/shared/external/ios-localization/evals/evals.json +23 -23
  99. package/pipeline/skills/shared/external/ios-localization/references/formatstyle-locale.md +283 -491
  100. package/pipeline/skills/shared/external/ios-localization/references/string-catalogs.md +313 -440
  101. package/pipeline/skills/shared/external/ios-networking/SKILL.md +265 -341
  102. package/pipeline/skills/shared/external/ios-networking/evals/evals.json +24 -24
  103. package/pipeline/skills/shared/external/ios-networking/references/background-websocket.md +425 -652
  104. package/pipeline/skills/shared/external/ios-networking/references/file-storage-patterns.md +143 -285
  105. package/pipeline/skills/shared/external/ios-networking/references/lightweight-clients.md +93 -53
  106. package/pipeline/skills/shared/external/ios-networking/references/network-framework.md +231 -456
  107. package/pipeline/skills/shared/external/ios-networking/references/urlsession-patterns.md +517 -784
  108. package/pipeline/skills/shared/external/ios-simulator/SKILL.md +265 -393
  109. package/pipeline/skills/shared/external/ios-simulator/evals/evals.json +21 -21
  110. package/pipeline/skills/shared/external/ios-simulator/references/simctl-commands.md +177 -270
  111. package/pipeline/skills/shared/external/live-activities/SKILL.md +318 -360
  112. package/pipeline/skills/shared/external/live-activities/evals/evals.json +21 -21
  113. package/pipeline/skills/shared/external/live-activities/references/activitykit-patterns.md +478 -710
  114. package/pipeline/skills/shared/external/localization-reuse-map/SKILL.md +3 -3
  115. package/pipeline/skills/shared/external/localization-reuse-map/example-mapping.json +1 -1
  116. package/pipeline/skills/shared/external/localization-reuse-map/reference/format-and-output.md +8 -7
  117. package/pipeline/skills/shared/external/localization-reuse-map/reference/publish-and-snapshot.md +2 -2
  118. package/pipeline/skills/shared/external/localization-reuse-map/reference/sources-and-recipes.md +5 -2
  119. package/pipeline/skills/shared/external/localization-reuse-map/scripts/_shared.py +100 -0
  120. package/pipeline/skills/shared/external/localization-reuse-map/scripts/build-artifact.py +45 -26
  121. package/pipeline/skills/shared/external/localization-reuse-map/scripts/build-spreadsheet.py +14 -16
  122. package/pipeline/skills/shared/external/localization-reuse-map/scripts/fetch-annotations.py +12 -5
  123. package/pipeline/skills/shared/external/localization-reuse-map/scripts/fetch-legacy-labels.py +2 -1
  124. package/pipeline/skills/shared/external/localization-reuse-map/scripts/publish-confluence.py +6 -5
  125. package/pipeline/skills/shared/external/localization-reuse-map/scripts/render-overlay.py +44 -18
  126. package/pipeline/skills/shared/external/localization-reuse-map/scripts/resolve-legacy-values.py +5 -2
  127. package/pipeline/skills/shared/external/localization-reuse-map/scripts/resolve-new-values.py +10 -11
  128. package/pipeline/skills/shared/external/localization-reuse-map/scripts/scan-screen-keys.py +4 -33
  129. package/pipeline/skills/shared/external/localization-reuse-map/scripts/verify-map.py +12 -59
  130. package/pipeline/skills/shared/external/mapkit-location/SKILL.md +297 -267
  131. package/pipeline/skills/shared/external/mapkit-location/evals/evals.json +28 -24
  132. package/pipeline/skills/shared/external/mapkit-location/references/mapkit-corelocation-patterns.md +378 -532
  133. package/pipeline/skills/shared/external/mapkit-location/references/mapkit-patterns.md +397 -499
  134. package/pipeline/skills/shared/external/metrickit-diagnostics/SKILL.md +165 -348
  135. package/pipeline/skills/shared/external/metrickit-diagnostics/evals/evals.json +26 -23
  136. package/pipeline/skills/shared/external/metrickit-diagnostics/references/metrickit-patterns.md +123 -130
  137. package/pipeline/skills/shared/external/musickit-audio/SKILL.md +189 -315
  138. package/pipeline/skills/shared/external/musickit-audio/evals/evals.json +22 -21
  139. package/pipeline/skills/shared/external/musickit-audio/references/musickit-patterns.md +181 -270
  140. package/pipeline/skills/shared/external/natural-language/SKILL.md +188 -340
  141. package/pipeline/skills/shared/external/natural-language/evals/evals.json +21 -21
  142. package/pipeline/skills/shared/external/natural-language/references/translation-patterns.md +171 -225
  143. package/pipeline/skills/shared/external/passkit-wallet/SKILL.md +258 -392
  144. package/pipeline/skills/shared/external/passkit-wallet/evals/evals.json +30 -29
  145. package/pipeline/skills/shared/external/passkit-wallet/references/wallet-passes.md +164 -231
  146. package/pipeline/skills/shared/external/pdfkit/SKILL.md +312 -344
  147. package/pipeline/skills/shared/external/pdfkit/evals/evals.json +19 -19
  148. package/pipeline/skills/shared/external/pdfkit/references/pdfkit-patterns.md +413 -624
  149. package/pipeline/skills/shared/external/pencilkit-drawing/SKILL.md +242 -358
  150. package/pipeline/skills/shared/external/pencilkit-drawing/evals/evals.json +25 -21
  151. package/pipeline/skills/shared/external/pencilkit-drawing/references/pencilkit-patterns.md +161 -226
  152. package/pipeline/skills/shared/external/permissionkit/SKILL.md +282 -400
  153. package/pipeline/skills/shared/external/permissionkit/evals/evals.json +27 -30
  154. package/pipeline/skills/shared/external/permissionkit/references/permissionkit-patterns.md +237 -350
  155. package/pipeline/skills/shared/external/photos-camera-media/SKILL.md +276 -325
  156. package/pipeline/skills/shared/external/photos-camera-media/references/av-playback.md +299 -545
  157. package/pipeline/skills/shared/external/photos-camera-media/references/camera-capture.md +344 -588
  158. package/pipeline/skills/shared/external/photos-camera-media/references/image-loading-caching.md +316 -660
  159. package/pipeline/skills/shared/external/photos-camera-media/references/photokit-patterns.md +270 -416
  160. package/pipeline/skills/shared/external/push-notifications/SKILL.md +312 -340
  161. package/pipeline/skills/shared/external/push-notifications/evals/evals.json +27 -26
  162. package/pipeline/skills/shared/external/push-notifications/references/notification-patterns.md +328 -485
  163. package/pipeline/skills/shared/external/push-notifications/references/rich-notifications.md +327 -560
  164. package/pipeline/skills/shared/external/realitykit-ar/SKILL.md +218 -410
  165. package/pipeline/skills/shared/external/realitykit-ar/evals/evals.json +24 -27
  166. package/pipeline/skills/shared/external/realitykit-ar/references/realitykit-patterns.md +221 -348
  167. package/pipeline/skills/shared/external/shareplay-activities/SKILL.md +222 -393
  168. package/pipeline/skills/shared/external/shareplay-activities/evals/evals.json +23 -24
  169. package/pipeline/skills/shared/external/shareplay-activities/references/shareplay-patterns.md +280 -420
  170. package/pipeline/skills/shared/external/skill-creator/template.md +7 -1
  171. package/pipeline/skills/shared/external/speech-recognition/SKILL.md +217 -421
  172. package/pipeline/skills/shared/external/speech-recognition/evals/evals.json +23 -26
  173. package/pipeline/skills/shared/external/speech-recognition/references/speechanalyzer-patterns.md +133 -125
  174. package/pipeline/skills/shared/external/storekit/SKILL.md +228 -204
  175. package/pipeline/skills/shared/external/storekit/evals/evals.json +27 -24
  176. package/pipeline/skills/shared/external/storekit/references/app-review-guidelines.md +98 -109
  177. package/pipeline/skills/shared/external/storekit/references/core-patterns.md +302 -241
  178. package/pipeline/skills/shared/external/storekit/references/storekit-advanced.md +356 -649
  179. package/pipeline/skills/shared/external/swift-api-design-guidelines/SKILL.md +274 -399
  180. package/pipeline/skills/shared/external/swift-api-design-guidelines/evals/evals.json +22 -24
  181. package/pipeline/skills/shared/external/swift-api-design-guidelines/references/argument-labels-and-parameters.md +107 -108
  182. package/pipeline/skills/shared/external/swift-api-design-guidelines/references/conventions-and-special-rules.md +93 -165
  183. package/pipeline/skills/shared/external/swift-api-design-guidelines/references/naming-and-clarity.md +99 -137
  184. package/pipeline/skills/shared/external/swift-api-design-guidelines/references/side-effects-and-mutating-pairs.md +77 -120
  185. package/pipeline/skills/shared/external/swift-architecture/SKILL.md +334 -350
  186. package/pipeline/skills/shared/external/swift-architecture/evals/evals.json +22 -22
  187. package/pipeline/skills/shared/external/swift-charts/SKILL.md +208 -394
  188. package/pipeline/skills/shared/external/swift-charts/evals/evals.json +27 -30
  189. package/pipeline/skills/shared/external/swift-charts/references/charts-patterns.md +351 -762
  190. package/pipeline/skills/shared/external/swift-codable/SKILL.md +339 -343
  191. package/pipeline/skills/shared/external/swift-codable/evals/evals.json +20 -20
  192. package/pipeline/skills/shared/external/swift-concurrency/SKILL.md +304 -351
  193. package/pipeline/skills/shared/external/swift-concurrency/evals/evals.json +27 -24
  194. package/pipeline/skills/shared/external/swift-concurrency/references/approachable-concurrency.md +65 -80
  195. package/pipeline/skills/shared/external/swift-concurrency/references/async-algorithms.md +48 -84
  196. package/pipeline/skills/shared/external/swift-concurrency/references/bridging-interop.md +134 -79
  197. package/pipeline/skills/shared/external/swift-concurrency/references/concurrency-patterns.md +145 -167
  198. package/pipeline/skills/shared/external/swift-concurrency/references/diagnostics.md +62 -50
  199. package/pipeline/skills/shared/external/swift-concurrency/references/swiftui-concurrency.md +92 -121
  200. package/pipeline/skills/shared/external/swift-concurrency/references/synchronization-primitives.md +177 -241
  201. package/pipeline/skills/shared/external/swift-formatstyle/SKILL.md +258 -234
  202. package/pipeline/skills/shared/external/swift-language/SKILL.md +342 -382
  203. package/pipeline/skills/shared/external/swift-language/evals/evals.json +24 -27
  204. package/pipeline/skills/shared/external/swift-language/references/swift-attributes-interop.md +79 -56
  205. package/pipeline/skills/shared/external/swift-language/references/swift-patterns-extended.md +297 -340
  206. package/pipeline/skills/shared/external/swift-security/SKILL.md +183 -162
  207. package/pipeline/skills/shared/external/swift-security/evals/evals.json +25 -25
  208. package/pipeline/skills/shared/external/swift-security/references/biometric-authentication.md +314 -469
  209. package/pipeline/skills/shared/external/swift-security/references/certificate-trust.md +411 -476
  210. package/pipeline/skills/shared/external/swift-security/references/common-anti-patterns.md +260 -530
  211. package/pipeline/skills/shared/external/swift-security/references/compliance-owasp-mapping.md +270 -477
  212. package/pipeline/skills/shared/external/swift-security/references/credential-storage-patterns.md +573 -571
  213. package/pipeline/skills/shared/external/swift-security/references/cryptokit-public-key.md +370 -441
  214. package/pipeline/skills/shared/external/swift-security/references/cryptokit-symmetric.md +332 -433
  215. package/pipeline/skills/shared/external/swift-security/references/keychain-access-control.md +346 -468
  216. package/pipeline/skills/shared/external/swift-security/references/keychain-fundamentals.md +375 -491
  217. package/pipeline/skills/shared/external/swift-security/references/keychain-item-classes.md +431 -432
  218. package/pipeline/skills/shared/external/swift-security/references/keychain-sharing.md +328 -425
  219. package/pipeline/skills/shared/external/swift-security/references/migration-legacy-stores.md +341 -579
  220. package/pipeline/skills/shared/external/swift-security/references/secure-enclave.md +397 -457
  221. package/pipeline/skills/shared/external/swift-security/references/testing-security-code.md +354 -614
  222. package/pipeline/skills/shared/external/swift-testing/SKILL.md +191 -175
  223. package/pipeline/skills/shared/external/swift-testing/evals/evals.json +26 -24
  224. package/pipeline/skills/shared/external/swift-testing/references/testing-advanced.md +81 -84
  225. package/pipeline/skills/shared/external/swift-testing/references/testing-patterns.md +317 -433
  226. package/pipeline/skills/shared/external/swiftdata/SKILL.md +394 -256
  227. package/pipeline/skills/shared/external/swiftdata/evals/evals.json +24 -24
  228. package/pipeline/skills/shared/external/swiftdata/references/core-data-coexistence.md +206 -402
  229. package/pipeline/skills/shared/external/swiftdata/references/indexing.md +59 -52
  230. package/pipeline/skills/shared/external/swiftdata/references/predicate-pitfalls.md +57 -33
  231. package/pipeline/skills/shared/external/swiftdata/references/swiftdata-advanced.md +354 -747
  232. package/pipeline/skills/shared/external/swiftdata/references/swiftdata-queries.md +300 -508
  233. package/pipeline/skills/shared/external/swiftlint/SKILL.md +175 -226
  234. package/pipeline/skills/shared/external/swiftlint/references/adoption-and-configuration.md +141 -208
  235. package/pipeline/skills/shared/external/swiftlint/references/custom-rules-and-analyze.md +100 -109
  236. package/pipeline/skills/shared/external/swiftlint/references/plugins-run-scripts-and-integrations.md +159 -179
  237. package/pipeline/skills/shared/external/swiftlint/references/rule-reference.md +383 -18
  238. package/pipeline/skills/shared/external/swiftlint/references/rules-suppressions-and-baselines.md +143 -229
  239. package/pipeline/skills/shared/external/swiftui-animation/SKILL.md +283 -366
  240. package/pipeline/skills/shared/external/swiftui-animation/references/animation-advanced.md +396 -608
  241. package/pipeline/skills/shared/external/swiftui-animation/references/core-animation-bridge.md +336 -385
  242. package/pipeline/skills/shared/external/swiftui-gestures/SKILL.md +239 -349
  243. package/pipeline/skills/shared/external/swiftui-gestures/references/gesture-patterns.md +228 -310
  244. package/pipeline/skills/shared/external/swiftui-layout-components/SKILL.md +260 -249
  245. package/pipeline/skills/shared/external/swiftui-layout-components/references/form.md +92 -74
  246. package/pipeline/skills/shared/external/swiftui-layout-components/references/grids.md +112 -177
  247. package/pipeline/skills/shared/external/swiftui-layout-components/references/list.md +61 -64
  248. package/pipeline/skills/shared/external/swiftui-layout-components/references/scrollview.md +94 -134
  249. package/pipeline/skills/shared/external/swiftui-liquid-glass/SKILL.md +193 -225
  250. package/pipeline/skills/shared/external/swiftui-liquid-glass/references/liquid-glass.md +173 -327
  251. package/pipeline/skills/shared/external/swiftui-navigation/SKILL.md +201 -168
  252. package/pipeline/skills/shared/external/swiftui-navigation/references/deeplinks.md +127 -150
  253. package/pipeline/skills/shared/external/swiftui-navigation/references/navigationstack.md +134 -133
  254. package/pipeline/skills/shared/external/swiftui-navigation/references/sheets.md +152 -117
  255. package/pipeline/skills/shared/external/swiftui-navigation/references/tabview.md +111 -138
  256. package/pipeline/skills/shared/external/swiftui-patterns/SKILL.md +316 -252
  257. package/pipeline/skills/shared/external/swiftui-patterns/references/architecture-patterns.md +341 -332
  258. package/pipeline/skills/shared/external/swiftui-patterns/references/deprecated-migration.md +547 -854
  259. package/pipeline/skills/shared/external/swiftui-patterns/references/design-polish.md +485 -537
  260. package/pipeline/skills/shared/external/swiftui-patterns/references/platform-and-sharing.md +417 -499
  261. package/pipeline/skills/shared/external/swiftui-performance/SKILL.md +213 -376
  262. package/pipeline/skills/shared/external/swiftui-performance/references/demystify-swiftui-performance-wwdc23.md +86 -175
  263. package/pipeline/skills/shared/external/swiftui-performance/references/optimizing-swiftui-performance-instruments.md +89 -195
  264. package/pipeline/skills/shared/external/swiftui-performance/references/understanding-hangs-in-your-app.md +95 -182
  265. package/pipeline/skills/shared/external/swiftui-performance/references/understanding-improving-swiftui-performance.md +71 -149
  266. package/pipeline/skills/shared/external/swiftui-performance/references/wwdc-session-sources.md +21 -27
  267. package/pipeline/skills/shared/external/swiftui-uikit-interop/SKILL.md +303 -295
  268. package/pipeline/skills/shared/external/swiftui-uikit-interop/references/hosting-migration.md +204 -387
  269. package/pipeline/skills/shared/external/swiftui-uikit-interop/references/representable-recipes.md +469 -683
  270. package/pipeline/skills/shared/external/swiftui-webkit/SKILL.md +140 -186
  271. package/pipeline/skills/shared/external/swiftui-webkit/references/loading-and-observation.md +75 -86
  272. package/pipeline/skills/shared/external/swiftui-webkit/references/local-content-and-custom-schemes.md +63 -60
  273. package/pipeline/skills/shared/external/swiftui-webkit/references/migration-and-fallbacks.md +69 -137
  274. package/pipeline/skills/shared/external/swiftui-webkit/references/navigation-and-javascript.md +95 -67
  275. package/pipeline/skills/shared/external/tipkit/SKILL.md +220 -335
  276. package/pipeline/skills/shared/external/tipkit/references/tipkit-patterns.md +356 -494
  277. package/pipeline/skills/shared/external/vision-framework/SKILL.md +260 -375
  278. package/pipeline/skills/shared/external/vision-framework/references/vision-requests.md +393 -515
  279. package/pipeline/skills/shared/external/vision-framework/references/visionkit-scanner.md +363 -539
  280. package/pipeline/skills/shared/external/weatherkit/SKILL.md +160 -315
  281. package/pipeline/skills/shared/external/weatherkit/references/weatherkit-patterns.md +288 -407
  282. package/pipeline/skills/shared/external/widgetkit/SKILL.md +224 -288
  283. package/pipeline/skills/shared/external/widgetkit/references/widgetkit-advanced.md +416 -719
  284. package/pipeline/skills/shared/external/NOTICE-swift-ios-skills.md +0 -39
@@ -1,239 +1,199 @@
1
1
  ---
2
2
  name: musickit-audio
3
- description: "Integrate Apple Music playback, catalog search, and Now Playing metadata using MusicKit and MediaPlayer. Use when adding music search, Apple Music subscription flows, queue management, playback controls, remote command handling, or Now Playing info to iOS apps."
3
+ description: "MusicKit and MediaPlayer on iOS: Apple Music authorization, catalog search, subscription checks and offers, ApplicationMusicPlayer playback controls and queues, Now Playing info, remote commands. Use when adding Apple Music playback or Now Playing controls."
4
4
  metadata:
5
- source: "dpearson2699/swift-ios-skills (PolyForm Perimeter 1.0.0)"
5
+ source: multi-agent-pipeline
6
6
  ---
7
7
 
8
- # MusicKit
8
+ # MusicKit and Now Playing
9
9
 
10
- Search the Apple Music catalog, manage playback with `ApplicationMusicPlayer`,
11
- check subscriptions, and publish Now Playing metadata via `MPNowPlayingInfoCenter`
12
- and `MPRemoteCommandCenter`. Targets Swift 6.3 / iOS 26+.
10
+ Two frameworks cover music in an iOS app. MusicKit talks to Apple Music:
11
+ permission, catalog, subscription state, library and an app-owned player.
12
+ MediaPlayer talks to the system: the Now Playing card on the Lock Screen, in
13
+ Control Center and in CarPlay, plus the remote commands that headphones and
14
+ those surfaces send. Code here targets Swift 6.3 and iOS 26.
13
15
 
14
- ## Contents
15
-
16
- - [Setup](#setup)
17
- - [Authorization](#authorization)
18
- - [Catalog Search](#catalog-search)
19
- - [Subscription Checks](#subscription-checks)
20
- - [Playback with ApplicationMusicPlayer](#playback-with-applicationmusicplayer)
21
- - [Queue Management](#queue-management)
22
- - [Now Playing Info](#now-playing-info)
23
- - [Remote Command Center](#remote-command-center)
24
- - [Common Mistakes](#common-mistakes)
25
- - [Review Checklist](#review-checklist)
26
- - [References](#references)
16
+ Longer building blocks (an observable player model, mini player, search screen,
17
+ charts, library and playlist work, `MPNowPlayingSession`, audio session setup,
18
+ interruptions and route changes) live in
19
+ [references/musickit-patterns.md](references/musickit-patterns.md).
27
20
 
28
21
  ## Setup
29
22
 
30
- ### Project Configuration
23
+ ### Portal and Info.plist
24
+
25
+ 1. In the developer portal, open the app's explicit App ID and turn on the
26
+ **MusicKit** App Service. That is what lets the system mint developer tokens
27
+ for the app automatically; there is no token code to write.
28
+ 2. Add `NSAppleMusicUsageDescription` to Info.plist. Without it, access to the
29
+ user's media library fails wherever the system requires the string.
30
+ 3. Only if audio must keep playing in the background: add `audio` to the
31
+ `UIBackgroundModes` array.
31
32
 
32
- 1. Enable the **MusicKit App Service** for the app's explicit bundle ID in the Apple Developer portal so MusicKit can generate developer tokens automatically.
33
- 2. Add `NSAppleMusicUsageDescription` to Info.plist explaining why the app accesses the user's media library.
34
- 3. For background playback, add the `audio` background mode to `UIBackgroundModes`.
33
+ There is no `com.apple.developer.musickit` entitlement to add on iOS, and a
34
+ missing entitlement is not what makes authorization fail. The App Service and
35
+ the usage string are the two requirements.
35
36
 
36
37
  ### Imports
37
38
 
38
39
  ```swift
39
- import MusicKit // Catalog, auth, playback
40
- import MediaPlayer // MPRemoteCommandCenter, MPNowPlayingInfoCenter
40
+ import MusicKit // authorization, catalog, subscription, ApplicationMusicPlayer
41
+ import MediaPlayer // MPNowPlayingInfoCenter, MPRemoteCommandCenter
41
42
  ```
42
43
 
43
44
  ## Authorization
44
45
 
45
- Request permission before accessing the user's music data or playing Apple Music
46
- content. `request()` presents Apple's consent dialog when necessary; use
47
- `currentStatus` to read the current setting without prompting.
46
+ Ask before touching the user's music data or starting Apple Music playback.
48
47
 
49
48
  ```swift
50
- func requestMusicAccess() async -> MusicAuthorization.Status {
51
- let status = await MusicAuthorization.request()
52
- switch status {
49
+ func ensureMusicAccess() async -> Bool {
50
+ switch await MusicAuthorization.request() {
53
51
  case .authorized:
54
- // Full access to MusicKit APIs
55
- break
52
+ return true
56
53
  case .denied, .restricted:
57
- // Show guidance to enable in Settings
58
- break
54
+ // Explain the limitation and point the user at Settings.
55
+ return false
59
56
  case .notDetermined:
60
- break
57
+ return false
61
58
  @unknown default:
62
- break
59
+ return false
63
60
  }
64
- return status
65
61
  }
66
-
67
- // Check current status without prompting
68
- let current = MusicAuthorization.currentStatus
69
62
  ```
70
63
 
71
- ## Catalog Search
64
+ `request()` shows the consent prompt only when the user has not answered yet;
65
+ otherwise it returns the stored answer. To read the state without any chance of
66
+ a prompt, use `MusicAuthorization.currentStatus`.
72
67
 
73
- Use `MusicCatalogSearchRequest` to search the Apple Music catalog. Catalog lookup
74
- can fetch Apple Music resources, but playback of subscription catalog content
75
- must still be gated on `MusicSubscription.current.canPlayCatalogContent`.
68
+ ## Catalog search
76
69
 
77
- ```swift
78
- func searchCatalog(term: String) async throws -> MusicItemCollection<Song> {
79
- var request = MusicCatalogSearchRequest(term: term, types: [Song.self])
80
- request.limit = 25
70
+ Searching the catalog works for anyone who granted access. Playing what you
71
+ found is a separate question, answered by the subscription check below.
81
72
 
82
- let response = try await request.response()
83
- return response.songs
73
+ ```swift
74
+ func findTracks(matching phrase: String) async throws -> MusicItemCollection<Song> {
75
+ var search = MusicCatalogSearchRequest(term: phrase, types: [Song.self])
76
+ search.limit = 25
77
+ let result = try await search.response()
78
+ return result.songs
84
79
  }
85
80
  ```
86
81
 
87
- ### Displaying Results
82
+ For a row, read `song.title`, `song.artistName` and
83
+ `song.artwork?.url(width: 120, height: 120)`.
84
+
85
+ ## Subscription state
88
86
 
89
87
  ```swift
90
- for song in songs {
91
- print("\(song.title) by \(song.artistName)")
92
- if let artwork = song.artwork {
93
- let url = artwork.url(width: 300, height: 300)
94
- // Load artwork from url
95
- }
96
- }
88
+ let membership = try await MusicSubscription.current
89
+ let mayPlay = membership.canPlayCatalogContent
97
90
  ```
98
91
 
99
- ## Subscription Checks
100
-
101
- Check whether the user has an active Apple Music subscription before offering playback features.
92
+ Subscription state changes while the app runs. Keep the UI in step:
102
93
 
103
94
  ```swift
104
- func checkSubscription() async throws -> Bool {
105
- let subscription = try await MusicSubscription.current
106
- return subscription.canPlayCatalogContent
107
- }
108
-
109
- // Observe subscription changes
110
- func observeSubscription() async {
111
- for await subscription in MusicSubscription.subscriptionUpdates {
112
- if subscription.canPlayCatalogContent {
113
- // Enable full playback UI
114
- } else {
115
- // Show subscription offer
116
- }
95
+ .task {
96
+ for await membership in MusicSubscription.subscriptionUpdates {
97
+ showsPlayControls = membership.canPlayCatalogContent
98
+ showsJoinButton = !membership.canPlayCatalogContent && membership.canBecomeSubscriber
117
99
  }
118
100
  }
119
101
  ```
120
102
 
121
- ### Offering Apple Music
103
+ ### Presenting the Apple Music offer
122
104
 
123
- Present the Apple Music subscription offer sheet when the user is not subscribed.
124
- Check `canBecomeSubscriber` first, and pass `MusicSubscriptionOffer.Options` or
125
- `onLoadCompletion` when the sheet needs contextual metadata or load-error handling.
105
+ Only offer when `canBecomeSubscriber` is true. The sheet comes from a view
106
+ modifier:
126
107
 
127
108
  ```swift
128
- import MusicKit
129
- import SwiftUI
130
-
131
- struct MusicOfferView: View {
132
- @State private var showOffer = false
109
+ struct JoinAppleMusicButton: View {
110
+ @State private var offerVisible = false
111
+ @State private var offerOptions = MusicSubscriptionOffer.Options.default
112
+ @State private var offerError: (any Error)?
133
113
 
134
114
  var body: some View {
135
- Button("Subscribe to Apple Music") {
136
- Task {
137
- let subscription = try? await MusicSubscription.current
138
- showOffer = subscription?.canBecomeSubscriber == true
139
- }
140
- }
141
- .musicSubscriptionOffer(
142
- isPresented: $showOffer,
143
- options: .default,
144
- onLoadCompletion: { error in
145
- if let error {
146
- // Surface loading errors in app UI or diagnostics.
147
- print(error)
148
- }
149
- }
150
- )
115
+ Button("Try Apple Music") { offerVisible = true }
116
+ .musicSubscriptionOffer(
117
+ isPresented: $offerVisible,
118
+ options: offerOptions,
119
+ onLoadCompletion: { failure in offerError = failure }
120
+ )
151
121
  }
152
122
  }
153
123
  ```
154
124
 
155
- ## Playback with ApplicationMusicPlayer
125
+ When `offerError` is non-nil the sheet did not load; show a fallback message.
156
126
 
157
- `ApplicationMusicPlayer` plays Apple Music content independently from the Music app. It does not affect the system player's state.
127
+ ## ApplicationMusicPlayer
158
128
 
159
- ```swift
160
- let player = ApplicationMusicPlayer.shared
129
+ `ApplicationMusicPlayer.shared` is the app's own player. It plays alongside the
130
+ Music app without touching the Music app's queue or state.
161
131
 
162
- func playSong(_ song: Song) async throws {
163
- player.queue = [song]
132
+ ```swift
133
+ func start(_ track: Song) async throws {
134
+ let player = ApplicationMusicPlayer.shared
135
+ player.queue = [track]
164
136
  try await player.play()
165
137
  }
166
138
 
167
- func pause() {
168
- player.pause()
169
- }
139
+ func halt() { ApplicationMusicPlayer.shared.pause() }
170
140
 
171
- func skipToNext() async throws {
172
- try await player.skipToNextEntry()
173
- }
141
+ func forward() async throws { try await ApplicationMusicPlayer.shared.skipToNextEntry() }
174
142
  ```
175
143
 
176
- ### Observing Playback State
144
+ The player is not `Sendable`. Read `.shared` where it is used; a global
145
+ `let player`, or a property on a main-actor type, fails Swift 6 checking once
146
+ an async method is called on it. The snippets below use `player` for
147
+ `ApplicationMusicPlayer.shared`.
148
+
149
+ `player.state` is observable, so SwiftUI redraws when it changes. Branch on
150
+ `playbackStatus`:
177
151
 
178
152
  ```swift
179
- func observePlayback() {
180
- // player.state is an @Observable property
181
- let state = player.state
182
- switch state.playbackStatus {
183
- case .playing:
184
- break
185
- case .paused:
186
- break
187
- case .stopped, .interrupted, .seekingForward, .seekingBackward:
188
- break
189
- @unknown default:
190
- break
191
- }
153
+ switch player.state.playbackStatus {
154
+ case .playing: label = "Playing"
155
+ case .paused: label = "Paused"
156
+ case .stopped: label = "Stopped"
157
+ case .interrupted: label = "Interrupted"
158
+ case .seekingForward,
159
+ .seekingBackward: label = "Seeking"
160
+ @unknown default: label = ""
192
161
  }
193
162
  ```
194
163
 
195
- ## Queue Management
164
+ ## Queue management
196
165
 
197
- Build and manipulate the playback queue using `ApplicationMusicPlayer.Queue`.
166
+ `player.queue` is an `ApplicationMusicPlayer.Queue`. Assigning a collection
167
+ replaces it, and an album or playlist works as well as songs:
198
168
 
199
169
  ```swift
200
- // Initialize with multiple items
201
- func playAlbum(_ album: Album) async throws {
202
- player.queue = [album]
203
- try await player.play()
204
- }
170
+ player.queue = [albumToPlay]
171
+ ```
205
172
 
206
- // Append songs to the existing queue
207
- func appendToQueue(_ songs: [Song]) async throws {
208
- try await player.queue.insert(songs, position: .tail)
209
- }
173
+ To add without replacing:
210
174
 
211
- // Insert song to play next
212
- func playNext(_ song: Song) async throws {
213
- try await player.queue.insert(song, position: .afterCurrentEntry)
214
- }
175
+ ```swift
176
+ try await player.queue.insert(extraTracks, position: .tail) // at the end
177
+ try await player.queue.insert(nextUp, position: .afterCurrentEntry) // play next
215
178
  ```
216
179
 
217
- ## Now Playing Info
180
+ ## Now Playing info
218
181
 
219
- Update `MPNowPlayingInfoCenter` so the Lock Screen, Control Center, and CarPlay
220
- display current track metadata. This is essential when playing custom audio
221
- (non-MusicKit sources). `ApplicationMusicPlayer` handles this automatically for
222
- Apple Music content.
182
+ `MPNowPlayingInfoCenter` feeds the Lock Screen, Control Center and CarPlay.
183
+ When `ApplicationMusicPlayer` plays Apple Music content, the system fills this
184
+ in for you. Write it yourself only for audio the app plays some other way, such
185
+ as an `AVPlayer` streaming podcasts.
223
186
 
224
187
  ```swift
225
- import MediaPlayer
226
-
227
- func updateNowPlaying(title: String, artist: String, duration: TimeInterval, elapsed: TimeInterval) {
228
- var info = [String: Any]()
229
- info[MPMediaItemPropertyTitle] = title
230
- info[MPMediaItemPropertyArtist] = artist
231
- info[MPMediaItemPropertyPlaybackDuration] = duration
232
- info[MPNowPlayingInfoPropertyElapsedPlaybackTime] = elapsed
233
- info[MPNowPlayingInfoPropertyPlaybackRate] = 1.0
234
- info[MPNowPlayingInfoPropertyMediaType] = MPNowPlayingInfoMediaType.audio.rawValue
235
-
236
- MPNowPlayingInfoCenter.default().nowPlayingInfo = info
188
+ func publishNowPlaying(for episode: Episode, position: TimeInterval) {
189
+ MPNowPlayingInfoCenter.default().nowPlayingInfo = [
190
+ MPMediaItemPropertyTitle: episode.title,
191
+ MPMediaItemPropertyArtist: episode.showName,
192
+ MPMediaItemPropertyPlaybackDuration: episode.length,
193
+ MPNowPlayingInfoPropertyElapsedPlaybackTime: position,
194
+ MPNowPlayingInfoPropertyPlaybackRate: 1.0,
195
+ MPNowPlayingInfoPropertyMediaType: MPNowPlayingInfoMediaType.audio.rawValue
196
+ ]
237
197
  }
238
198
 
239
199
  func clearNowPlaying() {
@@ -241,184 +201,98 @@ func clearNowPlaying() {
241
201
  }
242
202
  ```
243
203
 
244
- ### Adding Artwork
204
+ Artwork goes in under `MPMediaItemPropertyArtwork`. Merge it into the existing
205
+ dictionary rather than replacing the whole thing:
245
206
 
246
207
  ```swift
247
- func setArtwork(_ image: UIImage) {
248
- let artwork = MPMediaItemArtwork(boundsSize: image.size) { _ in image }
208
+ func attachCover(_ cover: UIImage) {
209
+ let art = MPMediaItemArtwork(boundsSize: cover.size) { _ in cover }
249
210
  var info = MPNowPlayingInfoCenter.default().nowPlayingInfo ?? [:]
250
- info[MPMediaItemPropertyArtwork] = artwork
211
+ info[MPMediaItemPropertyArtwork] = art
251
212
  MPNowPlayingInfoCenter.default().nowPlayingInfo = info
252
213
  }
253
214
  ```
254
215
 
255
- ## Remote Command Center
256
-
257
- Register handlers for `MPRemoteCommandCenter` to respond to Lock Screen controls,
258
- AirPods tap gestures, and CarPlay buttons.
216
+ Refresh the elapsed time on a timer or at each seek, so the Lock Screen
217
+ scrubber stays accurate.
259
218
 
260
- ```swift
261
- func setupRemoteCommands() {
262
- let center = MPRemoteCommandCenter.shared()
263
-
264
- center.playCommand.addTarget { _ in
265
- resumePlayback()
266
- return .success
267
- }
268
-
269
- center.pauseCommand.addTarget { _ in
270
- pausePlayback()
271
- return .success
272
- }
219
+ ## Remote commands
273
220
 
274
- center.nextTrackCommand.addTarget { _ in
275
- skipToNext()
276
- return .success
277
- }
221
+ `MPRemoteCommandCenter.shared()` receives Lock Screen buttons, AirPods taps and
222
+ CarPlay controls. Register the handlers from the main actor so they can call a
223
+ main-actor engine directly; `EpisodeEngine` stands for that type.
278
224
 
279
- center.previousTrackCommand.addTarget { _ in
280
- skipToPrevious()
281
- return .success
282
- }
225
+ ```swift
226
+ @MainActor
227
+ func wireRemoteControls(to engine: EpisodeEngine) {
228
+ let commands = MPRemoteCommandCenter.shared()
283
229
 
284
- // Disable commands you do not support
285
- center.seekForwardCommand.isEnabled = false
286
- center.seekBackwardCommand.isEnabled = false
287
- }
288
- ```
230
+ commands.playCommand.addTarget { _ in engine.resume(); return .success }
231
+ commands.pauseCommand.addTarget { _ in engine.suspend(); return .success }
232
+ commands.nextTrackCommand.addTarget { _ in engine.advance(); return .success }
233
+ commands.previousTrackCommand.addTarget { _ in engine.rewind(); return .success }
289
234
 
290
- ### Scrubbing Support
235
+ commands.seekForwardCommand.isEnabled = false
236
+ commands.seekBackwardCommand.isEnabled = false
291
237
 
292
- ```swift
293
- func enableScrubbing() {
294
- let center = MPRemoteCommandCenter.shared()
295
- center.changePlaybackPositionCommand.addTarget { event in
296
- guard let positionEvent = event as? MPChangePlaybackPositionCommandEvent else {
238
+ commands.changePlaybackPositionCommand.addTarget { event in
239
+ guard let jump = event as? MPChangePlaybackPositionCommandEvent else {
297
240
  return .commandFailed
298
241
  }
299
- seek(to: positionEvent.positionTime)
242
+ engine.move(to: jump.positionTime)
300
243
  return .success
301
244
  }
302
245
  }
303
246
  ```
304
247
 
305
- ## Common Mistakes
306
-
307
- ### DON'T: Skip MusicKit App Service setup or usage description
308
-
309
- Without the MusicKit App Service on the app's explicit bundle ID, automatic
310
- developer token generation for Apple Music API requests is not configured.
311
- Without `NSAppleMusicUsageDescription`, the app cannot access the user's media
312
- library on Apple platforms that require the purpose string.
313
-
314
- ```swift
315
- // WRONG: MusicKit App Service not enabled for this bundle ID
316
-
317
- // CORRECT: Enable MusicKit App Service in the developer portal,
318
- // set the matching bundle ID, then add NSAppleMusicUsageDescription.
319
- let status = await MusicAuthorization.request()
320
- ```
321
-
322
- ### DON'T: Forget to check subscription before playback
323
-
324
- Attempting to play catalog content without a subscription silently fails or throws.
325
-
326
- ```swift
327
- // WRONG
328
- func play(_ song: Song) async throws {
329
- player.queue = [song]
330
- try await player.play() // Fails if no subscription
331
- }
332
-
333
- // CORRECT
334
- func play(_ song: Song) async throws {
335
- let sub = try await MusicSubscription.current
336
- guard sub.canPlayCatalogContent else {
337
- showSubscriptionOffer()
338
- return
339
- }
340
- player.queue = [song]
341
- try await player.play()
342
- }
343
- ```
344
-
345
- ### DON'T: Use SystemMusicPlayer when you mean ApplicationMusicPlayer
346
-
347
- `SystemMusicPlayer` controls the global Music app queue. Changes affect the user's
348
- Music app state. Use `ApplicationMusicPlayer` for app-scoped playback.
349
-
350
- ```swift
351
- // WRONG: Modifies the user's Music app queue
352
- let player = SystemMusicPlayer.shared
353
-
354
- // CORRECT: App-scoped playback
355
- let player = ApplicationMusicPlayer.shared
356
- ```
357
-
358
- ### DON'T: Forget to update Now Playing info when track changes
359
-
360
- Stale metadata on the Lock Screen confuses users. Update Now Playing info
361
- every time the current track changes.
362
-
363
- ```swift
364
- // WRONG: Set once and forget
365
- updateNowPlaying(title: firstSong.title, ...)
366
-
367
- // CORRECT: Update on every track change
368
- func onTrackChanged(_ song: Song) {
369
- updateNowPlaying(
370
- title: song.title,
371
- artist: song.artistName,
372
- duration: song.duration ?? 0,
373
- elapsed: 0
374
- )
375
- }
376
- ```
377
-
378
- ### DON'T: Register remote commands without handling them
379
-
380
- Registering a command but returning `.commandFailed` breaks Lock Screen controls.
381
- Disable commands you do not support instead.
382
-
383
- ```swift
384
- // WRONG
385
- center.skipForwardCommand.addTarget { _ in .commandFailed }
386
-
387
- // CORRECT
388
- center.skipForwardCommand.isEnabled = false
389
- ```
390
-
391
- ## Review Checklist
392
-
393
- - [ ] MusicKit App Service enabled for the app's explicit bundle ID
394
- - [ ] `NSAppleMusicUsageDescription` added to Info.plist
395
- - [ ] `MusicAuthorization.request()` called before any MusicKit access
396
- - [ ] Subscription checked before attempting catalog playback
397
- - [ ] `canBecomeSubscriber` checked before presenting a subscription offer
248
+ ## Common mistakes
249
+
250
+ - **Skipping portal or plist setup.** Without the MusicKit App Service there is
251
+ no automatic developer token; without `NSAppleMusicUsageDescription`, library
252
+ access fails where it is required.
253
+ - **Playing catalog items without a subscription.** Playback fails quietly or
254
+ throws. Check `canPlayCatalogContent` first and show the offer when it is
255
+ false.
256
+ - **Reaching for `SystemMusicPlayer`.** It drives the Music app's global queue
257
+ and changes the user's own listening state. App-scoped playback belongs in
258
+ `ApplicationMusicPlayer`.
259
+ - **Stale Now Playing data.** For custom audio, rewrite the dictionary on every
260
+ track change: title, artist, duration (use `track.duration ?? 0` when it is
261
+ optional) and an elapsed time reset to 0.
262
+ - **Registering commands you cannot honor.** A handler that returns
263
+ `.commandFailed` leaves a dead button on the Lock Screen. Turn the command off
264
+ instead, for example `MPRemoteCommandCenter.shared().skipForwardCommand.isEnabled = false`.
265
+
266
+ ## Review checklist
267
+
268
+ - [ ] MusicKit App Service enabled on the explicit App ID
269
+ - [ ] `NSAppleMusicUsageDescription` present
270
+ - [ ] `MusicAuthorization.request()` runs before any MusicKit access
271
+ - [ ] Subscription checked before catalog playback
272
+ - [ ] `canBecomeSubscriber` checked before the offer is shown
273
+ - [ ] Offer shown when the user is not subscribed
398
274
  - [ ] `hasCloudLibraryEnabled` checked before library writes
399
- - [ ] `ApplicationMusicPlayer` used (not `SystemMusicPlayer`) for app-scoped playback
400
- - [ ] Background audio mode enabled if music plays in background
401
- - [ ] Now Playing info updated on every track change (for custom audio)
402
- - [ ] Remote command handlers return `.success` for supported commands
403
- - [ ] Unsupported remote commands disabled with `isEnabled = false`
404
- - [ ] Artwork provided in Now Playing info for Lock Screen display
405
- - [ ] Elapsed playback time updated periodically for scrubber accuracy
406
- - [ ] Subscription offer presented when user lacks Apple Music subscription
275
+ - [ ] `ApplicationMusicPlayer` used, not `SystemMusicPlayer`
276
+ - [ ] `audio` background mode set if playback continues in the background
277
+ - [ ] Now Playing updated on each track change (custom audio)
278
+ - [ ] Artwork supplied for the Lock Screen
279
+ - [ ] Elapsed time refreshed so the scrubber is accurate
280
+ - [ ] Supported remote commands return `.success`; unsupported ones are disabled
407
281
 
408
282
  ## References
409
283
 
410
- - Extended patterns (SwiftUI integration, genre browsing, playlist management): [references/musickit-patterns.md](references/musickit-patterns.md)
411
- - [MusicKit framework](https://sosumi.ai/documentation/musickit)
412
- - [Using automatic developer token generation for Apple Music API](https://sosumi.ai/documentation/musickit/using-automatic-token-generation-for-apple-music-api)
413
- - [MusicAuthorization](https://sosumi.ai/documentation/musickit/musicauthorization)
414
- - [ApplicationMusicPlayer](https://sosumi.ai/documentation/musickit/applicationmusicplayer)
415
- - [MusicCatalogSearchRequest](https://sosumi.ai/documentation/musickit/musiccatalogsearchrequest)
416
- - [MusicSubscription](https://sosumi.ai/documentation/musickit/musicsubscription)
417
- - [canPlayCatalogContent](https://sosumi.ai/documentation/musickit/musicsubscription/canplaycatalogcontent)
418
- - [canBecomeSubscriber](https://sosumi.ai/documentation/musickit/musicsubscription/canbecomesubscriber)
419
- - [hasCloudLibraryEnabled](https://sosumi.ai/documentation/musickit/musicsubscription/hascloudlibraryenabled)
420
- - [MusicCatalogChartsRequest initializer](https://sosumi.ai/documentation/musickit/musiccatalogchartsrequest/init(genre:kinds:types:))
421
- - [musicSubscriptionOffer(isPresented:options:onLoadCompletion:)](https://sosumi.ai/documentation/swiftui/view/musicsubscriptionoffer(ispresented:options:onloadcompletion:))
422
- - [MPRemoteCommandCenter](https://sosumi.ai/documentation/mediaplayer/mpremotecommandcenter)
423
- - [MPNowPlayingInfoCenter](https://sosumi.ai/documentation/mediaplayer/mpnowplayinginfocenter)
424
- - [NSAppleMusicUsageDescription](https://sosumi.ai/documentation/bundleresources/information-property-list/nsapplemusicusagedescription)
284
+ - [references/musickit-patterns.md](references/musickit-patterns.md)
285
+ - [MusicKit](https://developer.apple.com/documentation/musickit)
286
+ - [Using automatic developer token generation](https://developer.apple.com/documentation/musickit/using-automatic-developer-token-generation-for-apple-music-api)
287
+ - [MusicAuthorization](https://developer.apple.com/documentation/musickit/musicauthorization)
288
+ - [ApplicationMusicPlayer](https://developer.apple.com/documentation/musickit/applicationmusicplayer)
289
+ - [MusicCatalogSearchRequest](https://developer.apple.com/documentation/musickit/musiccatalogsearchrequest)
290
+ - [MusicSubscription](https://developer.apple.com/documentation/musickit/musicsubscription)
291
+ - [canPlayCatalogContent](https://developer.apple.com/documentation/musickit/musicsubscription/canplaycatalogcontent)
292
+ - [canBecomeSubscriber](https://developer.apple.com/documentation/musickit/musicsubscription/canbecomesubscriber)
293
+ - [hasCloudLibraryEnabled](https://developer.apple.com/documentation/musickit/musicsubscription/hascloudlibraryenabled)
294
+ - [MusicCatalogChartsRequest init(genre:kinds:types:)](https://developer.apple.com/documentation/musickit/musiccatalogchartsrequest/init(genre:kinds:types:))
295
+ - [musicSubscriptionOffer(isPresented:options:onLoadCompletion:)](https://developer.apple.com/documentation/swiftui/view/musicsubscriptionoffer(ispresented:options:onloadcompletion:))
296
+ - [MPRemoteCommandCenter](https://developer.apple.com/documentation/mediaplayer/mpremotecommandcenter)
297
+ - [MPNowPlayingInfoCenter](https://developer.apple.com/documentation/mediaplayer/mpnowplayinginfocenter)
298
+ - [NSAppleMusicUsageDescription](https://developer.apple.com/documentation/bundleresources/information-property-list/nsapplemusicusagedescription)