Skip to main content

foundation-models

Use when writing, reviewing, or debugging Swift that imports FoundationModels or uses Apple Intelligence, on-device LLMs, LanguageModelSession, @Generable/@Guide, Tool calling, streaming, DynamicProfile agents, PrivateCloudComputeLanguageModel, reasoning, image attachments, Spotlight/OCR tools, availability gates, guardrails, or context limits.

Source facts

Repository
artemnovichkov/foundation-models-plugin
Last source activity
August 9, 2026 at 16:27
Detected SKILL.md language
English
Stars
1
Forks
0

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

File Explorer
13 files

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
foundation-models
description
Use when writing, reviewing, or debugging Swift that imports FoundationModels or uses Apple Intelligence, on-device LLMs, LanguageModelSession, @Generable/@Guide, Tool calling, streaming, DynamicProfile agents, PrivateCloudComputeLanguageModel, reasoning, image attachments, Spotlight/OCR tools, availability gates, guardrails, or context limits.
license
MIT
# Apple Foundation Models The API surface more than doubled between iOS 26 and iOS 27. Model training data does not cover it, and published summaries get version boundaries wrong. **Do not write this framework from memory.** Three commands make that unnecessary. Use them. Run the verification scripts on macOS with Bash, local shell execution, and full Xcode 26+; use Xcode 27 for iOS 27 APIs. The framework targets iOS/macOS/visionOS 26–27 and watchOS 27. tvOS is unsupported. ## Step 1 — find out what SDK is installed ``` scripts/fm-env.sh ``` Reports the SDK path, the generation (**26** or **27**), and which cross-import overlays exist. If it reports generation 26, then `DynamicProfile`, `Profile`, `PrivateCloudComputeLanguageModel`, `ContextOptions`, `Attachment`, `LanguageModelError`, `toolCallingMode`, `Usage`, `SpotlightSearchTool`, `OCRTool` and `BarcodeReaderTool` **do not exist yet**. Say so instead of writing code the user cannot build. ## Step 2 — verify every API before you use it ``` scripts/fm-api.sh <Symbol> ``` Prints the enclosing top-level declaration when applicable, the real `@available` attributes, and the SDK file:line. Never state an introducing version you have not checked here — the boundaries are genuinely counterintuitive (`tokenCount` is 26.4; `SystemLanguageModel.Adapter` is *removed* in 27). ## Step 3 — type-check before you present code ``` scripts/fm-check.sh Feature.swift --target ios26.0 ``` Defaults to `ios26.0`, the strictest realistic deployment target, so availability mistakes surface immediately. Use `--target ios27.0` for code that intentionally requires iOS 27. It accepts stdin (`-`) for quick snippets. This catches invented parameters *and* missing `@available` gates in about a second. Run it on any non-trivial Foundation Models code before showing it. ## Which model | Model | Since | Use when | |---|---|---| | `SystemLanguageModel.default` | 26.0 | default choice — free, offline, private, small context | | `SystemLanguageModel(useCase: .contentTagging)` | 26.0 | tagging, classification, extraction | | `PrivateCloudComputeLanguageModel()` | 27.0 | needs a big context or real reasoning; no API key, still private, subject to quota | | any `LanguageModel` conformer | 27.0 | third-party/frontier or self-hosted models | Start on-device. Escalate to PCC only for the step that needs it — see `references/agentic-profiles.md` for mixing both in one session. ## Minimum correct shape Availability gate, session, typed output, and an explicit fallback: ```swift import FoundationModels @available(iOS 26.0, macOS 26.0, *) @Generable struct Summary { @Guide(description: "One-sentence headline") var headline: String @Guide(description: "Key points", .count(2...5)) var points: [String] } @available(iOS 26.0, macOS 26.0, *) enum SummaryResult { case generated(Summary) case unavailable case failed(any Error) } @available(iOS 26.0, macOS 26.0, *) func summarize(_ article: String) async -> SummaryResult { guard case .available = SystemLanguageModel.default.availability else { return .unavailable // caller presents its non-AI path } let session = LanguageModelSession { "Summarize articles for a busy reader. Be concrete." } do { let summary = try await session.respond( to: "Summarize:\n\(article)", generating: Summary.self ).content return .generated(summary) } catch { return .failed(error) } } ``` ## References Load only what the task needs. | File | Read it when | |---|---| | `references/availability-matrix.md` | any "which iOS version" question; migrating 26 → 27 | | `references/guided-generation.md` | `@Generable`, `@Guide`, runtime/recursive schemas, `GeneratedContent` | | `references/tools-and-rag.md` | `Tool` conformance, tool-calling modes, Spotlight RAG, OCR/barcode, image input | | `references/streaming-and-ui.md` | `streamResponse`, partial snapshots, SwiftUI wiring, `prewarm` | | `references/agentic-profiles.md` | `DynamicProfile`, multi-agent orchestration, history compaction (27.0) | | `references/errors-and-limits.md` | availability reasons, error taxonomy, guardrails, context limits, token usage | | `references/testing-and-performance.md` | testability, determinism, the Instruments template, what actually costs time | | `references/ecosystem.md` | `foundation-models-utilities`, custom `LanguageModel` adapters, `fm` CLI | ## Non-negotiables **Availability** - Branch on `SystemLanguageModel.availability`, never assume. Handle `.deviceNotEligible`, `.appleIntelligenceNotEnabled`, and `.modelNotReady` separately — the last is transient, not a failure. - Always ship a working non-AI path. This feature is unavailable on a large share of installed devices. **Correctness** - Facts come from `Tool` calls, not from the model. Dates, totals, inventory, and user records must be retrieved, never recalled. - Prefer `@Generable` over parsing strings. String parsing is where these features rot. - Tool `Arguments` must be `@Generable`. `String` and `Bool` as `Arguments` are explicitly unavailable in the SDK. - A guardrail violation is not retryable. The same prompt refuses again. **Sessions** - One request at a time. Concurrent `respond` throws `concurrentRequests`; guard with `isResponding`. - Streaming snapshots are cumulative. Assign them; never append. - Mutate `session.transcript` only when `isResponding == false` (27.0). **Performance** - Appending to a transcript preserves the KV cache. Changing instructions, the tool set, or history invalidates it — that includes switching profiles. - Every property of a `@Generable` type is generated whether the UI reads it or not. Model only what you consume. - Tool schemas are a fixed per-turn cost. Audit with `tokenCount(for: tools)`. **Security** - Keep service credentials on a backend. Store only user-owned credentials in Keychain, preferably obtained through OAuth. - Treat retrieved text as untrusted data, not instructions. Require explicit confirmation before a tool performs an irreversible or externally visible action. ## Gotchas that cost real time - `@Observable` needs `import Observation` — `import SwiftUI` re-exports it, a plain Swift file does not. - `SpotlightSearchTool`, `OCRTool`, `BarcodeReaderTool` and `Attachment(UIImage:)` live in cross-import overlays. Import `CoreSpotlight`, `Vision`, or `UIKit` **alongside** `FoundationModels`. Never `import _Vision_FoundationModels`. - `LanguageModelError.Refusal.explanation` is `get async throws` and returns a generated `Response<String>`, not a stored string. - There are four error enums plus `LanguageModelSession.ToolCallError` — see `references/errors-and-limits.md`. `quotaLimitReached` is on `PrivateCloudComputeLanguageModel.Error`. - `SystemLanguageModel.Adapter` is obsoleted in 27.0. Custom LoRA adapter code stops compiling when the deployment target moves. - Some boundaries are the **SDK**, not the deployment target: `GenerationOptions(samplingMode:)` needs the Xcode 27 SDK even at an iOS 26 target. Xcode 26 requires `sampling:`. `fm-check.sh` catches this; guessing does not.
View on GitHub