# Annotation Type AppIntent

@Retention(CLASS) @Target(METHOD) public @interface AppIntent

Exposes a capability of your application to the system: Siri, Spotlight, the Shortcuts app, an Android launcher shortcut, a widget button, or a language model.

    @AppIntent(value = "log_workout", title = "Log a workout",
            description = "Records a completed workout",
            phrases = {"Log a workout in ${applicationName}"},
            headless = true, timeoutSeconds = 5)
    public static IntentResult logWorkout(
            @IntentParam(value = "kind", title = "What kind of workout?",
                         options = {"run", "ride", "swim"}) String kind,
            @IntentParam(value = "minutes", title = "How many minutes?") int minutes) {
        WorkoutStore.append(kind, minutes);
        return IntentResult.spoken("Logged a " + minutes + " minute " + kind + ".");
    }

##### The handler must be `public static`

This is not a style preference. The build generates a direct static call to your method, and a direct call is the only form that survives the iOS translator's dead-code elimination and Android's obfuscation -- a reflective lookup would be stripped on iOS and renamed on Android, in both cases silently. `static` also makes the contract visible: a handler can be asked to run in a process that exists only to answer it, where no instance of yours has been constructed and nothing is on screen.

The method returns `com.codename1.intents.IntentResult`, or `void` when it has nothing to report. It may take `com.codename1.intents.IntentContext` as its first parameter to see the deadline, the source and the cancellation flag. Every other parameter must carry `IntentParam`.

##### At build time

The Codename One Maven plugin scans the project's compiled bytecode, validates every `@AppIntent`, and generates both the reflection-free dispatch table and the native declarations each platform compiles into the app. A malformed declaration fails the build rather than going quiet on a device.

##### Phrases

Apple enforces three rules on a spoken phrase, all of them as build failures that produce no App Intents metadata at all. The build checks them here instead, so the message names your declaration rather than arriving as an opaque failure from `appintentsmetadataprocessor`:

- Every phrase must contain `${applicationName}`.
- A phrase may reference at most one parameter. Write one phrase per parameter rather than combining them.
- A phrase parameter must be an `IntentEntity` type. A primitive cannot appear in a phrase, which is not much of a loss: leave it out and the platform still asks for it, using the title on its `IntentParam`.

An intent that declares phrases must also be `discoverable`, since a phrase is only reachable through an App Shortcut.

Phrases are ignored on platforms with no voice invocation, which today means Android.

- ## Required Element Summary

  Required Elements
  Modifier and Type
  Required Element
  Description
  `String`
  `title`
  The human-readable name shown in the Shortcuts app.
  `String`
  `value`
  The stable id, matching `[a-z][a-z0-9_]{2,63}`.

- ## Optional Element Summary

  Optional Elements
  Modifier and Type
  Optional Element
  Description
  `String`
  `description`
  A longer explanation shown alongside the title.
  `boolean`
  `destructive`
  True when the platform should confirm with the user before running this.
  `boolean`
  `discoverable`
  True when the platform may offer this intent before the user has ever run it.
  `Exposure[]`
  `exposure`
  Which consumers this intent is offered to.
  `boolean`
  `headless`
  True when this intent may run without bringing the app to the foreground.
  `String`
  `opensRoute`
  A route template to open instead of answering in place, for example `/orders/{orderId}`, where each `{name}` names one of this intent's parameters.
  `String[]`
  `phrases`
  Spoken phrases that invoke this intent.
  `int`
  `timeoutSeconds`
  How long the handler may run before the framework reports a failure.

- ## Element Details

  - ### value

    String value

    The stable id, matching `[a-z][a-z0-9_]{2,63}`. Required.

    It is stable in the strong sense: the system stores it in donated shortcuts and the user's own Shortcuts workflows, so renaming one breaks what people already built.

  - ### title

    String title
    The human-readable name shown in the Shortcuts app. Required.

  - ### description

    String description
    A longer explanation shown alongside the title.
    Default:
      `""`

  - ### phrases

    String[] phrases
    Spoken phrases that invoke this intent. Each must contain `${applicationName}`.
    Default:
      `{}`

  - ### headless

    boolean headless

    True when this intent may run without bringing the app to the foreground.

    A headless handler must not touch `Form`, `Dialog`, or anything else needing a window; see the `com.codename1.intents` package documentation for the full contract.

    Default:
      `false`

  - ### discoverable

    boolean discoverable
    True when the platform may offer this intent before the user has ever run it. False restricts it to appearing after a donation.
    Default:
      `true`

  - ### destructive

    boolean destructive

    True when the platform should confirm with the user before running this. Set it on anything that deletes, sends, or spends.

    It also closes the paths that cannot confirm. A destructive intent is not published as an Android launcher shortcut, is refused when an unauthenticated caller asks for it, and is not donated -- each of those runs on a single tap with nothing in between. The capability stays fully available through the assistant and the Shortcuts app, which confirm first; what goes away is the one-tap route to it.

    Default:
      `false`

  - ### opensRoute

    String opensRoute

    A route template to open instead of answering in place, for example `/orders/{orderId}`, where each `{name}` names one of this intent's parameters.

    The URL is resolved through the same `Route` table that handles deep links, so an intent and a link to the same screen cannot drift apart. A non-empty value is also what tells the platform to open the app.

    Default:
      `""`

  - ### exposure

    Exposure[] exposure
    Which consumers this intent is offered to. Defaults to the platform only; add `Exposure.MODEL` to also offer it to a language model through `com.codename1.intents.Intents#asTools()`.
    Default:
      `{ASSISTANT}`

  - ### timeoutSeconds

    int timeoutSeconds

    How long the handler may run before the framework reports a failure.

    The platform usually allows around twenty seconds. Do not use them: a spoken interaction that takes ten seconds has already failed as an interaction. Aim under two, and return `IntentResult.opens(...)` for anything genuinely slower.

    Default:
      `20`