AI-powered App Intent generator for SwiftData models.
Add one protocol, run one command, get a complete suite of Siri & Shortcuts intents.
Writing App Intents by hand for every data model in your app is tedious and error-prone. KTAutoIntents automates this:
- You conform your
@Modelclass toAutoIntentableand describe what it represents. - The CLI reads your model, sends the schema to an LLM, and writes a complete, production-ready
*Intents.swiftfile. - You add that file to Xcode. Done — your data is searchable via Siri, Spotlight, and the Shortcuts app.
┌──────────────────────┐ ┌─────────────┐ ┌─────────────────────────┐
│ Your @Model class │──────▶│ LLM (Gemini │──────▶│ RecipeIntents.swift │
│ Recipe.swift │ schema │ or OpenAI) │ Swift │ AppEntity, EntityQuery │
│ + AutoIntentable │ └─────────────┘ code │ 5 AppIntent subclasses │
└──────────────────────┘ │ AppShortcutsProvider │
└─────────────────────────┘
The generated code is committed to your project — no LLM calls at build time or runtime.
In Xcode: File → Add Package Dependencies… and paste:
https://github.com/ktaniguchi/KTAutoIntents
Or add to Package.swift:
.package(url: "https://github.com/ktaniguchi/KTAutoIntents", from: "1.0.0")Then add KTAutoIntents to your target's dependencies.
git clone https://github.com/ktaniguchi/KTAutoIntents
cd KTAutoIntents
swift build -c release --product KTAutoIntentsCLI
sudo cp .build/release/KTAutoIntentsCLI /usr/local/bin/import SwiftData
import KTAutoIntents
@Model
final class Recipe: AutoIntentable {
var name: String
var cuisineType: String
var preparationTime: Int // minutes
var isVegetarian: Bool
var difficultyLevel: String
// MARK: AutoIntentable metadata
static var intentDisplayName: String { "Recipe" }
static var intentDescription: String {
"A cooking recipe with cuisine type and preparation time"
}
static var intentKeywords: [String] { ["food", "cooking", "meal"] }
static var intentSearchablePropertyNames: [String] {
["name", "cuisineType", "isVegetarian", "preparationTime"]
}
}# Set your API key (Gemini is the default)
export GEMINI_API_KEY=your_key_here
# or for OpenAI:
# export OPENAI_API_KEY=your_key_here
KTAutoIntentsCLI generate \
--path ./MyApp/Models \
--output ./MyApp/GeneratedIntentsOutput:
┌─────────────────────────────────────────────┐
│ KTAutoIntents — App Intent Generator │
│ https://github.com/ktaniguchi/KTAutoIntents │
└─────────────────────────────────────────────┘
🔍 Scanning: ./MyApp/Models
Found 2 model(s): Recipe, Ingredient
🤖 Provider: gemini / gemini-2.0-flash
📝 Output: ./MyApp/GeneratedIntents
Generating intents for Recipe… ✅ RecipeIntents.swift
Generating intents for Ingredient… ✅ IngredientIntents.swift
🎉 Done. 2/2 file(s) generated in ./MyApp/GeneratedIntents
- Drag the generated
*Intents.swiftfiles into your Xcode target. - Register the model container once in your app entry point:
import SwiftUI
import SwiftData
import KTAutoIntents
@main
struct RecipeApp: App {
init() {
IntentConfiguration.shared.register {
try ModelContainer(for: Recipe.self)
}
}
var body: some Scene {
WindowGroup { ContentView() }
}
}That's it — build and run. Your recipes are now searchable via Siri ("Find quick recipes in Recipe App"), Spotlight, and the Shortcuts app.
USAGE: KTAutoIntentsCLI generate [options]
OPTIONS:
-p, --path <path> Directory containing your @Model source files. (required)
-o, --output <output> Output directory for generated files. (default: ./GeneratedIntents)
--provider <provider> LLM provider: gemini (default) | openai
--model <model> LLM model name override (e.g. gemini-2.0-flash, gpt-4o)
--dry-run Print the LLM prompts without calling the API.
--skip-validation Skip swiftc syntax validation of generated code.
-h, --help Show help information.
| Provider | Environment Variable |
|---|---|
| Gemini (default) | GEMINI_API_KEY |
| OpenAI | OPENAI_API_KEY |
public protocol AutoIntentable {
/// Singular human-readable name (e.g. "Recipe")
static var intentDisplayName: String { get }
/// Brief description to help the LLM understand the entity
static var intentDescription: String { get }
/// Siri search keywords (default: [])
static var intentKeywords: [String] { get }
/// Properties the LLM should focus intents on (default: inferred)
static var intentSearchablePropertyNames: [String] { get }
}The generator infers searchable properties automatically from type (String, Bool, numeric) when intentSearchablePropertyNames is empty.
For each @Model, the generator produces a single Swift file containing:
| Component | Description |
|---|---|
AppEntity extension |
Conformance with display representation |
EntityQuery |
SwiftData-backed entity lookup for system |
3–7 AppIntent subclasses |
Natural-language intents (search, filter, range, etc.) |
AppShortcutsProvider |
Registers top intents with Siri phrase templates |
| ModelContainer helper | Private extension for container access |
See Examples/RecipeApp/GeneratedIntents.swift for a real example.
Re-run the CLI after changing your model's properties. The existing *Intents.swift file will be overwritten with a fresh generation.
KTAutoIntentsCLI generate --path ./MyApp/Models --output ./MyApp/GeneratedIntentsConsider adding this as a Makefile target or a custom Xcode run script phase (disabled by default so it only runs on demand).
Contributions are welcome! See CONTRIBUTING.md for guidelines.
Pull requests for new LLM providers, improved prompt engineering, and additional example models are especially appreciated.
MIT — see LICENSE.