Explore local language models with Apple Core AI.
A minimal macOS showcase for building an on-device AI chat experience with SwiftUI, Core AI, and Foundation Models.
CoreAIChat demonstrates the shortest path from an exported model bundle to a native, local chat experience on macOS. Load the bundled model, submit a prompt, and receive a response through Apple's Foundation Models APIs—all without a remote inference service.
The project is model-agnostic. The included
gemma_3_4b_it_4bit_dynamic resource is an example; any compatible language
model supported by Apple's coreai-models
repository can take its place.
- Run inference on device: Load an exported Core AI model directly from the app bundle and generate responses locally.
- Use native frameworks: Combine SwiftUI, Foundation Models, and
CoreAILanguageModelsin a compact reference implementation. - Swap compatible models: Follow a model-specific
coreai-modelsrecipe, then replace the example resource and its name in the app. - Keep the interface responsive: Model loading and response generation use Swift concurrency.
- See the complete chat flow: The showcase covers loading, prewarming, prompt submission, progress feedback, conversation history, and errors.
- Learn from documented behavior: Concise feature specifications describe the observable model-loading, conversation, and error states.
The implemented behavior is documented in docs/features/,
including model loading,
chat conversations, and
error handling.
Important
CoreAIChat is a showcase app, not an App Store product. It is intended for learning, experimentation, and demonstrating Apple Core AI integration. It is not production-ready and is not distributed through the App Store.
Generated output may be inaccurate, incomplete, or misleading. Model
compatibility and setup requirements can vary between coreai-models releases.
| Area | Implementation |
|---|---|
| Interface | SwiftUI |
| Conversation API | Foundation Models |
| Local model runtime | CoreAILanguageModels from coreai-models |
| Concurrency | Swift async/await |
| Example model | Gemma 3 4B IT |
| Platform | macOS 27 |
You need macOS 27 and Xcode 27. Model export can require substantial disk space and memory; requirements vary by model.
Install uv if it is not already available:
brew install uvAlternatively, use the official installer:
curl -LsSf https://astral.sh/uv/install.sh | shClone Apple's coreai-models
repository and enter it:
git clone https://github.com/apple/coreai-models.git
cd coreai-modelsChoose one of the compatible model recipes in coreai-models and follow its
requirements and license terms. For the Gemma 3 example, accept the
Gemma license terms, install the
Hugging Face CLI, and authenticate:
brew install hf
hf auth login --token <YOUR_TOKEN>Then export the model from the coreai-models directory:
uv run coreai.llm.export google/gemma-3-4b-itExporting can take a few minutes because the source model may need to be
downloaded before conversion. For Gemma 3, the result is written to
exports/gemma_3_4b_it_4bit_dynamic and should have this structure:
gemma_3_4b_it_4bit_dynamic/
├── gemma_3_4b_it_4bit_dynamic.aimodel/
├── metadata.json
└── tokenizer/
Commands and prerequisites differ between models. Treat the matching recipe in
coreai-models as the source of truth.
Open the project:
open CoreAIChat.xcodeprojAdd the complete exported resource directory to the CoreAIChat app target.
The repository includes an empty gemma_3_4b_it_4bit_dynamic/ placeholder that
is already referenced by the project and ViewModel.swift.
When using another compatible model:
- Replace the example resource directory in the app target.
- Update the resource name in
CoreAIChat/ViewModel.swift. - Keep the
.aimodel,metadata.json, andtokenizer/resources together.
Exported model files are intentionally not committed to this repository.
For a signed local build, create your personal build configuration once:
cp Config/Local.xcconfig.example Config/Local.xcconfigThen replace YOUR_TEAM_ID and the example bundle identifier in
Config/Local.xcconfig. The local file is ignored by Git, so developer-specific
signing values do not end up in project.pbxproj. Unsigned command-line builds
do not require this file.
Select the CoreAIChat scheme in Xcode and run it. Choose Load Model, wait
for the local model to load and prewarm, then start a conversation. The first
load can take a little longer.
For a signing-independent compile check, use Xcode 27:
DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer \
xcodebuild -project CoreAIChat.xcodeproj \
-scheme CoreAIChat \
-sdk macosx \
-destination 'platform=macOS' \
-derivedDataPath /tmp/coreaichat-derived-data \
CODE_SIGNING_ALLOWED=NO buildThe central integration is deliberately small. This example uses the included Gemma 3 resource name; substitute your exported directory name when using a different compatible model.
import Foundation
import FoundationModels
import CoreAILanguageModels
func respond(to prompt: String) async throws -> String {
guard let modelURL = Bundle.main.url(
forResource: "gemma_3_4b_it_4bit_dynamic",
withExtension: nil
) else {
throw URLError(.fileDoesNotExist)
}
let model = try await CoreAILanguageModel(resourcesAt: modelURL)
let session = LanguageModelSession(model: model)
let response = try await session.respond(to: prompt)
return response.content
}CoreAIChat/
├── CoreAIChat/ SwiftUI app source
├── CoreAIChat.xcodeproj/ Xcode project and package resolution
├── Config/ Shared and local build settings
├── docs/features/ Feature behavior and acceptance criteria
├── docs/assets/ README assets
├── gemma_3_4b_it_4bit_dynamic/ Untracked model-resource placeholder
└── Icon.icon/ App icon source
CoreAIChat is available under the MIT License. Model weights and related resources remain subject to their respective licenses.