@mmerterden/multi-agent-pipeline 20.36.0 → 20.37.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 (222) hide show
  1. package/CHANGELOG.md +37 -0
  2. package/docs/facts.json +2 -2
  3. package/docs/features.md +1 -1
  4. package/docs/recovery-guide.md +1 -1
  5. package/install/catalog-history.json +1 -1
  6. package/manifest.json +225 -148
  7. package/package.json +1 -1
  8. package/pipeline/commands/multi-agent/SKILL.md +33 -154
  9. package/pipeline/commands/multi-agent/analysis/SKILL.md +14 -68
  10. package/pipeline/commands/multi-agent/analysis-jira/SKILL.md +5 -8
  11. package/pipeline/commands/multi-agent/autopilot-on/SKILL.md +38 -109
  12. package/pipeline/commands/multi-agent/channels/SKILL.md +38 -167
  13. package/pipeline/commands/multi-agent/complaint-analysis/SKILL.md +37 -144
  14. package/pipeline/commands/multi-agent/design-check/SKILL.md +27 -131
  15. package/pipeline/commands/multi-agent/garbage-collect/SKILL.md +22 -48
  16. package/pipeline/commands/multi-agent/ios-coding-standard/SKILL.md +37 -180
  17. package/pipeline/commands/multi-agent/jira/SKILL.md +16 -46
  18. package/pipeline/commands/multi-agent/manual-test/SKILL.md +12 -7
  19. package/pipeline/commands/multi-agent/refactor/SKILL.md +23 -184
  20. package/pipeline/commands/multi-agent/resume/SKILL.md +30 -136
  21. package/pipeline/commands/multi-agent/review/SKILL.md +24 -199
  22. package/pipeline/commands/multi-agent/setup/SKILL.md +25 -181
  23. package/pipeline/commands/multi-agent/stack/SKILL.md +9 -53
  24. package/pipeline/commands/multi-agent/status/SKILL.md +13 -2
  25. package/pipeline/commands/multi-agent/store-ready/SKILL.md +27 -226
  26. package/pipeline/commands/multi-agent/sync/SKILL.md +35 -164
  27. package/pipeline/commands/multi-agent/test-gen/SKILL.md +2 -4
  28. package/pipeline/commands/multi-agent/update/SKILL.md +18 -60
  29. package/pipeline/contract/CHANGELOG.md +9 -0
  30. package/pipeline/contract/fixtures/error-invalid-request.json +1 -1
  31. package/pipeline/contract/fixtures/error-unauthorized.json +1 -1
  32. package/pipeline/contract/fixtures/error-unsigned.json +1 -1
  33. package/pipeline/contract/fixtures/runs-awaiting-question.json +1 -1
  34. package/pipeline/contract/fixtures/runs-empty.json +1 -1
  35. package/pipeline/contract/fixtures/runs-failed.json +1 -1
  36. package/pipeline/contract/fixtures/runs-pr-opened-redacted.json +1 -1
  37. package/pipeline/contract/fixtures/runs-pr-opened.json +1 -1
  38. package/pipeline/contract/fixtures/runs-running.json +1 -1
  39. package/pipeline/contract/manifest.json +5 -5
  40. package/pipeline/contract/types/index.d.ts +3 -2
  41. package/pipeline/multi-agent-refs/audit-guide.md +20 -0
  42. package/pipeline/multi-agent-refs/autopilot-on/details.md +148 -0
  43. package/pipeline/multi-agent-refs/channels/generator.md +14 -0
  44. package/pipeline/multi-agent-refs/channels/preview.md +13 -0
  45. package/pipeline/multi-agent-refs/channels/reference.md +46 -0
  46. package/pipeline/multi-agent-refs/complaint-analysis/phases.md +159 -0
  47. package/pipeline/multi-agent-refs/design-check/export.md +1 -0
  48. package/pipeline/multi-agent-refs/design-check/init-inventory.md +1 -1
  49. package/pipeline/multi-agent-refs/design-check/scope-and-ledger.md +64 -0
  50. package/pipeline/multi-agent-refs/features/analysis-command-notes.md +53 -0
  51. package/pipeline/multi-agent-refs/features/commit-multi-repo.md +63 -0
  52. package/pipeline/multi-agent-refs/features/dev-multi-repo.md +51 -0
  53. package/pipeline/multi-agent-refs/features/test-gap.md +40 -0
  54. package/pipeline/multi-agent-refs/features/worktree-finalize.md +1 -1
  55. package/pipeline/multi-agent-refs/garbage-collect/phases.md +60 -0
  56. package/pipeline/multi-agent-refs/ios-coding-standard/plan.md +71 -0
  57. package/pipeline/multi-agent-refs/ios-coding-standard/resolve-and-scan.md +135 -0
  58. package/pipeline/multi-agent-refs/jira/picker-detail.md +71 -0
  59. package/pipeline/multi-agent-refs/orchestrator/copilot-pipeline.md +88 -0
  60. package/pipeline/multi-agent-refs/orchestrator/dispatcher.md +96 -1
  61. package/pipeline/multi-agent-refs/orchestrator/phase-3-user-test.md +12 -9
  62. package/pipeline/multi-agent-refs/phases/phase-1-plan.md +4 -4
  63. package/pipeline/multi-agent-refs/phases/phase-2-dev.md +8 -47
  64. package/pipeline/multi-agent-refs/phases/phase-3-review.md +21 -65
  65. package/pipeline/multi-agent-refs/phases/phase-4-commit.md +9 -59
  66. package/pipeline/multi-agent-refs/phases/phase-5-report.md +0 -31
  67. package/pipeline/multi-agent-refs/refactor/sweep.md +190 -0
  68. package/pipeline/multi-agent-refs/resume/details.md +115 -2
  69. package/pipeline/multi-agent-refs/review/inputs.md +33 -1
  70. package/pipeline/multi-agent-refs/review/module-guides.md +9 -1
  71. package/pipeline/multi-agent-refs/review/panel.md +75 -0
  72. package/pipeline/multi-agent-refs/review/valven.md +5 -1
  73. package/pipeline/multi-agent-refs/rules.md +1 -1
  74. package/pipeline/multi-agent-refs/setup/hooks-and-plugins.md +4 -0
  75. package/pipeline/multi-agent-refs/setup/token-save-flow.md +13 -0
  76. package/pipeline/multi-agent-refs/stack/background.md +72 -0
  77. package/pipeline/multi-agent-refs/store-ready/gates.md +139 -0
  78. package/pipeline/multi-agent-refs/store-ready/report.md +40 -2
  79. package/pipeline/multi-agent-refs/sync/office.md +10 -0
  80. package/pipeline/multi-agent-refs/sync/overview.md +61 -0
  81. package/pipeline/multi-agent-refs/sync/repo.md +91 -0
  82. package/pipeline/multi-agent-refs/update/details.md +83 -0
  83. package/pipeline/office/index.html +6 -3
  84. package/pipeline/office/toolkit.json +1 -1
  85. package/pipeline/rules/figma-pipeline.md +6 -3
  86. package/pipeline/schemas/prefs.schema.json +1 -1
  87. package/pipeline/schemas/runs-index.schema.json +2 -1
  88. package/pipeline/scripts/_memory-policy.mjs +27 -5
  89. package/pipeline/scripts/checkpoint-fold.sh +59 -0
  90. package/pipeline/scripts/contract-server.mjs +1 -1
  91. package/pipeline/scripts/gate-ledger.mjs +1 -1
  92. package/pipeline/scripts/office-control.mjs +41 -15
  93. package/pipeline/scripts/offload-ref.sh +1 -1
  94. package/pipeline/scripts/rework-rulings.mjs +5 -3
  95. package/pipeline/scripts/runs-index.mjs +34 -7
  96. package/pipeline/scripts/scope-check-gate.mjs +15 -2
  97. package/pipeline/scripts/status-overview.mjs +401 -0
  98. package/pipeline/scripts/user-test-handoff.sh +203 -0
  99. package/pipeline/scripts/validate-planning.mjs +5 -3
  100. package/pipeline/scripts/validate-triage.mjs +2 -1
  101. package/pipeline/scripts/write-state.mjs +13 -4
  102. package/pipeline/skills/.skill-manifest.json +64 -64
  103. package/pipeline/skills/shared/core/apple-archive-compliance/SKILL.md +7 -70
  104. package/pipeline/skills/shared/core/apple-archive-compliance/references/examples.md +67 -0
  105. package/pipeline/skills/shared/core/apple-archive-compliance/references/version-history.md +8 -0
  106. package/pipeline/skills/shared/core/google-play-compliance/SKILL.md +10 -72
  107. package/pipeline/skills/shared/core/google-play-compliance/references/examples.md +69 -0
  108. package/pipeline/skills/shared/core/google-play-compliance/references/notes.md +7 -0
  109. package/pipeline/skills/shared/core/google-play-compliance/references/version-history.md +5 -0
  110. package/pipeline/skills/shared/core/multi-agent/SKILL.md +39 -262
  111. package/pipeline/skills/shared/core/multi-agent-autopilot-on/SKILL.md +35 -73
  112. package/pipeline/skills/shared/core/multi-agent-channels/SKILL.md +37 -337
  113. package/pipeline/skills/shared/core/multi-agent-design-check/SKILL.md +27 -122
  114. package/pipeline/skills/shared/core/multi-agent-help/SKILL.md +8 -340
  115. package/pipeline/skills/shared/core/multi-agent-ios-coding-standard/SKILL.md +37 -180
  116. package/pipeline/skills/shared/core/multi-agent-manual-test/SKILL.md +12 -7
  117. package/pipeline/skills/shared/core/multi-agent-refactor/SKILL.md +23 -184
  118. package/pipeline/skills/shared/core/multi-agent-review/SKILL.md +14 -82
  119. package/pipeline/skills/shared/core/multi-agent-setup/SKILL.md +25 -277
  120. package/pipeline/skills/shared/core/multi-agent-status/SKILL.md +13 -2
  121. package/pipeline/skills/shared/core/multi-agent-sync/SKILL.md +73 -217
  122. package/pipeline/skills/shared/external/alarmkit/SKILL.md +11 -162
  123. package/pipeline/skills/shared/external/alarmkit/references/alarmkit-code.md +257 -0
  124. package/pipeline/skills/shared/external/android-architecture/SKILL.md +7 -58
  125. package/pipeline/skills/shared/external/android-architecture/references/code-examples.md +68 -0
  126. package/pipeline/skills/shared/external/app-intents/SKILL.md +3 -45
  127. package/pipeline/skills/shared/external/app-intents/references/code-examples.md +54 -0
  128. package/pipeline/skills/shared/external/app-store-optimization/SKILL.md +5 -81
  129. package/pipeline/skills/shared/external/app-store-optimization/references/engagement-and-localization.md +96 -0
  130. package/pipeline/skills/shared/external/app-store-review/SKILL.md +6 -112
  131. package/pipeline/skills/shared/external/app-store-review/references/monetization-and-submission.md +138 -0
  132. package/pipeline/skills/shared/external/apple-on-device-ai/SKILL.md +10 -117
  133. package/pipeline/skills/shared/external/apple-on-device-ai/references/foundation-models-code.md +186 -0
  134. package/pipeline/skills/shared/external/authentication/SKILL.md +3 -50
  135. package/pipeline/skills/shared/external/authentication/references/code-examples.md +59 -0
  136. package/pipeline/skills/shared/external/callkit-voip/SKILL.md +3 -84
  137. package/pipeline/skills/shared/external/callkit-voip/references/code-examples.md +93 -0
  138. package/pipeline/skills/shared/external/ci-cd-pipelines/SKILL.md +7 -263
  139. package/pipeline/skills/shared/external/ci-cd-pipelines/references/pipeline-examples.md +281 -0
  140. package/pipeline/skills/shared/external/clean-code/SKILL.md +8 -41
  141. package/pipeline/skills/shared/external/clean-code/references/code-examples.md +56 -0
  142. package/pipeline/skills/shared/external/cloudkit-sync/SKILL.md +8 -146
  143. package/pipeline/skills/shared/external/cloudkit-sync/references/cloudkit-code.md +214 -0
  144. package/pipeline/skills/shared/external/compose-components/SKILL.md +6 -80
  145. package/pipeline/skills/shared/external/compose-components/references/code-examples.md +89 -0
  146. package/pipeline/skills/shared/external/compose-navigation/SKILL.md +5 -64
  147. package/pipeline/skills/shared/external/compose-navigation/references/code-examples.md +70 -0
  148. package/pipeline/skills/shared/external/core-data/SKILL.md +9 -157
  149. package/pipeline/skills/shared/external/core-data/references/core-data-code.md +221 -0
  150. package/pipeline/skills/shared/external/core-nfc/SKILL.md +3 -89
  151. package/pipeline/skills/shared/external/core-nfc/references/code-examples.md +98 -0
  152. package/pipeline/skills/shared/external/coreml/SKILL.md +17 -133
  153. package/pipeline/skills/shared/external/coreml/references/coreml-code.md +208 -0
  154. package/pipeline/skills/shared/external/css-modern/SKILL.md +8 -131
  155. package/pipeline/skills/shared/external/css-modern/references/code-examples.md +142 -0
  156. package/pipeline/skills/shared/external/database-patterns/SKILL.md +6 -103
  157. package/pipeline/skills/shared/external/database-patterns/references/orm-examples.md +112 -0
  158. package/pipeline/skills/shared/external/html-semantic/SKILL.md +7 -48
  159. package/pipeline/skills/shared/external/html-semantic/references/code-examples.md +54 -0
  160. package/pipeline/skills/shared/external/humanizer/SKILL.md +6 -19
  161. package/pipeline/skills/shared/external/humanizer/references/voice.md +24 -0
  162. package/pipeline/skills/shared/external/ios-accessibility/SKILL.md +13 -170
  163. package/pipeline/skills/shared/external/ios-accessibility/references/assistive-tech-review.md +224 -0
  164. package/pipeline/skills/shared/external/ios-localization/SKILL.md +2 -24
  165. package/pipeline/skills/shared/external/ios-localization/references/code-examples.md +30 -0
  166. package/pipeline/skills/shared/external/ios-networking/SKILL.md +3 -58
  167. package/pipeline/skills/shared/external/ios-networking/references/code-examples.md +67 -0
  168. package/pipeline/skills/shared/external/ios-security/SKILL.md +4 -64
  169. package/pipeline/skills/shared/external/ios-security/references/code-examples.md +74 -0
  170. package/pipeline/skills/shared/external/live-activities/SKILL.md +4 -90
  171. package/pipeline/skills/shared/external/live-activities/references/code-examples.md +108 -0
  172. package/pipeline/skills/shared/external/localization-reuse-map/SKILL.md +9 -23
  173. package/pipeline/skills/shared/external/localization-reuse-map/references/project-settings.md +22 -0
  174. package/pipeline/skills/shared/external/mapkit-location/SKILL.md +5 -95
  175. package/pipeline/skills/shared/external/mapkit-location/references/code-examples.md +117 -0
  176. package/pipeline/skills/shared/external/nextjs-app-router/SKILL.md +7 -106
  177. package/pipeline/skills/shared/external/nextjs-app-router/references/app-router-examples.md +124 -0
  178. package/pipeline/skills/shared/external/permissionkit/SKILL.md +2 -31
  179. package/pipeline/skills/shared/external/permissionkit/references/code-examples.md +37 -0
  180. package/pipeline/skills/shared/external/play-store-review/SKILL.md +6 -74
  181. package/pipeline/skills/shared/external/play-store-review/references/signing-and-policies.md +83 -0
  182. package/pipeline/skills/shared/external/push-notifications/SKILL.md +8 -125
  183. package/pipeline/skills/shared/external/push-notifications/references/notification-code.md +176 -0
  184. package/pipeline/skills/shared/external/python-patterns/SKILL.md +7 -158
  185. package/pipeline/skills/shared/external/python-patterns/references/python-examples.md +176 -0
  186. package/pipeline/skills/shared/external/rest-api-design/SKILL.md +7 -157
  187. package/pipeline/skills/shared/external/rest-api-design/references/api-examples.md +175 -0
  188. package/pipeline/skills/shared/external/swift-architecture/SKILL.md +11 -230
  189. package/pipeline/skills/shared/external/swift-architecture/references/pattern-examples.md +295 -0
  190. package/pipeline/skills/shared/external/swift-codable/SKILL.md +17 -149
  191. package/pipeline/skills/shared/external/swift-codable/references/codable-recipes.md +207 -0
  192. package/pipeline/skills/shared/external/swift-concurrency/SKILL.md +12 -99
  193. package/pipeline/skills/shared/external/swift-concurrency/references/code-examples.md +100 -0
  194. package/pipeline/skills/shared/external/swift-concurrency/references/swift-6-2-additions.md +18 -0
  195. package/pipeline/skills/shared/external/swift-formatstyle/SKILL.md +9 -78
  196. package/pipeline/skills/shared/external/swift-formatstyle/references/formatstyle-examples.md +113 -0
  197. package/pipeline/skills/shared/external/swift-language/SKILL.md +3 -56
  198. package/pipeline/skills/shared/external/swift-language/references/code-examples.md +65 -0
  199. package/pipeline/skills/shared/external/swift-testing-pro/SKILL.md +1 -0
  200. package/pipeline/skills/shared/external/swiftdata/SKILL.md +6 -122
  201. package/pipeline/skills/shared/external/swiftdata/references/code-examples.md +140 -0
  202. package/pipeline/skills/shared/external/swiftui-uikit-interop/SKILL.md +12 -139
  203. package/pipeline/skills/shared/external/swiftui-uikit-interop/references/interop-code.md +198 -0
  204. package/pipeline/skills/shared/external/tailwind-css/SKILL.md +9 -81
  205. package/pipeline/skills/shared/external/tailwind-css/references/code-examples.md +91 -0
  206. package/pipeline/skills/shared/external/testing-backend/SKILL.md +7 -207
  207. package/pipeline/skills/shared/external/testing-backend/references/testing-examples.md +225 -0
  208. package/pipeline/skills/shared/external/typescript-patterns/SKILL.md +8 -89
  209. package/pipeline/skills/shared/external/typescript-patterns/references/code-examples.md +100 -0
  210. package/pipeline/skills/shared/external/vision-framework/SKILL.md +2 -20
  211. package/pipeline/skills/shared/external/vision-framework/references/code-examples.md +26 -0
  212. package/pipeline/skills/shared/external/vue-composition/SKILL.md +7 -169
  213. package/pipeline/skills/shared/external/vue-composition/references/vue-examples.md +187 -0
  214. package/pipeline/skills/shared/external/web-accessibility/SKILL.md +7 -174
  215. package/pipeline/skills/shared/external/web-accessibility/references/a11y-examples.md +192 -0
  216. package/pipeline/skills/shared/external/web-performance/SKILL.md +8 -66
  217. package/pipeline/skills/shared/external/web-performance/references/code-examples.md +77 -0
  218. package/pipeline/skills/shared/external/web-testing/SKILL.md +11 -186
  219. package/pipeline/skills/shared/external/web-testing/references/testing-examples.md +213 -0
  220. /package/pipeline/skills/shared/external/localization-reuse-map/{reference → references}/format-and-output.md +0 -0
  221. /package/pipeline/skills/shared/external/localization-reuse-map/{reference → references}/publish-and-snapshot.md +0 -0
  222. /package/pipeline/skills/shared/external/localization-reuse-map/{reference → references}/sources-and-recipes.md +0 -0
@@ -0,0 +1,186 @@
1
+ # Foundation Models and multi-backend code
2
+
3
+ <!-- toc -->
4
+ - [Check availability first](#check-availability-first)
5
+ - [Structured output](#structured-output)
6
+ - [Tools](#tools)
7
+ - [Errors](#errors)
8
+ - [Running several backends](#running-several-backends)
9
+ <!-- /toc -->
10
+
11
+ Code for availability checks, structured output, tools, error handling and routing between several backends. SKILL.md keeps stack choice, rules and review guidance.
12
+
13
+ ## Check availability first
14
+
15
+ Every entry point checks availability and falls back without crashing.
16
+
17
+ ```swift
18
+ import Foundation
19
+ import FoundationModels
20
+ import os
21
+
22
+ private let aiLog = Logger(subsystem: "StudyApp", category: "AI")
23
+
24
+ enum SummaryState { case ready, openSettings, downloading, unsupported }
25
+
26
+ func summaryState() -> SummaryState {
27
+ let model = SystemLanguageModel.default
28
+ switch model.availability {
29
+ case .available:
30
+ return model.supportsLocale(Locale.current) ? .ready : .unsupported
31
+ case .unavailable(.appleIntelligenceNotEnabled):
32
+ return .openSettings // point the user to Settings
33
+ case .unavailable(.modelNotReady):
34
+ return .downloading // assets still arriving; show progress
35
+ case .unavailable(.deviceNotEligible):
36
+ return .unsupported // hardware cannot run it; use a fallback
37
+ case .unavailable(let other):
38
+ aiLog.notice("Model unavailable: \(String(describing: other))")
39
+ return .unsupported
40
+ }
41
+ }
42
+ ```
43
+
44
+ ## Structured output
45
+
46
+ `@Generable` builds the output schema at compile time, and the response comes
47
+ back as your type.
48
+
49
+ ```swift
50
+ @Generable
51
+ struct StudyCard {
52
+ @Guide(description: "The term being studied, two to four words")
53
+ var term: String
54
+ @Guide(description: "Plain-language definitions", .count(2))
55
+ var definitions: [String]
56
+ @Guide(.range(1...5))
57
+ var difficulty: Int
58
+ }
59
+
60
+ let reply = try await tutor.respond(to: "Make a card for osmosis",
61
+ generating: StudyCard.self)
62
+ let card = reply.content
63
+ ```
64
+
65
+ `@Guide` options:
66
+
67
+ | Guide | Effect |
68
+ |---|---|
69
+ | `description:` | Natural-language hint for the field |
70
+ | `.anyOf([...])` | String must be one of the listed values |
71
+ | `.count(n)` | Array has exactly `n` elements |
72
+ | `.range(a...b)` | Number within a closed range |
73
+ | `.minimum(n)` / `.maximum(n)` | Lower or upper limit on a number |
74
+ | `.minimumCount(n)` / `.maximumCount(n)` | Limits on how many elements an array has |
75
+ | `.constant(value)` | Field is always exactly this |
76
+ | `.pattern(regex)` | String matches a pattern |
77
+ | `.element(guide)` | Applies a guide to every array element |
78
+
79
+ Fields are generated in declaration order. Put the fields that others depend on
80
+ first.
81
+
82
+ Streaming gives partial values as they form; each property of
83
+ `StudyCard.PartiallyGenerated` is optional:
84
+
85
+ ```swift
86
+ let cardStream = tutor.streamResponse(to: "Card for diffusion", generating: StudyCard.self)
87
+ for try await partial in cardStream {
88
+ draft.term = partial.content.term ?? draft.term
89
+ draft.definitions = partial.content.definitions ?? draft.definitions
90
+ }
91
+ ```
92
+
93
+ ## Tools
94
+
95
+ ```swift
96
+ struct GlossaryTool: Tool {
97
+ let name = "lookUpTerm"
98
+ let description = "Returns the course glossary entry for a biology term."
99
+
100
+ @Generable
101
+ struct Arguments {
102
+ @Guide(description: "Singular form of the term to look up")
103
+ var term: String
104
+ @Guide(.range(1...3))
105
+ var gradeLevel: Int
106
+ }
107
+
108
+ func call(arguments: Arguments) async throws -> String {
109
+ await Glossary.shared.entry(for: arguments.term, level: arguments.gradeLevel)
110
+ ?? "No entry found."
111
+ }
112
+ }
113
+ ```
114
+
115
+ - Register tools when creating the session, and only the ones the task needs.
116
+ - `Tool` is `Sendable`; captured state must be safe to share.
117
+ - Tool names, descriptions and argument schemas, like `@Generable` schemas,
118
+ use up part of the context budget.
119
+ - Whether a tool runs is the model's decision. Data the answer always needs
120
+ should be fetched beforehand and put in the prompt; keep tools for lookups
121
+ that depend on the conversation.
122
+
123
+ ## Errors
124
+
125
+ ```swift
126
+ do {
127
+ let answer = try await tutor.respond(to: question)
128
+ show(answer.content)
129
+ } catch let failure as LanguageModelSession.GenerationError {
130
+ switch failure {
131
+ case .exceededContextWindowSize: restartWithSummary() // too many tokens
132
+ case .guardrailViolation: showRephraseHint() // safety filter hit
133
+ case .concurrentRequests: queueUntilIdle() // session already busy
134
+ case .unsupportedLanguageOrLocale: showLanguageNotice()
135
+ case .unsupportedGuide: logSchemaProblem() // a @Guide the model cannot honour
136
+ case .assetsUnavailable: showDownloadingState()
137
+ case .refusal(let refusal, _): explain(refusal) // stream refusal.explanation
138
+ case .rateLimited: retryLater() // back off
139
+ case .decodingFailure: logSchemaProblem() // output did not fit the type
140
+ default: showGenericFailure()
141
+ }
142
+ }
143
+ ```
144
+
145
+ ## Running several backends
146
+
147
+ Try the system model first, then a local open model, and fail clearly when
148
+ neither is there:
149
+
150
+ ```swift
151
+ func pickBackend() async throws -> Backend {
152
+ let systemModel = SystemLanguageModel.default
153
+ if systemModel.isAvailable { return .foundationModels }
154
+ if await mlxModelCanLoad() { return .mlx }
155
+ throw AIError.noBackendAvailable
156
+ }
157
+ ```
158
+
159
+ Send every model call through one actor so requests never compete for the same
160
+ hardware. Actors are reentrant: a method that awaits lets the next caller in,
161
+ so an actor that only forwards the call does not serialise anything. Chain the
162
+ work instead:
163
+
164
+ ```swift
165
+ actor InferenceGate {
166
+ private var last: Task<Void, Never>?
167
+
168
+ func exclusive<Value: Sendable>(
169
+ _ work: @escaping @Sendable () async throws -> Value
170
+ ) async throws -> Value {
171
+ let previous = last
172
+ let current = Task { () async throws -> Value in
173
+ await previous?.value
174
+ return try await work()
175
+ }
176
+ last = Task { _ = try? await current.value }
177
+ return try await current.value
178
+ }
179
+ }
180
+ ```
181
+
182
+ - For a custom Core ML model, this skill stops at conversion and
183
+ optimisation. Swift integration, loading, Vision hookup and running
184
+ predictions are for `coreml`.
185
+ - Private material such as journals or health notes stays on the device unless
186
+ the product has deliberately chosen a non-local fallback.
@@ -51,32 +51,7 @@ extension WelcomeViewController: ASAuthorizationControllerPresentationContextPro
51
51
 
52
52
  ### Delegate callbacks
53
53
 
54
- ```swift
55
- extension WelcomeViewController: ASAuthorizationControllerDelegate {
56
- func authorizationController(controller: ASAuthorizationController,
57
- didCompleteWithAuthorization authorization: ASAuthorization) {
58
- let credential = authorization.credential
59
- guard let apple = credential as? ASAuthorizationAppleIDCredential else { return }
60
- AccountVault.shared.rememberAppleUser(apple.user) // stable per-team ID
61
- if let name = apple.fullName { ProfileDraft.shared.name = name } // first time only
62
- if let mail = apple.email { ProfileDraft.shared.email = mail } // first time only
63
- Task { try await SessionAPI.exchange(token: apple.identityToken, code: apple.authorizationCode) }
64
- }
65
-
66
- func authorizationController(controller: ASAuthorizationController,
67
- didCompleteWithError error: Error) {
68
- guard let authError = error as? ASAuthorizationError else { return }
69
- switch authError.code {
70
- case .canceled: break // user closed the sheet
71
- case .notInteractive: break // silent check found nothing
72
- case .failed, .invalidResponse, .notHandled:
73
- showSignInProblem(authError)
74
- default:
75
- showSignInProblem(authError)
76
- }
77
- }
78
- }
79
- ```
54
+ Code: [Delegate callbacks](references/code-examples.md#delegate-callbacks).
80
55
 
81
56
  `user` is a stable identifier scoped to your team; save it in the Keychain so
82
57
  you can check credential state later. `identityToken` is a JWT for the server
@@ -138,30 +113,7 @@ user out as soon as it fires.
138
113
  Never accept the identity token on the device alone. Hand both values to your
139
114
  backend and keep only what it returns:
140
115
 
141
- ```swift
142
- enum SessionAPI {
143
- struct Session: Decodable { let accessToken: String }
144
- private static let transport = URLSession(configuration: .ephemeral)
145
-
146
- static func exchange(token: Data?, code: Data?) async throws {
147
- guard let token, let code,
148
- let jwt = String(data: token, encoding: .utf8),
149
- let grant = String(data: code, encoding: .utf8) else { throw URLError(.badServerResponse) }
150
-
151
- guard let endpoint = URL(string: "https://api.tasknest.app/auth/apple") else { throw URLError(.badURL) }
152
- var call = URLRequest(url: endpoint)
153
- call.httpMethod = "POST"
154
- call.addValue("application/json", forHTTPHeaderField: "Content-Type")
155
- let body = try JSONEncoder().encode(["identity_token": jwt, "authorization_code": grant])
156
- let (bytes, reply) = try await transport.upload(for: call, from: body)
157
- let status = (reply as? HTTPURLResponse)?.statusCode ?? 0
158
- if status != 200 { throw URLError(.userAuthenticationRequired) }
159
-
160
- let session = try JSONDecoder().decode(Session.self, from: bytes)
161
- try TokenVault(service: "auth").store(Data(session.accessToken.utf8), account: "access")
162
- }
163
- }
164
- ```
116
+ Code: [Server validation](references/code-examples.md#server-validation).
165
117
 
166
118
  `TokenVault` is in the [Keychain reference](references/keychain-biometric.md). The
167
119
  server verifies the JWT signature against Apple's published key set (the JWKS
@@ -388,3 +340,4 @@ mapping against OWASP MASVS/MASTG. App and device attestation belongs to `device
388
340
  - [ASAuthorizationPasswordProvider](https://developer.apple.com/documentation/authenticationservices/asauthorizationpasswordprovider)
389
341
  - [SignInWithAppleButton](https://developer.apple.com/documentation/authenticationservices/signinwithapplebutton)
390
342
  - Sample code: the AuthenticationServices sample on implementing user authentication with Apple ID sign-in
343
+ - [Code examples](references/code-examples.md): open for the full code behind Delegate callbacks, Server validation.
@@ -0,0 +1,59 @@
1
+ # Authentication Code Examples
2
+
3
+ Full code samples for the SKILL.md sections that link here. The rules and the decision guidance stay in SKILL.md; each heading below matches the SKILL.md section the code belongs to.
4
+
5
+ ## Delegate callbacks
6
+
7
+ ```swift
8
+ extension WelcomeViewController: ASAuthorizationControllerDelegate {
9
+ func authorizationController(controller: ASAuthorizationController,
10
+ didCompleteWithAuthorization authorization: ASAuthorization) {
11
+ let credential = authorization.credential
12
+ guard let apple = credential as? ASAuthorizationAppleIDCredential else { return }
13
+ AccountVault.shared.rememberAppleUser(apple.user) // stable per-team ID
14
+ if let name = apple.fullName { ProfileDraft.shared.name = name } // first time only
15
+ if let mail = apple.email { ProfileDraft.shared.email = mail } // first time only
16
+ Task { try await SessionAPI.exchange(token: apple.identityToken, code: apple.authorizationCode) }
17
+ }
18
+
19
+ func authorizationController(controller: ASAuthorizationController,
20
+ didCompleteWithError error: Error) {
21
+ guard let authError = error as? ASAuthorizationError else { return }
22
+ switch authError.code {
23
+ case .canceled: break // user closed the sheet
24
+ case .notInteractive: break // silent check found nothing
25
+ case .failed, .invalidResponse, .notHandled:
26
+ showSignInProblem(authError)
27
+ default:
28
+ showSignInProblem(authError)
29
+ }
30
+ }
31
+ }
32
+ ```
33
+
34
+ ## Server validation
35
+
36
+ ```swift
37
+ enum SessionAPI {
38
+ struct Session: Decodable { let accessToken: String }
39
+ private static let transport = URLSession(configuration: .ephemeral)
40
+
41
+ static func exchange(token: Data?, code: Data?) async throws {
42
+ guard let token, let code,
43
+ let jwt = String(data: token, encoding: .utf8),
44
+ let grant = String(data: code, encoding: .utf8) else { throw URLError(.badServerResponse) }
45
+
46
+ guard let endpoint = URL(string: "https://api.tasknest.app/auth/apple") else { throw URLError(.badURL) }
47
+ var call = URLRequest(url: endpoint)
48
+ call.httpMethod = "POST"
49
+ call.addValue("application/json", forHTTPHeaderField: "Content-Type")
50
+ let body = try JSONEncoder().encode(["identity_token": jwt, "authorization_code": grant])
51
+ let (bytes, reply) = try await transport.upload(for: call, from: body)
52
+ let status = (reply as? HTTPURLResponse)?.statusCode ?? 0
53
+ if status != 200 { throw URLError(.userAuthenticationRequired) }
54
+
55
+ let session = try JSONDecoder().decode(Session.self, from: bytes)
56
+ try TokenVault(service: "auth").store(Data(session.accessToken.utf8), account: "access")
57
+ }
58
+ }
59
+ ```
@@ -145,34 +145,7 @@ ended with `.failed` and fail the action.
145
145
  Outgoing calls start with a request to `CXCallController`. The system checks it
146
146
  and hands it back through `provider(_:perform:)` with a `CXStartCallAction`.
147
147
 
148
- ```swift
149
- extension PhoneLine {
150
- func dial(_ address: String, video: Bool) -> UUID {
151
- let id = UUID()
152
- let start = CXStartCallAction(call: id, handle: CXHandle(type: .phoneNumber, value: address))
153
- start.isVideo = video
154
- controller.request(CXTransaction(action: start)) { error in
155
- if let error { Log.calls.error("dial refused: \(error)") }
156
- }
157
- return id
158
- }
159
-
160
- func provider(_ cx: CXProvider, perform dial: CXStartCallAction) {
161
- AudioRoute.prepareForCall()
162
- let id = dial.callUUID
163
- cx.reportOutgoingCall(with: id, startedConnectingAt: .now)
164
- Task {
165
- do {
166
- try await SignalingClient.shared.place(call: id, to: dial.handle.value)
167
- cx.reportOutgoingCall(with: id, connectedAt: .now)
168
- dial.fulfill()
169
- } catch {
170
- dial.fail()
171
- }
172
- }
173
- }
174
- }
175
- ```
148
+ Code: [Outgoing call flow](references/code-examples.md#outgoing-call-flow).
176
149
 
177
150
  Report both `startedConnectingAt` and `connectedAt`; Recents and the call timer
178
151
  use them.
@@ -199,62 +172,7 @@ Report rules:
199
172
  | 26.4+ delegate, `mustReport == false` | No | After local handling |
200
173
  | Older delegate | Treat every VoIP call push as required | After the report callback |
201
174
 
202
- ```swift
203
- import PushKit
204
-
205
- @MainActor
206
- final class VoIPInbox: NSObject, @preconcurrency PKPushRegistryDelegate {
207
- private let registry = PKPushRegistry(queue: .main)
208
-
209
- func start() {
210
- registry.delegate = self
211
- registry.desiredPushTypes = [.voIP]
212
- }
213
-
214
- func pushRegistry(_ reg: PKPushRegistry, didUpdate credentials: PKPushCredentials, for type: PKPushType) {
215
- let hex = credentials.token.reduce(into: "") { out, byte in out += String(format: "%02x", byte) }
216
- Backend.shared.upload(voipToken: hex)
217
- }
218
-
219
- @available(iOS 26.4, *)
220
- func pushRegistry(_ reg: PKPushRegistry,
221
- didReceiveIncomingVoIPPushWith payload: PKPushPayload,
222
- metadata: PKVoIPPushMetadata,
223
- withCompletionHandler completion: @escaping @Sendable () -> Void) {
224
- guard metadata.mustReport else {
225
- completion()
226
- return
227
- }
228
- ring(from: payload, then: completion)
229
- }
230
-
231
- func pushRegistry(_ reg: PKPushRegistry,
232
- didReceiveIncomingPushWith payload: PKPushPayload,
233
- for type: PKPushType,
234
- completion: @escaping () -> Void) {
235
- guard type == .voIP else {
236
- completion()
237
- return
238
- }
239
- ring(from: payload, then: completion)
240
- }
241
-
242
- private func ring(from payload: PKPushPayload, then completion: @escaping () -> Void) {
243
- let body = payload.dictionaryPayload
244
- let number = body["from"] as? String ?? "Unknown"
245
- let name = body["display"] as? String ?? number
246
- let video = body["video"] as? Bool ?? false
247
- Task {
248
- do {
249
- try await PhoneLine.shared.announceIncoming(id: UUID(), number: number, name: name, video: video)
250
- } catch {
251
- Log.calls.notice("call filtered or rejected: \(error)")
252
- }
253
- completion()
254
- }
255
- }
256
- }
257
- ```
175
+ Code: [PushKit VoIP registration](references/code-examples.md#pushkit-voip-registration).
258
176
 
259
177
  Keep the older delegate method for iOS 26.0 through 26.3 and for lower
260
178
  deployment targets. The registry delivers on `.main`, which is why the inbox is
@@ -420,3 +338,4 @@ Rotating APNs keys and the usual notification registration are covered by
420
338
  - [PKVoIPPushMetadata](https://developer.apple.com/documentation/pushkit/pkvoippushmetadata)
421
339
  - Article: [VoIP call handling with CallKit](https://developer.apple.com/documentation/callkit/making-and-receiving-voip-calls)
422
340
  - Article: [PushKit VoIP notification handling](https://developer.apple.com/documentation/pushkit/responding-to-voip-notifications-from-pushkit)
341
+ - [Code examples](references/code-examples.md): open for the full code behind Outgoing call flow, PushKit VoIP registration.
@@ -0,0 +1,93 @@
1
+ # CallKit and PushKit Code Examples
2
+
3
+ Full code samples for the SKILL.md sections that link here. The rules and the decision guidance stay in SKILL.md; each heading below matches the SKILL.md section the code belongs to.
4
+
5
+ ## Outgoing call flow
6
+
7
+ ```swift
8
+ extension PhoneLine {
9
+ func dial(_ address: String, video: Bool) -> UUID {
10
+ let id = UUID()
11
+ let start = CXStartCallAction(call: id, handle: CXHandle(type: .phoneNumber, value: address))
12
+ start.isVideo = video
13
+ controller.request(CXTransaction(action: start)) { error in
14
+ if let error { Log.calls.error("dial refused: \(error)") }
15
+ }
16
+ return id
17
+ }
18
+
19
+ func provider(_ cx: CXProvider, perform dial: CXStartCallAction) {
20
+ AudioRoute.prepareForCall()
21
+ let id = dial.callUUID
22
+ cx.reportOutgoingCall(with: id, startedConnectingAt: .now)
23
+ Task {
24
+ do {
25
+ try await SignalingClient.shared.place(call: id, to: dial.handle.value)
26
+ cx.reportOutgoingCall(with: id, connectedAt: .now)
27
+ dial.fulfill()
28
+ } catch {
29
+ dial.fail()
30
+ }
31
+ }
32
+ }
33
+ }
34
+ ```
35
+
36
+ ## PushKit VoIP registration
37
+
38
+ ```swift
39
+ import PushKit
40
+
41
+ @MainActor
42
+ final class VoIPInbox: NSObject, @preconcurrency PKPushRegistryDelegate {
43
+ private let registry = PKPushRegistry(queue: .main)
44
+
45
+ func start() {
46
+ registry.delegate = self
47
+ registry.desiredPushTypes = [.voIP]
48
+ }
49
+
50
+ func pushRegistry(_ reg: PKPushRegistry, didUpdate credentials: PKPushCredentials, for type: PKPushType) {
51
+ let hex = credentials.token.reduce(into: "") { out, byte in out += String(format: "%02x", byte) }
52
+ Backend.shared.upload(voipToken: hex)
53
+ }
54
+
55
+ @available(iOS 26.4, *)
56
+ func pushRegistry(_ reg: PKPushRegistry,
57
+ didReceiveIncomingVoIPPushWith payload: PKPushPayload,
58
+ metadata: PKVoIPPushMetadata,
59
+ withCompletionHandler completion: @escaping @Sendable () -> Void) {
60
+ guard metadata.mustReport else {
61
+ completion()
62
+ return
63
+ }
64
+ ring(from: payload, then: completion)
65
+ }
66
+
67
+ func pushRegistry(_ reg: PKPushRegistry,
68
+ didReceiveIncomingPushWith payload: PKPushPayload,
69
+ for type: PKPushType,
70
+ completion: @escaping () -> Void) {
71
+ guard type == .voIP else {
72
+ completion()
73
+ return
74
+ }
75
+ ring(from: payload, then: completion)
76
+ }
77
+
78
+ private func ring(from payload: PKPushPayload, then completion: @escaping () -> Void) {
79
+ let body = payload.dictionaryPayload
80
+ let number = body["from"] as? String ?? "Unknown"
81
+ let name = body["display"] as? String ?? number
82
+ let video = body["video"] as? Bool ?? false
83
+ Task {
84
+ do {
85
+ try await PhoneLine.shared.announceIncoming(id: UUID(), number: number, name: name, video: video)
86
+ } catch {
87
+ Log.calls.notice("call filtered or rejected: \(error)")
88
+ }
89
+ completion()
90
+ }
91
+ }
92
+ }
93
+ ```