How to Implement App Intents and App Shortcuts in iOS Applications

Implement App Intents and App Shortcuts in iOS applications by defining Swift structs that conform to AppIntent, registering them via AppShortcutsProvider, and executing logic either inline through perform() or via an app hand-off routed by an observable manager.

The openai/plugins repository provides production-ready reference implementations for integrating App Intents into iOS projects, specifically within plugins/build-ios-apps/skills/ios-app-intents/. According to the source code in SKILL.md and code-templates.md, the architecture separates intent definitions, entity models, and shortcut registration into three distinct layers. This guide demonstrates how to expose high-value app actions to Shortcuts, Siri, Spotlight, and widgets without requiring users to navigate your full UI.

Core Architecture of App Intents

The implementation consists of three primary layers that work together to bridge your app with iOS system surfaces.

Intent definitions are lightweight Swift structs conforming to AppIntent (or WidgetConfigurationIntent) that declare a title, description, parameters, and the openAppWhenRun property. Entity and query models are optional AppEntity types representing domain objects like workspaces or projects, paired with EntityQuery implementations that supply suggestions to the system. App shortcuts providers are types conforming to AppShortcutsProvider that register AppShortcut objects linking intents to user-facing phrases and system images.

This architecture is documented in plugins/build-ios-apps/skills/ios-app-intents/SKILL.md and illustrated with concrete Swift templates in plugins/build-ios-apps/skills/ios-app-intents/references/code-templates.md.

Creating Open-App Handoff Intents

When an action requires UI presentation or navigation to a specific screen, set openAppWhenRun = true and use a hand-off pattern. This allows the intent to execute lightweight validation before transferring control to your app's scene.

The following implementation from code-templates.md (lines 5-33) demonstrates an intent that opens the app to a composer view:

import AppIntents

struct OpenComposerIntent: AppIntent {
    static let title: LocalizedStringResource = "Open composer"
    static let description = IntentDescription("Open the app to compose content")
    static let openAppWhenRun = true          // opens the app

    @Parameter(title: "Prefilled text",
               inputConnectionBehavior: .connectToPreviousIntentResult)
    var text: String?

    func perform() async throws -> some IntentResult {
        await MainActor.run {
            AppIntentRouter.shared.handledIntent = .init(intent: self)
        }
        return .result()
    }
}

The perform() method sets a hand-off object on a shared router observable by your app's scene, then returns an empty IntentResult to signal completion.

Routing Intents to Your UI

To handle the hand-off from the previous example, implement an AppIntentRouter that your scene delegate observes. This pattern separates intent handling from UI presentation logic.

import AppIntents
import Observation

@Observable
final class AppIntentRouter {
    struct HandledIntent: Equatable {
        let id = UUID()
        let intent: any AppIntent
        static func == (lhs: Self, rhs: Self) -> Bool { lhs.id == rhs.id }
    }
    static let shared = AppIntentRouter()
    var handledIntent: HandledIntent?
    private init() {}
}

In your scene delegate, monitor AppIntentRouter.shared.handledIntent and call handleIntent() to route to the appropriate view controller based on the intent type.

Implementing Inline Action Intents

For actions that complete without UI—such as creating a database record or toggling a setting—set openAppWhenRun = false. The perform() method executes entirely in the background and returns a result with an optional dialog.

This example from code-templates.md (lines 64-88) shows an inline creation intent:

import AppIntents

struct CreateItemIntent: AppIntent {
    static let title: LocalizedStringResource = "Create item"
    static let description = IntentDescription("Create a new item without opening the app")
    static let openAppWhenRun = false          // stays in the background

    @Parameter(title: "Title")
    var title: String

    @Parameter(title: "Workspace")
    var workspace: WorkspaceEntity

    func perform() async throws -> some IntentResult & ProvidesDialog {
        do {
            try await ItemService.shared.createItem(title: title,
                                                    workspaceID: workspace.id)
            return .result(dialog: "Created \(title).")
        } catch {
            return .result(dialog: "Could not create the item. Please try again.")
        }
    }
}

The ProvidesDialog protocol allows the intent to return spoken feedback to the user via Siri or displayed confirmation in Shortcuts.

Defining AppEntity and EntityQuery for Domain Objects

When intents operate on specific domain objects, define AppEntity conforming types to represent them. These entities provide display representations and unique identifiers that the system uses in Shortcuts interfaces and Siri disambiguation.

The following pattern from code-templates.md (lines 37-48) implements a workspace entity:

import AppIntents

struct WorkspaceEntity: AppEntity, Identifiable {
    let workspace: Workspace
    var id: String { workspace.id }

    static let typeDisplayRepresentation = TypeDisplayRepresentation("Workspace")
    static let defaultQuery = WorkspaceQuery()

    var displayRepresentation: DisplayRepresentation {
        DisplayRepresentation(title: "\(workspace.name)")
    }
}

Pair the entity with a query implementation that fetches specific identifiers and provides suggestions:

struct WorkspaceQuery: EntityQuery {
    func entities(for identifiers: [WorkspaceEntity.ID]) async throws -> [WorkspaceEntity] {
        let workspaces = try await WorkspaceStore.shared.workspaces(matching: identifiers)
        return workspaces.map(WorkspaceEntity.init)
    }
    // suggestedEntities & defaultResult implementations omitted for brevity
}

Registering Discoverable Shortcuts

To make intents available in the Shortcuts app, Siri, and Spotlight, implement an AppShortcutsProvider. This static provider declares the phrases users can speak and the system images representing each action.

This registration pattern from code-templates.md (lines 41-68) links intents to discoverable phrases:

import AppIntents

struct AppShortcuts: AppShortcutsProvider {
    static var appShortcuts: [AppShortcut] {
        [
            AppShortcut(
                intent: OpenComposerIntent(),
                phrases: [
                    "Open composer in \(.applicationName)",
                    "Draft with \(.applicationName)"
                ],
                shortTitle: "Open composer",
                systemImageName: "square.and.pencil"
            ),
            AppShortcut(
                intent: CreateItemIntent(),
                phrases: [
                    "Create item with \(.applicationName)",
                    "Add a task in \(.applicationName)"
                ],
                shortTitle: "Create item",
                systemImageName: "plus.circle"
            )
        ]
    }
}

Registering shortcuts does not require submitting to the App Store; the system indexes them locally based on this provider.

Implementation Workflow Checklist

According to SKILL.md in the openai/plugins repository, follow this architectural workflow:

  1. Identify high-value actions (verbs) that users need outside the UI, starting with actions rather than screens (SKILL.md#L20-L24).
  2. Define minimal AppEntity types for objects the system must understand, keeping the entity surface small (SKILL.md#L25-L29).
  3. Choose execution context by setting openAppWhenRun to true for hand-off intents or false for inline execution (SKILL.md#L30-L34).
  4. Register shortcuts via AppShortcutsProvider to surface intents in system locations (SKILL.md#L36-L40).
  5. Implement perform() validation to handle runtime logic or prepare the hand-off object (SKILL.md#L42-L45).

For additional guidance on system surfaces and release checklists, consult plugins/build-ios-apps/skills/ios-app-intents/references/system-surfaces.md and first-pass-checklist.md.

Summary

  • App Intents are defined as Swift structs conforming to AppIntent, exposing specific actions to iOS system surfaces without full UI launches.
  • Open-app handoffs use openAppWhenRun = true and an AppIntentRouter observable to transfer execution to your scene, while inline actions set openAppWhenRun = false and return IntentResult directly.
  • AppEntity and EntityQuery model domain objects for parameterized intents, providing display representations and suggestion logic to the system.
  • AppShortcutsProvider registers intents with user-facing phrases and system images, making them discoverable in Shortcuts, Siri, and Spotlight.
  • Reference templates and architectural guidance are available in plugins/build-ios-apps/skills/ios-app-intents/references/code-templates.md and SKILL.md.

Frequently Asked Questions

What is the difference between openAppWhenRun set to true versus false?

When openAppWhenRun is true, the intent prepares data (such as setting AppIntentRouter.shared.handledIntent) and the system launches your app's UI, allowing your scene delegate to handle navigation. When false, the intent executes the perform() method entirely in the background without launching the app, suitable for database writes or API calls that return immediate confirmation dialogs.

Do I need to define AppEntity types for every intent?

No, AppEntity types are only required when your intent operates on specific domain objects that users must select from a list or reference by identifier. Simple intents that create new objects or perform global actions can use primitive parameters like String or Int without defining custom entities, as shown in the CreateItemIntent example.

How does the system discover my App Intents?

The system discovers intents through a concrete implementation of AppShortcutsProvider, which you define with a static appShortcuts property containing AppShortcut instances. Each shortcut links an intent to trigger phrases and a system image, registering them with the Shortcuts app and Siri without requiring server-side configuration or App Store submission.

Where can I find the reference templates for App Intents implementation?

Complete Swift templates for intents, entities, queries, and shortcuts are located in plugins/build-ios-apps/skills/ios-app-intents/references/code-templates.md within the openai/plugins repository. Architectural guidance and workflow checklists are available in SKILL.md, system-surfaces.md, and first-pass-checklist.md in the same directory.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →