mcpField
C
capacitor-app-intents

capacitor-app-intents

github.com/cap-goDevelopment7352 installsUpdated 2w ago
Repository

About capacitor-app-intents

A skill for adding native iOS App Intents to Capacitor apps and connecting foreground actions to the web layer. It guides app developers through design, implementation, and verification, including cold-start routing and background execution limits.

Key features

  1. 01Native Swift App Intents setup
  2. 02Foreground intent-to-web routing
  3. 03Background intent constraints
  4. 04Shortcuts, widgets, and controls
  5. 05Version-aware API guidance
  6. 06Build and device verification

Use cases

  1. 01Adding Siri or Shortcuts actions
  2. 02Routing an intent on cold launch
  3. 03Debugging headless intent failures

Install

Copy the command and run it in a terminal.

$npx skills add https://github.com/cap-go/capgo-skills --skill capacitor-app-intents

After installing, type/capacitor-app-intentsin Claude Code to confirm it loaded.

Bundled files

References and scripts installed along with SKILL.md.

metadata.json
references/
intent-traps.md
ios-26-27-apis.md
project-setup.md
web-bridge.md
widgets-and-controls.md

Details

From the project README

App Intents for Capacitor Apps

Add native App Intents to the iOS project so system surfaces can run app actions, and connect them to the web layer. App Intents are Swift only. There is no JavaScript API for them, so every intent is native code in the App target or an extension, and the web layer is reached through a URL or a small local plugin.

When to Use

TRIGGER when:

  • The user wants Siri phrases, Shortcuts actions, App Shortcuts, Spotlight actions, Action button or Apple Intelligence integration for a Capacitor app
  • The user wants a widget button or a Control Center control to run an app action
  • An intent opens the app, but the web view does not navigate, or it navigates only on warm launch
  • A background intent crashes, times out, or tries to call JS
  • Migrating openAppWhenRun to supportedModes, or adopting iOS 26/27 App Intents APIs
  • A plugin author wants to ship App Intents with a plugin

Do not use:

  • Universal Links / custom scheme / appUrlOpen setup: capacitor-deep-linking
  • AppDelegate to SceneDelegate migration: capacitor-uiscene-migration
  • Push notification actions: capacitor-push-notifications
  • Live Activities or SVG widgets driven from JS: capacitor-plugins (@capgo/capacitor-widget-kit)
  • Android app shortcuts and intents: not covered here

Facts that drive the design

  • App Intents need iOS 16. Capacitor 8 deploys to iOS 15, so every intent type, entity, query and AppShortcutsProvider needs @available(iOS 16.0, *), or the user raises the deployment target. Capacitor 9 deploys to iOS 16, so the base API needs no gating. Newer APIs still do (tables in references/ios-26-27-apis.md).
  • A background intent has no WebView. iOS can launch the app process headless for .background intents. AppDelegate.application(_:didFinishLaunchingWithOptions:) runs, but no scene connects and CAPBridgeViewController never loads. Background intents must do native work only (network, storage, HealthKit, etc.). They cannot call JS or plugins through the bridge.
  • perform() is not on the main actor, and it can run more than once. Hop explicitly (await MainActor.run or @MainActor func perform()) before you touch UIKit, the bridge or @MainActor state. Do irreversible work last. Details: references/intent-traps.md.
  • With UIScene (Capacitor 8.5+) URL delivery moved. Universal Links and custom-scheme opens reach SceneDelegate and are forwarded by SceneDelegateProxy, which posts the notifications @capacitor/app listens to. If the app still has custom URL code in AppDelegate, it no longer runs. Check capacitor-deep-linking first if appUrlOpen does not fire for a normal link. An intent cannot fix a broken link pipeline.
  • On cold launch the JS listener does not exist yet. Any route an intent hands to the web layer must survive until JS asks for it: use App.getLaunchUrl() for URLs, or a pending-route store plus notifyListeners(..., retainUntilConsumed: true) for the local-plugin path.
  • Identifiers are a public contract. Intent type names, AppEntity.id values, AppEnum raw values, URL formats and shipped phrases are stored in users' saved shortcuts. Add new ones; do not rename or remove shipped ones without telling the user.

References

Only load a reference when its topic is in play.

FileLoad when
references/project-setup.mdCreating files, target membership, extensions, App Groups, availability gating, build verification
references/web-bridge.mdConnecting an intent to the web layer: URL routing, the local AppIntentsBridge plugin, pending routes, shared data
references/intent-traps.mdWriting or reviewing any intent, entity, query, phrase, dependency, error or donation
references/ios-26-27-apis.mdsupportedModes, foreground continuation, long-running/cancellable/undoable intents, execution targets, snippets, Spotlight indexing, schemas, testing
references/widgets-and-controls.mdWidget configuration intents, interactive widget buttons, Control Center controls

Workflow

1. Inspect (read-only)
  1. Read package.json (@capacitor/ios version), ios/App/App/Info.plist (scene manifest present?), ios/App/App/AppDelegate.swift, ios/App/App/SceneDelegate.swift, the App target's deployment target, and any existing *.entitlements (Associated Domains, App Groups).
  2. Check whether the app already handles deep links in JS (App.addListener('appUrlOpen', ...), App.getLaunchUrl()) and which routes exist.
  3. Search for existing intents: grep -rn "AppIntent\|AppShortcutsProvider\|openAppWhenRun" ios/App.
  4. List extension targets (widgets) in ios/App/App.xcodeproj/project.pbxproj (PBXNativeTarget entries other than App).
2. Design with the user

For each action the user wants, decide and confirm:

QuestionOptions
Does it need the UI?No: background intent, native only. Yes: foreground intent that routes into the web app
How does it reach JS?Universal Link via OpenURLIntent (iOS 18+, needs Associated Domains), or a local plugin with a pending-route store (works with custom schemes and iOS 16+)
What data does it need?Fixed set: AppEnum. Dynamic, queryable: AppEntity + EntityQuery. Free text or number: plain @Parameter
Where must it run?App target only, or also a widget / control (then the intent file needs both target memberships)
Which surfaces?App Shortcut phrase (at most 10 App Shortcuts per app), Spotlight, widget, control

Keep one intent per atomic task. Report the plan (files to add, targets, entitlements, JS changes) before editing.

3. Implement
  1. Create the Swift files in ios/App/App/Intents/ with the App target membership (references/project-setup.md).
  2. Write the intents following references/intent-traps.md. Gate APIs by version.
  3. Add the web bridge (references/web-bridge.md): either reuse the deep-link router, or add the local plugin and register it in a CAPBridgeViewController subclass.
  4. Add an AppShortcutsProvider with shortTitle, systemImageName and \(.applicationName) in every phrase.
  5. Add entitlements only when needed (App Groups for shared data, Associated Domains for Universal Links), and on every target that uses them.
  6. JS side: handle the route on warm and cold start.
4. Verify
npx cap sync ios
xcodebuild -project ios/App/App.xcodeproj -scheme App \
  -destination 'generic/platform=iOS Simulator' build
# CocoaPods projects: -workspace ios/App/App.xcworkspace
  • The build log shows the App Intents metadata extraction step with no warnings about phrases. A phrase without \(.applicationName) produces a build warning and is dropped at runtime.
  • Product > App Shortcuts Preview in Xcode shows the phrases matching.
  • Run on a simulator or device: open the Shortcuts app, find the app's actions, run each one.
    • Background intent: completes without the app coming to the foreground. Check the native logs (ios-android-logs).
    • Foreground intent, app killed first (cold) and app running (warm): the web view lands on the right route both times.
  • Spotlight: search the shortcut title.
  • If tests exist, add AppIntentsTesting coverage for iOS 27 test runners (references/ios-26-27-apis.md).

Error Handling

SymptomCauseFix
'AppIntent' is only available in iOS 16.0 or newerCapacitor 8 project deploys to iOS 15Add @available(iOS 16.0, *) to every App Intents type, or raise the deployment target with the user's approval
Intent missing from Shortcuts after installFile not in the App target, or metadata extraction failedCheck target membership. Read the build log for the App Intents metadata step. Reinstall the app
Phrase never triggers Siri; build warning about the application namePhrase lacks \(.applicationName)Add the token to every phrase
Build error about more than 10 App ShortcutsPer-app capMerge actions or drop low-value ones
Crash "...was not initialized prior to access" from @DependencyDependency registered too late (in a view controller)Register in AppDelegate.application(_:didFinishLaunchingWithOptions:), which runs on headless launches too
Foreground intent opens the app but the web view stays on the home route on cold startThe route was posted before JS added its listenerUse the pending-route store + retainUntilConsumed, or App.getLaunchUrl()
appUrlOpen never fires for OpenURLIntentUniversal Links not configured, or custom AppDelegate URL code under UISceneFix with capacitor-deep-linking. OpenURLIntent needs a real https Universal Link
Swift 6 error: main actor-isolated property cannot satisfy nonisolated requirementThe intent type is marked @MainActorRemove @MainActor from the type. Put it on perform() or hop inside
Background intent killed after about 30 secondsiOS limit for background intentsShorten the work, or use LongRunningIntent on iOS 27
'openAppWhenRun' was deprecated in iOS 26.0iOS 26 SDKAdd a gated supportedModes (references/ios-26-27-apis.md). Keep openAppWhenRun while the deployment target is below 26

Related Skills

  • capacitor-deep-linking: Universal Links and appUrlOpen routing the intents rely on
  • capacitor-uiscene-migration: required before Xcode 27; moves URL handling to SceneDelegate
  • capacitor-plugins: @capgo/capacitor-widget-kit for Live Activities and JS-driven widgets
  • capacitor-testing: native unit tests and the device verification loop
  • ios-android-logs: logs from headless intent runs

Comments

Markdown supported