Sample CodeiOS 27.0+, iPadOS 27.0+, Mac Catalyst 27.0+Reviewed 2026-07-21View on Apple Developer

Integrating your calendar app with Apple Intelligence

At a glance

Item Summary
Purpose Adopt calendar-domain entities and create, update, delete, and open schemas for system experiences.
Architecture One SwiftUI/SwiftData app with a main-actor CalendarManager shared by views, entity queries, and intents.
State strategy SwiftData models are authoritative; entity structs are snapshots/adapters; NavigationManager.shared owns foreground presentation state.
Boundary App and UI-test targets only; there is no App Intents extension or widget.

Project structure

CometCal/
├── AppIntents/
│   ├── Entities/
│   ├── Intents/
│   └── TestSupport/
├── Managers/
├── Model/
├── Views/
└── CometCalApp.swift
CometCalUITests/               # AppIntentsTesting user-path tests

Feature folders keep the system contract, persistence models, orchestration, and views distinct.

Overall architecture

Reference code

CometCal/CometCalApp.swift:14 — one manager is registered for UI-independent intent execution.

init() {
    let manager = CalendarManager.shared
    AppDependencyManager.shared.add(dependency: manager)
}

WindowGroup { CalendarListView() }
    .modelContainer(CalendarManager.shared.modelContainer)

Ownership and state

Ownership evidence

CometCal/Managers/CalendarManager.swift:13 — the main-actor repository owns persistence and indexing collaborators.

@MainActor @Observable
final class CalendarManager {
    static let shared = CalendarManager()
    let modelContainer: ModelContainer
    var modelContext: ModelContext
    nonisolated(unsafe) let searchableIndex: CSSearchableIndex
}

Only CalendarManager performs CRUD and synchronization with Spotlight. Entities and intents do not own stored models.

Class and protocol design

Entities adopt domain schemas and framework protocols: EventEntity is an IndexedEntity and OwnershipProvidingEntity at CometCal/AppIntents/Entities/EventEntity.swift:11. Nested query types bind lookup closely to their entity. Intent structs use @AppIntent(schema:) rather than app-defined command protocols, and inject the repository through @Dependency.

Access control

Symbol Access Rationale
Manager and app types internal default The system discovers App Intents from the app target; no public library API is required.
Update resolution helpers private Preserve unset-vs-clear translation inside one intent (CometCal/AppIntents/Intents/UpdateEventIntent.swift:69).
Seed fixtures/helpers private Test/sample data cannot be mutated externally.
searchableIndex internal + nonisolated(unsafe) Async indexing needs nonisolated use; the exception is explicit and narrow.
Public/file-private API none Cross-file collaboration is target-internal.

Logic ownership and placement

Logic Owner Placement reason
CRUD, SwiftData save, Spotlight, donations CalendarManager One transactional mutation boundary (CometCal/Managers/CalendarManager.swift:139).
Schema conversion and query Entity files Keeps system representation near its contract.
Parameter resolution Intent perform and private helpers Translates system optionality before calling the repository.
Foreground routes NavigationManager UI state is isolated from persistence (CometCal/Managers/NavigationManager.swift:9).
Test seeding AppIntents/TestSupport Keeps testing entry points out of production feature code.

Design patterns

Pattern Evidence Purpose
Repository CalendarManager owns all model operations Prevents intents and views from duplicating persistence rules.
Entity adapter Model .entity projections Separates SwiftData identity/lifetime from system values.
Composition root / DI Manager registration in app init Makes background invocations resolve data.
Router NavigationManager.shared Opens system-selected content in foreground UI (CometCal/AppIntents/Intents/OpenEventIntent.swift:20).
Schema adapter Calendar @AppIntent declarations Maps domain operations into system contracts.

Naming conventions

  • Stored types end in Model; system projections end in Entity.
  • Mutation entry points use verb-noun names (CreateEventIntent, UpdateEventIntent).
  • Coordinators use Manager; UI presentation types use View.
  • Test-only intents state their operation (Seed, Fetch, Reset, Clear).

Architecture takeaways

  • Put persistence, indexing, and donations behind one mutation owner.
  • Treat entities as snapshots and resolve them back to stored models by stable identifiers.
  • Keep schema optionality resolution in the intent adapter, not the repository.
  • A separate extension is unnecessary when the app target can host these App Intents.

Source map

Source Role
CometCal/Managers/CalendarManager.swift:28 Data stack creation
CometCal/AppIntents/Entities/EventEntity.swift:67 Entity ownership semantics
CometCal/AppIntents/Entities/EventEntity.swift:125 Event query
CometCal/AppIntents/Intents/CreateEventIntent.swift:30 Create schema adapter
CometCal/AppIntents/Intents/UpdateEventIntent.swift:33 Update orchestration