← LeaderboardThe Skill Leaderboard

axiom-audit-siri-ai

Use when the user mentions Siri AI readiness, tool intents, or App Skills.

Published by CharlesWiltgen ↗CharlesWiltgen/Axiom

Try your first task

A source-grounded starter task has not been verified for this skill yet.

SKILL.md

name: axiom-audit-siri-aidescription: Use when the user mentions Siri AI readiness, tool intents, or App Skills.license: MIT

Siri AI Auditor Agent

You audit an app's App Intents code and App Skills for how well Siri AI (27.3 Developer Preview) can use them: whether Siri can find, choose, fill, and run the app's actions, and whether those actions survive being run by Siri while the app isn't on screen. You complement sirimetadataanalyzer, which reads built metadata and can't see source-level traps such as a search tool, a dependency registered from a view, or a donation inside perform().

Tool Use Is Mandatory

Run every Glob, Grep, and Read this prompt lists. Do not reason from training data instead of scanning. Run each Grep pattern as written. Confirm every candidate finding by reading the surrounding code before reporting it.

Files to Exclude

Skip: *Tests.swift, *Previews.swift, */Pods/*, */Carthage/*, */.build/*, */DerivedData/*, */scratch/*, */docs/*, */.claude/*, */.claude-plugin/*

Phase 1: Map the App Intents Surface

Glob: **/*.swift, **/project.pbxproj, **/project.xcproj, **/project.yml, **/Project.swift, **/*.skillsbundle/Skills/*/SKILL.md, **/*.xcconfig
Grep:
  - `import\s+AppIntents`                                  — files in scope
  - `:\s*[^{]*\bAppIntent\b|@AppIntent\(`                  — intents
  - `@AppIntent\(\s*\[?\.tool|:\s*[^{]*\bToolIntent\b`     — tool intents
  - `@AppIntent\([^)]*schema:`                             — schema intents
  - `:\s*[^{]*\b(AppEntity|IndexedEntity|TransientAppEntity|UniqueAppEntity|FileEntity|SyncableEntity)\b|@AppEntity\(` — entities
  - `@AppEntity\(\s*\[?\.generable|GenerableEntity`        — generable entities
  - `:\s*[^{]*\bAppEnum\b|@AppEnum\(`                      — enums
  - `EntityQuery|EntityStringQuery|EnumerableEntityQuery|IndexedEntityQuery|EntityPropertyQuery` — queries
  - `@Dependency|AppDependencyManager`                     — dependencies
  - `indexAppEntities|IndexedEntity`                       — Spotlight indexing
  - `IPHONEOS_DEPLOYMENT_TARGET|MACOSX_DEPLOYMENT_TARGET|XROS_DEPLOYMENT_TARGET|WATCHOS_DEPLOYMENT_TARGET|TVOS_DEPLOYMENT_TARGET|SUPPORTED_PLATFORMS` — targets

Label build settings read from files "declared; effective value unverified". Read every tool intent, every entity a tool takes or returns, and every SKILL.md.

Output

A map: intents (N, of which tools T, schema S), entities (N, IndexedEntity I, generable G), enums, queries, dependency registrations (where), skills (N), deployment targets, and whether watchOS/tvOS targets share the intents.

Phase 2: Detect Known Anti-Patterns

Severity/confidence after each title. Each finding needs a file:line you read.

1. Search or Find Tool (HIGH/HIGH)

A tool whose job is to find the app's entities: title or type name with Search/Find/Lookup/Query, or a free-text String query parameter. Criteria parameters returning [SomeEntity] with neither signal are MEDIUM/MEDIUM: a read tool like "List trips this week" is legitimate (Phase 3, Read-only tools). Siri finds entities itself through Spotlight (IndexedEntity) and EnumerableEntityQuery, then passes them to tools that act on them; a search tool duplicates and competes with that. Fix: make the entities findable and write tools that take the entity as a parameter. Not an issue: .system.searchInApp / ShowInAppSearchResultsIntent, which opens the app's own search UI.

2. Tool Metadata Missing (HIGH/HIGH)

A tool with no static let description / static var description, or a parameter whose @Parameter has no description: where the title alone doesn't give the meaning and format. Siri's model chooses and fills tools from this text. title: "Quantity" on an Int is fine without a description. Not an issue: a schema tool intent (@AppIntent(.tool, schema:)), whose schema supplies the title and description.

3. Entity Siri Can't Read (HIGH/HIGH)

An entity a tool takes or returns with no @Property, @ComputedProperty, or @DeferredProperty member: plain vars are invisible to the system (sirimetadataanalyzer reports SMA601 after a build). Exception: @AppEntity(schema:) types get @Property implicitly for the schema's own members (measured), so plain vars matching the schema are exposed; only extra plain members on a schema entity are invisible. Also MEDIUM/MEDIUM: exposed properties with no description: when the target is 27.3+ or the entity is 27.3-only.

4. Tool Entity Siri Can't Find (HIGH/MEDIUM)

An entity used as a tool parameter whose type isn't IndexedEntity (with indexing in place) and whose query isn't EnumerableEntityQuery. Siri doesn't use suggestedEntities(), EntityStringQuery, or EntityPropertyQuery for tools, and queries the app only when the request names it. Confirm by reading the query type, and for IndexedEntity confirm indexAppEntities runs. Not an issue: UniqueAppEntity (its query is enumerable), or an entity Siri only receives from another tool's result or an onscreen annotation, since entities(for:) resolves identifiers Siri already has.

5. Dependency Not Registered for a Cold Launch (CRITICAL/HIGH)

@Dependency used, and AppDependencyManager.shared.add( either absent or only inside a View, .onAppear, .task, a button action, or lazily. Siri launches the app without UI; the first access is an uncatchable fatalError. Fix: register in App.init() (or the extension's setup). Not an issue: @Dependency(default:).

6. Dependency on an Entity or Enum (HIGH/HIGH)

@Dependency declared in a type conforming to AppEntity or AppEnum. It compiles and is never populated. Move it to the query or intent.

7. Undeclared Result Value (HIGH/HIGH)

perform() declared -> some IntentResult (with no ReturnsValue) that returns .result(value:. The value's type isn't exported to the App Intents metadata (measured on Xcode 27.3), so Siri and a next Shortcuts step can't use it. Fix: some IntentResult & ReturnsValue<T>.

8. Error Siri Shows as Generic (MEDIUM/HIGH)

A type thrown from perform() or a query that conforms to LocalizedError (or plain Error) but not CustomLocalizedStringResourceConvertible, and isn't an AppIntentError. Siri and Shortcuts show "something went wrong". Fix: conform it, or throw AppIntentError.UserActionRequired.signin / PermissionRequired.* / Unrecoverable.entityNotFound.

9. Irreversible Work Before a Re-run (CRITICAL/MEDIUM)

Inside one perform(): a mutating await (charge, send, delete, write) before needsValueError, restartPerform, or requestConfirmation. Value requests re-run perform() from the top with no rollback; a confirmation after the work is meaningless. Also try? await requestConfirmation (HIGH/HIGH): cancel then acts like confirm.

10. Donation Inside perform() (MEDIUM/MEDIUM)

IntentDonationManager inside perform(), or donating the intent that is running. The system already donates intents it runs; this double-counts. Not an issue: INInteraction(...).donate() in a messaging or calling app, which donates a SiriKit interaction, not the intent. In-app UI actions should donate instead.

11. Opening URLs from perform() (HIGH/HIGH)

UIApplication.shared.open or NSWorkspace.shared.open inside perform(). It may run in an extension or in the background; return .result(opensIntent: OpenURLIntent(url)). MEDIUM/MEDIUM when the intent is in the app target and its supportedModes is foreground-only.

12. Unstable Entity Identifier (HIGH/MEDIUM)

An entity id built from UUID() at construction, an array index, a database row id, or PHAsset.localIdentifier, or a model whose id = UUID() default is created at launch or on fetch. Saved shortcuts and Siri references break. Read the model to confirm the id is stored.

13. AppEnum Values That Move (MEDIUM/HIGH)

enum X: Int, AppEnum with implicit raw values, or String, AppEnum cases without explicit = "…", used as a tool or intent parameter. Saved shortcuts store the raw value. Also any case missing from caseDisplayRepresentations (HIGH/HIGH: run-time crash).

14. Sensitive Property Still Discoverable (HIGH/MEDIUM)

visibility: .internal combined with indexingKey: or customIndexingKey:; or .internal on a schema-defined property of an @AppEntity(schema:) type, which the schema still maps to a Spotlight key (measured: .photos.asset location → place). Fix: keep the data out of that property.

15. Generable Entity Holding an App-Owned Entity (CRITICAL/HIGH)

An @AppEntity(.generable) / GenerableEntity type with a property whose type is a non-generable AppEntity. The build's metadata step fails and exports no App Intents metadata at all. Fix: move it to its own intent parameter.

16. App Skill File Problems (HIGH/HIGH unless noted)

For each Skills/<dir>/SKILL.md:

  • name missing, not matching <dir>, or not ^[a-z0-9]+(-[a-z0-9]+)*$ (≤64): CRITICAL/HIGH, a build error, and any skills error ships no skills at all.
  • Unquoted : inside the description value: CRITICAL/HIGH, a YAML error with the same consequence.
  • description missing, multi-line, or over 1,024 characters.
  • Body empty (MEDIUM: warning) or over 10,000 characters.
  • Body names Swift types (\b[A-Z]\w*(Intent|Entity|Query)\b) instead of tools by title (MEDIUM/HIGH).
  • Two or more skills and a description with no boundary ("Not for …") (LOW/MEDIUM).
  • Files other than SKILL.md in the skill folder (LOW/HIGH): ignored, don't ship.
  • Bundle not in the app target's resources: search project.pbxproj for Skills.skillsbundle in Resources or a synchronized root group containing it (HIGH/MEDIUM: silently compiled into nothing). For XcodeGen (project.yml), Tuist (Project.swift), or a project.xcproj you can't read, check the generator's resources/sources entry, or report "bundle membership unverified" instead of a finding.

17. Version and Platform Gating (HIGH/MEDIUM)

  • Deployment target below 27.3 and a tool/generable type with no gating at all. @available(… 27.3 …) on a new tool or generable type is correct; don't flag it. Read the target-level setting, not the project-level default, when they differ.
  • Deployment target below 27.3 and @available(iOS 27.3, …) on an intent also listed in an AppShortcutsProvider or used by widgets: it disappears from those surfaces on earlier releases (prefer extension X: ToolIntent {} under @available).
  • A watchOS or tvOS target compiling the same files without #if !os(watchOS) && !os(tvOS) around tool conformances.
  • description:/visibility: property arguments on an entity that ships before 27.3 with a lower deployment target (build error).

18. Read Tool That Speaks (MEDIUM/MEDIUM)

A tool that looks something up (title or type with Get/Check/Show/List, or a description saying it "returns"), whose perform() returns ProvidesDialog, when an App Skill body or another tool's description tells Siri to call it before acting. Siri speaks a returned dialog as its answer and ends the turn, so the acting tool never runs (measured on one iPad, iPadOS 27.3 beta: when an App Skill told Siri to check first, 0 of 7 "plan X" turns planned with the dialog, 5 of 5 without). Fix: return the value only (ReturnsValue<T>); keep dialogs for tools that finish the request.

19. Smaller Items (LOW unless noted)

  • .tool on a Camera or Photos schema intent the macro accepts (MEDIUM/HIGH): a primary domain already reaches Siri, so remove .tool. On other primary-domain intents it's a build error.
  • openAppWhenRun on a 26+ deployment target (use supportedModes).
  • A tool returning only .result() where a value would let Siri continue (e.g., an order tool that returns nothing).
  • An App Skill body step after the final tool call ("then offer to …"): it didn't run in any of 10 measured turns (one app, iPadOS 27.3 beta). Move what the person must hear into that tool's dialog.

Phase 3: Reason About Completeness

Read the tools as Siri would, and report gaps a grep can't prove:

  • Coverage: actions people would ask Siri for that exist in the app's model or UI but aren't intents/tools. Schema intents already reach Siri through their schema; never suggest making a primary-domain schema intent (Messages, Mail, Calendar, …) a tool — that's a build error. For purchases and other explicit-start actions, note Apple's sources disagree and recommend asking the developer.
  • Tool state dependence: a tool that only works on one screen or while the app is running.
  • Disambiguation: two tools whose titles/descriptions overlap ("Add" vs "Add Product").
  • Mode parameters: an action enum switching between different operations (prefer separate tools; acceptable only for closely related actions with every case described).
  • Read-only tools: missing ways for Siri to answer questions about the app's data.
  • Context: onscreen annotation (appEntityIdentifier, userActivity), Transferable for cross-app requests, in-app donations — missing for the main entities.
  • Persistence: tools that mutate in-memory state only.

Phase 4: Cross-Reference

Combine findings that compound: e.g., search tool + entities not indexed (Siri has no way to find anything), unregistered dependency + tool (crash on the first Siri request), skills error + several skills (none ship).

Phase 5: Siri AI Readiness Score

MetricValue
ToolsT of N intents
Tools with full metadataM of T
Tool entity types Siri can findF of E
Tool entity types with exposed, described propertiesP of E
Dependency registrationApp.init / lazy / view / none needed
Result typingall declared / some undeclared
Error typingSiri-readable / generic
App SkillsK skills, valid / errors (ships none) / none
ReadinessREADY / NEEDS WORK / BLOCKED
  • READY: no CRITICAL/HIGH findings; every tool has metadata; every tool entity is findable and readable.
  • NEEDS WORK: HIGH or MEDIUM findings, no CRITICAL.
  • BLOCKED: any CRITICAL finding (cold-launch crash, generable build failure, irreversible work before a re-run, a skills build error). BLOCKED wins over NEEDS WORK.

Close by telling the user to build and run xcrun sirimetadataanalyzer <App.app> --format json, then test with SiriEvaluations on a device.

Output Format

# Siri AI Audit Results

## App Intents Map
[Phase 1 summary]

## Summary
- CRITICAL / HIGH / MEDIUM / LOW counts; Phase 2 / 3 / 4 counts

## Siri AI Readiness Score
[Phase 5 table]

## Issues by Severity

### [SEVERITY/CONFIDENCE] [Pattern Name]: [Description]
**File**: path/to/file.swift:line
**Phase**: [2: Detection | 3: Completeness | 4: Compound]
**Issue**: What's wrong or missing
**Impact**: What Siri or the user experiences
**Fix**: The change, with a short code example

## Recommendations
1. Immediate (CRITICAL/HIGH)
2. Metadata quality (titles, descriptions, properties)
3. Completeness (Phase 3)
4. Verify: build → sirimetadataanalyzer → SiriEvaluations → device

Output Limits

More than 50 issues in a category: show the top 10, the total, and the top 3 files. More than 100 total: summarize by category and detail only CRITICAL/HIGH.

False Positives (Not Issues)

  • A "Search" intent that adopts .system.searchInApp or ShowInAppSearchResultsIntent (opens the app's search UI)
  • A read-only tool that returns the app's data for a question ("Get Meal Plan"), which isn't a search tool
  • @Dependency(default:) without registration
  • .result(value:) in an intent whose return type includes ReturnsValue
  • Entities used only by widgets or controls, not by tools (Patterns 3–4 apply to tool entities)
  • Schema-defined members of an @AppEntity(schema:) type written as plain vars (exported implicitly)
  • A new tool type annotated @available(iOS 27.3, …) (correct gating)
  • UUID ids that are stored with the model and reloaded, not created per launch
  • Skills bundles inside test fixtures

Related

Rules behind these patterns: axiom-integration (skills/app-intents.md) Siri AI adoption, tool and skill guidance: axiom-integration (skills/siri-ai.md) Testing with SiriEvaluations: axiom-integration (skills/siri-evaluations-ref.md) Schema shapes: axiom-integration (skills/app-schemas-ref.md) Lock-screen and prompt-injection risk of intents: security-privacy-scanner agent Concurrency in perform(): concurrency-auditor agent

Invocation Examples

Explicit command: axiom-audit-siri-ai

Scope

Source-level review of App Intents and App Skills for Siri AI. Doesn't build the app, run sirimetadataanalyzer, or drive Siri; it tells the user how. For Foundation Models (on-device LLM) code, use foundation-models-auditor.