@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,500 +1,492 @@
1
1
  ---
2
2
  name: alarmkit
3
- description: "Implement AlarmKit alarms and countdown timers for iOS and iPadOS with Lock Screen, Dynamic Island, StandBy, and paired Apple Watch system UI. Covers AlarmManager scheduling, AlarmAttributes and AlarmPresentation, AlarmButton stop and snooze actions, authorization, state observation, countdown widget-extension handoff, and Live Activity integration. Use when building wake-up alarms, countdown timers, or alarm-style alerts that need Apple's system alarm experience."
3
+ description: "AlarmKit alarms and countdown timers on iOS and iPadOS 26: AlarmManager scheduling and authorization, AlarmAttributes, AlarmPresentation, AlarmButton stop and snooze, state observation, and the widget extension for countdown Live Activity UI on the Lock Screen, Dynamic Island, StandBy and paired Apple Watch. Use when an app needs wake-up alarms, countdown timers or any alert that needs the system alarm experience. Not for plain widgets or non-alarm Live Activities."
4
4
  metadata:
5
- source: "dpearson2699/swift-ios-skills (PolyForm Perimeter 1.0.0)"
5
+ source: multi-agent-pipeline
6
6
  ---
7
- # AlarmKit
8
7
 
9
- Schedule prominent alarms and countdown timers that surface on the Lock Screen,
10
- Dynamic Island, StandBy, and a paired Apple Watch when the alarm fires. AlarmKit
11
- requires iOS 26+ / iPadOS 26+. Alarms can break through Focus and Silent mode.
8
+ # AlarmKit
12
9
 
13
- AlarmKit uses ActivityKit data models for its Live Activity, but the firing alert
14
- is system-managed alarm UI, not a general custom notification UI surface. Custom
15
- UI belongs only to countdown and paused Live Activity states rendered by a Widget
16
- Extension with the same `AlarmAttributes<Metadata>` and
17
- `AlarmPresentationState` used when scheduling.
10
+ AlarmKit lets an app hand an alarm or a countdown timer to the system. When it
11
+ fires, the alert shows up on the Lock Screen, in the Dynamic Island, in StandBy
12
+ and on the Apple Watch paired with the phone, and it can sound through Focus
13
+ and the Silent switch. The framework is available on iOS 26 and iPadOS 26 and later.
18
14
 
19
- See [references/alarmkit-patterns.md](references/alarmkit-patterns.md) for complete code patterns including
20
- authorization, scheduling, countdown timers, snooze handling, and widget setup.
15
+ Under the hood an alarm is a Live Activity built on ActivityKit types, but the
16
+ firing alert itself is drawn by the system and cannot be restyled. The only
17
+ custom UI an app provides is for the countdown and paused states, and that UI
18
+ lives in a widget extension that uses the same `AlarmAttributes<Metadata>` and
19
+ `AlarmPresentationState` the app used when scheduling.
21
20
 
22
21
  ```swift
23
22
  import AlarmKit
24
23
  ```
25
24
 
26
- ## Contents
27
-
28
- - [Workflow](#workflow)
29
- - [Authorization](#authorization)
30
- - [Alarm vs Timer Decision](#alarm-vs-timer-decision)
31
- - [Scheduling Alarms](#scheduling-alarms)
32
- - [Countdown Timers](#countdown-timers)
33
- - [Alarm States](#alarm-states)
34
- - [AlarmAttributes and AlarmPresentation](#alarmattributes-and-alarmpresentation)
35
- - [AlarmButton](#alarmbutton)
36
- - [Live Activity Integration](#live-activity-integration)
37
- - [Common Mistakes](#common-mistakes)
38
- - [Review Checklist](#review-checklist)
39
- - [References](#references)
25
+ Availability note: the `AlarmPresentation.Alert(title:secondaryButton:secondaryButtonBehavior:)`
26
+ initializer used throughout this skill is iOS 26.1+. On a 26.0 deployment target,
27
+ gate it with `if #available(iOS 26.1, *)`; the older initializer with a
28
+ `stopButton:` argument is deprecated from 26.1 and should only appear in that
29
+ fallback branch.
40
30
 
41
- ## Workflow
31
+ ## Workflows
42
32
 
43
- ### 1. Create a new alarm or timer
33
+ ### Adding an alarm or timer
44
34
 
45
- 1. Add `NSAlarmKitUsageDescription` to Info.plist with a user-facing string.
46
- 2. Request authorization with `AlarmManager.shared.requestAuthorization()` when the app can explain the value, or handle the first-schedule system prompt.
47
- 3. If authorization is `.denied` or not `.authorized`, show recovery UI instead of scheduling.
48
- 4. Configure `AlarmPresentation` (alert, countdown, paused states).
49
- 5. Create `AlarmAttributes` with the presentation, optional metadata, and tint color.
50
- 6. Build an `AlarmManager.AlarmConfiguration` (.alarm or .timer).
51
- 7. Schedule with `AlarmManager.shared.schedule(id:configuration:)`.
52
- 8. Observe state changes via `alarmManager.alarmUpdates`.
53
- 9. If using countdown, add a Widget Extension target with an `ActivityConfiguration` for the same `AlarmAttributes<Metadata>` type.
35
+ 1. Put `NSAlarmKitUsageDescription` in the app's Info.plist with a sentence the
36
+ user will understand.
37
+ 2. Ask for permission with `AlarmManager.shared.requestAuthorization()` at a
38
+ moment where the value is obvious, or let the system ask on the first
39
+ `schedule` call.
40
+ 3. If the state comes back `.denied` (or anything other than `.authorized`),
41
+ show a recovery screen instead of scheduling.
42
+ 4. Describe each state's text and buttons with `AlarmPresentation` (alert, plus
43
+ countdown and paused if used).
44
+ 5. Wrap that in `AlarmAttributes` with optional metadata and a tint color.
45
+ 6. Build an `AlarmManager.AlarmConfiguration`, either an alarm or a timer.
46
+ 7. Call `AlarmManager.shared.schedule(id:configuration:)`.
47
+ 8. Watch `alarmUpdates` to keep the UI in sync.
48
+ 9. If a countdown is shown, create a widget extension; its
49
+ `ActivityConfiguration` must name the identical `AlarmAttributes<Metadata>` type.
54
50
 
55
- ### 2. Review existing alarm code
51
+ ### Reviewing existing alarm code
56
52
 
57
- Run through the Review Checklist at the end of this document.
53
+ Go through the [Review checklist](#review-checklist) item by item.
58
54
 
59
55
  ## Authorization
60
56
 
61
- AlarmKit requires user authorization. Request early when the app can explain the
62
- value, or let AlarmKit prompt automatically on first schedule. If authorization
63
- is not granted after the explicit or automatic prompt, alarms are not scheduled
64
- and will not alert.
57
+ The user must grant access. The app may ask up front, or AlarmKit will prompt
58
+ the first time something is scheduled. If neither prompt ends in approval, no
59
+ alarm is scheduled and nothing will ring.
65
60
 
66
61
  ```swift
67
- let manager = AlarmManager.shared
68
-
69
- // Request authorization explicitly
70
- let state = try await manager.requestAuthorization()
71
- guard state == .authorized else { return }
72
-
73
- // Check current state synchronously
74
- let current = manager.authorizationState // .authorized, .denied, .notDetermined
75
-
76
- // Observe authorization changes
77
- for await state in manager.authorizationUpdates {
78
- switch state {
79
- case .authorized: print("Alarms enabled")
80
- case .denied: print("Alarms disabled")
81
- case .notDetermined: break
82
- @unknown default: break
62
+ import AlarmKit
63
+
64
+ func ensureAlarmAccess() async -> Bool {
65
+ let center = AlarmManager.shared
66
+ switch center.authorizationState {
67
+ case .authorized:
68
+ return true
69
+ case .denied:
70
+ return false
71
+ case .notDetermined:
72
+ let answer = try? await center.requestAuthorization()
73
+ return answer == .authorized
74
+ @unknown default:
75
+ return false
76
+ }
77
+ }
78
+
79
+ func watchAlarmAccess(onChange: @escaping (Bool) -> Void) async {
80
+ for await state in AlarmManager.shared.authorizationUpdates {
81
+ switch state {
82
+ case .authorized: onChange(true)
83
+ case .denied, .notDetermined: onChange(false)
84
+ @unknown default: onChange(false)
85
+ }
83
86
  }
84
87
  }
85
88
  ```
86
89
 
87
- ## Alarm vs Timer Decision
90
+ `AlarmManager.AuthorizationState` has three cases: `.notDetermined`,
91
+ `.denied` and `.authorized`. `authorizationState` is a synchronous read;
92
+ `authorizationUpdates` is an async sequence of changes.
93
+
94
+ ## Alarm or timer?
88
95
 
89
- | Feature | Alarm (`.alarm`) | Timer (`.timer`) |
96
+ | | `.alarm` | `.timer` |
90
97
  |---|---|---|
91
- | Fires at | Specific time (schedule) | After duration elapses |
92
- | Countdown UI | Optional | Always shown |
93
- | Recurring | Yes (weekly days) | No |
94
- | Use case | Wake-up, scheduled reminders | Cooking, workout intervals |
98
+ | Fires | at a clock time | when a duration has elapsed |
99
+ | Countdown UI | optional | always shown |
100
+ | Repeats | yes, on chosen weekdays | no, one-shot |
101
+ | Typical use | wake-up, daily reminder | steeping tea, rest between sets |
95
102
 
96
- Use `.alarm(schedule:...)` when firing at a clock time. Use `.timer(duration:...)`
97
- when firing after a duration from now.
103
+ Rule of thumb: the user picked a time of day, use `.alarm(schedule:...)`; the
104
+ user picked "in N minutes", use `.timer(duration:...)`.
98
105
 
99
- ## Scheduling Alarms
106
+ ## Scheduling
100
107
 
101
108
  ### Alarm.Schedule
102
109
 
103
- Alarms use `Alarm.Schedule` to define when they fire.
104
-
105
110
  ```swift
106
- // Fixed: fire at an exact Date (one-time only)
107
- let fixed: Alarm.Schedule = .fixed(myDate)
108
-
109
- // Relative one-time: fire at 7:30 AM in device time zone, no repeat
110
- let oneTime: Alarm.Schedule = .relative(.init(
111
- time: .init(hour: 7, minute: 30),
112
- repeats: .never
113
- ))
114
-
115
- // Recurring: fire at 6:00 AM on weekdays
116
- let weekday: Alarm.Schedule = .relative(.init(
117
- time: .init(hour: 6, minute: 0),
118
- repeats: .weekly([.monday, .tuesday, .wednesday, .thursday, .friday])
119
- ))
111
+ import AlarmKit
112
+
113
+ let oneOff = Alarm.Schedule.fixed(Date(timeIntervalSinceNow: 3_600))
114
+
115
+ let sixAM = Alarm.Schedule.Relative.Time(hour: 6, minute: 0)
116
+ let tomorrowAtSix = Alarm.Schedule.relative(.init(time: sixAM, repeats: .never))
117
+
118
+ let classDays: [Locale.Weekday] = [.monday, .tuesday, .wednesday, .thursday, .friday]
119
+ let schoolRun = Alarm.Schedule.relative(.init(time: sixAM, repeats: .weekly(classDays)))
120
120
  ```
121
121
 
122
- ### Schedule and Configure
122
+ - `.fixed(Date)` rings once at that exact instant.
123
+ - `.relative` with `repeats: .never` rings once at a wall-clock time in the
124
+ device's current time zone.
125
+ - `.relative` with `repeats: .weekly([Locale.Weekday])` repeats on those days.
126
+
127
+ ### Configuring and scheduling
123
128
 
124
129
  ```swift
125
- let id = UUID()
126
-
127
- let snooze = Alarm.CountdownDuration(preAlert: nil, postAlert: 300)
128
- let configuration = AlarmManager.AlarmConfiguration(
129
- countdownDuration: snooze,
130
- schedule: .relative(.init(
131
- time: .init(hour: 7, minute: 0),
132
- repeats: .never
133
- )),
134
- attributes: attributes,
135
- sound: .default
136
- )
137
-
138
- let alarm = try await AlarmManager.shared.schedule(
139
- id: id,
140
- configuration: configuration
141
- )
142
- ```
130
+ import AlarmKit
131
+ import SwiftUI
132
+
133
+ struct ShiftInfo: AlarmMetadata {
134
+ var shiftName: String
135
+ }
143
136
 
144
- `stopIntent` and `secondaryIntent` default to `nil`. Omit `stopIntent` for
145
- AlarmKit's standard system Stop behavior; provide it only when Stop must run app
146
- cleanup, custom stop behavior, or other side effects. Omit `secondaryIntent` for
147
- ordinary Snooze/Repeat with `secondaryButtonBehavior: .countdown` and
148
- `Alarm.CountdownDuration.postAlert`; provide it only for `.custom` secondary
149
- behavior or app cleanup/custom behavior.
150
-
151
- ### Alarm State Transitions
152
-
153
- ```text
154
- cancel(id:)
155
- |
156
- scheduled --> countdown --> alerting
157
- | | |
158
- | pause(id:) stop(id:) / countdown(id:)
159
- | |
160
- | paused ----> countdown (via resume(id:))
161
- |
162
- cancel(id:) removes from system entirely
137
+ @available(iOS 26.1, *)
138
+ func scheduleShiftAlarm() async throws -> Alarm {
139
+ let dawn = Alarm.Schedule.Relative.Time(hour: 5, minute: 30)
140
+ let alert = AlarmPresentation.Alert(
141
+ title: "Early shift",
142
+ secondaryButton: AlarmButton(text: "Later", textColor: .white, systemImageName: "zzz"),
143
+ secondaryButtonBehavior: .countdown
144
+ )
145
+ let attributes = AlarmAttributes(
146
+ presentation: AlarmPresentation(alert: alert),
147
+ metadata: ShiftInfo(shiftName: "Warehouse A"),
148
+ tintColor: .teal
149
+ )
150
+ let config = AlarmManager.AlarmConfiguration(
151
+ countdownDuration: Alarm.CountdownDuration(preAlert: nil, postAlert: 9 * 60),
152
+ schedule: .relative(.init(time: dawn, repeats: .never)),
153
+ attributes: attributes,
154
+ sound: .default
155
+ )
156
+ let center = AlarmManager.shared
157
+ return try await center.schedule(id: UUID(), configuration: config)
158
+ }
163
159
  ```
164
160
 
165
- - `cancel(id:)` -- remove the alarm completely, including repeating alarms
166
- - `pause(id:)` -- pause a counting-down alarm; throws from other states
167
- - `resume(id:)` -- resume a paused alarm; throws from other states
168
- - `stop(id:)` -- stop the alarm; one-shot alarms are removed, repeating alarms reschedule
169
- - `countdown(id:)` -- restart countdown from alerting state (snooze); throws from other states
161
+ Here `postAlert` is what makes the secondary button a snooze: pressing it
162
+ starts a nine-minute countdown and then rings again.
163
+
164
+ `stopIntent` and `secondaryIntent` both default to `nil`, and that is usually
165
+ right:
166
+
167
+ - Leave `stopIntent` out when the system Stop is all you need. Pass one only
168
+ when stopping must also clean up app state or trigger some side effect.
169
+ - Leave `secondaryIntent` out for a plain snooze or repeat, which is
170
+ `secondaryButtonBehavior: .countdown` plus `CountdownDuration.postAlert`.
171
+ Pass one only with `.custom` behavior or when the app must do its own work.
172
+
173
+ ### Lifecycle and transitions
174
+
175
+ The normal path is scheduled, then countdown, then alerting. From countdown
176
+ `pause(id:)` leads to paused and `resume(id:)` leads back. From alerting,
177
+ `stop(id:)` ends it and `countdown(id:)` snoozes it. `cancel(id:)` works from
178
+ anywhere.
179
+
180
+ | Call | Valid in | Effect |
181
+ |---|---|---|
182
+ | `cancel(id:)` | any state | deletes the alarm entirely, repeating ones included |
183
+ | `pause(id:)` | `.countdown` | freezes the countdown; throws elsewhere |
184
+ | `resume(id:)` | `.paused` | continues the countdown; throws elsewhere |
185
+ | `stop(id:)` | alerting | a one-shot alarm is deleted; a repeating one moves on to its next occurrence |
186
+ | `countdown(id:)` | `.alerting` | restarts the post-alert countdown (snooze); throws elsewhere |
170
187
 
171
- ## Countdown Timers
188
+ ## Countdown timers
172
189
 
173
- Timers fire after a duration and always show a countdown UI. Use
174
- `Alarm.CountdownDuration` to control pre-alert and post-alert durations.
190
+ A timer rings once a duration has passed and always shows its countdown.
175
191
 
176
192
  ```swift
177
- // Simple timer: 5-minute countdown, no snooze
178
- let timerConfig = AlarmManager.AlarmConfiguration.timer(
179
- duration: 300,
180
- attributes: attributes,
181
- stopIntent: StopTimerIntent(timerID: id.uuidString),
182
- sound: .default
183
- )
184
-
185
- let alarm = try await AlarmManager.shared.schedule(
186
- id: UUID(),
187
- configuration: timerConfig
188
- )
193
+ import AlarmKit
194
+ import SwiftUI
195
+
196
+ struct BrewInfo: AlarmMetadata {
197
+ var blend: String
198
+ }
199
+
200
+ @available(iOS 26.1, *)
201
+ func startSteepTimer() async throws {
202
+ let presentation = AlarmPresentation(
203
+ alert: .init(title: "Tea is ready"),
204
+ countdown: .init(title: "Steeping"),
205
+ paused: .init(title: "Steeping paused",
206
+ resumeButton: AlarmButton(text: "Resume", textColor: .white, systemImageName: "play.fill"))
207
+ )
208
+ let attributes = AlarmAttributes(presentation: presentation,
209
+ metadata: BrewInfo(blend: "Sencha"),
210
+ tintColor: .green)
211
+ let threeMinutes = AlarmManager.AlarmConfiguration.timer(duration: 180, attributes: attributes, sound: .default)
212
+ let center = AlarmManager.shared
213
+ _ = try await center.schedule(id: UUID(), configuration: threeMinutes)
214
+ }
189
215
  ```
190
216
 
191
217
  ### CountdownDuration
192
218
 
193
- `Alarm.CountdownDuration` controls the visible countdown phases:
219
+ | Property | Meaning |
220
+ |---|---|
221
+ | `preAlert` | seconds counted down before the alert fires (the main countdown) |
222
+ | `postAlert` | seconds counted down after the alert when the user snoozes or repeats |
194
223
 
195
- - `preAlert` -- seconds to count down before the alarm fires (the main countdown)
196
- - `postAlert` -- seconds for a repeat/snooze countdown after the alarm fires
224
+ Both can be combined with a schedule. A 7:00 alarm with `preAlert: 900` shows a
225
+ fifteen-minute countdown starting at 6:45; `postAlert: 600` gives a ten-minute
226
+ snooze:
197
227
 
198
228
  ```swift
199
- let countdown = Alarm.CountdownDuration(
200
- preAlert: 600, // 10-minute countdown before alert
201
- postAlert: 300 // 5-minute snooze countdown if user taps Repeat
202
- )
203
-
204
- let config = AlarmManager.AlarmConfiguration(
205
- countdownDuration: countdown,
206
- schedule: .relative(.init(
207
- time: .init(hour: 8, minute: 0),
208
- repeats: .never
209
- )),
210
- attributes: attributes,
211
- sound: .default
212
- )
229
+ import AlarmKit
230
+
231
+ func napDurations<M: AlarmMetadata>(_ attrs: AlarmAttributes<M>) -> AlarmManager.AlarmConfiguration<M> {
232
+ let seven = Alarm.Schedule.Relative.Time(hour: 7, minute: 0)
233
+ return .init(countdownDuration: .init(preAlert: 900, postAlert: 600),
234
+ schedule: .relative(.init(time: seven)), attributes: attrs, sound: .default)
235
+ }
213
236
  ```
214
237
 
215
- ## Alarm States
238
+ ## Alarm states
216
239
 
217
- Each `Alarm` has a `state` property reflecting its current lifecycle position.
240
+ `Alarm.state` says where an alarm is in its lifecycle:
218
241
 
219
242
  | State | Meaning |
220
243
  |---|---|
221
- | `.scheduled` | Scheduled and ready to alert at the appropriate time |
222
- | `.countdown` | Actively counting down (timer or pre-alert phase) |
223
- | `.paused` | Countdown paused by user or app |
224
- | `.alerting` | Alarm is firing -- sound playing, UI prominent |
244
+ | `.scheduled` | waiting for its time |
245
+ | `.countdown` | counting down (a timer, or an alarm's pre-alert) |
246
+ | `.paused` | countdown frozen by the user or the app |
247
+ | `.alerting` | ringing, with the prominent system UI |
225
248
 
226
- ### Observing State Changes
249
+ ### Observing changes
227
250
 
228
- `AlarmManager.shared.alarms` is a throwing getter for the current daemon
229
- snapshot. Use `try`, and either propagate the error or wrap launch refresh in
230
- `do/catch` before relying on the snapshot.
251
+ Reading `AlarmManager.shared.alarms` can throw; it hands back whatever the
252
+ alarm daemon currently holds, so it needs `try` inside a throwing context or a `do/catch`.
253
+ Changes arrive through `alarmUpdates`:
231
254
 
232
255
  ```swift
233
- let manager = AlarmManager.shared
234
-
235
- // Get all current alarms
236
- let alarms = try manager.alarms
237
-
238
- // Observe changes as an async sequence
239
- for await updatedAlarms in manager.alarmUpdates {
240
- for alarm in updatedAlarms {
241
- switch alarm.state {
242
- case .scheduled: print("\(alarm.id) waiting")
243
- case .countdown: print("\(alarm.id) counting down")
244
- case .paused: print("\(alarm.id) paused")
245
- case .alerting: print("\(alarm.id) alerting!")
246
- @unknown default: break
256
+ import AlarmKit
257
+
258
+ func trackAlarms(render: ([Alarm]) -> Void) async throws {
259
+ let center = AlarmManager.shared
260
+ render(try center.alarms)
261
+ for await batch in center.alarmUpdates {
262
+ for item in batch {
263
+ switch item.state {
264
+ case .scheduled, .countdown, .paused, .alerting: break
265
+ @unknown default: break
266
+ }
247
267
  }
268
+ render(batch)
248
269
  }
249
270
  }
250
271
  ```
251
272
 
252
- An alarm that disappears from `alarmUpdates` is no longer scheduled with
253
- AlarmKit. Compare against app-persisted IDs when you need to distinguish fired,
254
- cancelled, and rescheduled alarms.
273
+ When an ID disappears from `alarmUpdates`, AlarmKit no longer has it scheduled.
274
+ The sequence does not say why. To tell a fired one-shot from a cancelled alarm
275
+ or a rescheduled one, compare against the IDs the app saved itself.
255
276
 
256
277
  ## AlarmAttributes and AlarmPresentation
257
278
 
258
- `AlarmAttributes` conforms to `ActivityAttributes` and defines the static
259
- data for the alarm's Live Activity. It is generic over a `Metadata` type
260
- conforming to `AlarmMetadata`, which inherits `Decodable`, `Encodable`,
261
- `Hashable`, and `Sendable`. The `metadata` value itself is optional and defaults
262
- to `nil`.
279
+ `AlarmAttributes` conforms to `ActivityAttributes` and carries the static part
280
+ of that Live Activity. Its generic parameter is `Metadata: AlarmMetadata`, a
281
+ protocol that refines `Decodable`, `Encodable`, `Hashable` and `Sendable`.
282
+ Passing `metadata` is optional; leave it out and it is `nil`.
263
283
 
264
284
  ### AlarmPresentation
265
285
 
266
- Defines the UI content for each alarm state. The system renders the alerting UI,
267
- while a widget extension can customize countdown and paused Live Activity views
268
- with the same attributes and presentation state.
286
+ `AlarmPresentation` describes the text and buttons per state. The system draws
287
+ the alerting UI from it; the widget extension may draw countdown and paused.
288
+
289
+ | Type | State | Required |
290
+ |---|---|---|
291
+ | `AlarmPresentation.Alert(title:secondaryButton:secondaryButtonBehavior:)` | alerting | yes |
292
+ | `AlarmPresentation.Countdown(title:pauseButton:)` | counting down | no |
293
+ | `AlarmPresentation.Paused(title:resumeButton:)` | paused | no |
294
+
295
+ Combine them with `AlarmPresentation(alert:countdown:paused:)`:
269
296
 
270
297
  ```swift
271
- // Alert state (required) -- shown when alarm is firing
272
- let alert = AlarmPresentation.Alert(
273
- title: "Wake Up",
274
- secondaryButton: AlarmButton(
275
- text: "Snooze",
276
- textColor: .white,
277
- systemImageName: "bell.slash"
278
- ),
279
- secondaryButtonBehavior: .countdown // snooze restarts countdown
280
- )
281
-
282
- // Countdown state (optional) -- shown during pre-alert countdown
283
- let countdown = AlarmPresentation.Countdown(
284
- title: "Morning Alarm",
285
- pauseButton: AlarmButton(
286
- text: "Pause",
287
- textColor: .orange,
288
- systemImageName: "pause.fill"
289
- )
290
- )
291
-
292
- // Paused state (optional) -- shown when countdown is paused
293
- let paused = AlarmPresentation.Paused(
294
- title: "Paused",
295
- resumeButton: AlarmButton(
296
- text: "Resume",
297
- textColor: .green,
298
- systemImageName: "play.fill"
298
+ import AlarmKit
299
+ import SwiftUI
300
+
301
+ @available(iOS 26.1, *)
302
+ func workoutPresentation() -> AlarmPresentation {
303
+ let again = AlarmButton(text: "Again", textColor: .white, systemImageName: "repeat")
304
+ let hold = AlarmButton(text: "Hold", textColor: .orange, systemImageName: "pause.fill")
305
+ let go = AlarmButton(text: "Go", textColor: .orange, systemImageName: "play.fill")
306
+ return AlarmPresentation(
307
+ alert: .init(title: "Rest over", secondaryButton: again, secondaryButtonBehavior: .countdown),
308
+ countdown: .init(title: "Resting", pauseButton: hold),
309
+ paused: .init(title: "Rest on hold", resumeButton: go)
299
310
  )
300
- )
301
-
302
- let presentation = AlarmPresentation(
303
- alert: alert,
304
- countdown: countdown,
305
- paused: paused
306
- )
311
+ }
307
312
  ```
308
313
 
309
- ### AlarmAttributes
314
+ ### Metadata
310
315
 
311
316
  ```swift
312
- struct CookingMetadata: AlarmMetadata {
313
- var recipeName: String
314
- var stepNumber: Int
315
- }
316
-
317
- let attributes = AlarmAttributes(
318
- presentation: presentation,
319
- metadata: CookingMetadata(recipeName: "Pasta", stepNumber: 3),
320
- tintColor: .blue
321
- )
317
+ import AlarmKit
318
+ import SwiftUI
322
319
 
323
- let attributesWithoutMetadata = AlarmAttributes<EmptyAlarmMetadata>(
324
- presentation: presentation,
325
- metadata: nil,
326
- tintColor: .blue
327
- )
320
+ struct PlantInfo: AlarmMetadata { var plantName: String; var litres: Double }
321
+ struct NoAlarmData: AlarmMetadata {}
328
322
 
329
- struct EmptyAlarmMetadata: AlarmMetadata {}
323
+ @available(iOS 26.1, *)
324
+ func plantAttributes() -> (AlarmAttributes<PlantInfo>, AlarmAttributes<NoAlarmData>) {
325
+ let look = AlarmPresentation(alert: .init(title: "Water the fern"))
326
+ let withData = AlarmAttributes(presentation: look, metadata: PlantInfo(plantName: "Fern", litres: 0.5), tintColor: .mint)
327
+ let plain = AlarmAttributes<NoAlarmData>(presentation: look, metadata: nil, tintColor: .mint)
328
+ return (withData, plain)
329
+ }
330
330
  ```
331
331
 
332
+ When there is nothing to carry, declare an empty type that conforms to
333
+ `AlarmMetadata` and pass `metadata: nil`.
334
+
332
335
  ### AlarmPresentationState
333
336
 
334
- `AlarmPresentationState` is the system-managed `ContentState` of the alarm
335
- Live Activity. It contains the alarm ID and a `Mode` enum:
337
+ `AlarmPresentationState` is the alarm Live Activity's `ContentState`, owned and
338
+ updated by the system. It pairs an `alarmID` with a `mode` value:
336
339
 
337
- - `.alert(Alert)` -- alarm is firing, includes the scheduled time
338
- - `.countdown(Countdown)` -- actively counting down, includes fire date and durations
339
- - `.paused(Paused)` -- countdown paused, includes elapsed and total durations
340
+ | Mode | When | Carries |
341
+ |---|---|---|
342
+ | `.alert(Alert)` | ringing | the scheduled `time` |
343
+ | `.countdown(Countdown)` | counting down | fire date and durations |
344
+ | `.paused(Paused)` | paused | elapsed and total durations |
340
345
 
341
- The widget extension reads `AlarmPresentationState.mode` to decide which UI to
342
- render in the Dynamic Island and Lock Screen for non-alerting states.
346
+ The widget extension switches on `context.state.mode` to choose Lock Screen and
347
+ Dynamic Island content for the non-alerting modes.
343
348
 
344
349
  ## AlarmButton
345
350
 
346
- `AlarmButton` defines the appearance of action buttons in the alarm UI.
347
-
348
- ```swift
349
- let stopButton = AlarmButton(
350
- text: "Stop",
351
- textColor: .red,
352
- systemImageName: "stop.fill"
353
- )
354
-
355
- let snoozeButton = AlarmButton(
356
- text: "Snooze",
357
- textColor: .white,
358
- systemImageName: "bell.slash"
359
- )
360
- ```
361
-
362
- ### Secondary Button Behavior
351
+ `AlarmButton(text:textColor:systemImageName:)` sets a button's label, color and
352
+ SF Symbol, for example a red `"stop.fill"` look for dismissing and a
353
+ `"bell.slash"` look for snoozing:
354
+ `AlarmButton(text: "Snooze", textColor: .yellow, systemImageName: "bell.slash")`.
363
355
 
364
- The secondary button on the alert UI has two behaviors:
356
+ ### Secondary button behavior
365
357
 
366
- | Behavior | Effect |
358
+ | Behavior | What happens |
367
359
  |---|---|
368
- | `.countdown` | Restarts a countdown using `postAlert` duration (snooze) |
369
- | `.custom` | Triggers the `secondaryIntent` (e.g., open app) |
370
-
371
- ## Live Activity Integration
372
-
373
- AlarmKit alarms appear as Live Activities on the Lock Screen, Dynamic Island,
374
- StandBy, and on a paired Apple Watch when the alarm fires. The system manages
375
- the alerting UI. For countdown and paused states, add a Widget Extension target
376
- whose `ActivityConfiguration` uses the same `AlarmAttributes<Metadata>` type
377
- used when scheduling the alarm.
378
-
379
- A widget extension is expected if your alarm uses countdown presentation. Keep
380
- that lightweight metadata type available to both the app and widget extension.
381
- Without the extension, alarms may be dismissed unexpectedly or fail to alert,
382
- though the system can still show a fallback countdown UI in limited cases such
383
- as after a device restart before first unlock.
384
-
385
- When explaining AlarmKit boundaries, say the ownership line explicitly. AlarmKit
386
- owns alarm authorization, `AlarmManager` scheduling and state, `AlarmAttributes`,
387
- `AlarmPresentation`, `AlarmPresentationState`, sound, and system Stop/Repeat/Open
388
- App alarm actions for alarm and timer experiences. The firing alert remains
389
- system-rendered alarm UI; do not describe AlarmKit as a general custom
390
- notification UI surface.
391
-
392
- Custom countdown or paused alarm UI belongs in a Widget Extension
393
- `ActivityConfiguration` for the same `AlarmAttributes<Metadata>` type and
394
- `AlarmPresentationState`. Name the Apple-sourced alarm surfaces together: Lock
395
- Screen, Dynamic Island, StandBy, and paired Apple Watch. Do not claim Smart Stack
396
- as an AlarmKit surface.
397
-
398
- Route ordinary Home Screen or Smart Stack widgets, `WidgetFamily` layout choices,
399
- widget timelines, and `WidgetCenter` reload policy to `widgetkit`. Route non-alarm
400
- Live Activity lifecycle (`Activity.request`, `update`, `end`), push-to-start
401
- tokens, per-activity update tokens, and remote Live Activity `content-state`
402
- payload contracts to `activitykit`. Route generic APNs, `UNUserNotificationCenter`,
403
- notification categories/actions, and custom notification UI to `push-notifications`
404
- unless app code ultimately calls `AlarmManager`.
405
-
406
- For setup, name Apple-documented `NSAlarmKitUsageDescription` and `AlarmManager`
407
- authorization. Do not require unsupported AlarmKit setup keys or
408
- `com.apple.developer.alarmkit` unless a current Apple source documents them.
360
+ | `.countdown` | starts a new countdown of `postAlert` seconds (snooze) |
361
+ | `.custom` | runs `secondaryIntent`, for example to open the app |
362
+
363
+ ## Live Activity integration
364
+
365
+ A ringing alarm is a Live Activity that the system renders on the Lock Screen,
366
+ in the Dynamic Island, in StandBy and on a paired Apple Watch; the app has no
367
+ say over that screen. Countdown and paused are different: the app supplies a widget
368
+ extension whose `ActivityConfiguration` names the same
369
+ `AlarmAttributes<Metadata>` type used at scheduling.
370
+
371
+ - Plan on the extension whenever countdown presentation is used. The metadata
372
+ type must be compiled into both the app and the extension, and it should stay
373
+ small.
374
+ - Leave the extension out and an alarm can vanish early or never ring. The
375
+ system only draws a fallback countdown in narrow cases, such as after a
376
+ restart before the first unlock.
377
+
378
+ AlarmKit is responsible for: permission to schedule alarms, `AlarmManager` scheduling and state,
379
+ `AlarmAttributes`, `AlarmPresentation`, `AlarmPresentationState`, the sound,
380
+ and the system Stop, Repeat and Open App actions. It is not a general surface
381
+ for custom notification UI.
382
+
383
+ When describing where alarms appear, name Lock Screen, Dynamic Island, StandBy
384
+ and paired Apple Watch together. Smart Stack is not an AlarmKit surface.
385
+
386
+ Hand-offs:
387
+
388
+ - Widgets on the Home Screen or in Smart Stack, `WidgetFamily`, timelines,
389
+ `WidgetCenter` reloads: `widgetkit`.
390
+ - Non-alarm Live Activities (`Activity.request`, `update`, `end`),
391
+ push-to-start and per-activity update tokens, and remote `content-state`
392
+ payloads: `live-activities`.
393
+ - APNs, `UNUserNotificationCenter`, notification categories and actions,
394
+ custom notification UI: `push-notifications`, unless the code ends up
395
+ calling `AlarmManager`.
396
+
397
+ Setup stays with what Apple documents: `NSAlarmKitUsageDescription` and
398
+ `AlarmManager` authorization. Do not require extra keys or a
399
+ `com.apple.developer.alarmkit` entitlement unless a current Apple source says so.
409
400
 
410
401
  ```swift
411
- struct AlarmWidgetBundle: WidgetBundle {
412
- var body: some Widget {
413
- AlarmActivityWidget()
414
- }
402
+ import ActivityKit
403
+ import AlarmKit
404
+ import SwiftUI
405
+ import WidgetKit
406
+
407
+ struct CoachInfo: AlarmMetadata {
408
+ var drill: String
415
409
  }
416
410
 
417
- struct AlarmActivityWidget: Widget {
411
+ struct CoachAlarmWidget: Widget {
418
412
  var body: some WidgetConfiguration {
419
- ActivityConfiguration(for: AlarmAttributes<CookingMetadata>.self) { context in
420
- // Lock Screen presentation for countdown/paused states
421
- AlarmLockScreenView(context: context)
413
+ ActivityConfiguration(for: AlarmAttributes<CoachInfo>.self) { context in
414
+ Text(context.attributes.metadata?.drill ?? "Timer")
415
+ .padding()
422
416
  } dynamicIsland: { context in
423
417
  DynamicIsland {
424
418
  DynamicIslandExpandedRegion(.center) {
425
- Text(context.attributes.presentation.alert.title)
419
+ let heading = context.attributes.presentation.alert.title
420
+ Text(heading)
426
421
  }
427
422
  DynamicIslandExpandedRegion(.bottom) {
428
- // Show countdown or paused info based on mode
429
- AlarmExpandedView(state: context.state)
423
+ if case .countdown(let run) = context.state.mode {
424
+ Text(timerInterval: Date.now...run.fireDate, countsDown: true)
425
+ }
430
426
  }
431
427
  } compactLeading: {
432
428
  Image(systemName: "alarm.fill")
433
429
  } compactTrailing: {
434
- AlarmCompactTrailing(state: context.state)
430
+ Image(systemName: "alarm.fill")
435
431
  } minimal: {
436
432
  Image(systemName: "alarm.fill")
437
433
  }
438
434
  }
439
435
  }
440
436
  }
441
- ```
442
-
443
- ## Common Mistakes
444
-
445
- **DON'T:** Forget `NSAlarmKitUsageDescription` in Info.plist.
446
- **DO:** Add a descriptive usage string. Without it, AlarmKit cannot schedule alarms at all.
447
-
448
- **DON'T:** Skip authorization and assume alarms will schedule.
449
- **DO:** Call `requestAuthorization()` early and handle `.denied` gracefully.
450
-
451
- **DON'T:** Use `.timer` when you need a recurring schedule.
452
- **DO:** Use `.alarm` with `.weekly([...])` for recurring alarms. Timers are one-shot.
453
437
 
454
- **DON'T:** Omit the widget extension when using countdown presentation.
455
- **DO:** Add a widget extension target for countdown/paused Live Activity UI.
456
- **Why:** Without a widget extension, alarms may be dismissed before they alert; the system fallback is limited.
457
-
458
- **DON'T:** Ignore `alarmUpdates` and track alarm state manually.
459
- **DO:** Observe `alarmManager.alarmUpdates` to stay synchronized with the system.
460
- **Why:** Alarm state can change while your app is backgrounded.
461
-
462
- **DON'T:** Treat `stopIntent` and `secondaryIntent` as mandatory for every alarm.
463
- **DO:** Omit them for standard system Stop/Snooze; provide intents only for app cleanup or custom behavior.
464
-
465
- **DON'T:** Fold ordinary widgets, generic Live Activities, or push/local notification behavior into AlarmKit.
466
- **DO:** Route Home Screen/Smart Stack widgets, `WidgetFamily`, timelines, and `WidgetCenter` reloads to `widgetkit`; route non-alarm `Activity.request`/`update`/`end`, push-to-start, update tokens, and remote `content-state` payloads to `activitykit`; route generic APNs, `UNUserNotificationCenter`, and notification categories/actions to `push-notifications` unless app code ultimately calls `AlarmManager`.
467
-
468
- **DON'T:** Store large data in `AlarmMetadata`.
469
- **DO:** Keep metadata lightweight or pass `nil`. Store large data in your app and reference by ID.
470
-
471
- **DON'T:** Use deprecated `stopButton` parameter on `AlarmPresentation.Alert`.
472
- **DO:** Use the current `init(title:secondaryButton:secondaryButtonBehavior:)` initializer.
473
-
474
- ## Review Checklist
438
+ @main
439
+ struct CoachWidgets: WidgetBundle {
440
+ var body: some Widget {
441
+ CoachAlarmWidget()
442
+ }
443
+ }
444
+ ```
475
445
 
476
- - [ ] `NSAlarmKitUsageDescription` present in Info.plist with non-empty string
477
- - [ ] Authorization requested and `.denied` state handled in UI
478
- - [ ] `AlarmPresentation` covers all relevant states (alert, countdown, paused)
479
- - [ ] Widget Extension target uses `ActivityConfiguration` for the same `AlarmAttributes<Metadata>` type if countdown presentation is used
480
- - [ ] `AlarmAttributes` metadata is lightweight, optional when unused, and conforms to `AlarmMetadata`
481
- - [ ] Alarm ID stored for later cancel/pause/resume/stop operations
482
- - [ ] `alarmUpdates` async sequence observed to track state changes
483
- - [ ] `stopIntent` and `secondaryIntent` omitted for standard system Stop/Snooze and provided only for cleanup/custom behavior
484
- - [ ] `postAlert` duration set on `CountdownDuration` if snooze (`.countdown` behavior) is used
485
- - [ ] AlarmKit ownership is limited to authorization, `AlarmManager` scheduling/state, `AlarmAttributes`, `AlarmPresentation`, `AlarmPresentationState`, sound, and alarm actions
486
- - [ ] Alerting UI is described as system-managed alarm UI, not a general custom notification UI surface
487
- - [ ] Custom countdown/paused UI is routed to a Widget Extension `ActivityConfiguration` using the same `AlarmAttributes<Metadata>` and `AlarmPresentationState`
488
- - [ ] Boundary routing is explicit: Home Screen/Smart Stack widgets, `WidgetFamily`, timelines, and `WidgetCenter` reloads go to `widgetkit`; non-alarm `Activity.request`/`update`/`end`, push-to-start/update tokens, and remote `content-state` payloads go to `activitykit`; generic APNs/`UNUserNotificationCenter` goes to `push-notifications`
489
- - [ ] Setup is source-grounded: `NSAlarmKitUsageDescription` and authorization are named; unsupported keys such as `com.apple.developer.alarmkit` are not required unless Apple documents them
490
- - [ ] Tint color set on `AlarmAttributes` to differentiate from other apps
491
- - [ ] Error handling for `AlarmManager.AlarmError.maximumLimitReached`
492
- - [ ] Tested on device (alarm sound/vibration differs from Simulator)
446
+ ## Common mistakes
447
+
448
+ - **No `NSAlarmKitUsageDescription`.** Nothing can be scheduled.
449
+ - **Skipping authorization.** Ask early with `requestAuthorization()` and give
450
+ `.denied` a real screen.
451
+ - **Recurring timers.** Timers are one-shot. Use `.alarm` with
452
+ `.weekly([...])` for repetition.
453
+ - **Countdown without the widget extension.** Alarms can be dismissed before
454
+ they ring; the fallback UI covers very little.
455
+ - **Hand-tracking state.** Alarms change state while the app is suspended.
456
+ Read it from `alarmUpdates`.
457
+ - **Treating `stopIntent` or `secondaryIntent` as required.** Leave both out
458
+ for the standard Stop and Snooze.
459
+ - **Pulling other features into AlarmKit.** Route them as listed under Hand-offs.
460
+ - **Heavy metadata.** Keep `AlarmMetadata` small or `nil`; keep large data in
461
+ the app and refer to it by ID.
462
+ - **The deprecated `stopButton` argument.** Use
463
+ `AlarmPresentation.Alert(title:secondaryButton:secondaryButtonBehavior:)`
464
+ (iOS 26.1+); keep the `stopButton:` form only in a 26.0 fallback branch.
465
+
466
+ ## Review checklist
467
+
468
+ - [ ] `NSAlarmKitUsageDescription` is present and not empty
469
+ - [ ] Authorization is requested and `.denied` has UI
470
+ - [ ] `AlarmPresentation` covers every state the app uses (alert, countdown, paused)
471
+ - [ ] Any countdown has a matching widget extension whose `ActivityConfiguration` names the same `AlarmAttributes<Metadata>`
472
+ - [ ] Metadata conforms to `AlarmMetadata`, stays small, and is `nil` if there is none
473
+ - [ ] Each alarm ID is saved for later cancel, pause, resume or stop
474
+ - [ ] `alarmUpdates` is observed
475
+ - [ ] `stopIntent` and `secondaryIntent` are omitted for standard behavior and only passed for cleanup or custom work
476
+ - [ ] `postAlert` is set when `.countdown` snooze is used
477
+ - [ ] AlarmKit is credited only with authorization, `AlarmManager` scheduling and state, attributes, presentation, presentation state, sound and system alarm actions
478
+ - [ ] The ringing screen is described as drawn by the system
479
+ - [ ] Custom countdown and paused UI lives in the widget extension with the same attributes and `AlarmPresentationState`
480
+ - [ ] Hand-offs to `widgetkit`, `live-activities` and `push-notifications` are explicit
481
+ - [ ] Setup cites only documented requirements; no `com.apple.developer.alarmkit` unless Apple documents it
482
+ - [ ] `tintColor` is set on `AlarmAttributes` so the alarm is recognisable
483
+ - [ ] `AlarmManager.AlarmError.maximumLimitReached` is handled
484
+ - [ ] Sound and vibration are tested on a device, not only in Simulator
493
485
 
494
486
  ## References
495
487
 
496
- - Patterns and code: [references/alarmkit-patterns.md](references/alarmkit-patterns.md)
497
- - Apple docs: [AlarmKit](https://sosumi.ai/documentation/alarmkit) |
498
- [AlarmManager](https://sosumi.ai/documentation/alarmkit/alarmmanager) |
499
- [AlarmAttributes](https://sosumi.ai/documentation/alarmkit/alarmattributes) |
500
- [Scheduling an alarm](https://sosumi.ai/documentation/alarmkit/scheduling-an-alarm-with-alarmkit)
488
+ - [AlarmKit patterns](references/alarmkit-patterns.md) - complete alarm and timer flows, authorization manager, state store, widget extension, recurrence, snooze and custom actions, Info.plist, errors
489
+ - [AlarmKit](https://developer.apple.com/documentation/alarmkit)
490
+ - [AlarmManager](https://developer.apple.com/documentation/alarmkit/alarmmanager)
491
+ - [AlarmAttributes](https://developer.apple.com/documentation/alarmkit/alarmattributes)
492
+ - [Apple sample: scheduling alarms](https://developer.apple.com/documentation/alarmkit/scheduling-an-alarm-with-alarmkit)