app-intents

AppIntents framework for Siri, Shortcuts, Spotlight, and Visual Intelligence integration. Covers AppIntent protocol, OpenIntent for deep linking, intent modes (.background, .foreground(.dynamic), .foreground(.deferred)), continueInForeground API, @ComputedProperty and @DeferredProperty macros, IndexedEntity for Spotlight with CSSearchableItemAttributeSet, interactive snippets (SnippetIntent), AppShortcutsProvider, multiple choice API (requestChoice), Swift Package support (AppIntentsPackage), Visual Intelligence integration (@UnionValue, IntentValueQuery, SemanticContentDescriptor). Use when adding Siri support, Shortcuts actions, Spotlight indexing, or system-wide app entity exposure.

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "app-intents" with this command: npx skills add makgunay/claude-swift-skills/makgunay-claude-swift-skills-app-intents

AppIntents — Siri, Shortcuts & Spotlight

Critical Constraints

  • ❌ DO NOT use old SiriKit INIntent → ✅ Use AppIntent protocol
  • ❌ DO NOT use NSUserActivity alone for Spotlight → ✅ Use IndexedEntity + CSSearchableIndex.default().indexAppEntities()
  • ❌ DO NOT hardcode foreground-only intents → ✅ Use supportedModes for flexible execution

Basic App Intent

import AppIntents

struct FindNearestLandmarkIntent: AppIntent {
    static var title: LocalizedStringResource = "Find Nearest Landmark"

    @Parameter(title: "Category")
    var category: String?

    func perform() async throws -> some IntentResult {
        let landmark = await findNearestLandmark(category: category)
        return .result(value: landmark)
    }
}

Intent Modes (Background/Foreground Control)

struct GetCrowdStatusIntent: AppIntent {
    static let supportedModes: IntentModes = [.background, .foreground(.dynamic)]

    func perform() async throws -> some ReturnsValue<Int> & ProvidesDialog {
        guard await modelData.isOpen(landmark) else {
            return .result(value: 0, dialog: "Currently closed.")
        }
        if systemContext.currentMode.canContinueInForeground {
            do {
                try await continueInForeground(alwaysConfirm: false)
                await navigator.navigateToCrowdStatus(landmark)
            } catch { }
        }
        let status = await modelData.getCrowdStatus(landmark)
        return .result(value: status, dialog: "Crowd level: \(status)")
    }
}

Mode combinations:

  • [.background, .foreground] — foreground default, background fallback
  • [.background, .foreground(.dynamic)] — background default, can request foreground
  • [.background, .foreground(.deferred)] — background first, guaranteed foreground later

Property Macros

struct LandmarkEntity: IndexedEntity {
    // Computed — reads from source of truth
    @ComputedProperty
    var isFavorite: Bool { UserDefaults.standard.favorites.contains(id) }

    // Deferred — expensive, fetched only when requested
    @DeferredProperty
    var crowdStatus: Int {
        get async throws { await modelData.getCrowdStatus(self) }
    }
}

Spotlight Integration

struct LandmarkEntity: AppEntity, IndexedEntity {
    static var typeDisplayRepresentation = TypeDisplayRepresentation(
        name: "Landmark", systemImage: "mountain.2"
    )
    var id: String
    var name: String
    var displayRepresentation: DisplayRepresentation {
        DisplayRepresentation(title: "\(name)", image: .init(systemName: "mountain.2"))
    }

    var searchableAttributes: CSSearchableItemAttributeSet {
        let attrs = CSSearchableItemAttributeSet()
        attrs.title = name
        return attrs
    }
}

// Index entities
try await CSSearchableIndex.default().indexAppEntities(landmarks, priority: .normal)

// Remove from index
try await CSSearchableIndex.default().deleteAppEntities(identifiedBy: [id], ofType: LandmarkEntity.self)

Interactive Snippets

struct LandmarkSnippetIntent: SnippetIntent {
    @Parameter var landmark: LandmarkEntity

    var snippet: some View {
        VStack {
            Text(landmark.name).font(.headline)
            HStack {
                Button("Add to Favorites") { }
                Button("Search Tickets") { }
            }
        }.padding()
    }
}

App Shortcuts

struct AppShortcuts: AppShortcutsProvider {
    static var appShortcuts: [AppShortcut] {
        AppShortcut(
            intent: FindNearestLandmarkIntent(),
            phrases: ["Find the closest landmark with \(.applicationName)"],
            systemImageName: "location"
        )
    }
}

Swift Package Support

// In framework
public struct LandmarksKitPackage: AppIntentsPackage { }

// In app target
struct LandmarksPackage: AppIntentsPackage {
    static var includedPackages: [any AppIntentsPackage.Type] {
        [LandmarksKitPackage.self]
    }
}

References

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

macos-permissions

No summary provided by upstream source.

Repository SourceNeeds Review
General

macos-app-structure

No summary provided by upstream source.

Repository SourceNeeds Review
General

swiftui-core

No summary provided by upstream source.

Repository SourceNeeds Review
General

global-hotkeys

No summary provided by upstream source.

Repository SourceNeeds Review