@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,42 +1,34 @@
1
1
  ---
2
2
  name: tipkit
3
- description: "Implement, review, or improve in-app tips and onboarding using Apple's TipKit framework. Use when adding feature discovery tooltips, onboarding flows, contextual tips, first-run experiences, coach marks, or working with Tip protocol, TipView, popoverTip, tip rules, tip events, or feature education UI."
3
+ description: "TipKit in-app tips (iOS 17+): Tip protocol, TipView, popoverTip, rules, events, TipGroup, styles, CloudKit sync. Use when building or reviewing feature-discovery tooltips, onboarding flows, first-run experiences, coach marks, contextual tips or other feature-education UI."
4
4
  metadata:
5
- source: "dpearson2699/swift-ios-skills (PolyForm Perimeter 1.0.0)"
5
+ source: multi-agent-pipeline
6
6
  ---
7
7
 
8
8
  # TipKit
9
9
 
10
- Add feature discovery tips, contextual hints, and onboarding coach marks to
11
- iOS 17+ apps using Apple's TipKit framework. TipKit manages display frequency,
12
- eligibility rules, and persistence so tips appear at the right time and
13
- disappear once the user has learned the feature.
10
+ TipKit (iOS 17 and later) shows short hints that teach a feature at the
11
+ moment it matters. The framework owns the hard parts: it decides when a tip
12
+ is eligible, throttles how often tips appear, and remembers which tips a
13
+ person has already learned so they stop appearing.
14
14
 
15
- ## Contents
16
-
17
- - [Setup](#setup)
18
- - [Defining Tips](#defining-tips)
19
- - [Displaying Tips](#displaying-tips)
20
- - [Tip Rules](#tip-rules)
21
- - [Tip Actions](#tip-actions)
22
- - [Tip Groups](#tip-groups)
23
- - [Programmatic Control](#programmatic-control)
24
- - [Common Mistakes](#common-mistakes)
25
- - [Review Checklist](#review-checklist)
26
- - [References](#references)
15
+ Tips are for discovery and progressive disclosure. They can be dismissed and
16
+ do not come back, so anything critical or safety related goes in an alert or
17
+ an inline warning instead.
27
18
 
28
19
  ## Setup
29
20
 
30
- Call `Tips.configure()` once in `App.init`, before any views render. This
31
- initializes the tips datastore and begins rule evaluation. Calling it later
32
- risks a race where tip views attempt to display before the datastore is ready.
21
+ Configure TipKit once, in the `App` initializer, before the first view is
22
+ built. `Tips.configure` opens the tips datastore and starts evaluating rules;
23
+ if it runs later (in `onAppear` or `.task`), tip views can render against a
24
+ store that is not ready yet.
33
25
 
34
26
  ```swift
35
27
  import SwiftUI
36
28
  import TipKit
37
29
 
38
30
  @main
39
- struct MyApp: App {
31
+ struct GardenJournalApp: App {
40
32
  init() {
41
33
  try? Tips.configure([
42
34
  .datastoreLocation(.applicationDefault)
@@ -44,99 +36,117 @@ struct MyApp: App {
44
36
  }
45
37
 
46
38
  var body: some Scene {
47
- WindowGroup { ContentView() }
39
+ WindowGroup {
40
+ JournalHomeView()
41
+ }
48
42
  }
49
43
  }
50
44
  ```
51
45
 
52
- ### DatastoreLocation Options
46
+ ### Where the datastore lives
53
47
 
54
- | Option | Use Case |
55
- |---|---|
56
- | `.applicationDefault` | Default location, app sandbox (most apps) |
57
- | `.groupContainer(identifier:)` | Share tips state across app and extensions |
58
- | `.url(_:)` | Custom file URL for full control over storage location |
48
+ | Option | When to pick it |
49
+ | --- | --- |
50
+ | `.applicationDefault` | The app sandbox default. Correct for most apps. |
51
+ | `.groupContainer(identifier:)` | Tip state shared between the app and its extensions. |
52
+ | `.url(_:)` | A file URL you choose, when you need full control. |
59
53
 
60
- ### CloudKit Sync
54
+ ### Syncing tip state with CloudKit
61
55
 
62
- Sync tip state across a user's devices so they do not see the same tip on
63
- every device. Add the CloudKit container option alongside the datastore
64
- location.
56
+ When the app runs on several devices, sync tip state so a person who learned
57
+ a feature on their iPhone is not taught it again on their iPad. Add a CloudKit
58
+ container next to the datastore option (`cloudKitContainer` needs iOS 18):
65
59
 
66
60
  ```swift
67
61
  try? Tips.configure([
68
62
  .datastoreLocation(.applicationDefault),
69
- .cloudKitContainer(.named("iCloud.com.example.app"))
63
+ .cloudKitContainer(.named("iCloud.com.example.gardenjournal"))
70
64
  ])
71
65
  ```
72
66
 
73
- ## Defining Tips
67
+ ## Defining a tip
74
68
 
75
- Conform a struct to the `Tip` protocol. Provide a `title` at minimum.
76
- Add `message` for supporting detail and `image` for a leading icon. Keep
77
- titles short and action-oriented because the tip appears as a compact callout.
69
+ A tip is a struct that conforms to `Tip`. Only `title` (a `Text`) is
70
+ required. `message` (`Text?`) adds a line of context and `image` (`Image?`)
71
+ adds a leading icon. The callout is small, so write the title as a short
72
+ instruction.
78
73
 
79
74
  ```swift
80
- import TipKit
75
+ struct PinPlantTip: Tip {
76
+ var title: Text {
77
+ Text("Pin a plant")
78
+ }
79
+
80
+ var message: Text? {
81
+ Text("Pinned plants stay at the top of your journal.")
82
+ }
81
83
 
82
- struct FavoriteTip: Tip {
83
- var title: Text { Text("Pin Your Favorites") }
84
- var message: Text? { Text("Tap the heart icon to save items for quick access.") }
85
- var image: Image? { Image(systemName: "heart") }
84
+ var image: Image? {
85
+ Image(systemName: "pin")
86
+ }
86
87
  }
87
88
  ```
88
89
 
89
- **Properties**: `title` (required), `message` (optional detail), `image` (optional leading icon), `actions` (optional buttons), `rules` (optional eligibility conditions), `options` (display frequency, max count).
90
+ Optional members:
91
+
92
+ - `actions`: buttons shown inside the tip.
93
+ - `rules`: conditions that must hold before the tip can appear.
94
+ - `options`: per-tip display settings such as a maximum count.
90
95
 
91
- **Lifecycle**: Pending (rules unsatisfied) -> Eligible (all rules pass) -> Invalidated (dismissed, actioned, or programmatically removed). Once invalidated, a tip does not reappear unless the datastore is reset.
96
+ A tip moves through three states. It is pending while its rules are not yet
97
+ satisfied, eligible once every rule passes, and invalidated when it is
98
+ dismissed, acted on, or invalidated in code. An invalidated tip stays hidden
99
+ for good unless the datastore is reset.
92
100
 
93
- ## Displaying Tips
101
+ ## Showing a tip
94
102
 
95
- ### Inline Tips with TipView
103
+ ### Inline with TipView
96
104
 
97
- Embed a `TipView` directly in your layout. It renders as a rounded card that
98
- appears and disappears with animation. Use for tips within scrollable content.
105
+ `TipView(tip)` places the tip in the layout as a rounded card that animates
106
+ in and out. Use it for tips that sit among scrolling content.
99
107
 
100
108
  ```swift
101
- let favoriteTip = FavoriteTip()
102
- var body: some View {
103
- VStack {
104
- TipView(favoriteTip)
105
- ItemListView()
109
+ struct JournalHomeView: View {
110
+ let pinTip = PinPlantTip()
111
+
112
+ var body: some View {
113
+ VStack {
114
+ TipView(pinTip)
115
+ PlantListView()
116
+ }
106
117
  }
107
118
  }
108
119
  ```
109
120
 
110
- ### Popover Tips with .popoverTip()
121
+ ### As a popover
111
122
 
112
- Attach a tip as a popover anchored to any view. The framework draws an arrow
113
- from the popover to the anchor. Use for tips pointing to a specific control.
123
+ `.popoverTip(tip)` attaches the tip to a view and draws an arrow to it. Use it
124
+ when the tip explains one particular control. Pass `arrowEdge:` to choose the
125
+ arrow direction, or leave it out and let the system decide.
114
126
 
115
127
  ```swift
116
- Button { toggleFavorite() } label: { Image(systemName: "heart") }
117
- .popoverTip(favoriteTip)
118
-
119
- // Control arrow direction (omit to let system choose)
120
- .popoverTip(favoriteTip, arrowEdge: .bottom)
128
+ Button("Water", systemImage: "drop") {
129
+ logWatering()
130
+ }
131
+ .popoverTip(waterTip, arrowEdge: .bottom)
121
132
  ```
122
133
 
123
- ### Custom TipViewStyle
134
+ ### A custom look with TipViewStyle
124
135
 
125
- Create a custom style to control tip appearance across the app. Conform
126
- to `TipViewStyle` and implement `makeBody(configuration:)`.
136
+ To restyle tips across the app, adopt `TipViewStyle` and implement
137
+ `makeBody(configuration:)`. The configuration carries `title` plus optional
138
+ `image` and `message`.
127
139
 
128
140
  ```swift
129
- struct CustomTipStyle: TipViewStyle {
141
+ struct LeafTipStyle: TipViewStyle {
130
142
  func makeBody(configuration: Configuration) -> some View {
131
- HStack {
132
- configuration.image?
133
- .font(.title2)
134
- .foregroundStyle(.tint)
135
-
136
- VStack(alignment: .leading) {
143
+ HStack(alignment: .top, spacing: 10) {
144
+ configuration.image
145
+ .foregroundStyle(.green)
146
+ VStack(alignment: .leading, spacing: 4) {
137
147
  configuration.title
138
148
  .font(.headline)
139
- configuration.message?
149
+ configuration.message
140
150
  .font(.subheadline)
141
151
  .foregroundStyle(.secondary)
142
152
  }
@@ -144,353 +154,228 @@ struct CustomTipStyle: TipViewStyle {
144
154
  .padding()
145
155
  }
146
156
  }
147
-
148
- // Apply globally or per view
149
- TipView(favoriteTip)
150
- .tipViewStyle(CustomTipStyle())
151
157
  ```
152
158
 
153
- ## Tip Rules
159
+ Apply it with `.tipViewStyle(LeafTipStyle())` on a single tip view or on a
160
+ container to cover everything below it.
161
+
162
+ ## Rules
154
163
 
155
- Rules control when a tip becomes eligible. All rules in the `rules` array
156
- must pass before the tip displays. TipKit supports two rule types:
157
- parameter-based and event-based.
164
+ Rules decide eligibility. Every rule in `rules` has to pass before the tip is
165
+ shown. There are two kinds.
158
166
 
159
- ### Parameter-Based Rules
167
+ ### Parameter rules (app state)
160
168
 
161
- Use `@Parameter` to track app state. The tip becomes eligible when the
162
- parameter value satisfies the rule condition.
169
+ Declare a `@Parameter` static on the tip, write a rule against its projected
170
+ value, and assign the static when the state changes.
163
171
 
164
172
  ```swift
165
- struct FavoriteTip: Tip {
173
+ struct SortPlantsTip: Tip {
166
174
  @Parameter
167
- static var hasSeenList: Bool = false
175
+ static var hasOpenedList: Bool = false
168
176
 
169
- var title: Text { Text("Pin Your Favorites") }
177
+ var title: Text { Text("Sort by watering date") }
170
178
 
171
179
  var rules: [Rule] {
172
- #Rule(Self.$hasSeenList) { $0 == true }
180
+ #Rule(Self.$hasOpenedList) { $0 == true }
173
181
  }
174
182
  }
175
183
 
176
- // Set the parameter when the user reaches the list
177
- FavoriteTip.hasSeenList = true
184
+ SortPlantsTip.hasOpenedList = true
178
185
  ```
179
186
 
180
- ### Event-Based Rules
187
+ ### Event rules (user actions)
181
188
 
182
- Use `Tips.Event` to track user actions. Donate to the event each time the
183
- action occurs. The rule fires when the donation count or timing condition
184
- is met. This is ideal for tips that should appear after the user has
185
- performed an action several times without discovering a related feature.
189
+ Declare a `Tips.Event`, donate to it every time the action happens, and write
190
+ a rule on the donations. A rule can look at how many donations there are or
191
+ when they happened.
186
192
 
187
193
  ```swift
188
- struct ShortcutTip: Tip {
189
- static let appOpenedEvent = Tips.Event(id: "appOpened")
194
+ struct QuickLogTip: Tip {
195
+ static let entryAdded = Tips.Event(id: "entryAdded")
190
196
 
191
- var title: Text { Text("Try the Quick Action") }
197
+ var title: Text { Text("Log faster with a long press") }
192
198
 
193
199
  var rules: [Rule] {
194
- #Rule(Self.appOpenedEvent) { $0.donations.count >= 3 }
200
+ #Rule(Self.entryAdded) { $0.donations.count >= 3 }
195
201
  }
196
202
  }
197
203
 
198
- // Donate each time the app opens
199
- ShortcutTip.appOpenedEvent.donate()
204
+ Task { await QuickLogTip.entryAdded.donate() }
200
205
  ```
201
206
 
202
- ### Combining Multiple Rules
207
+ Event rules fit tips that should appear only after someone has repeated a
208
+ task several times without finding the shortcut that would help.
203
209
 
204
- Place multiple rules in the array. All must pass (logical AND).
210
+ ### Several rules together
205
211
 
206
- ```swift
207
- struct AdvancedTip: Tip {
208
- @Parameter
209
- static var isLoggedIn: Bool = false
210
-
211
- static let featureUsedEvent = Tips.Event(id: "featureUsed")
212
-
213
- var title: Text { Text("Unlock Advanced Mode") }
212
+ List more than one `#Rule` and all of them must pass (logical AND):
214
213
 
215
- var rules: [Rule] {
216
- #Rule(Self.$isLoggedIn) { $0 == true }
217
- #Rule(Self.featureUsedEvent) { $0.donations.count >= 5 }
218
- }
214
+ ```swift
215
+ var rules: [Rule] {
216
+ #Rule(Self.$isSignedIn) { $0 == true }
217
+ #Rule(Self.entryAdded) { $0.donations.count >= 5 }
219
218
  }
220
219
  ```
221
220
 
222
- ### Display Frequency Options
221
+ ### How often tips appear
223
222
 
224
- Control how often tips appear using the `options` property.
223
+ Per tip, `options` adjusts display behavior:
225
224
 
226
225
  ```swift
227
- struct DailyTip: Tip {
228
- var title: Text { Text("Daily Reminder") }
229
-
230
- var options: [TipOption] {
231
- MaxDisplayCount(3) // Show at most 3 times total
232
- IgnoresDisplayFrequency(true) // Bypass global frequency limit
233
- }
226
+ var options: [TipOption] {
227
+ Tips.MaxDisplayCount(3)
228
+ Tips.IgnoresDisplayFrequency(true)
234
229
  }
235
230
  ```
236
231
 
237
- Global display frequency is set at configuration time:
232
+ - `MaxDisplayCount(3)` stops the tip after three showings in total.
233
+ - `IgnoresDisplayFrequency(true)` lets this tip bypass the global limit.
234
+
235
+ The global limit is set at configuration time with
236
+ `.displayFrequency(...)`, taking `.immediate`, `.hourly`, `.daily`, `.weekly`
237
+ or `.monthly`. With `.daily`, the whole app shows at most one tip per day,
238
+ except for tips that opt out with `IgnoresDisplayFrequency(true)`.
238
239
 
239
240
  ```swift
240
- try? Tips.configure([
241
- .displayFrequency(.daily) // .immediate, .hourly, .daily, .weekly, .monthly
242
- ])
241
+ try? Tips.configure([.displayFrequency(.daily)])
243
242
  ```
244
243
 
245
- With `.daily`, the system shows at most one tip per day across the entire
246
- app, unless a specific tip sets `IgnoresDisplayFrequency(true)`.
244
+ ## Actions
247
245
 
248
- ## Tip Actions
249
-
250
- Add action buttons to a tip for direct interaction. Each action has an `id`
251
- and a label. Handle the action in the tip view's action handler.
246
+ `actions` adds buttons to a tip. Each `Action(id:title:)` gets an identifier
247
+ and a label. Handle taps in the closure passed to `TipView`, switching on the
248
+ identifier.
252
249
 
253
250
  ```swift
254
- struct FeatureTip: Tip {
255
- var title: Text { Text("Try the New Editor") }
256
- var message: Text? { Text("We added a powerful new editing mode.") }
251
+ struct ReminderTip: Tip {
252
+ var title: Text { Text("Never miss a watering") }
257
253
 
258
254
  var actions: [Action] {
259
- Action(id: "open-editor", title: "Open Editor")
260
- Action(id: "learn-more", title: "Learn More")
255
+ Action(id: "set-reminder", title: "Set Reminder")
256
+ Action(id: "show-guide", title: "How It Works")
261
257
  }
262
258
  }
263
- ```
264
-
265
- Handle actions in the view:
266
259
 
267
- ```swift
268
- TipView(featureTip) { action in
260
+ TipView(reminderTip) { action in
269
261
  switch action.id {
270
- case "open-editor":
271
- navigateToEditor()
272
- featureTip.invalidate(reason: .actionPerformed)
273
- case "learn-more":
274
- showHelpSheet = true
262
+ case "set-reminder":
263
+ reminderTip.invalidate(reason: .actionPerformed)
264
+ openReminderEditor()
265
+ case "show-guide":
266
+ isGuidePresented = true
275
267
  default:
276
268
  break
277
269
  }
278
270
  }
279
271
  ```
280
272
 
281
- ## Tip Groups
273
+ ## Tip groups
282
274
 
283
- Use `TipGroup` to coordinate multiple tips within a single view.
284
- `TipGroup` ensures only one tip from the group displays at a time,
285
- preventing tip overload. Tips display in priority order.
275
+ When one screen has several tips, put them in a `TipGroup` (iOS 18 and
276
+ later) so only one is visible at a time. The `.ordered` priority shows them in
277
+ the order listed. Render `currentTip` when it is not nil; invalidating it
278
+ makes the next eligible tip current.
286
279
 
287
280
  ```swift
288
- struct OnboardingView: View {
289
- let tipGroup = TipGroup(.ordered) {
290
- WelcomeTip()
291
- NavigationTip()
292
- ProfileTip()
281
+ struct PlantDetailView: View {
282
+ @State private var tips = TipGroup(.ordered) {
283
+ PinPlantTip()
284
+ SortPlantsTip()
285
+ QuickLogTip()
293
286
  }
294
287
 
295
288
  var body: some View {
296
289
  VStack {
297
- if let currentTip = tipGroup.currentTip {
298
- TipView(currentTip)
290
+ if let tip = tips.currentTip {
291
+ TipView(tip)
299
292
  }
300
-
301
- Button("Next") {
302
- tipGroup.currentTip?.invalidate(reason: .actionPerformed)
293
+ Button("Next hint") {
294
+ tips.currentTip?.invalidate(reason: .actionPerformed)
303
295
  }
304
296
  }
305
297
  }
306
298
  }
307
299
  ```
308
300
 
309
- ### Priority Options
310
-
311
- | Initializer | Behavior |
312
- |---|---|
313
- | `.ordered` | Tips display in the order they are listed |
314
-
315
- When the current tip is invalidated, the next eligible tip in the group
316
- becomes `currentTip`.
317
-
318
- ## Programmatic Control
319
-
320
- ### Invalidating Tips
321
-
322
- Call `invalidate(reason:)` when the user performs the discovered action or
323
- when the tip is no longer relevant.
324
-
325
- ```swift
326
- let tip = FavoriteTip()
327
- tip.invalidate(reason: .actionPerformed)
328
- ```
329
-
330
- | Reason | When to Use |
331
- |---|---|
332
- | `.actionPerformed` | User performed the action the tip describes |
333
- | `.displayCountExceeded` | Tip hit its maximum display count |
334
- | `.tipClosed` | User explicitly dismissed the tip |
335
-
336
- ### Testing Utilities
337
-
338
- TipKit provides static methods to control tip visibility during development
339
- and testing. Gate these behind `#if DEBUG` or `ProcessInfo` checks so they
340
- never run in production builds.
301
+ ## Controlling tips from code
341
302
 
342
- ```swift
343
- #if DEBUG
344
- // Show all tips regardless of rules (useful during development)
345
- Tips.showAllTipsForTesting()
346
-
347
- // Show only specific tips
348
- Tips.showTipsForTesting([FavoriteTip.self, ShortcutTip.self])
349
-
350
- // Hide all tips (useful for UI tests that do not involve tips)
351
- Tips.hideAllTipsForTesting()
303
+ ### Invalidation
352
304
 
353
- // Reset the datastore (clears all tip state, invalidations, and events)
354
- try? Tips.resetDatastore()
355
- #endif
356
- ```
357
-
358
- ### Using ProcessInfo for Test Schemes
305
+ Call `tip.invalidate(reason:)` once the person performs the action the tip
306
+ describes, or when the tip no longer applies.
359
307
 
360
- ```swift
361
- if ProcessInfo.processInfo.arguments.contains("--show-all-tips") {
362
- Tips.showAllTipsForTesting()
363
- }
364
- ```
308
+ | Reason | Meaning |
309
+ | --- | --- |
310
+ | `.actionPerformed` | The person did what the tip suggests. |
311
+ | `.displayCountExceeded` | The tip hit its maximum display count. |
312
+ | `.tipClosed` | The person closed the tip. |
365
313
 
366
- Pass `--show-all-tips` as a launch argument in the Xcode scheme for
367
- development builds.
314
+ ### Testing helpers
368
315
 
369
- ## Common Mistakes
316
+ | Call | Effect |
317
+ | --- | --- |
318
+ | `Tips.showAllTipsForTesting()` | Shows every tip and ignores rules. |
319
+ | `Tips.showTipsForTesting([PinPlantTip.self, QuickLogTip.self])` | Shows only the listed tip types. |
320
+ | `Tips.hideAllTipsForTesting()` | Hides all tips, for UI tests that are not about tips. |
321
+ | `try? Tips.resetDatastore()` | Clears tip state, invalidations and event donations. |
370
322
 
371
- ### DON'T: Call Tips.configure() anywhere except App.init
323
+ None of these may run in production. Put them behind `#if DEBUG` or a
324
+ launch-argument check.
372
325
 
373
- Calling `Tips.configure()` in a view's `onAppear` or `task` modifier
374
- creates a race condition where tip views try to render before the
375
- datastore is ready, causing missing or flickering tips.
326
+ ### Launch arguments for development schemes
376
327
 
377
328
  ```swift
378
- // WRONG
379
- struct ContentView: View {
380
- var body: some View {
381
- Text("Hello")
382
- .task { try? Tips.configure() } // Too late, views already rendered
329
+ init() {
330
+ #if DEBUG
331
+ if ProcessInfo.processInfo.arguments.contains("--show-all-tips") {
332
+ Tips.showAllTipsForTesting()
383
333
  }
384
- }
385
-
386
- // CORRECT
387
- @main struct MyApp: App {
388
- init() { try? Tips.configure() }
389
- var body: some Scene { WindowGroup { ContentView() } }
334
+ #endif
335
+ try? Tips.configure()
390
336
  }
391
337
  ```
392
338
 
393
- ### DON'T: Show too many tips at once
394
-
395
- Displaying multiple tips simultaneously overwhelms users and dilutes the
396
- impact of each tip. Users learn to ignore them.
397
-
398
- ```swift
399
- // WRONG: Three tips visible at the same time
400
- VStack {
401
- TipView(tipA)
402
- TipView(tipB)
403
- TipView(tipC)
404
- }
405
-
406
- // CORRECT: Use TipGroup to sequence them
407
- let group = TipGroup(.ordered) { TipA(); TipB(); TipC() }
408
- if let currentTip = group.currentTip {
409
- TipView(currentTip)
410
- }
411
- ```
412
-
413
- ### DON'T: Forget to invalidate tips after the user performs the action
414
-
415
- If a tip says "Tap the star to favorite" and the user taps the star but
416
- the tip remains, it erodes trust in the UI.
417
-
418
- ```swift
419
- // WRONG: Tip stays visible after user acts
420
- Button("Favorite") { toggleFavorite() }
421
- .popoverTip(favoriteTip)
422
-
423
- // CORRECT: Invalidate on action
424
- Button("Favorite") {
425
- toggleFavorite()
426
- favoriteTip.invalidate(reason: .actionPerformed)
427
- }
428
- .popoverTip(favoriteTip)
429
- ```
430
-
431
- ### DON'T: Leave testing tips enabled in production
432
-
433
- `Tips.showAllTipsForTesting()` bypasses all rules and frequency limits.
434
- Shipping this in production means every user sees every tip immediately.
435
-
436
- ```swift
437
- // WRONG: Always active
438
- Tips.showAllTipsForTesting()
439
-
440
- // CORRECT: Gated behind DEBUG
441
- #if DEBUG
442
- Tips.showAllTipsForTesting()
443
- #endif
444
- ```
445
-
446
- ### DON'T: Make tip titles too long
447
-
448
- Long titles get truncated or wrap awkwardly in the compact tip callout.
449
- Put the key action in the title and supporting context in the message.
450
-
451
- ```swift
452
- // WRONG
453
- var title: Text { Text("You can tap the heart button to save this item to your favorites list") }
454
-
455
- // CORRECT
456
- var title: Text { Text("Save to Favorites") }
457
- var message: Text? { Text("Tap the heart icon to keep items for quick access.") }
458
- ```
459
-
460
- ### DON'T: Use tips for critical information
461
-
462
- Users can dismiss tips at any time and they do not reappear. Never put
463
- essential instructions or safety information in a tip.
464
-
465
- ```swift
466
- // WRONG: Critical info in a dismissible tip
467
- struct DataLossTip: Tip {
468
- var title: Text { Text("Unsaved changes will be lost") }
469
- }
470
-
471
- // CORRECT: Use an alert or inline warning for critical information
472
- // Reserve tips for feature discovery and progressive disclosure
473
- ```
474
-
475
- ## Review Checklist
476
-
477
- - [ ] `Tips.configure()` called in `App.init`, before any views render
478
- - [ ] Each tip has a clear, concise title (action-oriented, under ~40 characters)
479
- - [ ] Tips invalidated when the user performs the discovered action
480
- - [ ] Rules set so tips appear at the right time (not immediately on first launch for all tips)
481
- - [ ] `TipGroup` used when multiple tips exist in one view
482
- - [ ] Testing utilities (`showAllTipsForTesting`, `resetDatastore`) gated behind `#if DEBUG`
483
- - [ ] CloudKit sync configured if the app supports multiple devices
484
- - [ ] Display frequency set appropriately (`.daily` or `.weekly` for most apps)
485
- - [ ] Tips used for feature discovery only, not for critical information
486
- - [ ] Custom `TipViewStyle` applied consistently if the default style does not match the app design
487
- - [ ] Tip actions handled and tip invalidated in the action handler
488
- - [ ] Event donations placed at the correct user action points
489
- - [ ] Ensure custom Tip types are Sendable; configure Tips on @MainActor
339
+ Add `--show-all-tips` under Arguments Passed On Launch in a development
340
+ scheme.
341
+
342
+ ## Pitfalls
343
+
344
+ - Configuring in `onAppear` or `.task`. The race leaves tips missing or
345
+ flickering. Configure in `App.init`.
346
+ - Several `TipView`s on screen at once. People feel swamped and start
347
+ ignoring tips. Sequence them with `TipGroup(.ordered)` and `currentTip`.
348
+ - Leaving a tip up after the person already did the thing. A stale hint costs
349
+ trust. Call `invalidate(reason: .actionPerformed)` in the action of the
350
+ control that carries the `.popoverTip`.
351
+ - Shipping `showAllTipsForTesting()` without a guard. It skips rules and
352
+ frequency limits, so every user sees every tip at once. Wrap it in
353
+ `#if DEBUG`.
354
+ - Long titles. They truncate or wrap awkwardly. Keep the action in the title
355
+ and the explanation in the message.
356
+ - Using a tip for critical or safety information. Tips can be dismissed and
357
+ never return. Use an alert or an inline warning.
358
+
359
+ ## Review checklist
360
+
361
+ - [ ] `Tips.configure()` runs in `App.init`, before any view renders.
362
+ - [ ] Titles are short, clear and action oriented, roughly 40 characters or
363
+ fewer.
364
+ - [ ] Each tip is invalidated when its action is performed.
365
+ - [ ] Rules keep tips from all firing on first launch.
366
+ - [ ] Screens with more than one tip use `TipGroup`.
367
+ - [ ] `showAllTipsForTesting` and `resetDatastore` sit behind `#if DEBUG`.
368
+ - [ ] CloudKit sync is configured when the app runs on more than one device.
369
+ - [ ] Display frequency suits the app; `.daily` or `.weekly` fits most.
370
+ - [ ] Tips are used for feature discovery only, never for critical information.
371
+ - [ ] A custom `TipViewStyle` is applied consistently where the default look
372
+ clashes with the design.
373
+ - [ ] Tip actions are handled and the tip is invalidated in the handler.
374
+ - [ ] Event donations happen at the right user-action points.
375
+ - [ ] Tip types are `Sendable`, and TipKit is configured on the `@MainActor`.
490
376
 
491
377
  ## References
492
378
 
493
- - See [references/tipkit-patterns.md](references/tipkit-patterns.md) for complete implementation patterns
494
- including custom styles, event-based rules, tip groups, testing strategies,
495
- onboarding flows, and SwiftUI preview configuration.
496
-
379
+ - [references/tipkit-patterns.md](references/tipkit-patterns.md): complete
380
+ tips with rules and events, placement, donation values, custom styles, tip
381
+ group sequencing, previews and tests, onboarding and a full app example.