@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,216 +1,222 @@
1
1
  ---
2
2
  name: live-activities
3
- description: "Implement, review, or improve Live Activities and Dynamic Island experiences in iOS apps using ActivityKit. Use when building real-time updating widgets for the Lock Screen and Dynamic Island - delivery tracking, sports scores, ride-sharing status, workout timers, media playback, or any time-sensitive information that updates in real time. Also use when working with ActivityKit, ActivityAttributes, Activity lifecycle (request/update/end), Dynamic Island layouts (compact/minimal/expanded), push-to-update Live Activities, or Lock Screen live widgets."
3
+ description: "ActivityKit Live Activities on the Lock Screen and Dynamic Island: ActivityAttributes and ContentState, request/update/end lifecycle, compact, minimal and expanded layouts, stale dates, push-to-update, push-to-start and channel pushes, update tokens, scheduled starts, ActivityStyle. Use when building, reviewing or improving glanceable live status (delivery tracking, scores, rides, workout timers, media playback) or sending Live Activity APNs payloads. Not for Home Screen or timeline widgets (widgetkit) or generic APNs setup (push-notifications)."
4
4
  metadata:
5
- source: "dpearson2699/swift-ios-skills (PolyForm Perimeter 1.0.0)"
5
+ source: multi-agent-pipeline
6
6
  ---
7
7
 
8
- # ActivityKit
9
-
10
- ActivityKit owns real-time, glanceable Live Activities displayed on the Lock
11
- Screen and, on supported devices, Dynamic Island. StandBy, CarPlay, and a
12
- paired Mac can also display Live Activities, but do not blur that core routing:
13
- ordinary Home Screen/timeline widgets belong in `widgetkit`, and generic APNs
14
- setup belongs in `push-notifications`. Live Activity push payload shape stays in
15
- ActivityKit: device-token updates use `apns-push-type: liveactivity` and
16
- `apns-topic: <bundle-id>.push-type.liveactivity`, while `aps.content-state` must
17
- decode into the app's actual `ActivityAttributes.ContentState` `Codable` shape.
18
- Do not assume `Date` or `ClosedRange<Date>` use Unix timestamp
19
- `lowerBound`/`upperBound` dictionaries unless the Swift model and server
20
- contract coordinate that encoding. Boundary answers that keep ActivityKit APNs
21
- payloads, `content-state`, or Live Activity data contracts in scope should
22
- include these payload-shape invariants even when routing generic APNs setup
23
- elsewhere. Patterns target iOS 26+ with Swift 6.3;
24
- modern `ActivityContent` lifecycle examples require iOS 16.2+ unless noted.
25
-
26
- See [references/activitykit-patterns.md](references/activitykit-patterns.md) for complete code patterns including push payload formats, concurrent activities, state observation, and testing.
27
-
28
- ## Contents
29
-
30
- - [Workflow](#workflow)
31
- - [ActivityAttributes Definition](#activityattributes-definition)
32
- - [Activity Lifecycle](#activity-lifecycle)
33
- - [Lock Screen Presentation](#lock-screen-presentation)
34
- - [Dynamic Island](#dynamic-island)
35
- - [Push-to-Update](#push-to-update)
36
- - [Recent Additions](#recent-additions)
37
- - [Common Mistakes](#common-mistakes)
38
- - [Review Checklist](#review-checklist)
39
- - [References](#references)
8
+ # Live Activities (ActivityKit)
9
+
10
+ A Live Activity is a small, time-boxed status card that ActivityKit keeps on the
11
+ Lock Screen and, on hardware that has one, in the Dynamic Island. A paired
12
+ Mac, CarPlay and StandBy may mirror the same card; none of that changes where
13
+ the work lives. The code and the push contract belong here.
14
+
15
+ Boundaries:
16
+
17
+ - Home Screen widgets, `TimelineProvider` and timeline reloads are `widgetkit`
18
+ work. A Live Activity is driven by the ActivityKit lifecycle, not a timeline.
19
+ - APNs auth keys, certificates and app-level remote-notification registration
20
+ are `push-notifications` work.
21
+ - The Live Activity payload itself stays here, even in an answer that routes
22
+ the rest of APNs away. Always state the two invariants:
23
+ - token pushes carry `apns-push-type: liveactivity` and
24
+ `apns-topic: BUNDLE_ID.push-type.liveactivity`;
25
+ - the JSON in `aps.content-state` is decoded with the app's own
26
+ `ActivityAttributes.ContentState` `Codable` conformance, so it has to
27
+ match that shape exactly. `Date` and
28
+ `ClosedRange<Date>` have no universal wire format: do not assume a Unix
29
+ timestamp or a `lowerBound`/`upperBound` object unless the Swift model and
30
+ the server were written to agree on it.
31
+
32
+ Examples target iOS 26 and Swift 6.3. Anything built on `ActivityContent`
33
+ needs iOS 16.2 or later unless a section says otherwise. Longer patterns (a
34
+ full attributes model, server payloads, concurrent activities, state
35
+ observation, errors, testing) are in the
36
+ [patterns reference](references/activitykit-patterns.md).
40
37
 
41
38
  ## Workflow
42
39
 
43
- ### 1. Create a new Live Activity
40
+ ### Adding a Live Activity
44
41
 
45
- 1. Add `NSSupportsLiveActivities = YES` to the host app's Info.plist.
46
- 2. Define an `ActivityAttributes` struct with a nested `ContentState`.
47
- 3. Create an `ActivityConfiguration` in the widget bundle with Lock Screen
48
- content and Dynamic Island closures.
49
- 4. Start the activity with `Activity.request(attributes:content:pushType:)`.
50
- 5. Update with `activity.update(_:)` and end with `activity.end(_:dismissalPolicy:)`.
51
- 6. Forward push tokens to your server for remote updates.
42
+ 1. In the main app target's Info.plist, turn on `NSSupportsLiveActivities`
43
+ (`YES`).
44
+ 2. Declare an `ActivityAttributes` type with a nested `ContentState`.
45
+ 3. In the widget extension's bundle, add an `ActivityConfiguration` that
46
+ supplies the Lock Screen view and the Dynamic Island closures.
47
+ 4. Start it: `Activity.request(attributes:content:pushType:)`.
48
+ 5. Change it with `activity.update(_:)` and finish it with
49
+ `activity.end(_:dismissalPolicy:)`.
50
+ 6. If a server will drive it, send the activity's push token to that server.
52
51
 
53
- ### 2. Review existing Live Activity code
52
+ ### Reviewing one
54
53
 
55
- Run through the Review Checklist at the end of this document.
54
+ Go through the [Review checklist](#review-checklist) item by item.
56
55
 
57
- ## ActivityAttributes Definition
56
+ ## Modelling the data
58
57
 
59
- Define both static data (immutable for the activity lifetime) and dynamic
60
- `ContentState` (changes with each update). Keep `ContentState` small because
61
- the entire struct is serialized on every update and push payload.
58
+ Two layers, with different lifetimes:
59
+
60
+ - Properties on the attributes struct are fixed for the whole life of the
61
+ activity.
62
+ - `ContentState` carries whatever changes. The entire value is encoded on
63
+ every update and in every push, so keep it lean.
62
64
 
63
65
  ```swift
64
66
  import ActivityKit
65
67
 
66
- struct DeliveryAttributes: ActivityAttributes {
67
- // Static -- set once at activity creation, never changes
68
- var orderNumber: Int
69
- var restaurantName: String
70
-
71
- // Dynamic -- updated throughout the activity lifetime
68
+ struct ChargingAttributes: ActivityAttributes {
72
69
  struct ContentState: Codable, Hashable {
73
- var driverName: String
74
- var estimatedDeliveryTime: ClosedRange<Date>
75
- var currentStep: DeliveryStep
70
+ var batteryPercent: Int
71
+ var finishWindow: ClosedRange<Date>
72
+ var phase: ChargePhase
76
73
  }
74
+
75
+ var stationName: String
76
+ var connectorLabel: String
77
77
  }
78
78
 
79
- enum DeliveryStep: String, Codable, Hashable, CaseIterable {
80
- case confirmed, preparing, pickedUp, delivering, delivered
79
+ enum ChargePhase: String, Codable, Hashable, CaseIterable {
80
+ case queued, connecting, charging, balancing, complete
81
81
 
82
- var icon: String {
82
+ var symbolName: String {
83
83
  switch self {
84
- case .confirmed: "checkmark.circle"
85
- case .preparing: "frying.pan"
86
- case .pickedUp: "bag.fill"
87
- case .delivering: "box.truck.fill"
88
- case .delivered: "house.fill"
84
+ case .queued: "hourglass"
85
+ case .connecting: "powerplug"
86
+ case .charging: "bolt.car"
87
+ case .balancing: "slider.horizontal.3"
88
+ case .complete: "checkmark.circle.fill"
89
89
  }
90
90
  }
91
91
  }
92
92
  ```
93
93
 
94
- ### Stale Date
94
+ ### Stale date
95
95
 
96
- Set `staleDate` on `ActivityContent` to tell the system when content becomes outdated. The system sets `context.isStale` to `true` after this date; show fallback UI (e.g., "Updating...") in your views.
96
+ `ActivityContent` takes a `staleDate`. Once that moment passes without a newer
97
+ update, the system flips `context.isStale` to `true`, and the view should swap
98
+ in a fallback such as a "Refreshing" label instead of showing a number that may
99
+ be wrong.
97
100
 
98
101
  ```swift
99
- let content = ActivityContent(
102
+ let snapshot = ActivityContent(
100
103
  state: state,
101
- staleDate: Date().addingTimeInterval(300), // stale after 5 minutes
104
+ staleDate: .now.addingTimeInterval(5 * 60),
102
105
  relevanceScore: 75
103
106
  )
104
107
  ```
105
108
 
106
- ## Activity Lifecycle
109
+ ## Lifecycle
107
110
 
108
- ### Starting
111
+ ### Start
109
112
 
110
- Use `Activity.request` to create and display a Live Activity. Pass `.token` as
111
- the `pushType` to enable remote updates via APNs. The `ActivityContent` request
112
- shown here requires iOS 16.2+.
113
+ `Activity.request` creates the activity and puts it on screen. Pass
114
+ `pushType: .token` when a server should be able to update it. The
115
+ `ActivityContent` form of `request` is iOS 16.2+.
113
116
 
114
117
  ```swift
115
- let attributes = DeliveryAttributes(orderNumber: 42, restaurantName: "Pizza Place")
116
- let state = DeliveryAttributes.ContentState(
117
- driverName: "Alex",
118
- estimatedDeliveryTime: Date()...Date().addingTimeInterval(1800),
119
- currentStep: .preparing
120
- )
121
- let content = ActivityContent(state: state, staleDate: nil, relevanceScore: 75)
122
-
123
- do {
124
- let activity = try Activity.request(
125
- attributes: attributes,
126
- content: content,
127
- pushType: .token
118
+ func beginCharging(at station: String) {
119
+ let attributes = ChargingAttributes(stationName: station, connectorLabel: "B2")
120
+ let window = Date.now...Date.now.addingTimeInterval(30 * 60)
121
+ let initial = ChargingAttributes.ContentState(
122
+ batteryPercent: 18, finishWindow: window, phase: .connecting
128
123
  )
129
- print("Started activity: \(activity.id)")
130
- } catch {
131
- print("Failed to start activity: \(error)")
124
+ do {
125
+ let activity = try Activity.request(
126
+ attributes: attributes,
127
+ content: ActivityContent(state: initial, staleDate: nil, relevanceScore: 75),
128
+ pushType: .token
129
+ )
130
+ sessionStore.remember(activity.id)
131
+ } catch {
132
+ logger.error("Live Activity refused: \(error.localizedDescription)")
133
+ }
132
134
  }
133
135
  ```
134
136
 
135
- ### Updating
137
+ ### Update
136
138
 
137
- Update the dynamic content state from the app. Use `AlertConfiguration` to
138
- trigger a visible banner and sound alongside the update.
139
+ `await activity.update(content)` changes the card silently. To also light the
140
+ screen with a banner and a sound, use `update(_:alertConfiguration:)`:
139
141
 
140
142
  ```swift
141
- let updatedState = DeliveryAttributes.ContentState(
142
- driverName: "Alex",
143
- estimatedDeliveryTime: Date()...Date().addingTimeInterval(600),
144
- currentStep: .delivering
145
- )
146
- let updatedContent = ActivityContent(
147
- state: updatedState,
148
- staleDate: Date().addingTimeInterval(300),
143
+ let next = ActivityContent(
144
+ state: newState,
145
+ staleDate: .now.addingTimeInterval(300),
149
146
  relevanceScore: 90
150
147
  )
151
-
152
- // Silent update
153
- await activity.update(updatedContent)
154
-
155
- // Update with an alert
156
- await activity.update(updatedContent, alertConfiguration: AlertConfiguration(
157
- title: "Order Update",
158
- body: "Your driver is nearby!",
159
- sound: .default
160
- ))
148
+ await activity.update(
149
+ next,
150
+ alertConfiguration: AlertConfiguration(
151
+ title: "Almost full",
152
+ body: "Battery is at 95 percent.",
153
+ sound: .default
154
+ )
155
+ )
161
156
  ```
162
157
 
163
- ### Ending
158
+ ### End
159
+
160
+ End the activity when the thing it tracks is over. The dismissal policy decides
161
+ how long the ended card lingers on the Lock Screen:
164
162
 
165
- End the activity when the tracked event completes. Choose a dismissal policy
166
- to control how long the ended activity lingers on the Lock Screen.
163
+ | Policy | Removal |
164
+ |---|---|
165
+ | `.default` | The system chooses, at most 4 hours later |
166
+ | `.immediate` | Right away |
167
+ | `.after(date)` | At `date`, no later than 4 hours from now |
167
168
 
168
169
  ```swift
169
- let finalState = DeliveryAttributes.ContentState(
170
- driverName: "Alex",
171
- estimatedDeliveryTime: Date()...Date(),
172
- currentStep: .delivered
170
+ let closing = ChargingAttributes.ContentState(
171
+ batteryPercent: 100, finishWindow: Date.now...Date.now, phase: .complete
173
172
  )
174
- let finalContent = ActivityContent(state: finalState, staleDate: nil, relevanceScore: 0)
175
-
176
- // System decides when to remove (up to 4 hours)
177
- await activity.end(finalContent, dismissalPolicy: .default)
173
+ await activity.end(
174
+ ActivityContent(state: closing, staleDate: nil, relevanceScore: 0),
175
+ dismissalPolicy: .after(.now.addingTimeInterval(3600))
176
+ )
177
+ ```
178
178
 
179
- // Remove immediately
180
- await activity.end(finalContent, dismissalPolicy: .immediate)
179
+ End on every terminal path, not just the happy one: success, cancellation by
180
+ the user or the app, sign-out or session teardown, an app error you cannot
181
+ recover from, and a terminal failure reported by the server. If the backend
182
+ reports that the tracked event is over or that its status is no longer
183
+ reliable, push or apply a
184
+ final terminal state and end; never leave frozen progress on the Lock Screen.
181
185
 
182
- // Remove after a specific time (max 4 hours from now)
183
- await activity.end(finalContent, dismissalPolicy: .after(Date().addingTimeInterval(3600)))
184
- ```
186
+ Time limits, which are easy to conflate:
185
187
 
186
- Always end activities on all terminal code paths -- success, user/app
187
- cancellation, sign-out/session stop, unrecoverable app error, and terminal server
188
- failure. If the server says the tracked event can no longer continue or be
189
- represented accurately, apply or send a final terminal state and end the activity
190
- instead of leaving stale progress visible. When reviewing duration claims,
191
- distinguish the active lifetime (up to 8 hours unless the app or user ends it
192
- sooner), system-ended Lock Screen presence (up to 4 additional hours, for 12
193
- hours total from start), and app-ended `.default` dismissal linger (up to 4 hours
194
- after ending).
188
+ - The active phase lasts at most 8 hours; the app or the user may end it
189
+ earlier.
190
+ - When the system ends it at that limit, the card may remain on the Lock Screen
191
+ for up to 4 more hours, 12 hours in total from the start.
192
+ - When the app ends it with `.default`, the card can stay visible for as much
193
+ as 4 hours past the end call.
195
194
 
196
- ## Lock Screen Presentation
195
+ ## Lock Screen
197
196
 
198
- The Lock Screen is the primary Live Activity display surface. Every device with
199
- iOS 16.1+ displays Live Activities here. Design this layout first, then adapt
200
- for Dynamic Island where available.
197
+ The Lock Screen is the surface that always exists: every device on iOS 16.1 or
198
+ later shows Live Activities there. Lay it out first, then squeeze it into the
199
+ Dynamic Island.
201
200
 
202
201
  ```swift
203
- struct DeliveryActivityWidget: Widget {
204
- var body: some WidgetConfiguration {
205
- ActivityConfiguration(for: DeliveryAttributes.self) { context in
206
- VStack(alignment: .leading) {
207
- Text(context.attributes.restaurantName).font(.headline)
202
+ import SwiftUI
203
+ import WidgetKit
208
204
 
205
+ struct ChargingLiveActivity: Widget {
206
+ var body: some WidgetConfiguration {
207
+ ActivityConfiguration(for: ChargingAttributes.self) { context in
208
+ HStack(spacing: 12) {
209
+ Image(systemName: context.state.phase.symbolName)
210
+ VStack(alignment: .leading) {
211
+ Text(context.attributes.stationName).font(.headline)
212
+ Text("\(context.state.batteryPercent)%")
213
+ }
214
+ Spacer()
209
215
  if context.isStale {
210
- Label("Updating...", systemImage: "arrow.trianglehead.2.clockwise")
216
+ Label("Refreshing", systemImage: "arrow.trianglehead.2.clockwise")
211
217
  .foregroundStyle(.secondary)
212
218
  } else {
213
- Text(timerInterval: context.state.estimatedDeliveryTime, countsDown: true)
219
+ Text(timerInterval: context.state.finishWindow, countsDown: true)
214
220
  .monospacedDigit()
215
221
  }
216
222
  }
@@ -218,274 +224,226 @@ struct DeliveryActivityWidget: Widget {
218
224
  } dynamicIsland: { context in
219
225
  DynamicIsland {
220
226
  DynamicIslandExpandedRegion(.center) {
221
- Text(context.attributes.restaurantName).font(.headline)
227
+ Text(context.attributes.stationName)
222
228
  }
223
229
  DynamicIslandExpandedRegion(.trailing) {
224
- Text(timerInterval: context.state.estimatedDeliveryTime, countsDown: true)
230
+ Text("\(context.state.batteryPercent)%")
225
231
  }
226
232
  } compactLeading: {
227
- Image(systemName: "box.truck.fill")
233
+ Image(systemName: "bolt.car")
228
234
  } compactTrailing: {
229
- Text(timerInterval: context.state.estimatedDeliveryTime, countsDown: true)
235
+ Text(timerInterval: context.state.finishWindow, countsDown: true)
236
+ .monospacedDigit()
230
237
  } minimal: {
231
- Image(systemName: "box.truck.fill")
238
+ Image(systemName: "bolt.car")
232
239
  }
233
240
  }
234
241
  }
235
242
  }
236
243
  ```
237
244
 
238
- ### Supplemental Activity Families
245
+ Static values come from `context.attributes`; changing values from
246
+ `context.state`.
239
247
 
240
- The Lock Screen presentation has limited vertical space. Avoid layouts taller
241
- than roughly 160 points. On iOS 18+, use `supplementalActivityFamilies` when
242
- you provide adaptive layouts beyond the default: `.medium` for iOS/macOS
243
- Live Activity sizing and `.small` for watchOS Live Activity sizing.
248
+ ### Height and supplemental families
244
249
 
245
- ```swift
246
- ActivityConfiguration(for: DeliveryAttributes.self) { context in
247
- // Lock Screen content
248
- } dynamicIsland: { context in
249
- // Dynamic Island
250
- }
251
- .supplementalActivityFamilies([.medium, .small])
252
- ```
250
+ The Lock Screen gives a Live Activity little vertical room; keep the layout
251
+ under roughly 160 points. From iOS 18,
252
+ `.supplementalActivityFamilies([.small, .medium])` on the
253
+ `ActivityConfiguration` opts into adaptive sizes: `.medium` is the iPhone and
254
+ Mac size, `.small` the Apple Watch size.
253
255
 
254
256
  ## Dynamic Island
255
257
 
256
- Dynamic Island presentations appear only on devices that include Dynamic Island.
257
- Design all three modes, but treat the Lock Screen as the primary surface since
258
- not all devices have a Dynamic Island.
259
-
260
- ### Compact (Leading + Trailing)
261
-
262
- Used when one Live Activity occupies Dynamic Island compact space. Space is
263
- extremely limited -- show only the most critical information.
264
-
265
- | Region | Purpose |
266
- |---|---|
267
- | `compactLeading` | Icon or tiny label identifying the activity |
268
- | `compactTrailing` | One key value (timer, score, status) |
269
-
270
- ### Minimal
271
-
272
- Shown when multiple Live Activities compete for space. Only one activity gets
273
- the minimal slot. Display a single icon or glyph.
274
-
275
- ### Expanded Regions
276
-
277
- Shown when the user long-presses the Dynamic Island.
258
+ Only devices with a Dynamic Island show these presentations. Implement all
259
+ three modes anyway; the Lock Screen remains the main design.
278
260
 
279
- | Region | Position |
280
- |---|---|
281
- | `.leading` | Left of the TrueDepth camera; wraps below |
282
- | `.trailing` | Right of the TrueDepth camera; wraps below |
283
- | `.center` | Directly below the camera |
284
- | `.bottom` | Below all other regions |
285
-
286
- ### Keyline Tint
287
-
288
- Apply a subtle tint to the Dynamic Island border:
289
-
290
- ```swift
291
- DynamicIsland { /* expanded */ }
292
- compactLeading: { /* ... */ }
293
- compactTrailing: { /* ... */ }
294
- minimal: { /* ... */ }
295
- .keylineTint(.blue)
296
- ```
261
+ - **Compact**: one Live Activity owns the island. Show the single most
262
+ important fact.
263
+ - `compactLeading`: an icon or a very short label saying what this is.
264
+ - `compactTrailing`: one value, such as a timer, a score or a status.
265
+ - **Minimal**: several Live Activities compete; one of them gets the minimal
266
+ slot. Show a single glyph.
267
+ - **Expanded**: appears on a long press of the island. Regions:
268
+ - `.leading`: the camera's left side; content can wrap below it.
269
+ - `.trailing`: the camera's right side; content can wrap below it.
270
+ - `.center`: directly below the camera.
271
+ - `.bottom`: below everything else.
297
272
 
298
- ## Push-to-Update
273
+ `.keylineTint(_:)` on the `DynamicIsland` tints the island's outline subtly.
299
274
 
300
- Push-to-update sends Live Activity updates through APNs, which is more
301
- efficient than polling from the app and works when the app is suspended, subject
302
- to APNs delivery, priority, budget, and throttling.
275
+ ## Server-driven updates
303
276
 
304
- ### Setup
277
+ APNs pushes are cheaper than having the app poll, and they reach an activity
278
+ while the app is suspended. They are still subject to APNs delivery, priority,
279
+ the system budget and throttling.
305
280
 
306
- Pass `.token` as the `pushType` when starting the activity, then forward the
307
- per-activity update token to your server. Update tokens can rotate, so observe
308
- `activity.pushTokenUpdates` and re-register every emitted token:
281
+ Setup: request with `pushType: .token`, then give the server the update token
282
+ that belongs to this one activity. Tokens rotate, so consume `activity.pushTokenUpdates` (an async
283
+ sequence of `Data`) for the whole life of the activity and re-register every
284
+ value it emits.
309
285
 
310
286
  ```swift
311
- let activity = try Activity.request(
312
- attributes: attributes,
313
- content: content,
314
- pushType: .token
315
- )
316
-
317
- // Observe token changes -- tokens can rotate
318
287
  Task {
319
- for await token in activity.pushTokenUpdates {
320
- let tokenString = token.map { String(format: "%02x", $0) }.joined()
321
- try await ServerAPI.shared.registerActivityToken(
322
- tokenString, activityID: activity.id
323
- )
288
+ for await tokenData in activity.pushTokenUpdates {
289
+ let hex = tokenData.reduce(into: "") { $0 += String(format: "%02x", $1) }
290
+ try? await backend.registerActivityToken(hex, for: activity.id)
324
291
  }
325
292
  }
326
293
  ```
327
294
 
328
- ### APNs Payload Format
295
+ ### Payload and headers
329
296
 
330
- Send an HTTP/2 POST to APNs with these headers and JSON body:
297
+ Send an HTTP/2 `POST` to APNs carrying these headers:
331
298
 
332
- **Required device-token HTTP headers:**
333
- - `apns-push-type: liveactivity`
334
- - `apns-topic: <bundle-id>.push-type.liveactivity`
335
- - `apns-priority: 5` (lower priority) or `10` (immediate, counts against budget)
299
+ - `apns-push-type: liveactivity` (required)
300
+ - `apns-topic: BUNDLE_ID.push-type.liveactivity` (required)
301
+ - `apns-priority: 5` for low priority, or `10` for immediate delivery that
302
+ counts against the budget
336
303
 
337
- The `aps.alert` payload controls visible alert/banner/sound behavior; priority
338
- alone does not create an alert.
304
+ Priority never produces an alert. A visible banner or sound comes only from an
305
+ `aps.alert` object.
339
306
 
340
- **Payload body:** Put `timestamp`, `event`, and the full `content-state` inside `aps`. Use `event: "update"` for updates, `event: "end"` plus optional `dismissal-date` for ending, and `event: "start"` with `attributes-type`, `attributes`, `content-state`, and required `alert` for push-to-start. Add `stale-date`, `relevance-score`, or `alert` when appropriate.
307
+ Everything sits inside `aps`: `timestamp`, `event`, and the full
308
+ `content-state`.
341
309
 
342
- The `content-state` JSON must decode into `ActivityAttributes.ContentState`. Use the default synthesized `Codable` key and value shape unless the Swift model declares custom `CodingKeys`; then coordinate those exact keys and value shapes server-side. Do not assume `Date` or `ClosedRange<Date>` values are Unix timestamp dictionaries unless your Swift model explicitly encodes them that way. Mismatched keys or types can prevent ActivityKit from applying the update.
310
+ - `"event": "update"` changes the activity.
311
+ - `"event": "end"` ends it; `dismissal-date` is optional.
312
+ - `"event": "start"` is push-to-start; it adds `attributes-type` and
313
+ `attributes` alongside `content-state`, and `alert` is required.
314
+ - Optional on any event: `stale-date`, `relevance-score`, `alert`.
343
315
 
344
- ### Push-to-Start
316
+ `content-state` must decode into `ContentState`. With synthesized `Codable`,
317
+ the keys are the property names and the values use the default encodings. If
318
+ the type has custom `CodingKeys` or custom coding, agree on the exact keys and
319
+ value shapes with the server team. A misspelled key, or a number sent as text,
320
+ can be enough for ActivityKit to drop the update.
345
321
 
346
- Start a Live Activity remotely without the app running (iOS 17.2+). Push-to-start tokens are ActivityKit-specific tokens from `Activity<Attributes>.pushToStartTokenUpdates`; they are distinct from ordinary app/device APNs tokens and per-activity update tokens:
322
+ ### Push-to-start (iOS 17.2+)
347
323
 
348
- ```swift
349
- Task {
350
- for await token in Activity<DeliveryAttributes>.pushToStartTokenUpdates {
351
- let tokenString = token.map { String(format: "%02x", $0) }.joined()
352
- try await ServerAPI.shared.registerPushToStartToken(tokenString)
353
- }
354
- }
355
- ```
324
+ A server can start an activity while the app is not running. The token comes
325
+ from the static sequence `Activity<ChargingAttributes>.pushToStartTokenUpdates`.
326
+ It is neither the app's ordinary device token nor any activity's update token;
327
+ store and send it separately.
356
328
 
357
- ### Frequent Push Updates
329
+ ### Frequent updates
358
330
 
359
- Add `NSSupportsLiveActivitiesFrequentUpdates = YES` to Info.plist to increase
360
- the system-managed push update budget. When cadence matters, check
361
- `ActivityAuthorizationInfo.frequentPushesEnabled` and observe
362
- `frequentPushEnablementUpdates`; Apple does not guarantee a fixed update rate.
331
+ `NSSupportsLiveActivitiesFrequentUpdates = YES` in Info.plist raises the
332
+ system-managed push budget. The user can switch it off, so when cadence
333
+ matters read `ActivityAuthorizationInfo().frequentPushesEnabled` and observe
334
+ `frequentPushEnablementUpdates`. There is no guaranteed update rate; do not
335
+ promise one.
363
336
 
364
- ## Recent Additions
337
+ ## Newer capabilities
365
338
 
366
- ### Scheduled Live Activities (iOS 26+)
339
+ ### ActivityStyle (iOS 18+)
367
340
 
368
- Schedule a Live Activity to start at a future time. The system starts the
369
- activity automatically without the app being in the foreground. Use for events
370
- with known start times (sports games, product launches, scheduled deliveries).
341
+ `Activity.request(...style:)` is available from iOS 18, not only iOS 26.
371
342
 
372
- ```swift
373
- let scheduledDate = Calendar.current.date(
374
- from: DateComponents(year: 2026, month: 3, day: 15, hour: 19, minute: 0)
375
- )!
376
-
377
- let activity = try Activity.request(
378
- attributes: attributes,
379
- content: content,
380
- pushType: .token,
381
- style: .standard,
382
- alertConfiguration: AlertConfiguration(
383
- title: "Game Starting",
384
- body: "The live score is ready.",
385
- sound: .default
386
- ),
387
- start: scheduledDate
388
- )
389
- ```
343
+ - `.standard`: for anything that should persist: deliveries, rides, scores,
344
+ timers, order boards.
345
+ - `.transient`: only for brief expanded Dynamic Island moments. The system may
346
+ end it when the device locks, when the expanded view collapses, when the
347
+ user leaves the app, or when the activity would appear outside the Dynamic
348
+ Island.
390
349
 
391
- ### ActivityStyle (iOS 18+ request parameter)
350
+ ### Scheduled start (iOS 26+)
392
351
 
393
- Use the iOS 18+ `style:` request parameter to choose persistence behavior. Use
394
- `.standard` for persistent Live Activities such as deliveries, rides, sports
395
- scores, timers, and order-status boards. Use `.transient` only for a
396
- short-lived expanded Dynamic Island presentation; it can auto-end when the user
397
- locks the device, collapses or shrinks the expanded presentation, leaves the
398
- app, or does other work outside Dynamic Island.
352
+ For events with a known start time (a match, a product launch, a booked
353
+ delivery slot), schedule the activity and let the system start it without the
354
+ app in the foreground:
399
355
 
400
356
  ```swift
357
+ guard let kickoff = Calendar.current.date(
358
+ from: DateComponents(year: 2026, month: 11, day: 14, hour: 19, minute: 30)
359
+ ) else { return }
401
360
  let activity = try Activity.request(
402
361
  attributes: attributes,
403
362
  content: content,
404
363
  pushType: .token,
405
- style: .standard
406
- )
407
- ```
408
-
409
- ### Paired Mac & CarPlay (iOS 26+)
410
-
411
- Live Activities can appear on a paired Mac and on the CarPlay Home Screen. No additional ActivityKit API is required, but validate compact layouts; buttons and toggles in Live Activities do not perform actions in CarPlay.
412
-
413
- ### Channel-Based Push (iOS 18+)
414
-
415
- Broadcast updates to many Live Activities at once with an APNs-created channel
416
- ID. Enable the broadcast capability outside Xcode, create the channel on the
417
- server, then subscribe with `.channel(channelID)`. Channel pushes update or end
418
- Live Activities; they do not start them. Use `apns-channel-id` and expiration
419
- for channel pushes instead of the device-token `apns-topic` example above.
420
-
421
- ```swift
422
- let activity = try Activity.request(
423
- attributes: attributes, content: content,
424
- pushType: .channel(channelIDFromServer)
364
+ style: .standard,
365
+ alertConfiguration: AlertConfiguration(
366
+ title: "Match starting", body: "Tap to follow live.", sound: .default
367
+ ),
368
+ start: kickoff
425
369
  )
426
370
  ```
427
371
 
428
- ## Common Mistakes
429
-
430
- **DON'T:** Put too much content in the compact presentation -- it is tiny.
431
- **DO:** Show only the most critical info (icon + one value) in compact leading/trailing.
432
-
433
- **DON'T:** Update Live Activities too frequently from the app (drains battery).
434
- **DO:** Use push-to-update for server-driven updates. Limit app-side updates to user actions.
435
-
436
- **DON'T:** Forget to end the activity when the event reaches any terminal state.
437
- **DO:** End activities on success, cancellation, sign-out, unrecoverable errors, and terminal server failures. A leaked activity frustrates users.
438
-
439
- **DON'T:** Assume every device has Dynamic Island.
440
- **DO:** Design for the Lock Screen as the primary surface; Dynamic Island is supplementary.
441
-
442
- **DON'T:** Treat Lock Screen or Dynamic Island Live Activities as ordinary Home Screen/timeline widgets.
443
- **DO:** Use ActivityKit for the Live Activity lifecycle and those display surfaces; route ordinary Home Screen/timeline widgets to `widgetkit`.
444
-
445
- **DON'T:** Reduce Live Activity payload routing to generic `content-state` matching when the prompt involves APNs payloads.
446
- **DO:** Include the actual `ContentState` `Codable` contract and coordinated `Date`/`ClosedRange<Date>` encoding caveat; route generic APNs auth and registration to `push-notifications`.
447
-
448
- **DON'T:** Store sensitive information in ActivityAttributes (visible on Lock Screen).
449
- **DO:** Keep sensitive data in the app and show only safe-to-display summaries.
450
-
451
- **DON'T:** Forget to handle stale dates.
452
- **DO:** Check `context.isStale` in views and show fallback UI ("Updating..." or similar).
453
-
454
- **DON'T:** Ignore push token rotation. Tokens can change at any time.
455
- **DO:** Use `activity.pushTokenUpdates` async sequence and re-register on every emission.
456
-
457
- **DON'T:** Forget the `NSSupportsLiveActivities` Info.plist key.
458
- **DO:** Add `NSSupportsLiveActivities = YES` to the host app's Info.plist (not the extension).
459
-
460
- **DON'T:** Use the deprecated `contentState`-based API for request/update/end.
461
- **DO:** Use `ActivityContent` for all lifecycle calls.
462
-
463
- **DON'T:** Fetch network data or location directly from Live Activity views.
464
- **DO:** Pre-compute display values in the app or server and pass them through ActivityKit updates or pushes.
465
-
466
- ## Review Checklist
467
-
468
- - [ ] `ActivityAttributes` defines static properties and `ContentState`
469
- - [ ] `NSSupportsLiveActivities = YES` in host app Info.plist
470
- - [ ] Activity uses `ActivityContent` (not deprecated contentState API)
471
- - [ ] Activity ended in all terminal paths (success, error, cancellation, sign-out, terminal server failure)
472
- - [ ] ActivityKit lifecycle and Lock Screen/Dynamic Island Live Activity surfaces are separated from ordinary Home Screen/timeline widget work
473
- - [ ] Lock Screen layout, the primary Live Activity surface, handles `context.isStale`
474
- - [ ] Dynamic Island compact, expanded, and minimal implemented with Lock Screen fallback
475
- - [ ] Push update token forwarded to server via `activity.pushTokenUpdates`
476
- - [ ] Push-to-start token collected via `Activity<Attributes>.pushToStartTokenUpdates`
477
- - [ ] Push-to-start payload includes required `alert`
478
- - [ ] `content-state` JSON matches the actual `ContentState` `Codable` shape, including coordinated date/range encoding
479
- - [ ] Review distinguishes 8-hour active lifetime, 12-hour total system-ended Lock Screen presence, and 4-hour app-ended `.default` linger
372
+ ### Paired Mac and CarPlay (iOS 26+)
373
+
374
+ A paired Mac and the CarPlay Home Screen both show Live Activities, and
375
+ ActivityKit needs no additional code for either. Check that the compact layouts read well there.
376
+ Buttons and toggles inside a Live Activity do nothing in CarPlay.
377
+
378
+ ### Channel pushes (iOS 18+)
379
+
380
+ One push can update many activities through a channel ID that APNs creates.
381
+ Turn on the broadcast capability for the app in the developer portal (it is not
382
+ an Xcode setting), have the server create the channel, then request with `pushType: .channel(channelID)`. Channel pushes
383
+ update or end activities; they cannot start one. They are addressed with
384
+ `apns-channel-id` and an expiration rather than the device-token `apns-topic`.
385
+
386
+ ## Common mistakes
387
+
388
+ 1. A crowded compact view. One icon and one value is the budget.
389
+ 2. Updating from the app too often, which drains battery. Let the server push
390
+ its own changes; update locally only in response to user actions.
391
+ 3. Forgetting to end on some terminal path. A leftover activity is a bug the
392
+ user has to clear by hand.
393
+ 4. Designing for the Dynamic Island first. Many devices have none; the Lock
394
+ Screen is primary.
395
+ 5. Treating a Live Activity as a Home Screen widget with a timeline. Use the
396
+ ActivityKit lifecycle; send timeline widgets to `widgetkit`.
397
+ 6. Reducing payload guidance to "match the content-state". State the real
398
+ `ContentState` `Codable` contract and the `Date` / `ClosedRange<Date>`
399
+ caveat; only the generic APNs pieces (auth keys, registration) move to
400
+ `push-notifications`.
401
+ 7. Sensitive values in attributes or state. The card is readable on a locked
402
+ phone; show a safe summary.
403
+ 8. Ignoring `staleDate`. Check `context.isStale` and render a fallback.
404
+ 9. Registering the update token once. It can change at any time; re-send it on
405
+ every `pushTokenUpdates` value.
406
+ 10. `NSSupportsLiveActivities` placed in the extension target's plist. The key
407
+ is read from the main app.
408
+ 11. The deprecated `contentState:` variants of request, update and end. Use
409
+ `ActivityContent` throughout.
410
+ 12. Network or location work inside Live Activity views. Compute it in the app
411
+ or on the server and deliver the result through an update or a push.
412
+
413
+ ## Review checklist
414
+
415
+ - [ ] `ActivityAttributes` separates static properties from `ContentState`
416
+ - [ ] Host app Info.plist has `NSSupportsLiveActivities = YES`
417
+ - [ ] Request, update and end use `ActivityContent`, not the deprecated
418
+ `contentState` API
419
+ - [ ] Activity ends on success, error, cancellation, sign-out and terminal
420
+ server failure
421
+ - [ ] ActivityKit lifecycle and surfaces are kept apart from Home Screen or
422
+ timeline widget code
423
+ - [ ] Lock Screen view handles `context.isStale`
424
+ - [ ] Compact, expanded and minimal Dynamic Island modes exist, with the Lock
425
+ Screen as the fallback
426
+ - [ ] Update token forwarded from `activity.pushTokenUpdates`
427
+ - [ ] Push-to-start token collected from
428
+ `Activity<Attributes>.pushToStartTokenUpdates`
429
+ - [ ] Push-to-start payload carries `alert`
430
+ - [ ] `content-state` JSON matches the real `ContentState` coding, including an
431
+ agreed date and range encoding
432
+ - [ ] Durations are stated separately: 8 h active, 12 h total after a system
433
+ end, 4 h linger after an app end with `.default`
480
434
  - [ ] `ActivityAuthorizationInfo` checked before starting
481
- - [ ] `frequentPushesEnabled` checked before assuming high-cadence pushes
482
- - [ ] ContentState kept small (serialized on every update)
483
- - [ ] iOS 18+ availability guarded for `style:`, `.channel`, and supplemental families
484
- - [ ] iOS 18+ `style:` choices are justified: `.standard` for persistent Live Activities, `.transient` only for short-lived expanded Dynamic Island presentations
485
- - [ ] ActivityKit push priority and `aps.alert` behavior are handled separately
486
- - [ ] Live Activity views avoid direct network/location work
487
- - [ ] Tested on device for push delivery and Dynamic Island behavior
435
+ - [ ] `frequentPushesEnabled` checked before relying on high-cadence pushes
436
+ - [ ] `ContentState` is small
437
+ - [ ] `style:`, `.channel` and supplemental families are gated on iOS 18
438
+ - [ ] Each `style:` choice is justified: `.standard` for persistent,
439
+ `.transient` only for short expanded moments
440
+ - [ ] Push priority and `aps.alert` are handled as separate concerns
441
+ - [ ] Views do no network or location work
442
+ - [ ] Push delivery and Dynamic Island tested on a real device
488
443
 
489
444
  ## References
490
445
 
491
- - See [references/activitykit-patterns.md](references/activitykit-patterns.md) for patterns and code examples
446
+ - [ActivityKit patterns](references/activitykit-patterns.md): complete
447
+ attributes model, start/update/end variants, server payloads and headers, channel pushes, concurrent activities, state and token observation,
448
+ authorization, errors, background behaviour, testing, Info.plist keys and
449
+ documentation links.