Skip to content

Build a private AI feature in Swift with Foundation Models, SwiftUI and App Intents

A production-focused Apple developer guide to Foundation Models, SwiftUI, App Intents, Swift Testing, privacy, evaluation, fallbacks, and accessible AI experiences.

Aya Mensah
Aya Mensah· Senior Editor · iPhone
September 5, 2026Updated September 5, 2026 8 min read
Build a private AI feature in Swift with Foundation Models, SwiftUI and App Intents

Apple's Foundation Models framework can place language-model features inside a native Swift application while App Intents exposes useful actions to system experiences. This guide shows a production-minded architecture with SwiftUI, structured output, privacy checks, testing, accessibility, and measurable fallbacks.

What Apple changed for developers

At WWDC26, Apple described new Foundation Models capabilities including additional model options, vision workflows, context management, semantic search, evaluations, and server-side paths. Review Apple's official session before adopting APIs because SDK names and availability can change.

Apple Developer Foundation Models framework
Start with a narrow, measurable feature before expanding the model workflow.

1. Design one focused user outcome

Do not begin with a generic chatbot. Choose a task with a clear success condition: summarize release notes, classify feedback, extract structured fields, or propose a draft that the user reviews.

8.8/10

Final score

Pros

  • Native Swift integration and system-aware experiences
  • Privacy-preserving on-device paths where supported
  • Structured generation, tools, sessions, and evaluation workflows
  • App Intents can surface actions beyond the app interface

Cons

  • Availability differs across devices, languages, and regions
  • Generative output still requires validation and product safeguards
  • New SDK capabilities can evolve between beta and final releases

2. Build the SwiftUI model layer

ReleaseNotesModel.swift
import FoundationModelsimport Observation @MainActor@Observablefinal class ReleaseNotesModel {    private let session = LanguageModelSession()    var summary = ""     func summarize(_ notes: String) async throws {        let response = try await session.respond(            to: "Summarize these release notes for an iOS developer: \(notes)"        )        summary = response.content    }}

A deliberately small model layer suitable for progressive enhancement.

Q=0.35A+0.25R+0.20L+0.20PQ = 0.35A + 0.25R + 0.20L + 0.20P
A practical evaluation score combining accuracy, reliability, latency, and privacy.

3. Connect actions with App Intents

Use App Intents to describe actions and entities in a structured way so supported system experiences can discover them. Start from the official App Intents documentation , keep parameter summaries understandable, and avoid hiding essential confirmation steps.

Official Apple Developer WWDC26 Foundation Models session.
A practical development workflow: prototype, test, measure, and iterate. Jakub Zerdzicki via Pexels

4. Test behavior, not phrasing

Generated wording can change while the product requirement remains stable. Test required facts, prohibited content, structured constraints, cancellation, unavailable-model behavior, and the manual fallback.

ReleaseNotesModelTests.swift
import Testing@testable import DeveloperAssistant @Test("Generated summaries keep the essential migration warning")func summaryContainsMigrationWarning() async throws {    let result = try await fixtureSummary()    #expect(result.localizedCaseInsensitiveContains("migration"))}

Swift Testing assertion focused on an essential product requirement.

Production decision matrix
ConcernPreferred approachFallback
PrivacyOn-device processing when availableExplicitly disclosed server path
AvailabilityRuntime capability checksDeterministic non-AI workflow
QualityEvaluation set and structured constraintsHuman review and retry

5. Treat availability as a product state

A model-powered feature should never be represented by a single enabled or disabled flag. Build an explicit state machine for supported, temporarily unavailable, restricted, downloading, failed, and fallback modes. That state belongs in the view model so SwiftUI can explain what is happening instead of presenting a spinner that never resolves.

AssistantAvailability.swift
import FoundationModels enum AssistantAvailability {    case ready    case unavailable(reason: String)} func assistantAvailability() -> AssistantAvailability {    let model = SystemLanguageModel.default     switch model.availability {    case .available:        return .ready    case .unavailable(let reason):        return .unavailable(reason: String(describing: reason))    }}

Convert framework availability into a user-facing product state.

  • Show the reason when a capability is unavailable, using plain language.
  • Keep core navigation, saved data, and manual workflows usable without the model.
  • Recheck availability when the app becomes active or relevant settings change.
  • Log aggregate availability states without collecting prompt or private user content.

6. Prefer structured generation over fragile text parsing

Free-form text is useful for drafts, but product logic should consume constrained values whenever possible. Apple documents generation and task workflows in its Foundation Models guide . Define a small output contract, validate every field, and reject values that do not satisfy business rules.

For a release-note assistant, a useful contract might contain a short summary, affected platforms, migration urgency, required actions, and source citations. The UI can then render predictable sections, localize labels independently, and prevent generated prose from controlling navigation or permissions.

Choosing the right output shape
Use caseRecommended outputValidation
Editorial draftConstrained prose with citationsLength, source coverage, prohibited claims
UI fieldsTyped structured outputSchema, ranges, enums, required fields
Search suggestionsShort ranked listDeduplication, relevance, safe destinations
Destructive actionNever execute directlyPreview plus explicit user confirmation

7. Put strict trust boundaries around tools

Tool calling can connect the model to calendars, local databases, network services, or app actions. Treat model-proposed arguments as untrusted input. Validate types and ranges, enforce authorization outside the model, rate-limit expensive operations, and require confirmation for purchases, deletion, publishing, messaging, or account changes.

  • Expose the minimum tool surface needed for the current task.
  • Return compact, typed tool results rather than entire private records.
  • Separate read-only tools from tools that mutate data or contact other people.
  • Record the tool name, result category, latency, and error class for debugging.
  • Never place API keys, authentication tokens, or hidden policy text in prompts.

8. Make App Intents useful outside the app

App Intents can make a focused capability available to supported system experiences. Follow Apple's first App Intent guidance , provide localized titles and descriptions, keep parameters understandable, and return a result that remains useful when the full app interface is not visible.

SummarizeReleaseNotesIntent.swift
import AppIntents struct SummarizeReleaseNotesIntent: AppIntent {    static let title: LocalizedStringResource = "Summarize Release Notes"    static let description = IntentDescription(        "Creates a concise draft while preserving migration warnings."    )     @Parameter(title: "Release notes")    var notes: String     func perform() async throws -> some IntentResult & ReturnsValue<String> {        let summary = try await ReleaseNotesService.shared.summarize(notes)        return .result(value: summary)    }}

A small App Intent that delegates business logic to a testable service.

The intent should not duplicate model orchestration. Keep prompting, validation, persistence, and telemetry in an application service that can also be called from SwiftUI and tests. This prevents different entry points from producing contradictory behavior.

9. Build an evaluation dataset before tuning prompts

A useful evaluation set represents the real distribution of inputs, including short notes, long notes, mixed languages, missing context, malformed text, sensitive data, and adversarial instructions. Store expected facts and unacceptable claims rather than one exact reference paragraph.

EvaluationCase.swift
struct EvaluationCase: Codable {    let id: String    let input: String    let requiredFacts: [String]    let prohibitedClaims: [String]} func score(_ output: String, against test: EvaluationCase) -> Double {    let required = test.requiredFacts.filter(output.localizedCaseInsensitiveContains)    let violations = test.prohibitedClaims.filter(output.localizedCaseInsensitiveContains)    let recall = Double(required.count) / Double(max(test.requiredFacts.count, 1))    return max(0, recall - Double(violations.count) * 0.25)}

A deterministic scoring layer for required facts and prohibited claims.

S=0.40F+0.20C+0.15U+0.15A+0.10ES = 0.40F + 0.20C + 0.15U + 0.15A + 0.10E
Example release score: factuality, constraint compliance, usefulness, accessibility, and efficiency.
  • Keep a frozen regression set for every released version.
  • Add failed real-world cases only after removing personal or confidential data.
  • Compare the AI path with the manual fallback, not only with an earlier prompt.
  • Track median, tail latency, cancellation rate, and fallback completion rate.

10. Design privacy and security into the data flow

Draw the complete data path before implementation: user input, app memory, local storage, model session, tools, analytics, crash reports, server calls, and deletion. Classify every field and decide which data must never leave the device. A privacy claim is credible only when the architecture and logging configuration enforce it.

Privacy review by data class
Data classDefault treatmentRequired control
Public documentationMay be processed for the featureKeep source and version metadata
Account dataMinimize and isolatePurpose limitation and access control
Secrets and credentialsNever include in promptsKeychain or server-side secret storage
TelemetryAggregate by defaultConsent, retention limit, deletion process

11. Build accessibility into every generated state

Generated content must remain readable with Dynamic Type, VoiceOver, increased contrast, reduced motion, keyboard navigation, and switch control. Announce meaningful state changes, keep focus stable when results arrive, and identify generated drafts as drafts. Never encode confidence using color alone.

  • Use semantic headings and concise accessibility labels for generated sections.
  • Let users pause media, animation, and automatic updates.
  • Provide text alternatives and transcripts for images, audio, and video.
  • Test the longest French and English strings at accessibility text sizes.
  • Preserve selection and focus when a result is regenerated or rejected.

12. Localize behavior, not only interface strings

English and French versions need separate evaluation cases because names, dates, units, punctuation, terminology, and acceptable summaries differ. Keep the user language explicit in the request, use localized App Intent resources, and never silently translate private content through an undisclosed service.

Official Apple Developer learning material used to validate the implementation path.
1 / 2

Official Apple Developer learning material used to validate the implementation path.

13. Set a performance and energy budget

Measure cold start, time to first meaningful token, total completion time, memory pressure, cancellation, and battery impact on the oldest supported device. Debounce repeated requests, cancel work when the view disappears, cache only content that is safe to retain, and stream results only when progressive rendering improves comprehension.

14. Observe failures without recording private prompts

Operational dashboards should answer whether the capability was available, which version ran, whether validation passed, whether the user accepted the result, and whether the fallback completed. Use redacted error categories and synthetic test identifiers instead of raw prompts or generated responses.

  • Availability rate by operating system, device class, language, and region.
  • Validation failure and retry rate by feature version.
  • P50, P95, and P99 latency plus user cancellation rate.
  • Fallback completion rate and user-reported correction rate.
  • Crash-free sessions and memory warnings around model operations.

A measured development loop

Prototype one outcome, run repeatable tests, inspect failures, and improve the product contract.
Transcript

Supporting visual: a developer workflow representing implementation, testing, measurement, and iteration. No spoken instruction is required to understand this media.

15. Release checklist for a production team

Before TestFlight

  1. Verify runtime availability on every supported device family.
  2. Run the frozen evaluation set in English and French.
  3. Test offline, cancellation, backgrounding and low-memory states.
  4. Review tool permissions and destructive-action confirmations.
  5. Audit analytics, retention and deletion behavior.
  6. Complete VoiceOver, Dynamic Type and reduced-motion checks.
  7. Confirm source links against the current SDK documentation.

Editorial rule: update this guide when Apple changes API names, availability or platform requirements.

Frequently asked questions

Can every supported iPhone run Foundation Models features?

No. Availability depends on the operating system, compatible hardware, language, region, Apple Intelligence state, and the specific model or capability. Check availability at runtime and provide a complete fallback.

Should generated text be stored automatically?

Usually not before validation and user review. Store only what the product requires, explain retention, protect sensitive fields, and give users a way to edit or delete saved results.

How should a team test nondeterministic output?

Test required facts, forbidden claims, schema validity, safety rules, latency, and fallback behavior across a representative dataset. Avoid comparing every response with one exact sentence.

When should an App Intent require confirmation?

Require explicit confirmation before destructive, financial, privacy-sensitive, publishing, messaging, or account-changing actions. Authorization and validation must live outside the model.

Official learning resources

Start with the Foundation Models documentation .

Review App Intents documentation for system integration.

Use Swift Testing documentation to build repeatable suites.

When an application requires another model provider, review Apple's provider integration session and disclose the resulting data path clearly.

A practical Mac for Xcode and Swift development
Mac 4.6

A practical Mac for Xcode and Swift development

Check memory, storage, and current Xcode requirements before buying.

M5 · 13.6″ Liquid Retina · Up to 18h · 16GB unified

Production checklist

  • Provide an accessible non-AI fallback.
  • Test supported languages and regions.
  • Measure latency, cancellation and failure states.
  • Keep source links and an update log.

Read the official Foundation Models documentation.

Final verdict

Our verdict

8.8/10
Recommended

A strong native foundation when the fallback is equally well designed

Foundation Models, SwiftUI, App Intents, and Swift Testing form a credible Apple-native stack. The quality of the result still depends on narrow product scope, availability checks, evaluations, accessibility, and transparent data handling.

Community rating

8.8/10

How would you rate this verdict?

Community score 8.8/10 from 5 votes

Aya Mensah

Aya Mensah

Senior Editor · iPhone

Aya has covered Apple since the original iPhone. She specialises in hands-on iPhone reviews and smartphone comparisons for African readers.

iPhone Comparisons Camera
View full profile
Share this article

0 comments

Loading…

Comments are moderated. Please keep it respectful.

Comments are submitted for moderation before publication.

Continue reading