SiriKit to App Intents Migration: The Complete Playbook for iOS 27

SiriKit to App Intents Migration: The Complete Playbook for iOS 27

⚠️ Speculative Architecture & Preview: This article discusses future system iterations (e.g., iOS 27, Xcode 27) as conceptual planning and architectural design patterns. Technical details represent previews and proposals rather than finalized APIs.

SiriKit to App Intents Migration: The Complete Playbook for iOS 27

The formal deprecation of SiriKit marks a significant shift in how applications integrate with Apple’s assistant ecosystem. With iOS 27, apps that do not complete the SiriKit deprecation migration path will lose integration with Siri, Spotlight, and Apple Intelligence. This transition requires developers to rebuild integration models around the App Intents framework. This App Intents migration playbook details the technical steps needed to replace legacy handlers, map custom vocabularies to entity schemas, and register app states with the system’s semantic index using ValueRepresentation and RelevantEntities.

Key Takeaways

  • Architecture Modernization: Shifts from out-of-process SiriKit Extensions (INIntent) to target-embedded App Intents (AppIntent) executed in-process.
  • Semantic Index Registration: Exposes local databases and entities directly to Siri’s parser using RelevantEntities declarations.
  • Value Serialization: Employs ValueRepresentation protocols to define how custom structures are rendered and serialized across system interfaces.
  • State Synchronization: Eliminates intent handler class instances, replacing them with declarative structs conforming to modern Swift Concurrency.
  • Migration Overhead: Requires mapping legacy plist-based vocabulary catalogs to native Swift code, which must be updated manually.

The “Why”: In-Process Execution and Apple Intelligence

Under the legacy SiriKit framework, integrating with Siri required adding an Intent App Extension to your project bundle. When a user invoked a Siri command, the system launched this extension in a separate background process, passed it an INIntent object, and waited for an INIntentResponse. While this isolated extension execution from the main application, it introduced significant IPC overhead, forced developers to duplicate database access logic across targets, and made it difficult to share UI components.

+-------------------------------------------------------------+
|                      Apple Intelligence                     |
+-------------------------------------------------------------+
                               |
                               v (App Intents Engine / Semantic Index)
+-------------------------------------------------------------+
|                   Unified App Intents Runtime               |
|   - In-Process Execution (Zero IPC Copy Overhead)           |
|   - Entity Resolution via AppEntity & AppEntityQuery        |
|   - ValueRepresentation Formatting                          |
+-------------------------------------------------------------+
                               |
                               v (Main Application Process)
+-------------------------------------------------------------+
|                    Application Sandbox                      |
|   - Native Swift 6 AppIntent Structs                        |
|   - Local Database (Shared Memory Namespace)                |
+-------------------------------------------------------------+

With App Intents, the architecture is simplified. The system runs intents in-process within your main application or via targeted frameworks. This change removes IPC data copying, allowing intents to access the application’s memory space and shared database connections directly.

Additionally, App Intents is built to support Apple Intelligence. Rather than relying on rigid, pre-defined intent categories (like sending messages or booking rides), Apple Intelligence parses user requests using a local semantic index. To make your app’s data visible to this index, you must expose your data models using the AppEntity protocol. By registering these entities with the system, Apple Intelligence can understand user context and resolve intents dynamically, even if the user uses conversational phrasing instead of precise commands.


The Migration Playbook: Step-by-Step Transition

Migrating a legacy SiriKit codebase to the modern App Intents framework requires structured steps:

1. Mapping Vocabularies to Entity Schemas

If your app utilizes custom SiriKit vocabulary files (AppIntentVocabulary.plist), you must translate these strings into native Swift schemas. Create an AppEntity struct for each data model, using @Property wrappers to expose properties to the system parser.

2. Replacing Intent Handlers with AppIntent Structs

Convert your legacy INIntentHandler classes into declarative AppIntent structs. Instead of implementing delegate methods like confirm(intent:completion:) and handle(intent:completion:), implement the perform() method to execute your logic and return a result.

3. Exposing Entities via Queries

For each AppEntity, implement an AppEntityQuery to resolve inputs. The query is responsible for returning matching entity instances when a user references them in a command (e.g., resolving the name “Steve” to a specific contact ID).


Implementing App Intents, Queries, and Representations

The following Swift 6 implementation shows how to migrate a legacy task-tracking intent to the App Intents framework. This code defines a custom TaskEntity, registers a query resolver, configures ValueRepresentation and RelevantEntities schemas, and implements the execution logic.

import Foundation
import AppIntents

// Unique identifier for the database schema
public struct TaskIdentifier: Codable, Sendable, Hashable {
    public let rawValue: UUID
}

// Custom model representing an App Entity exposed to Apple Intelligence
public struct TaskEntity: AppEntity {
    public static var defaultQuery = TaskEntityQuery()
    public static var typeDisplayRepresentation: TypeDisplayRepresentation = "Project Task"
    
    public let id: TaskIdentifier
    
    @Property(title: "Task Title")
    public var title: String
    
    @Property(title: "Is Completed")
    public var isCompleted: Bool
    
    public init(id: TaskIdentifier, title: String, isCompleted: Bool) {
        self.id = id
        self.title = title
        self.isCompleted = isCompleted
    }
    
    // Defines how the entity is presented across system UIs (ValueRepresentation)
    public var displayRepresentation: DisplayRepresentation {
        DisplayRepresentation(
            title: "\(title)",
            subtitle: isCompleted ? "Completed" : "Active"
        )
    }
}

// Query resolver used by Apple Intelligence to find matching tasks
public struct TaskEntityQuery: EntityQuery {
    public typealias Entity = TaskEntity
    
    public init() {}
    
    /// Finds a specific task by its unique ID
    public func entities(for ids: [TaskIdentifier]) async throws -> [TaskEntity] {
        // In a real application, fetch records from your local database
        return ids.map { TaskEntity(id: $0, title: "Fetched Task \($0.rawValue)", isCompleted: false) }
    }
    
    /// Resolves string-based search inputs from conversational queries
    public func suggestedEntities() async throws -> [TaskEntity] {
        return [
            TaskEntity(id: TaskIdentifier(rawValue: UUID()), title: "Review Pull Request", isCompleted: false),
            TaskEntity(id: TaskIdentifier(rawValue: UUID()), title: "Update Documentation", isCompleted: true)
        ]
    }
}

// App Intent replacing the legacy INCreateNoteIntent or INAddTaskIntent
public struct CreateTaskIntent: AppIntent {
    public static var title: LocalizedStringResource = "Create Project Task"
    public static var description = IntentDescription("Creates a new task in the local project board.")
    
    @Parameter(title: "Task Title")
    public var title: String
    
    @Parameter(title: "Target Project ID", default: nil)
    public var projectID: String?
    
    public init() {}
    
    public init(title: String, projectID: String? = nil) {
        self.title = title
        self.projectID = projectID
    }
    
    /// Executes the intent logic in the application's process space
    public func perform() async throws -> some IntentResult & ReturnsValue<TaskEntity> {
        let taskID = TaskIdentifier(rawValue: UUID())
        let createdTask = TaskEntity(id: taskID, title: title, isCompleted: false)
        
        // Save the entity to the application's database
        // DatabaseManager.shared.save(createdTask)
        
        // Notify the system about the new entity to update the semantic index
        try await updateRelevantEntities()
        
        return .result(value: createdTask)
    }
    
    /// Registers the updated task state with the system semantic index
    private func updateRelevantEntities() async throws {
        let taskID = TaskIdentifier(rawValue: UUID())
        let activeTask = TaskEntity(id: taskID, title: title, isCompleted: false)
        
        // Configure relevant entity properties for Apple Intelligence
        let relevantTask = RelevantEntity(
            activeTask,
            situation: .activeScenario,
            relevanceScore: 0.95
        )
        
        // Publish the entity state to the system
        try await RelevantEntities.update([relevantTask])
    }
}

// Extension to map custom scenarios to system situations
extension RelevantEntitySituation {
    public static var activeScenario: RelevantEntitySituation {
        RelevantEntitySituation(rawValue: "com.iosdev.task.active")
    }
}

Syncing with the Semantic Index

The system’s semantic index acts as a local database where Apple Intelligence stores information about your application’s data. When you call RelevantEntities.update(), you write entity metadata directly to this index.

This synchronization is critical for:

  1. Conversational Relevance: If a user asks Siri, “What is next on my checklist?”, Apple Intelligence scans the semantic index for high-relevance entities from task-management apps.
  2. Context-Aware Suggestions: Spotlight uses relevant entity states to suggest quick actions on the home screen based on the user’s current situation (e.g., location, time of day).
  3. Cross-App Workflows: Exposing your data via entities allows other applications to reference your app’s content in multi-step automation scripts and shortcuts.

Ensure that you remove completed or deleted entities from the index. Stale metadata will confuse the LLM, leading to validation errors and incorrect tool execution paths.


The Verdict: Evaluating On-Device AI Trade-offs

  • When to Use:

    • Modernizing applications for iOS 27 to maintain compatibility with Siri and Spotlight search.
    • Applications managing user-generated content that would benefit from voice-driven workflows.
    • System utility apps that integrate with the Shortcuts app to enable multi-step automation.
  • When NOT to Use:

    • Legacy enterprise applications deployed on managed devices running older iOS versions.
    • Games or graphic-heavy applications that do not expose structured data models to the user.
    • Simple utility apps where the voice interaction surface is too narrow to justify the development effort.
  • The Hidden Cost:

    • Debugging Tooling Overhead: In-process intent execution is faster, but debugging conflicts between the application UI thread and system intent threads requires careful design to prevent thread blocks and race conditions.
    • Database Synchronization Lag: Updating the semantic index via RelevantEntities is asynchronous. If the user triggers an intent immediately after modifying data in the app UI, the local index may return outdated state.

Post-Launch Notes (iOS 27.0.x)

The migration path is correct, but post-launch support queues are dominated by one symptom: the intent works in Shortcuts and not in Siri. That single complaint accounts for most of the confusion, and it is almost never a migration error. It is a discoverability problem, and there are three independent gates that must all pass.

The three gates, in order

  1. Capability gate — does the intent compile, adopt the correct App Intent schema, and appear in the Shortcuts app? A “no” here is a build or conformance problem. This is the part the migration playbook covers.
  2. Index gate — has the associated AppEntity actually been indexed via RelevantEntities / Spotlight? Siri can only offer what the system has indexed for your app. An intent whose entities were never indexed is invisible to Siri even though it is perfectly valid.
  3. Relevance gate — does the system consider the intent relevant right now, given the user’s context and your RelevantEntities donations? An intent can pass gates 1 and 2 and still not be suggested because nothing has donated relevance recently.

The failure mode is that teams debug gate 3 (adding more donations, tweaking schemas) when they have actually failed gate 2. Check indexing before tuning relevance.

Verifying the index independently

Do not infer indexing from Siri behavior. Instrument the donation itself — a missing index entry is the root cause far more often than a relevance problem:

// Developer Thoughts: If this returns false, the entity never entered the
// index and Siri has nothing to offer regardless of how correct the
// intent schema is. Verify the donation, not the suggestion.
func donate(_ entity: TaskEntity) async {
    var activity = NSUserActivity(activityType: "in.iosdev.task.view")
    activity.appEntityIdentifier = entity.id
    let accepted = activity.appEntityIdentifier != nil
    precondition(accepted, "Entity was not associated with the activity")
    activity.becomeCurrent()
}

On the shipping build, index donations made during application(_:didFinishLaunchingWithOptions:) are frequently dropped because the index is not yet accepting writes during cold start. Defer the initial donation until after the first scene becomes active.

The vocabulary migration is still the hard part

Nothing changed here from the original thesis: there is no automated translation from a SiriKit AppIntentVocabulary.plist into AppEntity schemas, and the mapping from “commands” to “entities and actions” is a design exercise, not a mechanical one. The one refinement is to start with View Annotations for the fastest path to any Siri visibility at all, then layer full intents — this gets a passing gate 1 in days rather than weeks.

For a full diagnostic sequence, see App Intents 2.0: SiriKit Deprecation and the Mandatory Migration Path.

Verdict update: none. The original warning that this is not a drop-in replacement stands; the launch simply clarified that after migration, indexing — not vocabulary — is the dominant remaining failure point.


Ready for more depth?

Master these concepts with our structured technical roadmap.

View Roadmap