Back to skills
SkillHub ClubBuild MobileFull StackMobile

shortcuts-generator

Generate macOS/iOS Shortcuts by creating plist files. Use when asked to create shortcuts, automate workflows, build .shortcut files, or generate Shortcuts plists. Covers 1,155 actions (427 WF*Actions + 728 AppIntents), variable references, and control flow.

Packaged view

This page reorganizes the original catalog entry around fit, installability, and workflow context first. The original raw source lives below.

Stars
3,071
Hot score
99
Updated
March 20, 2026
Overall rating
C4.0
Composite score
4.0
Best-practice grade
B75.6

Install command

npx @skill-hub/cli install openclaw-skills-shortcuts-skill

Repository

openclaw/skills

Skill path: skills/erik-agens/shortcuts-skill

Generate macOS/iOS Shortcuts by creating plist files. Use when asked to create shortcuts, automate workflows, build .shortcut files, or generate Shortcuts plists. Covers 1,155 actions (427 WF*Actions + 728 AppIntents), variable references, and control flow.

Open repository

Best for

Primary workflow: Build Mobile.

Technical facets: Full Stack, Mobile.

Target audience: everyone.

License: Unknown.

Original source

Catalog source: SkillHub Club.

Repository owner: openclaw.

This is still a mirrored public skill entry. Review the repository before installing into production workflows.

What it helps with

  • Install shortcuts-generator into Claude Code, Codex CLI, Gemini CLI, or OpenCode workflows
  • Review https://github.com/openclaw/skills before adding shortcuts-generator to shared team environments
  • Use shortcuts-generator for development workflows

Works across

Claude CodeCodex CLIGemini CLIOpenCode

Favorites: 0.

Sub-skills: 0.

Aggregator: No.

Original source / Raw SKILL.md

---
name: shortcuts-generator
description: Generate macOS/iOS Shortcuts by creating plist files. Use when asked to create shortcuts, automate workflows, build .shortcut files, or generate Shortcuts plists. Covers 1,155 actions (427 WF*Actions + 728 AppIntents), variable references, and control flow.
allowed-tools: Write, Bash
---

# macOS Shortcuts Generator

Generate valid `.shortcut` files that can be signed and imported into Apple's Shortcuts app.

## Quick Start

A shortcut is a binary plist with this structure:

```xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>WFWorkflowActions</key>
    <array>
        <!-- Actions go here -->
    </array>
    <key>WFWorkflowClientVersion</key>
    <string>2700.0.4</string>
    <key>WFWorkflowHasOutputFallback</key>
    <false/>
    <key>WFWorkflowIcon</key>
    <dict>
        <key>WFWorkflowIconGlyphNumber</key>
        <integer>59511</integer>
        <key>WFWorkflowIconStartColor</key>
        <integer>4282601983</integer>
    </dict>
    <key>WFWorkflowImportQuestions</key>
    <array/>
    <key>WFWorkflowMinimumClientVersion</key>
    <integer>900</integer>
    <key>WFWorkflowMinimumClientVersionString</key>
    <string>900</string>
    <key>WFWorkflowName</key>
    <string>My Shortcut</string>
    <key>WFWorkflowOutputContentItemClasses</key>
    <array/>
    <key>WFWorkflowTypes</key>
    <array/>
</dict>
</plist>
```

### Minimal Hello World

```xml
<dict>
    <key>WFWorkflowActionIdentifier</key>
    <string>is.workflow.actions.gettext</string>
    <key>WFWorkflowActionParameters</key>
    <dict>
        <key>UUID</key>
        <string>A1B2C3D4-E5F6-7890-ABCD-EF1234567890</string>
        <key>WFTextActionText</key>
        <string>Hello World!</string>
    </dict>
</dict>
<dict>
    <key>WFWorkflowActionIdentifier</key>
    <string>is.workflow.actions.showresult</string>
    <key>WFWorkflowActionParameters</key>
    <dict>
        <key>Text</key>
        <dict>
            <key>Value</key>
            <dict>
                <key>attachmentsByRange</key>
                <dict>
                    <key>{0, 1}</key>
                    <dict>
                        <key>OutputName</key>
                        <string>Text</string>
                        <key>OutputUUID</key>
                        <string>A1B2C3D4-E5F6-7890-ABCD-EF1234567890</string>
                        <key>Type</key>
                        <string>ActionOutput</string>
                    </dict>
                </dict>
                <key>string</key>
                <string></string>
            </dict>
            <key>WFSerializationType</key>
            <string>WFTextTokenString</string>
        </dict>
    </dict>
</dict>
```

## Core Concepts

### 1. Actions
Every action has:
- **Identifier**: `is.workflow.actions.<name>` (e.g., `is.workflow.actions.showresult`)
- **Parameters**: Action-specific configuration in `WFWorkflowActionParameters`
- **UUID**: Unique identifier for referencing this action's output

### 2. Variable References
To use output from a previous action:
1. The source action needs a `UUID` parameter
2. Reference it using `OutputUUID` in an `attachmentsByRange` dictionary
3. Use `` (U+FFFC) as placeholder in the string where the variable goes
4. Set `WFSerializationType` to `WFTextTokenString`

### 3. Control Flow
Control flow actions (repeat, conditional, menu) use:
- `GroupingIdentifier`: UUID linking start/middle/end actions
- `WFControlFlowMode`: 0=start, 1=middle (else/case), 2=end

## Common Actions Quick Reference

| Action | Identifier | Key Parameters |
|--------|------------|----------------|
| Text | `is.workflow.actions.gettext` | `WFTextActionText` |
| Show Result | `is.workflow.actions.showresult` | `Text` |
| Ask for Input | `is.workflow.actions.ask` | `WFAskActionPrompt`, `WFInputType` |
| Use AI Model | `is.workflow.actions.askllm` | `WFLLMPrompt`, `WFLLMModel`, `WFGenerativeResultType` |
| Comment | `is.workflow.actions.comment` | `WFCommentActionText` |
| URL | `is.workflow.actions.url` | `WFURLActionURL` |
| Get Contents of URL | `is.workflow.actions.downloadurl` | `WFURL`, `WFHTTPMethod` |
| Get Weather | `is.workflow.actions.weather.currentconditions` | (none required) |
| Open App | `is.workflow.actions.openapp` | `WFAppIdentifier` |
| Open URL | `is.workflow.actions.openurl` | `WFInput` |
| Alert | `is.workflow.actions.alert` | `WFAlertActionTitle`, `WFAlertActionMessage` |
| Notification | `is.workflow.actions.notification` | `WFNotificationActionTitle`, `WFNotificationActionBody` |
| Set Variable | `is.workflow.actions.setvariable` | `WFVariableName`, `WFInput` |
| Get Variable | `is.workflow.actions.getvariable` | `WFVariable` |
| Number | `is.workflow.actions.number` | `WFNumberActionNumber` |
| List | `is.workflow.actions.list` | `WFItems` |
| Dictionary | `is.workflow.actions.dictionary` | `WFItems` |
| Repeat (count) | `is.workflow.actions.repeat.count` | `WFRepeatCount`, `GroupingIdentifier`, `WFControlFlowMode` |
| Repeat (each) | `is.workflow.actions.repeat.each` | `WFInput`, `GroupingIdentifier`, `WFControlFlowMode` |
| If/Otherwise | `is.workflow.actions.conditional` | `WFInput`, `WFCondition`, `GroupingIdentifier`, `WFControlFlowMode` |
| Choose from Menu | `is.workflow.actions.choosefrommenu` | `WFMenuPrompt`, `WFMenuItems`, `GroupingIdentifier`, `WFControlFlowMode` |
| Find Photos | `is.workflow.actions.filter.photos` | `WFContentItemFilter` (see FILTERS.md) |
| Delete Photos | `is.workflow.actions.deletephotos` | `photos` (**NOT** `WFInput`!) |

## Detailed Reference Files

For complete documentation, see:
- [PLIST_FORMAT.md](PLIST_FORMAT.md) - Complete plist structure
- [ACTIONS.md](ACTIONS.md) - All 427 WF*Action identifiers and parameters
- [APPINTENTS.md](APPINTENTS.md) - All 728 AppIntent actions
- [PARAMETER_TYPES.md](PARAMETER_TYPES.md) - All parameter value types and serialization formats
- [VARIABLES.md](VARIABLES.md) - Variable reference system
- [CONTROL_FLOW.md](CONTROL_FLOW.md) - Repeat, Conditional, Menu patterns
- [FILTERS.md](FILTERS.md) - Content filters for Find/Filter actions (photos, files, etc.)
- [EXAMPLES.md](EXAMPLES.md) - Complete working examples

## Signing Shortcuts

Shortcuts MUST be signed before they can be imported. Use the macOS `shortcuts` CLI:

```bash
# Sign for anyone to use
shortcuts sign --mode anyone --input MyShortcut.shortcut --output MyShortcut_signed.shortcut

# Sign for people who know you
shortcuts sign --mode people-who-know-me --input MyShortcut.shortcut --output MyShortcut_signed.shortcut
```

The signing process:
1. Write your plist as XML to a `.shortcut` file
2. Run `shortcuts sign` to add cryptographic signature (~19KB added)
3. The signed file can be opened/imported into Shortcuts.app

## Workflow for Creating Shortcuts

1. **Define actions** - List what the shortcut should do
2. **Generate UUIDs** - Each action that produces output needs a unique UUID
3. **Build action array** - Create each action dictionary with identifier and parameters
4. **Wire variable references** - Connect outputs to inputs using `OutputUUID`
5. **Wrap in plist** - Add the root structure with icon, name, version
6. **Write to file** - Save as `.shortcut` (XML plist format is fine)
7. **Sign** - Run `shortcuts sign` to make it importable

## Key Rules

1. **UUIDs must be uppercase**: `A1B2C3D4-E5F6-7890-ABCD-EF1234567890`
2. **WFControlFlowMode is an integer**: Use `<integer>0</integer>` not `<string>0</string>`
3. **Range keys use format**: `{position, length}` - e.g., `{0, 1}` for first character
4. **The placeholder character**: `` (U+FFFC) marks where variables are inserted
5. **Control flow needs matching ends**: Every repeat/if/menu start needs an end action with same `GroupingIdentifier`


---

## Referenced Files

> The following files are referenced in this skill and included for context.

### PLIST_FORMAT.md

```markdown
# Shortcut Plist Format

Complete documentation of the `.shortcut` file structure.

**Related docs:**
- [ACTIONS.md](./ACTIONS.md) - Action identifiers and parameters
- [FILTERS.md](./FILTERS.md) - Content filters for Find/Filter actions
- [PARAMETER_TYPES.md](./PARAMETER_TYPES.md) - All parameter value types
- [VARIABLES.md](./VARIABLES.md) - Variable references and outputs
- [CONTROL_FLOW.md](./CONTROL_FLOW.md) - Conditionals, loops, menus

## Root Structure

A `.shortcut` file is a binary plist (can be written as XML, then converted). The root is a dictionary with these keys:

```xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <!-- REQUIRED -->
    <key>WFWorkflowActions</key>
    <array>
        <!-- Array of action dictionaries -->
    </array>

    <!-- REQUIRED - Version info -->
    <key>WFWorkflowClientVersion</key>
    <string>2700.0.4</string>
    <key>WFWorkflowClientRelease</key>
    <string>26A0000a</string>
    <key>WFWorkflowMinimumClientVersion</key>
    <integer>900</integer>
    <key>WFWorkflowMinimumClientVersionString</key>
    <string>900</string>

    <!-- REQUIRED - Icon -->
    <key>WFWorkflowIcon</key>
    <dict>
        <key>WFWorkflowIconGlyphNumber</key>
        <integer>59511</integer>
        <key>WFWorkflowIconStartColor</key>
        <integer>4282601983</integer>
    </dict>

    <!-- OPTIONAL - Shortcut name (displayed in app) -->
    <key>WFWorkflowName</key>
    <string>My Shortcut</string>

    <!-- OPTIONAL - Usually empty arrays -->
    <key>WFWorkflowHasOutputFallback</key>
    <false/>
    <key>WFWorkflowImportQuestions</key>
    <array/>
    <key>WFWorkflowOutputContentItemClasses</key>
    <array/>
    <key>WFWorkflowTypes</key>
    <array/>

    <!-- OPTIONAL - Input content types accepted -->
    <key>WFWorkflowInputContentItemClasses</key>
    <array>
        <string>WFStringContentItem</string>
        <string>WFURLContentItem</string>
        <!-- ... more content types ... -->
    </array>
</dict>
</plist>
```

## Root Keys Reference

| Key | Type | Required | Description |
|-----|------|----------|-------------|
| `WFWorkflowActions` | Array | Yes | Array of action dictionaries |
| `WFWorkflowClientVersion` | String | Yes | Client version (e.g., "2700.0.4") |
| `WFWorkflowClientRelease` | String | No | Release identifier |
| `WFWorkflowMinimumClientVersion` | Integer | Yes | Minimum version number (900+) |
| `WFWorkflowMinimumClientVersionString` | String | Yes | String version of minimum |
| `WFWorkflowIcon` | Dict | Yes | Icon configuration |
| `WFWorkflowName` | String | No | Display name |
| `WFWorkflowHasOutputFallback` | Boolean | No | Has output fallback |
| `WFWorkflowImportQuestions` | Array | No | Import-time questions |
| `WFWorkflowInputContentItemClasses` | Array | No | Accepted input types |
| `WFWorkflowOutputContentItemClasses` | Array | No | Output types |
| `WFWorkflowTypes` | Array | No | Workflow types |

## Icon Configuration

```xml
<key>WFWorkflowIcon</key>
<dict>
    <key>WFWorkflowIconGlyphNumber</key>
    <integer>59511</integer>
    <key>WFWorkflowIconStartColor</key>
    <integer>4282601983</integer>
</dict>
```

### Common Glyph Numbers

| Glyph | Number | Description |
|-------|--------|-------------|
| Globe | 59511 | Default globe icon |
| Star | 59446 | Star icon |
| Heart | 59448 | Heart icon |
| Gear | 59458 | Settings gear |
| Document | 59493 | Document icon |
| Folder | 59495 | Folder icon |
| Play | 59477 | Play button |
| Message | 59412 | Message bubble |

### Color Values

Colors are ARGB integers. Common values:

| Color | Value | Description |
|-------|-------|-------------|
| Blue | 4282601983 | Default blue |
| Red | 4282601983 | Red |
| Green | 4292093695 | Green |
| Orange | 4294967295 | Orange |
| Purple | 4285887861 | Purple |
| Gray | 2846468607 | Gray |

## Action Structure

Each action in `WFWorkflowActions` is a dictionary:

```xml
<dict>
    <key>WFWorkflowActionIdentifier</key>
    <string>is.workflow.actions.showresult</string>
    <key>WFWorkflowActionParameters</key>
    <dict>
        <!-- Action-specific parameters -->
        <key>UUID</key>
        <string>A1B2C3D4-E5F6-7890-ABCD-EF1234567890</string>
        <!-- ... more parameters ... -->
    </dict>
</dict>
```

### Action Keys

| Key | Type | Required | Description |
|-----|------|----------|-------------|
| `WFWorkflowActionIdentifier` | String | Yes | Action identifier (e.g., `is.workflow.actions.showresult`) |
| `WFWorkflowActionParameters` | Dict | Yes | Action configuration |

### Common Parameter Keys

| Key | Type | Description |
|-----|------|-------------|
| `UUID` | String | Unique ID for referencing this action's output |
| `GroupingIdentifier` | String | Links control flow actions (repeat, if, menu) |
| `WFControlFlowMode` | Integer | 0=start, 1=middle, 2=end |

## Input Content Item Classes

These define what input types the shortcut accepts:

```xml
<key>WFWorkflowInputContentItemClasses</key>
<array>
    <string>WFAppStoreAppContentItem</string>
    <string>WFArticleContentItem</string>
    <string>WFContactContentItem</string>
    <string>WFDateContentItem</string>
    <string>WFEmailAddressContentItem</string>
    <string>WFGenericFileContentItem</string>
    <string>WFImageContentItem</string>
    <string>WFiTunesProductContentItem</string>
    <string>WFLocationContentItem</string>
    <string>WFDCMapsLinkContentItem</string>
    <string>WFAVAssetContentItem</string>
    <string>WFPDFContentItem</string>
    <string>WFPhoneNumberContentItem</string>
    <string>WFRichTextContentItem</string>
    <string>WFSafariWebPageContentItem</string>
    <string>WFStringContentItem</string>
    <string>WFURLContentItem</string>
</array>
```

## Binary vs XML Plist

Shortcuts are stored as binary plists but can be created as XML:

```bash
# Convert XML to binary (optional - signing handles this)
plutil -convert binary1 MyShortcut.shortcut

# Convert binary to XML (for debugging)
plutil -convert xml1 MyShortcut.shortcut
```

The `shortcuts sign` command accepts both formats.

## Complete Template

```xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>WFWorkflowActions</key>
    <array>
        <dict>
            <key>WFWorkflowActionIdentifier</key>
            <string>is.workflow.actions.gettext</string>
            <key>WFWorkflowActionParameters</key>
            <dict>
                <key>UUID</key>
                <string>11111111-1111-1111-1111-111111111111</string>
                <key>WFTextActionText</key>
                <string>Hello World!</string>
            </dict>
        </dict>
        <dict>
            <key>WFWorkflowActionIdentifier</key>
            <string>is.workflow.actions.showresult</string>
            <key>WFWorkflowActionParameters</key>
            <dict>
                <key>Text</key>
                <dict>
                    <key>Value</key>
                    <dict>
                        <key>attachmentsByRange</key>
                        <dict>
                            <key>{0, 1}</key>
                            <dict>
                                <key>OutputName</key>
                                <string>Text</string>
                                <key>OutputUUID</key>
                                <string>11111111-1111-1111-1111-111111111111</string>
                                <key>Type</key>
                                <string>ActionOutput</string>
                            </dict>
                        </dict>
                        <key>string</key>
                        <string></string>
                    </dict>
                    <key>WFSerializationType</key>
                    <string>WFTextTokenString</string>
                </dict>
            </dict>
        </dict>
    </array>
    <key>WFWorkflowClientVersion</key>
    <string>2700.0.4</string>
    <key>WFWorkflowHasOutputFallback</key>
    <false/>
    <key>WFWorkflowIcon</key>
    <dict>
        <key>WFWorkflowIconGlyphNumber</key>
        <integer>59511</integer>
        <key>WFWorkflowIconStartColor</key>
        <integer>4282601983</integer>
    </dict>
    <key>WFWorkflowImportQuestions</key>
    <array/>
    <key>WFWorkflowMinimumClientVersion</key>
    <integer>900</integer>
    <key>WFWorkflowMinimumClientVersionString</key>
    <string>900</string>
    <key>WFWorkflowName</key>
    <string>Hello World</string>
    <key>WFWorkflowOutputContentItemClasses</key>
    <array/>
    <key>WFWorkflowTypes</key>
    <array/>
</dict>
</plist>
```

```

### ACTIONS.md

```markdown
# Shortcuts Actions Reference

Complete catalog of all 427 WF*Action classes and their identifiers.

## Identifier Mapping Rules

### Standard Mapping
Class `WF<Name>Action` maps to `is.workflow.actions.<lowercasename>`

Example: `WFShowResultAction` → `is.workflow.actions.showresult`

### Irregular Mappings

Some actions have non-standard mappings:

| Class Name | Identifier |
|------------|-----------|
| `WFRepeatAction` | `is.workflow.actions.repeat.count` |
| `WFForEachRepeatAction` | `is.workflow.actions.repeat.each` |
| `WFFiniteRepeatAction` | `is.workflow.actions.repeat.count` |
| `WFAskForInputAction` | `is.workflow.actions.ask` |
| `WFTextAction` | `is.workflow.actions.gettext` |
| `WFConditionalAction` | `is.workflow.actions.conditional` |
| `WFChooseFromMenuAction` | `is.workflow.actions.choosefrommenu` |
| `WFGetFileAction` | `is.workflow.actions.documentpicker.open` |
| `WFSelectFilesAction` | `is.workflow.actions.documentpicker.open` |
| `WFSaveFileAction` | `is.workflow.actions.documentpicker.save` |
| `WFGetCurrentWeatherConditionsAction` | `is.workflow.actions.weather.currentconditions` |
| `WFGetWeatherForecastAction` | `is.workflow.actions.weather.forecast` |
| `WFContentItemFilterAction` | `is.workflow.actions.filter.contentitems` |
| `WFGetUpcomingCalendarItemsAction` | `is.workflow.actions.getupcomingevents` |
| `WFAppendFileAction` | `is.workflow.actions.file.append` (was `appendfile` in older versions) |

---

## Actions by Category

### Text & Input

| Identifier | Class | Description |
|------------|-------|-------------|
| `gettext` | WFTextAction | Create a text value |
| `ask` | WFAskForInputAction | Ask user for input |
| `askllm` | WFAskLLMAction | Use AI model (Apple Intelligence) |
| `comment` | WFCommentAction | Add a comment (no effect) |
| `dictatetext` | WFDictateTextAction | Dictate text |
| `showresult` | WFShowResultAction | Display result to user |
| `alert` | WFAlertAction | Show alert dialog |
| `notification` | WFNotificationAction | Send notification |
| `speaktext` | WFSpeakTextAction | Speak text aloud |
| `translatetext` | WFTranslateTextAction | Translate text |
| `detectlanguage` | WFDetectLanguageAction | Detect language |

### Variables

| Identifier | Class | Description |
|------------|-------|-------------|
| `setvariable` | WFSetVariableAction | Set a variable |
| `getvariable` | WFGetVariableAction | Get a variable |
| `appendvariable` | WFAppendVariableAction | Append to variable |
| `nothing` | WFNothingAction | Do nothing (pass-through) |

### Control Flow

| Identifier | Class | Description |
|------------|-------|-------------|
| `repeat.count` | WFRepeatAction | Repeat N times |
| `repeat.each` | WFForEachRepeatAction | Repeat for each item |
| `conditional` | WFConditionalAction | If/Otherwise |
| `choosefrommenu` | WFChooseFromMenuAction | Menu with cases |
| `choosefromlist` | WFChooseFromListAction | Choose from list |
| `exit` | WFExitAction | Exit shortcut |
| `output` | WFOutputAction | Set output |

### Files & Documents

| Identifier | Class | Description |
|------------|-------|-------------|
| `file` | WFFileAction | Create file reference |
| `documentpicker.open` | WFSelectFilesAction | Open file picker |
| `documentpicker.save` | WFSaveFileAction | Save file |
| `getfoldercontents` | WFGetFolderContentsAction | List folder contents |
| `createfolder` | WFCreateFolderAction | Create folder |
| `deletefile` | WFDeleteFileAction | Delete file |
| `movefile` | WFMoveFileAction | Move file |
| `renamefile` | WFRenameFileAction | Rename file |
| `file.append` | WFAppendFileAction | Append to text file (was `appendfile` in older versions) |
| `makearchive` | WFMakeArchiveAction | Create archive |
| `extractarchive` | WFExtractArchiveAction | Extract archive |

### Web & URLs

| Identifier | Class | Description |
|------------|-------|-------------|
| `url` | WFURLAction | Create URL |
| `downloadurl` | WFDownloadURLAction | Get contents of URL |
| `openurl` | WFOpenURLAction | Open URL |
| `expandurl` | WFExpandURLAction | Expand shortened URL |
| `geturlheaders` | WFGetURLHeadersAction | Get URL headers |
| `urlgetcomponent` | WFURLGetComponentAction | Get URL component |
| `urlencode` | WFURLEncodeAction | URL encode |
| `getwebpage` | WFGetWebPageAction | Get web page |
| `searchweb` | WFSearchWebAction | Search web |

### Apps & System

| Identifier | Class | Description |
|------------|-------|-------------|
| `openapp` | WFOpenAppAction | Open app |
| `quitapp` | WFQuitAppAction | Quit app |
| `hideapp` | WFHideAppAction | Hide app |
| `getcurrentapp` | WFGetCurrentAppAction | Get current app |
| `runworkflow` | WFRunWorkflowAction | Run another shortcut |
| `runshellscript` | WFRunShellScriptAction | Run shell script |
| `runosascript` | WFRunOSAScriptAction | Run AppleScript |
| `getdevicedetails` | WFGetDeviceDetailsAction | Get device info |
| `batterylevel` | WFBatteryLevelAction | Get battery level |
| `getclipboard` | WFGetClipboardAction | Get clipboard |
| `setclipboard` | WFSetClipboardAction | Set clipboard |

### Lists & Data

| Identifier | Class | Description |
|------------|-------|-------------|
| `list` | WFListAction | Create list |
| `dictionary` | WFDictionaryAction | Create dictionary |
| `getdictionaryvalue` | WFGetDictionaryValueAction | Get dictionary value |
| `setdictionaryvalue` | WFSetDictionaryValueAction | Set dictionary value |
| `getitemfromlist` | WFGetItemFromListAction | Get item from list |
| `count` | WFCountAction | Count items |
| `filter.contentitems` | WFContentItemFilterAction | Filter content |

### Numbers & Math

| Identifier | Class | Description |
|------------|-------|-------------|
| `number` | WFNumberAction | Create number |
| `calculate` | WFCalculateAction | Calculate |
| `calculatestatistics` | WFCalculateStatisticsAction | Statistics |
| `randomnumber` | WFRandomNumberAction | Random number |
| `roundnumber` | WFRoundNumberAction | Round number |
| `measurementcreate` | WFMeasurementCreateAction | Create measurement |
| `measurementconvert` | WFMeasurementConvertAction | Convert measurement |

### Date & Time

| Identifier | Class | Description |
|------------|-------|-------------|
| `date` | WFDateAction | Create date |
| `formatdate` | WFFormatDateAction | Format date |
| `adjustdate` | WFAdjustDateAction | Adjust date |
| `converttimezone` | WFConvertTimeZoneAction | Convert timezone |
| `timeuntildate` | WFTimeUntilDateAction | Time between dates |
| `delay` | WFDelayAction | Wait |
| `waittoreturn` | WFWaitToReturnAction | Wait to return |

### Calendar & Reminders

| Identifier | Class | Description |
|------------|-------|-------------|
| `addnewevent` | WFAddNewEventAction | Create event |
| `getupcomingevents` | WFGetUpcomingCalendarItemsAction | Get upcoming events |
| `removecalendaritems` | WFRemoveCalendarItemsAction | Remove calendar items |
| `addnewreminder` | WFAddNewReminderAction | Create reminder |
| `showreminderslist` | WFShowRemindersListAction | Show reminders |

### Weather & Location

| Identifier | Class | Description |
|------------|-------|-------------|
| `weather.currentconditions` | WFGetCurrentWeatherConditionsAction | Current weather |
| `weather.forecast` | WFGetWeatherForecastAction | Weather forecast |
| `getcurrentlocation` | WFGetCurrentLocationAction | Current location |
| `location` | WFLocationAction | Create location |
| `getdirections` | WFGetDirectionsAction | Get directions |
| `getdistance` | WFGetDistanceAction | Get distance |
| `searchmaps` | WFSearchMapsAction | Search maps |

### Media

| Identifier | Class | Description |
|------------|-------|-------------|
| `takephoto` | WFTakePhotoAction | Take photo |
| `takevideo` | WFTakeVideoAction | Take video |
| `selectphoto` | WFSelectPhotoAction | Select photos |
| `getlatestphotos` | WFGetLatestPhotosAction | Get latest photos |
| `filter.photos` | WFContentItemFilterAction | Find/filter photos (see FILTERS.md) |
| `savetocameraroll` | WFSaveToCameraRollAction | Save to camera roll |
| `deletephotos` | WFDeletePhotosAction | Delete photos (**uses `photos` param, not `WFInput`**) |
| `playmusic` | WFPlayMusicAction | Play music |
| `playpause` | WFPlayPauseAction | Play/Pause |
| `skipsong` | WFSkipSongAction | Skip song |
| `recordaudio` | WFRecordAudioAction | Record audio |
| `playsound` | WFPlaySoundAction | Play sound |

### Images

| Identifier | Class | Description |
|------------|-------|-------------|
| `imageresize` | WFImageResizeAction | Resize image |
| `imagecrop` | WFImageCropAction | Crop image |
| `imagerotate` | WFImageRotateAction | Rotate image |
| `imageflip` | WFImageFlipAction | Flip image |
| `imageconvert` | WFImageConvertAction | Convert image |
| `imagecombine` | WFImageCombineAction | Combine images |
| `overlayimage` | WFOverlayImageAction | Overlay image |
| `overlaytext` | WFOverlayTextAction | Overlay text |
| `imageremovebackground` | WFImageRemoveBackgroundAction | Remove background |
| `maskimage` | WFMaskImageAction | Mask image |
| `extracttextfromimage` | WFExtractTextFromImageAction | OCR |

### PDF

| Identifier | Class | Description |
|------------|-------|-------------|
| `makepdf` | WFMakePDFAction | Create PDF |
| `splitpdf` | WFSplitPDFAction | Split PDF |
| `compresspdf` | WFCompressPDFAction | Compress PDF |
| `gettextfrompdf` | WFGetTextFromPDFAction | Extract text from PDF |
| `makeimagefrompdfpage` | WFMakeImageFromPDFPageAction | PDF page to image |

### Sharing & Communication

| Identifier | Class | Description |
|------------|-------|-------------|
| `share` | WFShareAction | Share |
| `airdrop` | WFAirDropAction | AirDrop |
| `sendmessage` | WFSendMessageAction | Send message |
| `sendemail` | WFSendEmailAction | Send email |
| `startcall` | WFStartCallAction | Start call |
| `contacts` | WFContactsAction | Get contacts |
| `selectcontacts` | WFSelectContactsAction | Select contacts |

### Settings

| Identifier | Class | Description |
|------------|-------|-------------|
| `setappearance` | WFSetAppearanceAction | Set light/dark mode |
| `setwifi` | WFSetWiFiAction | Set WiFi |
| `setcellulardata` | WFSetCellularDataAction | Set cellular data |
| `setlowpowermode` | WFSetLowPowerModeAction | Set low power mode |
| `setvolume` | WFSetVolumeAction | Set volume |
| `toggledonotdisturb` | WFToggleDoNotDisturbAction | Toggle Do Not Disturb |
| `setorientationlock` | WFSetOrientationLockAction | Set orientation lock |
| `setwallpaper` | WFSetWallpaperAction | Set wallpaper |

---

## Complete Identifier List

All 427 action identifiers (prefix `is.workflow.actions.` omitted):

```
addframetogif, addmusictoupnext, addnewcalendar, addnewcontact, addnewevent,
addnewreminder, addquickreminder, address, addtoplaylist, addtoreadinglist,
adjustdate, airdrop, alert, appattributed, appenddropboxfile, file.append,
appendtonote, appendvariable, appintentexecution, ask, askllm, batterylevel,
calculate, calculateexpression, calculatestatistics, changeplaybackdestination,
choosefromlist, choosefrommenu, clearupnext, coercion, comment, compactdialog,
compresspdf, conditional, configuredactionbuttonintent, configuredactionbuttonnothing,
configuredactionbuttonworkflow, configuredstaccato, configuredstaccatointent,
configuredstaccatonothing, configuredstaccatotophit, configuredstaccatoworkflow,
configuredsystem, configuredsystemcontrol, configuredsystemintent,
configuredsystemnothing, configuredsystemworkflow, connecttoservers, contacts,
contentattributionsetdebugger, contentitem, contentitemproperties, contentitemsetter,
controlflow, converttimezone, count, createfolder, createnote, createphotoalbum,
createplaylist, date, delay, deletefile, deletephotos, detectlanguage, dictatetext,
dictionary, displaysleep, documentpicker.open, documentpicker.save, downloadurl,
ejectdisk, emailaddress, encodemedia, evernoteappend, evernotecreate, evernotedelete,
evernotegetlink, evernotegetnotes, exit, expandurl, extractarchive,
extracttextfromimage, file, filter.contentitems, finderimageconvert,
findhealthsamples, focusconfigurationlink, folder, formatdate, formatfilesize,
formatnumber, generatehash, generatemachinereadablecode, getclass, getclipboard,
getcurrentapp, getcurrentlocation, getcurrentsafariwebpage, getcurrentsong,
getdevicedetails, getdictionaryvalue, getdirections, getdistance, getdropboxfile,
getemojiname, getepisodesforpodcast, getfilelink, getfocus, getfoldercontents,
getframesfromimage, gethalfwaypoint, gethomeaccessorystate, gethotspotpassword,
getipaddress, getitemfromlist, getitemname, getitemtype, getlatestphotoimport,
getlatestphotos, getmapslink, getmyworkflows, getnetworkdetails, getonscreencontent,
getparentdirectory, getparkedcarlocation, getplaylist, getpodcastsfromlibrary,
getposters, getselectedfinderfiles, gettext, gettextfrompdf, gettraveltime,
gettype, getupcomingevents, geturlheaders, getvariable, getwebpage, giphy,
handlecustomintent, handledonatedintent, handleintent, handlepaymentintent,
handlesystemintent, handoff, handoffplayback, hideapp, homeaccessory,
htmlfromrichtext, imagecombine, imageconvert, imagecrop, imageflip,
imageremovebackground, imageresize, imagerotate, imgurupload, importaudiofiles,
importtolightroom, input, instapaper, instapaperadd, instapaperget, interchange,
interchangescheme, intercom, labelfiles, link, linkactionserializedparametersforln,
linkbookschangepagenavigation, linkbookschangetheme, linkbooksfind,
linkbooksnavigatepages, linkcalculateappusageintent, linkcalendarclosescreen,
linkcalendarcreatecalendar, linkcalendardeletecalendar, linkcalendaropenscreen,
linkchangebinarysetting, linkclockcreatealarm, linkclockdeletealarm,
linkclocktogglealarm, linkcloseentity, linkcontentitemfilter, linkcopyentity,
linkcreateentity, linkdeleteentity, linkentity, linkfavoriteentity, linkfindhome,
linkfindhomecameraclip, linkfindhomedevice, linkfindhomeroom, linkfindhomescene,
linkfindhomezone, linkfindselectedhome, linkimageplaygroundgenerateimage,
linkinsertintelligencetext, linkipdatafindsportsevents,
linkmusicrecognitionrecognizemusic, linknavigatesequentially,
linknotesaddtagstonotes, linknoteschangesetting, linknotescreatefolder,
linknotescreatetag, linknotesdeletefolders, linknotesdeletetags, linknotesfind,
linknotesmovenotestofolder, linknotesopenaccount, linknotesopenapplocation,
linknotesopenfolder, linknotesopentag, linknotespinnotes,
linknotesremovetagsfromnotes, linkopencamera, linkopenentity,
linkphotoscreatememory, linkreminderscreatelist, linkremindersopensmartlist,
linkrunintelligencecommand, linksafarichangereadermodestate, linksafariclosetab,
linksafaricreateprivatetab, linksafaricreatetab, linksafaricreatetabgroup,
linksafarifindbookmarks, linksafarifindreadinglistitems, linksafarifindtabgroups,
linksafarifindtabs, linksafariopenbookmark, linksafariopenreadinglistitem,
linksafariopentab, linksafariopentabgroup, linksafariopenview, linksearch,
linkshortcutscreateicloudlink, linkshortcutscreateworkflow,
linkshortcutsdeleteworkflow, linkshortcutsresetcellulardatastatistics,
linkshortcutssearchshortcuts, linkshortcutssetdataroaming, linkshortcutssetdefaultline,
linkshortcutstogglecellularplan, linkstartstopwatch, linkstartworkout,
linktogglehomeaccessory, linkvisualintelligencecamera,
linkvoicememoschangerecordingplaybacksetting, linkvoicememoscreatefolder,
linkvoicememosdeletefolders, linkvoicememosdeleterecordings, linkvoicememosopenfolder,
linkvoicememosopenrecording, linkvoicememosplayrecording, linkvoicememosrecordingfind,
linkvoicememossearchrecordings, linkwritingtools, linkwritingtoolsadjusttone,
linkwritingtoolsformatlist, linkwritingtoolsformattable, linkwritingtoolsproofread,
linkwritingtoolsrewrite, linkwritingtoolssummarize, list, location, lockapp,
lockscreen, loghealthsample, logoutuser, logworkout, makearchive, makediskimage,
makegif, makeimagefrompdfpage, makeimagefromrichtext, makepdf,
makespokenaudiofromtext, makevideofromgif, markdownfromrichtext, markup, maskimage,
measurementconvert, measurementcreate, missing, mountdiskimage, movefile, movewindow,
nothing, notification, number, openapp, openin, openincalendar, openurl,
openuseractivity, openxcallbackurl, output, overlayimage, overlaytext,
overridablelink, phonenumber, pinboardadd, pinboardget, playmusic, playpause,
playpodcast, playsound, pocketadd, pocketget, print, quicklook, quitapp,
randomnumber, recognizemusic, recordaudio, remoteappintentexecution, remotelink,
removecalendaritems, removephotofromalbum, renamefile, repeat.count, repeat.each,
replacetext, requestrideintent, requestuber, resizewindow, returntohomescreen,
revealfiles, reversiblelink, richtextfromhtml, richtextfrommarkdown, roundnumber,
rssfeed, rssfeedextract, runjavascriptonwebpage, runosascript, runshellscript,
runshortcutconfigurationintent, runshortcutintent, runsshscript, runworkflow,
savedropboxfile, savetocameraroll, scanmachinereadablecode, searchitunes,
searchlocalbusinesses, searchmaps, searchweb, seek, selectcontacts, selectmusic,
selectphoto, sendemail, sendmessage, sendtogoodreader, setairdropreceiving,
setalwaysondisplay, setappearance, setcellulardata, setclipboard, setdictionaryvalue,
sethotspotpassword, setitemname, setlisteningmode, setlowpowermode, setorientationlock,
setparkedcar, setvariable, setvolume, setvpn, setwallpaper, setwifi, share,
shareextension, shazammedia, showdefinition, showinblindsquare, showinstore, shownote,
showpasswords, showreminderslist, showresult, showwebpage, shutdowndevice, skipsong,
sleepdevice, social, speaktext, splitpdf, splitscreenapp, spotlightsearch,
staccatolink, standaloneshortcut, startcall, startscreensaver, starttimer,
storageservice, storageserviceinput, subscribetopodcast, switchposter, takephoto,
takescreenshot, takevideo, textcomponents, timeuntildate, todoistadd,
toggledonotdisturb, translatetext, trelloaddcard, trellocreateboard, trellocreatelist,
trellogetitems, trimvideo, trimwhitespace, tumblrpost, ulyssesattach, url, urlencode,
urlgetcomponent, vibrate, viewcontentgraph, waittoreturn, watchmedo,
weather.currentconditions, weather.forecast, wordpresspost
```

---

## Common Parameter Patterns

### Text Parameters
```xml
<key>WFTextActionText</key>
<string>Your text here</string>
```

### Variable Reference Parameters
```xml
<key>Text</key>
<dict>
    <key>Value</key>
    <dict>
        <key>attachmentsByRange</key>
        <dict>
            <key>{0, 1}</key>
            <dict>
                <key>OutputUUID</key>
                <string>SOURCE-UUID</string>
                <key>OutputName</key>
                <string>Text</string>
                <key>Type</key>
                <string>ActionOutput</string>
            </dict>
        </dict>
        <key>string</key>
        <string></string>
    </dict>
    <key>WFSerializationType</key>
    <string>WFTextTokenString</string>
</dict>
```

### Boolean Parameters
```xml
<key>WFSomeOption</key>
<true/>
```

### Number Parameters
```xml
<key>WFRepeatCount</key>
<integer>5</integer>
```

### Enum Parameters
```xml
<key>WFHTTPMethod</key>
<string>GET</string>
```

---

## Action-Specific Parameters

### Get Contents of URL (`is.workflow.actions.downloadurl`)

The `downloadurl` action (WFDownloadURLAction) makes HTTP requests. It supports various methods, headers, and body types.

#### Basic Parameters

| Parameter | Type | Description |
|-----------|------|-------------|
| `UUID` | String | Unique identifier for variable references |
| `WFURL` | Variable ref or string | The URL to request |
| `WFHTTPMethod` | String | HTTP method: `GET`, `POST`, `PUT`, `PATCH`, `DELETE` |
| `WFHTTPBodyType` | String | Body type: `JSON`, `Form`, `File` |

#### Headers (`WFHTTPHeaders`)

Headers use `WFDictionaryFieldValue` serialization with key-value items:

```xml
<key>WFHTTPHeaders</key>
<dict>
    <key>Value</key>
    <dict>
        <key>WFDictionaryFieldValueItems</key>
        <array>
            <dict>
                <key>WFItemType</key>
                <integer>0</integer>
                <key>WFKey</key>
                <dict>
                    <key>Value</key>
                    <dict>
                        <key>string</key>
                        <string>Content-Type</string>
                    </dict>
                    <key>WFSerializationType</key>
                    <string>WFTextTokenString</string>
                </dict>
                <key>WFValue</key>
                <dict>
                    <key>Value</key>
                    <dict>
                        <key>string</key>
                        <string>application/json</string>
                    </dict>
                    <key>WFSerializationType</key>
                    <string>WFTextTokenString</string>
                </dict>
            </dict>
        </array>
    </dict>
    <key>WFSerializationType</key>
    <string>WFDictionaryFieldValue</string>
</dict>
```

#### JSON Body (`WFJSONValues`)

When `WFHTTPBodyType` is `JSON`, use `WFJSONValues` for key-value pairs:

```xml
<key>WFJSONValues</key>
<dict>
    <key>Value</key>
    <dict>
        <key>WFDictionaryFieldValueItems</key>
        <array>
            <dict>
                <key>WFItemType</key>
                <integer>0</integer>
                <key>WFKey</key>
                <dict>
                    <key>Value</key>
                    <dict>
                        <key>string</key>
                        <string>prompt</string>
                    </dict>
                    <key>WFSerializationType</key>
                    <string>WFTextTokenString</string>
                </dict>
                <key>WFValue</key>
                <!-- Can be a static string or variable reference -->
                <dict>
                    <key>Value</key>
                    <dict>
                        <key>attachmentsByRange</key>
                        <dict>
                            <key>{0, 1}</key>
                            <dict>
                                <key>OutputUUID</key>
                                <string>ASK-ACTION-UUID</string>
                                <key>OutputName</key>
                                <string>Provided Input</string>
                                <key>Type</key>
                                <string>ActionOutput</string>
                            </dict>
                        </dict>
                        <key>string</key>
                        <string></string>
                    </dict>
                    <key>WFSerializationType</key>
                    <string>WFTextTokenString</string>
                </dict>
            </dict>
        </array>
    </dict>
    <key>WFSerializationType</key>
    <string>WFDictionaryFieldValue</string>
</dict>
```

#### Form Body (`WFFormValues`)

When `WFHTTPBodyType` is `Form`, use `WFFormValues` (same structure as `WFJSONValues`).

#### File Body (`WFRequestVariable`)

When `WFHTTPBodyType` is `File`, use `WFRequestVariable` to reference file data:

```xml
<key>WFRequestVariable</key>
<dict>
    <key>Value</key>
    <dict>
        <key>attachmentsByRange</key>
        <dict>
            <key>{0, 1}</key>
            <dict>
                <key>OutputUUID</key>
                <string>FILE-SOURCE-UUID</string>
                <key>OutputName</key>
                <string>File</string>
                <key>Type</key>
                <string>ActionOutput</string>
            </dict>
        </dict>
        <key>string</key>
        <string></string>
    </dict>
    <key>WFSerializationType</key>
    <string>WFTextTokenString</string>
</dict>
```

#### WFItemType Values

The `WFItemType` field in dictionary items indicates the value type:

| Value | Type |
|-------|------|
| 0 | Text/String |
| 1 | Number |
| 2 | Array |
| 3 | Dictionary |
| 4 | Boolean |

---

### Find Photos (`is.workflow.actions.filter.photos`)

Searches the photo library with filters. See [FILTERS.md](./FILTERS.md) for complete filter documentation.

#### Key Parameters

| Parameter | Type | Description |
|-----------|------|-------------|
| `UUID` | String | Action identifier for output reference |
| `WFContentItemFilter` | Dict | Filter conditions (see FILTERS.md) |
| `WFContentItemSortProperty` | String | Sort by: `Date Taken`, `Creation Date`, etc. |
| `WFContentItemSortOrder` | String | `Latest First` or `Oldest First` |
| `WFContentItemLimitEnabled` | Boolean | Enable result limit |
| `WFContentItemLimitNumber` | Integer | Max results to return |

#### Filter Properties for Photos

| Property | Type | Notes |
|----------|------|-------|
| `Is a Screenshot` | Boolean | Use this for screenshots, NOT media_type |
| `Media Type` | Enum | ONLY: `Image`, `Video`, `Live Photo` |
| `Date Taken` | Date | Use operators 1002 (is today), 1001 (is in the last) |
| `Album` | String | Album name |
| `Is Favorite` | Boolean | Favorited photos |
| `Is Hidden` | Boolean | Hidden photos |

#### Common Mistake: Screenshot Filtering

**WRONG:** Using `Media Type` = `Screenshot` - This value is invalid!

**CORRECT:** Use `Is a Screenshot` = `true` (boolean filter)

---

### Delete Photos (`is.workflow.actions.deletephotos`)

Deletes photos from the library.

#### Critical: Parameter Key

**The parameter key is `photos` (lowercase), NOT `WFInput`!**

This is an exception to the normal pattern where most actions use `WFInput`.

#### Correct Structure

```xml
<dict>
    <key>WFWorkflowActionIdentifier</key>
    <string>is.workflow.actions.deletephotos</string>
    <key>WFWorkflowActionParameters</key>
    <dict>
        <key>UUID</key>
        <string>DELETE-UUID</string>
        <key>photos</key>  <!-- NOT WFInput! -->
        <dict>
            <key>Value</key>
            <dict>
                <key>OutputName</key>
                <string>Photos</string>
                <key>OutputUUID</key>
                <string>FIND-PHOTOS-UUID</string>
                <key>Type</key>
                <string>ActionOutput</string>
            </dict>
            <key>WFSerializationType</key>
            <string>WFTextTokenAttachment</string>
        </dict>
    </dict>
</dict>
```

```

### APPINTENTS.md

```markdown
# AppIntents Reference

Complete catalog of all 728 AppIntent actions available in macOS/iOS.

## AppIntents vs WF*Actions

| Aspect | WF*Actions | AppIntents |
|--------|-----------|------------|
| Identifier format | `is.workflow.actions.*` | Various (e.g., `OpenAboutSettingsStaticDeepLinks`) |
| Origin | Legacy Shortcuts (pre-iOS 16) | App Intents framework (iOS 16+) |
| Invocation | Direct identifier in action | Via `WFAppIntentExecutionAction` wrapper |
| Scope | Core shortcut actions | System integrations, deep links, app extensions |

## How to Invoke AppIntents

AppIntents are invoked using the `WFAppIntentExecutionAction` wrapper:

```xml
<dict>
    <key>WFWorkflowActionIdentifier</key>
    <string>is.workflow.actions.appintentexecution</string>
    <key>WFWorkflowActionParameters</key>
    <dict>
        <key>AppIntentDescriptor</key>
        <dict>
            <key>BundleIdentifier</key>
            <string>com.apple.AccessibilityUtilities.AXSettingsShortcuts</string>
            <key>Name</key>
            <string>Open VoiceOver</string>
            <key>TeamIdentifier</key>
            <string>0000000000</string>
            <key>AppIntentIdentifier</key>
            <string>OpenAccessibilityVoiceOverStaticDeepLinks</string>
        </dict>
    </dict>
</dict>
```

---

## AppIntents by Category

### Settings Deep Links (34 actions)

Open specific Settings panes:

| Identifier | Title |
|------------|-------|
| `OpenAboutSettingsStaticDeepLinks` | Open About |
| `OpenAirDropSettingsStaticDeepLinks` | Open AirDrop |
| `OpenAppleIDSettingsStaticDeepLinks` | Open Apple ID |
| `OpenBatterySettingsStaticDeepLinks` | Open Battery |
| `OpenBluetoothSettingsStaticDeepLinks` | Open Bluetooth |
| `OpenDisplaySettingsStaticDeepLinks` | Open Display |
| `OpenFamilySettingsStaticDeepLinks` | Open Family |
| `OpenFocusSettingsStaticDeepLinks` | Open Focus |
| `OpenGeneralSettingsStaticDeepLinks` | Open General |
| `OpenInternetAccountsSettingsStaticDeepLinks` | Open Internet Accounts |
| `OpenKeyboardSettingsStaticDeepLinks` | Open Keyboard |
| `OpenLanguageSettingsStaticDeepLinks` | Open Language |
| `OpenNetworkSettingsStaticDeepLinks` | Open Network |
| `OpenNotificationSettingsStaticDeepLinks` | Open Notifications |
| `OpenPasswordsSettingsStaticDeepLinks` | Open Passwords |
| `OpenPrivacySettingsStaticDeepLinks` | Open Privacy |
| `OpenScreenTimeSettingsStaticDeepLinks` | Open Screen Time |
| `OpenSecuritySettingsStaticDeepLinks` | Open Security |
| `OpenSiriSettingsStaticDeepLinks` | Open Siri |
| `OpenSoftwareUpdateSettingsStaticDeepLinks` | Open Software Update |
| `OpenSoundSettingsStaticDeepLinks` | Open Sound |
| `OpenStorageSettingsStaticDeepLinks` | Open Storage |
| `OpenTrackpadSettingsStaticDeepLinks` | Open Trackpad |
| `OpenWalletSettingsStaticDeepLinks` | Open Wallet |
| `OpenWiFiSettingsStaticDeepLinks` | Open WiFi |

### Accessibility (164 actions)

Accessibility settings and controls:

| Identifier Pattern | Description |
|-------------------|-------------|
| `OpenAccessibility*StaticDeepLinks` | Open specific accessibility pane |
| `UpdateAx*EntityValueIntent` | Update accessibility setting value |
| `ToggleAx*` | Toggle accessibility feature |

Examples:
- `OpenAccessibilityVoiceOverStaticDeepLinks` - Open VoiceOver
- `OpenAccessibilityZoomStaticDeepLinks` - Open Zoom
- `OpenAccessibilitySwitchControlStaticDeepLinks` - Open Switch Control
- `UpdateAxVoiceOverSpeakingRateEntityValueIntent` - Update VoiceOver rate
- `ToggleAxVoiceOverIntent` - Toggle VoiceOver

### Clock & Alarms (23 actions)

| Identifier | Description |
|------------|-------------|
| `CreateAlarmIntent` | Create new alarm |
| `DeleteAlarmIntent` | Delete alarm |
| `ToggleAlarmIntent` | Toggle alarm on/off |
| `CreateTimerIntent` | Create timer |
| `PauseTimerIntent` | Pause timer |
| `ResumeTimerIntent` | Resume timer |
| `CancelTimerIntent` | Cancel timer |
| `StartStopwatchIntent` | Start stopwatch |
| `ResetStopwatchIntent` | Reset stopwatch |

### Calendar (5 actions)

| Identifier | Description |
|------------|-------------|
| `CreateCalendarIntent` | Create calendar |
| `DeleteCalendarIntent` | Delete calendar |
| `OpenCalendarScreenIntent` | Open calendar view |
| `CloseCalendarScreenIntent` | Close calendar |

### Reminders (12 actions)

| Identifier | Description |
|------------|-------------|
| `CreateReminderListIntent` | Create reminder list |
| `DeleteReminderListIntent` | Delete reminder list |
| `OpenReminderListIntent` | Open reminder list |
| `OpenSmartReminderListIntent` | Open smart list |
| `CompleteReminderIntent` | Complete reminder |

### Notes (8 actions)

| Identifier | Description |
|------------|-------------|
| `CreateNoteFolderIntent` | Create folder |
| `DeleteNoteFolderIntent` | Delete folder |
| `CreateNoteTagIntent` | Create tag |
| `DeleteNoteTagIntent` | Delete tag |
| `AddTagsToNotesIntent` | Add tags to notes |
| `RemoveTagsFromNotesIntent` | Remove tags |
| `PinNotesIntent` | Pin notes |
| `FindNotesIntent` | Find notes |

### Safari (18 actions)

| Identifier | Description |
|------------|-------------|
| `CreateTabIntent` | Create new tab |
| `CreatePrivateTabIntent` | Create private tab |
| `CloseTabIntent` | Close tab |
| `CreateTabGroupIntent` | Create tab group |
| `OpenTabIntent` | Open tab |
| `OpenTabGroupIntent` | Open tab group |
| `FindBookmarksIntent` | Find bookmarks |
| `FindReadingListItemsIntent` | Find reading list |
| `FindTabsIntent` | Find tabs |
| `FindTabGroupsIntent` | Find tab groups |
| `ChangeReaderModeStateIntent` | Toggle reader mode |

### Home (4 actions)

| Identifier | Description |
|------------|-------------|
| `FindHomeIntent` | Find home |
| `FindHomeDeviceIntent` | Find device |
| `FindHomeSceneIntent` | Find scene |
| `ToggleHomeAccessoryIntent` | Toggle accessory |

### Photos (24 actions)

| Identifier | Description |
|------------|-------------|
| `CreateMemoryIntent` | Create memory |
| `OpenCameraIntent` | Open camera |
| `FindPhotosIntent` | Find photos |
| `FindAlbumsIntent` | Find albums |
| `CreateAlbumIntent` | Create album |

### Music (2 actions)

| Identifier | Description |
|------------|-------------|
| `RecognizeMusicIntent` | Shazam recognition |
| `PlayMusicIntent` | Play music |

### Writing Tools (3 actions)

| Identifier | Description |
|------------|-------------|
| `ProofreadIntent` | Proofread text |
| `RewriteIntent` | Rewrite text |
| `SummarizeIntent` | Summarize text |

### Voice Memos (10 actions)

| Identifier | Description |
|------------|-------------|
| `CreateVoiceMemoFolderIntent` | Create folder |
| `DeleteVoiceMemoFolderIntent` | Delete folder |
| `OpenVoiceMemoFolderIntent` | Open folder |
| `FindVoiceMemosIntent` | Find recordings |
| `PlayVoiceMemoIntent` | Play recording |
| `DeleteVoiceMemosIntent` | Delete recordings |

### Shortcuts (8 actions)

| Identifier | Description |
|------------|-------------|
| `CreateWorkflowIntent` | Create shortcut |
| `DeleteWorkflowIntent` | Delete shortcut |
| `CreateiCloudLinkIntent` | Create iCloud link |
| `SearchShortcutsIntent` | Search shortcuts |
| `RunShortcutIntent` | Run shortcut |

### System Controls (154 actions)

Toggle and set system settings:

| Pattern | Description |
|---------|-------------|
| `Set*ModeIntent` | Set mode (silent, low power, etc.) |
| `Toggle*Intent` | Toggle setting |
| `Update*EntityValueIntent` | Update setting value |
| `Set*SettingIntent` | Set specific setting |

Examples:
- `SetLowPowerModeIntent` - Set low power mode
- `SetAirplaneModeIntent` - Set airplane mode
- `ToggleBluetoothIntent` - Toggle Bluetooth
- `SetBrightnessIntent` - Set brightness
- `SetVolumeIntent` - Set volume

### Data & Search (21 actions)

| Pattern | Description |
|---------|-------------|
| `Find*Intent` | Find/search items |
| `Get*Intent` | Get data |
| `Search*Intent` | Search for content |

Examples:
- `FindSportsEventsIntent` - Find sports events
- `GetPhysicalActivityIntent` - Get physical activity
- `SearchFilesIntent` - Search files

---

## Complete AppIntent Identifier List

All 728 AppIntent identifiers organized alphabetically by prefix:

### Open* (Settings Deep Links)
```
OpenAboutSettingsStaticDeepLinks, OpenAccessibilityAudioDescriptionsStaticDeepLinks,
OpenAccessibilityAudioStaticDeepLinks, OpenAccessibilityCaptionsStaticDeepLinks,
OpenAccessibilityDisplayStaticDeepLinks, OpenAccessibilityHearingDevicesStaticDeepLinks,
OpenAccessibilityHoverTextStaticDeepLinks, OpenAccessibilityKeyboardStaticDeepLinks,
OpenAccessibilityLiveCaptionsStaticDeepLinks, OpenAccessibilityLiveSpeechStaticDeepLinks,
OpenAccessibilityMotionStaticDeepLinks, OpenAccessibilityPersonalVoiceStaticDeepLinks,
OpenAccessibilityPointerControlStaticDeepLinks, OpenAccessibilityRootStaticDeepLinks,
OpenAccessibilityRTTStaticDeepLinks, OpenAccessibilityShortcutStaticDeepLinks,
OpenAccessibilitySiriStaticDeepLinks, OpenAccessibilitySpokenContentStaticDeepLinks,
OpenAccessibilitySwitchControlStaticDeepLinks, OpenAccessibilityVocalShortcutsStaticDeepLinks,
OpenAccessibilityVoiceControlStaticDeepLinks, OpenAccessibilityVoiceOverStaticDeepLinks,
OpenAccessibilityZoomStaticDeepLinks
```

### Create* (Creation Actions)
```
CreateAlarmIntent, CreateAlbumIntent, CreateCalendarIntent, CreateEventIntent,
CreateMemoryIntent, CreateNoteFolderIntent, CreateNoteTagIntent, CreateReminderIntent,
CreateReminderListIntent, CreateTabGroupIntent, CreateTabIntent, CreateTimerIntent,
CreateVoiceMemoFolderIntent, CreateWorkflowIntent
```

### Toggle* (Toggle Actions)
```
ToggleAlarmIntent, ToggleAxAssistiveTouchIntent, ToggleAxAudioDescriptionsIntent,
ToggleAxClosedCaptioningIntent, ToggleAxColorFiltersIntent, ToggleAxFullKeyboardAccessIntent,
ToggleAxGuidedAccessIntent, ToggleAxInvertColorsIntent, ToggleAxLiveListenIntent,
ToggleAxReduceMotionIntent, ToggleAxReduceTransparencyIntent, ToggleAxSpeakScreenIntent,
ToggleAxSwitchControlIntent, ToggleAxVoiceControlIntent, ToggleAxVoiceOverIntent,
ToggleAxZoomIntent, ToggleBluetoothIntent, ToggleCellularDataIntent,
ToggleDoNotDisturbIntent, ToggleFocusModeIntent, ToggleHomeAccessoryIntent,
ToggleLowPowerModeIntent, ToggleOrientationLockIntent, ToggleWiFiIntent
```

### Set* (Setting Actions)
```
SetAirplaneModeIntent, SetAlwaysOnDisplayIntent, SetAppearanceIntent,
SetBrightnessIntent, SetCellularDataIntent, SetFlashlightIntent,
SetListeningModeIntent, SetLowPowerModeIntent, SetNightShiftIntent,
SetOrientationLockIntent, SetPersonalHotspotIntent, SetStageManagerIntent,
SetTrueToneIntent, SetVolumeIntent, SetWiFiIntent
```

### Find* (Search Actions)
```
FindAlbumsIntent, FindBookmarksIntent, FindCalendarEventsIntent,
FindContactsIntent, FindFilesIntent, FindHomeDeviceIntent, FindHomeIntent,
FindHomeRoomIntent, FindHomeSceneIntent, FindNotesIntent, FindPhotosIntent,
FindReadingListItemsIntent, FindRemindersIntent, FindSportsEventsIntent,
FindTabGroupsIntent, FindTabsIntent, FindVoiceMemosIntent
```

---

## Invocation Template

To invoke any AppIntent:

```xml
<dict>
    <key>WFWorkflowActionIdentifier</key>
    <string>is.workflow.actions.appintentexecution</string>
    <key>WFWorkflowActionParameters</key>
    <dict>
        <key>AppIntentDescriptor</key>
        <dict>
            <key>BundleIdentifier</key>
            <string>BUNDLE_ID</string>
            <key>Name</key>
            <string>DISPLAY_NAME</string>
            <key>AppIntentIdentifier</key>
            <string>APPINTENT_IDENTIFIER</string>
        </dict>
        <!-- Additional parameters as needed -->
    </dict>
</dict>
```

Common Bundle Identifiers:
- `com.apple.AccessibilityUtilities.AXSettingsShortcuts` - Accessibility
- `com.apple.Preferences` - Settings
- `com.apple.clock` - Clock
- `com.apple.mobilenotes` - Notes
- `com.apple.reminders` - Reminders
- `com.apple.Safari` - Safari
- `com.apple.Home` - Home
- `com.apple.Photos` - Photos

```

### PARAMETER_TYPES.md

```markdown
# Parameter Types Reference

Complete documentation of all parameter value types used in iOS Shortcuts.

Based on analysis of 200 real-world shortcuts containing 338 unique actions and 543 parameter keys.

---

## Serialization Types

These are the `WFSerializationType` values that indicate how complex values are encoded:

| Serialization Type | Description | Use Case |
|--------------------|-------------|----------|
| `WFTextTokenString` | Text with embedded variable references | Text fields that can contain variables |
| `WFTextTokenAttachment` | Single variable reference | Input parameters referencing other actions |
| `WFDictionaryFieldValue` | Dictionary with key-value pairs | HTTP headers, JSON bodies |
| `WFContentPredicateTableTemplate` | Filter conditions | Find/Filter actions |
| `WFQuantityFieldValue` | Measurement with unit | Duration, file size, etc. |
| `WFContactFieldValue` | Contact field reference | Contact properties |
| `WFTimeOffsetValue` | Time offset/duration | Time adjustments |

---

## Basic Value Types

### String
Simple text value:
```xml
<key>WFMenuPrompt</key>
<string>Choose an option</string>
```

### Integer
Whole number:
```xml
<key>WFControlFlowMode</key>
<integer>0</integer>
```

### Number (Float)
Decimal number:
```xml
<key>WFNumberActionNumber</key>
<real>30.0</real>
```

### Boolean
True/false:
```xml
<key>WFShowWorkflow</key>
<true/>
```

### Array
List of values:
```xml
<key>WFMenuItems</key>
<array>
    <string>Option 1</string>
    <string>Option 2</string>
</array>
```

### Data
Binary data (base64 in XML):
```xml
<key>WFData</key>
<data>BASE64_ENCODED_DATA</data>
```

---

## Variable Reference Types

### WFTextTokenAttachment (Single Variable Reference)

Used when a parameter accepts a single variable/output reference:

```xml
<key>WFInput</key>
<dict>
    <key>Value</key>
    <dict>
        <key>OutputName</key>
        <string>Photos</string>
        <key>OutputUUID</key>
        <string>F2BEAE11-3F38-40C3-AD1F-FD48D90F9FE2</string>
        <key>Type</key>
        <string>ActionOutput</string>
    </dict>
    <key>WFSerializationType</key>
    <string>WFTextTokenAttachment</string>
</dict>
```

### WFTextTokenString (Text with Variables)

Used for text fields that can contain embedded variables:

```xml
<key>Text</key>
<dict>
    <key>Value</key>
    <dict>
        <key>attachmentsByRange</key>
        <dict>
            <key>{0, 1}</key>
            <dict>
                <key>OutputName</key>
                <string>Text</string>
                <key>OutputUUID</key>
                <string>A1B2C3D4-E5F6-7890-ABCD-EF1234567890</string>
                <key>Type</key>
                <string>ActionOutput</string>
            </dict>
        </dict>
        <key>string</key>
        <string></string>
    </dict>
    <key>WFSerializationType</key>
    <string>WFTextTokenString</string>
</dict>
```

Key points:
- `` (U+FFFC) is the placeholder character
- `{0, 1}` means "at position 0, length 1"
- Multiple variables: `"Hello , you have  messages"` with `{6, 1}` and `{22, 1}`

---

## Dictionary Field Value

Used for HTTP headers, JSON bodies, and form data:

```xml
<key>WFHTTPHeaders</key>
<dict>
    <key>Value</key>
    <dict>
        <key>WFDictionaryFieldValueItems</key>
        <array>
            <dict>
                <key>WFItemType</key>
                <integer>0</integer>
                <key>WFKey</key>
                <dict>
                    <key>Value</key>
                    <dict>
                        <key>string</key>
                        <string>Content-Type</string>
                    </dict>
                    <key>WFSerializationType</key>
                    <string>WFTextTokenString</string>
                </dict>
                <key>WFValue</key>
                <dict>
                    <key>Value</key>
                    <dict>
                        <key>string</key>
                        <string>application/json</string>
                    </dict>
                    <key>WFSerializationType</key>
                    <string>WFTextTokenString</string>
                </dict>
            </dict>
        </array>
    </dict>
    <key>WFSerializationType</key>
    <string>WFDictionaryFieldValue</string>
</dict>
```

### WFItemType Values

| Value | Type |
|-------|------|
| 0 | Text/String |
| 1 | Number |
| 2 | Array |
| 3 | Dictionary |
| 4 | Boolean |

---

## Content Filter (WFContentPredicateTableTemplate)

Used by all Find/Filter actions. See [FILTERS.md](./FILTERS.md) for complete documentation.

Actions that use content filters:
- `is.workflow.actions.filter.photos`
- `is.workflow.actions.filter.files`
- `is.workflow.actions.filter.reminders`
- `is.workflow.actions.filter.calendarevents`
- `is.workflow.actions.filter.contacts`
- `is.workflow.actions.filter.notes`
- `is.workflow.actions.filter.music`
- `is.workflow.actions.filter.articles`
- `is.workflow.actions.filter.apps`
- `is.workflow.actions.conditional` (via `WFConditions`)

---

## Quantity Field Value

Used for measurements with units (duration, file size, etc.):

```xml
<key>WFDuration</key>
<dict>
    <key>Value</key>
    <dict>
        <key>Magnitude</key>
        <real>5.0</real>
        <key>Unit</key>
        <string>min</string>
    </dict>
    <key>WFSerializationType</key>
    <string>WFQuantityFieldValue</string>
</dict>
```

### Common Units

| Category | Units |
|----------|-------|
| Time | `sec`, `min`, `hr`, `days` |
| Data | `bytes`, `KB`, `MB`, `GB` |
| Length | `m`, `km`, `ft`, `mi` |

---

## Named Variable Reference

For accessing named variables (not action outputs):

```xml
<key>WFVariable</key>
<dict>
    <key>Value</key>
    <dict>
        <key>Type</key>
        <string>Variable</string>
        <key>VariableName</key>
        <string>myVariable</string>
    </dict>
    <key>WFSerializationType</key>
    <string>WFTextTokenAttachment</string>
</dict>
```

---

## Special Input Types

### Magic Variable (Shortcut Input)

Reference the shortcut's input:
```xml
<key>WFInput</key>
<dict>
    <key>Value</key>
    <dict>
        <key>Type</key>
        <string>ExtensionInput</string>
    </dict>
    <key>WFSerializationType</key>
    <string>WFTextTokenAttachment</string>
</dict>
```

### Current Date

```xml
<key>WFDate</key>
<dict>
    <key>Value</key>
    <dict>
        <key>Type</key>
        <string>CurrentDate</string>
    </dict>
    <key>WFSerializationType</key>
    <string>WFTextTokenAttachment</string>
</dict>
```

### Clipboard

```xml
<key>WFInput</key>
<dict>
    <key>Value</key>
    <dict>
        <key>Type</key>
        <string>Clipboard</string>
    </dict>
    <key>WFSerializationType</key>
    <string>WFTextTokenAttachment</string>
</dict>
```

---

## App Identifier

For actions that reference apps:

```xml
<key>WFAppIdentifier</key>
<string>com.apple.safari</string>
```

Or with full app info:
```xml
<key>WFApp</key>
<dict>
    <key>BundleIdentifier</key>
    <string>com.apple.mobilesafari</string>
    <key>Name</key>
    <string>Safari</string>
    <key>TeamIdentifier</key>
    <string>0000000000</string>
</dict>
```

---

## Parameter Patterns by Action Type

### Text Actions
| Parameter | Type |
|-----------|------|
| `WFTextActionText` | string or WFTextTokenString |
| `Text` | string or WFTextTokenString |

### Control Flow Actions
| Parameter | Type |
|-----------|------|
| `GroupingIdentifier` | string (UUID) |
| `WFControlFlowMode` | integer (0=start, 1=middle, 2=end) |

### Input Parameters
| Parameter | Type |
|-----------|------|
| `WFInput` | WFTextTokenAttachment |
| `WFVariable` | WFTextTokenAttachment (named variable) |

### Photo Actions
| Parameter | Type | Notes |
|-----------|------|-------|
| `WFContentItemFilter` | WFContentPredicateTableTemplate | Filter conditions |
| `photos` | WFTextTokenAttachment | **DeletePhotos uses lowercase `photos`!** |
| `WFPhotoCount` | integer | Number of photos |

### HTTP Actions
| Parameter | Type |
|-----------|------|
| `WFURL` | string or WFTextTokenAttachment |
| `WFHTTPMethod` | string (`GET`, `POST`, `PUT`, `DELETE`) |
| `WFHTTPBodyType` | string (`JSON`, `Form`, `File`) |
| `WFHTTPHeaders` | WFDictionaryFieldValue |
| `WFJSONValues` | WFDictionaryFieldValue |
| `WFFormValues` | WFDictionaryFieldValue |

---

## Common Parameter Keys Across Actions

These parameters appear in many different actions:

| Parameter | Count | Type | Description |
|-----------|-------|------|-------------|
| `UUID` | all | string | Action's unique identifier |
| `WFInput` | 306 | variable_ref | Input from previous action |
| `GroupingIdentifier` | ~100 | string | Links control flow actions |
| `WFControlFlowMode` | ~100 | integer | Control flow position |
| `CustomOutputName` | ~50 | string | Custom name for output |
| `WFShowWorkflow` | ~30 | boolean | Show in workflow view |

---

## Type Coercion (Aggrandizements)

When you need to access a property or coerce a type:

```xml
<key>WFInput</key>
<dict>
    <key>Value</key>
    <dict>
        <key>Aggrandizements</key>
        <array>
            <dict>
                <key>CoercionItemClass</key>
                <string>WFStringContentItem</string>
                <key>Type</key>
                <string>WFCoercionVariableAggrandizement</string>
            </dict>
        </array>
        <key>OutputName</key>
        <string>Model Response</string>
        <key>OutputUUID</key>
        <string>LLM-UUID</string>
        <key>Type</key>
        <string>ActionOutput</string>
    </dict>
    <key>WFSerializationType</key>
    <string>WFTextTokenAttachment</string>
</dict>
```

### Common Coercion Classes

| Class | Description |
|-------|-------------|
| `WFStringContentItem` | Coerce to text |
| `WFNumberContentItem` | Coerce to number |
| `WFBooleanContentItem` | Coerce to boolean |
| `WFDictionaryContentItem` | Coerce to dictionary |
| `WFURLContentItem` | Coerce to URL |
| `WFImageContentItem` | Coerce to image |
| `WFFileContentItem` | Coerce to file |

### Property Access (Dictionary Values)

```xml
<key>Aggrandizements</key>
<array>
    <dict>
        <key>DictionaryKey</key>
        <string>fieldName</string>
        <key>Type</key>
        <string>WFDictionaryValueVariableAggrandizement</string>
    </dict>
</array>
```

```

### VARIABLES.md

```markdown
# Variable Reference System

How to pass data between actions in Shortcuts.

## Overview

Shortcuts uses a UUID-based system for referencing output from previous actions:

1. **Source action** has a `UUID` parameter identifying its output
2. **Consuming action** references that UUID via `OutputUUID` in `attachmentsByRange`
3. The placeholder character `` (U+FFFC) marks where variables are inserted in text

## UUID Format

UUIDs must be:
- **Uppercase** letters
- Standard UUID format: `XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX`

Example: `A1B2C3D4-E5F6-7890-ABCD-EF1234567890`

Generate with any UUID generator, just ensure uppercase.

---

## WFSerializationType Values

The `WFSerializationType` key indicates the type of value:

| Type | Description | Usage |
|------|-------------|-------|
| `WFTextTokenString` | Text with embedded variable references | Most common for text params |
| `WFTextTokenAttachment` | Single variable reference (no text) | When param is just a variable |
| `WFContentPredicateTableTemplate` | Filter/predicate definition | For filter actions |
| `WFDictionaryFieldValueItems` | Dictionary entries | For dictionary creation |

---

## attachmentsByRange Format

The `attachmentsByRange` dictionary maps character positions to variable references:

```xml
<key>attachmentsByRange</key>
<dict>
    <key>{position, length}</key>
    <dict>
        <key>OutputUUID</key>
        <string>SOURCE-ACTION-UUID</string>
        <key>OutputName</key>
        <string>Display Name</string>
        <key>Type</key>
        <string>ActionOutput</string>
    </dict>
</dict>
```

### Range Key Format

`{position, length}` where:
- **position**: Character index in the string (0-based)
- **length**: Always `1` (the placeholder is 1 character)

Examples:
- `{0, 1}` - Variable at start of string
- `{5, 1}` - Variable at position 5
- `{10, 1}` - Variable at position 10

---

## The Placeholder Character

The Object Replacement Character `` (U+FFFC, Unicode code point 65532) serves as a placeholder in the `string` value where variables are inserted.

In XML, represent it as:
- Direct character: ``
- Or escaped: `&#xFFFC;` or `&#65532;`

Example string with two variables:
```xml
<key>string</key>
<string>Hello , the weather is </string>
```

With attachments at positions 6 and 24.

---

## Complete Variable Reference Structure

### WFTextTokenString (Text with Variables)

Use when the parameter is text that may contain variable references:

```xml
<key>ParameterName</key>
<dict>
    <key>Value</key>
    <dict>
        <key>string</key>
        <string>The result is: </string>
        <key>attachmentsByRange</key>
        <dict>
            <key>{16, 1}</key>
            <dict>
                <key>OutputUUID</key>
                <string>11111111-1111-1111-1111-111111111111</string>
                <key>OutputName</key>
                <string>Result</string>
                <key>Type</key>
                <string>ActionOutput</string>
            </dict>
        </dict>
    </dict>
    <key>WFSerializationType</key>
    <string>WFTextTokenString</string>
</dict>
```

### WFTextTokenAttachment (Single Variable)

Use when the parameter is just a variable reference with no surrounding text:

```xml
<key>ParameterName</key>
<dict>
    <key>Value</key>
    <dict>
        <key>OutputUUID</key>
        <string>11111111-1111-1111-1111-111111111111</string>
        <key>OutputName</key>
        <string>Text</string>
        <key>Type</key>
        <string>ActionOutput</string>
    </dict>
    <key>WFSerializationType</key>
    <string>WFTextTokenAttachment</string>
</dict>
```

---

## Type Values

The `Type` key in attachment dictionaries indicates the variable source:

| Type | Description |
|------|-------------|
| `ActionOutput` | Output from a previous action |
| `Variable` | Named variable (from Set Variable) |
| `CurrentDate` | Current date/time |
| `Clipboard` | Clipboard contents |
| `Ask` | Ask When Run |
| `ExtensionInput` | Shortcut input |
| `DeviceDetails` | Device information |

Example with CurrentDate:
```xml
<dict>
    <key>Type</key>
    <string>CurrentDate</string>
</dict>
```

---

## Aggrandizements (Property Access)

Aggrandizements modify how a variable is accessed, like getting a property or coercing type:

```xml
<key>Aggrandizements</key>
<array>
    <dict>
        <key>PropertyName</key>
        <string>Name</string>
        <key>Type</key>
        <string>WFPropertyVariableAggrandizement</string>
    </dict>
</array>
```

### Common Aggrandizement Types

#### Property Access
```xml
<dict>
    <key>PropertyName</key>
    <string>Name</string>
    <key>Type</key>
    <string>WFPropertyVariableAggrandizement</string>
</dict>
```

#### Dictionary Key Access
```xml
<dict>
    <key>DictionaryKey</key>
    <string>keyName</string>
    <key>Type</key>
    <string>WFDictionaryValueVariableAggrandizement</string>
</dict>
```

#### Type Coercion
```xml
<dict>
    <key>CoercionItemClass</key>
    <string>WFStringContentItem</string>
    <key>Type</key>
    <string>WFCoercionVariableAggrandizement</string>
</dict>
```

---

## Common Output Names

When referencing action outputs, use these common `OutputName` values:

| Action | OutputName |
|--------|------------|
| Text (gettext) | `Text` |
| Ask for Input | `Provided Input` |
| Ask LLM | `Response` |
| Get Weather | `Weather Conditions` |
| Get Current Location | `Current Location` |
| URL | `URL` |
| Get Contents of URL | `Contents of URL` |
| Number | `Number` |
| Date | `Date` |
| List | `List` |
| Dictionary | `Dictionary` |
| Repeat Each | `Repeat Item` |
| Repeat Count | `Repeat Index` |

---

## Example: Chaining Three Actions

```xml
<!-- Action 1: Get Text -->
<dict>
    <key>WFWorkflowActionIdentifier</key>
    <string>is.workflow.actions.gettext</string>
    <key>WFWorkflowActionParameters</key>
    <dict>
        <key>UUID</key>
        <string>11111111-1111-1111-1111-111111111111</string>
        <key>WFTextActionText</key>
        <string>Hello World</string>
    </dict>
</dict>

<!-- Action 2: Ask LLM (references Action 1) -->
<dict>
    <key>WFWorkflowActionIdentifier</key>
    <string>is.workflow.actions.askllm</string>
    <key>WFWorkflowActionParameters</key>
    <dict>
        <key>UUID</key>
        <string>22222222-2222-2222-2222-222222222222</string>
        <key>WFLLMPrompt</key>
        <dict>
            <key>Value</key>
            <dict>
                <key>string</key>
                <string>Translate this to French: </string>
                <key>attachmentsByRange</key>
                <dict>
                    <key>{26, 1}</key>
                    <dict>
                        <key>OutputUUID</key>
                        <string>11111111-1111-1111-1111-111111111111</string>
                        <key>OutputName</key>
                        <string>Text</string>
                        <key>Type</key>
                        <string>ActionOutput</string>
                    </dict>
                </dict>
            </dict>
            <key>WFSerializationType</key>
            <string>WFTextTokenString</string>
        </dict>
    </dict>
</dict>

<!-- Action 3: Show Result (references Action 2) -->
<dict>
    <key>WFWorkflowActionIdentifier</key>
    <string>is.workflow.actions.showresult</string>
    <key>WFWorkflowActionParameters</key>
    <dict>
        <key>Text</key>
        <dict>
            <key>Value</key>
            <dict>
                <key>attachmentsByRange</key>
                <dict>
                    <key>{0, 1}</key>
                    <dict>
                        <key>OutputUUID</key>
                        <string>22222222-2222-2222-2222-222222222222</string>
                        <key>OutputName</key>
                        <string>Response</string>
                        <key>Type</key>
                        <string>ActionOutput</string>
                    </dict>
                </dict>
                <key>string</key>
                <string></string>
            </dict>
            <key>WFSerializationType</key>
            <string>WFTextTokenString</string>
        </dict>
    </dict>
</dict>
```

---

## Multiple Variables in One Parameter

When a parameter contains multiple variable references:

```xml
<key>Text</key>
<dict>
    <key>Value</key>
    <dict>
        <key>string</key>
        <string>Name: , Age: </string>
        <key>attachmentsByRange</key>
        <dict>
            <key>{6, 1}</key>
            <dict>
                <key>OutputUUID</key>
                <string>UUID-FOR-NAME</string>
                <key>OutputName</key>
                <string>Name</string>
                <key>Type</key>
                <string>ActionOutput</string>
            </dict>
            <key>{14, 1}</key>
            <dict>
                <key>OutputUUID</key>
                <string>UUID-FOR-AGE</string>
                <key>OutputName</key>
                <string>Age</string>
                <key>Type</key>
                <string>ActionOutput</string>
            </dict>
        </dict>
    </dict>
    <key>WFSerializationType</key>
    <string>WFTextTokenString</string>
</dict>
```

Note: Position counting includes all characters including the placeholder ``.

```

### CONTROL_FLOW.md

```markdown
# Control Flow Patterns

How to implement loops, conditionals, and menus in Shortcuts.

## Overview

Control flow actions use two key parameters:
- **GroupingIdentifier**: A UUID that links related actions (start, middle, end)
- **WFControlFlowMode**: An integer indicating the action's role
  - `0` = Start (begin block)
  - `1` = Middle (else, case)
  - `2` = End (close block)

**Important**: `WFControlFlowMode` must be an `<integer>`, not a `<string>`.

---

## Repeat Count

Repeat a block of actions a specific number of times.

### Structure
| Mode | Action | Description |
|------|--------|-------------|
| 0 | Start | Begin repeat, set count |
| 2 | End | Close repeat block |

### Template

```xml
<!-- Repeat Start -->
<dict>
    <key>WFWorkflowActionIdentifier</key>
    <string>is.workflow.actions.repeat.count</string>
    <key>WFWorkflowActionParameters</key>
    <dict>
        <key>GroupingIdentifier</key>
        <string>REPEAT-GROUP-UUID</string>
        <key>WFControlFlowMode</key>
        <integer>0</integer>
        <key>WFRepeatCount</key>
        <integer>5</integer>
    </dict>
</dict>

<!-- Actions inside the loop go here -->

<!-- Repeat End -->
<dict>
    <key>WFWorkflowActionIdentifier</key>
    <string>is.workflow.actions.repeat.count</string>
    <key>WFWorkflowActionParameters</key>
    <dict>
        <key>UUID</key>
        <string>END-ACTION-UUID</string>
        <key>GroupingIdentifier</key>
        <string>REPEAT-GROUP-UUID</string>
        <key>WFControlFlowMode</key>
        <integer>2</integer>
    </dict>
</dict>
```

### Accessing Repeat Index

Inside the loop, reference the current index using the End action's UUID:

```xml
<key>attachmentsByRange</key>
<dict>
    <key>{0, 1}</key>
    <dict>
        <key>OutputUUID</key>
        <string>END-ACTION-UUID</string>
        <key>OutputName</key>
        <string>Repeat Index</string>
        <key>Type</key>
        <string>ActionOutput</string>
    </dict>
</dict>
```

---

## Repeat with Each (For Each)

Iterate over each item in a list.

### Structure
| Mode | Action | Description |
|------|--------|-------------|
| 0 | Start | Begin loop, specify input list |
| 2 | End | Close loop |

### Template

```xml
<!-- Repeat Each Start -->
<dict>
    <key>WFWorkflowActionIdentifier</key>
    <string>is.workflow.actions.repeat.each</string>
    <key>WFWorkflowActionParameters</key>
    <dict>
        <key>GroupingIdentifier</key>
        <string>FOREACH-GROUP-UUID</string>
        <key>WFControlFlowMode</key>
        <integer>0</integer>
        <key>WFInput</key>
        <dict>
            <key>Value</key>
            <dict>
                <key>OutputUUID</key>
                <string>LIST-SOURCE-UUID</string>
                <key>OutputName</key>
                <string>List</string>
                <key>Type</key>
                <string>ActionOutput</string>
            </dict>
            <key>WFSerializationType</key>
            <string>WFTextTokenAttachment</string>
        </dict>
    </dict>
</dict>

<!-- Actions inside the loop go here -->

<!-- Repeat Each End -->
<dict>
    <key>WFWorkflowActionIdentifier</key>
    <string>is.workflow.actions.repeat.each</string>
    <key>WFWorkflowActionParameters</key>
    <dict>
        <key>UUID</key>
        <string>END-ACTION-UUID</string>
        <key>GroupingIdentifier</key>
        <string>FOREACH-GROUP-UUID</string>
        <key>WFControlFlowMode</key>
        <integer>2</integer>
    </dict>
</dict>
```

### Accessing Current Item

Reference the current item using the Start action's UUID with OutputName "Repeat Item":

```xml
<key>attachmentsByRange</key>
<dict>
    <key>{0, 1}</key>
    <dict>
        <key>OutputUUID</key>
        <string>START-ACTION-UUID</string>
        <key>OutputName</key>
        <string>Repeat Item</string>
        <key>Type</key>
        <string>ActionOutput</string>
    </dict>
</dict>
```

---

## Conditional (If/Otherwise)

Execute different actions based on a condition.

### Structure
| Mode | Action | Description |
|------|--------|-------------|
| 0 | If | Start conditional, define condition |
| 1 | Otherwise | Else branch |
| 2 | End If | Close conditional |

### Template

```xml
<!-- If -->
<dict>
    <key>WFWorkflowActionIdentifier</key>
    <string>is.workflow.actions.conditional</string>
    <key>WFWorkflowActionParameters</key>
    <dict>
        <key>GroupingIdentifier</key>
        <string>IF-GROUP-UUID</string>
        <key>WFControlFlowMode</key>
        <integer>0</integer>
        <key>WFCondition</key>
        <string>Equals</string>
        <key>WFInput</key>
        <dict>
            <key>Value</key>
            <dict>
                <key>OutputUUID</key>
                <string>VALUE-TO-TEST-UUID</string>
                <key>OutputName</key>
                <string>Text</string>
                <key>Type</key>
                <string>ActionOutput</string>
            </dict>
            <key>WFSerializationType</key>
            <string>WFTextTokenAttachment</string>
        </dict>
        <key>WFConditionalActionString</key>
        <string>expected value</string>
    </dict>
</dict>

<!-- Actions for "If" branch go here -->

<!-- Otherwise -->
<dict>
    <key>WFWorkflowActionIdentifier</key>
    <string>is.workflow.actions.conditional</string>
    <key>WFWorkflowActionParameters</key>
    <dict>
        <key>GroupingIdentifier</key>
        <string>IF-GROUP-UUID</string>
        <key>WFControlFlowMode</key>
        <integer>1</integer>
    </dict>
</dict>

<!-- Actions for "Otherwise" branch go here -->

<!-- End If -->
<dict>
    <key>WFWorkflowActionIdentifier</key>
    <string>is.workflow.actions.conditional</string>
    <key>WFWorkflowActionParameters</key>
    <dict>
        <key>GroupingIdentifier</key>
        <string>IF-GROUP-UUID</string>
        <key>WFControlFlowMode</key>
        <integer>2</integer>
    </dict>
</dict>
```

### Condition Types

| WFCondition Value | Description |
|-------------------|-------------|
| `Equals` | Value equals comparison |
| `Does Not Equal` | Value does not equal |
| `Contains` | String contains substring |
| `Does Not Contain` | String does not contain |
| `Begins With` | String starts with |
| `Ends With` | String ends with |
| `Is Greater Than` | Number comparison |
| `Is Less Than` | Number comparison |
| `Is Between` | Number in range |
| `Has Any Value` | Not empty |
| `Does Not Have Any Value` | Is empty |

---

## Choose from Menu

Present a menu of options and execute different actions based on the user's choice.

### Structure
| Mode | Action | Description |
|------|--------|-------------|
| 0 | Menu | Define menu with items |
| 1 | Case | One case per menu item |
| 2 | End Menu | Close menu |

### Template

```xml
<!-- Menu Definition -->
<dict>
    <key>WFWorkflowActionIdentifier</key>
    <string>is.workflow.actions.choosefrommenu</string>
    <key>WFWorkflowActionParameters</key>
    <dict>
        <key>GroupingIdentifier</key>
        <string>MENU-GROUP-UUID</string>
        <key>WFControlFlowMode</key>
        <integer>0</integer>
        <key>WFMenuPrompt</key>
        <string>Choose an option:</string>
        <key>WFMenuItems</key>
        <array>
            <string>Option 1</string>
            <string>Option 2</string>
            <string>Option 3</string>
        </array>
    </dict>
</dict>

<!-- Case 1: Option 1 -->
<dict>
    <key>WFWorkflowActionIdentifier</key>
    <string>is.workflow.actions.choosefrommenu</string>
    <key>WFWorkflowActionParameters</key>
    <dict>
        <key>GroupingIdentifier</key>
        <string>MENU-GROUP-UUID</string>
        <key>WFControlFlowMode</key>
        <integer>1</integer>
        <key>WFMenuItemTitle</key>
        <string>Option 1</string>
    </dict>
</dict>

<!-- Actions for Option 1 go here -->

<!-- Case 2: Option 2 -->
<dict>
    <key>WFWorkflowActionIdentifier</key>
    <string>is.workflow.actions.choosefrommenu</string>
    <key>WFWorkflowActionParameters</key>
    <dict>
        <key>GroupingIdentifier</key>
        <string>MENU-GROUP-UUID</string>
        <key>WFControlFlowMode</key>
        <integer>1</integer>
        <key>WFMenuItemTitle</key>
        <string>Option 2</string>
    </dict>
</dict>

<!-- Actions for Option 2 go here -->

<!-- Case 3: Option 3 -->
<dict>
    <key>WFWorkflowActionIdentifier</key>
    <string>is.workflow.actions.choosefrommenu</string>
    <key>WFWorkflowActionParameters</key>
    <dict>
        <key>GroupingIdentifier</key>
        <string>MENU-GROUP-UUID</string>
        <key>WFControlFlowMode</key>
        <integer>1</integer>
        <key>WFMenuItemTitle</key>
        <string>Option 3</string>
    </dict>
</dict>

<!-- Actions for Option 3 go here -->

<!-- End Menu -->
<dict>
    <key>WFWorkflowActionIdentifier</key>
    <string>is.workflow.actions.choosefrommenu</string>
    <key>WFWorkflowActionParameters</key>
    <dict>
        <key>GroupingIdentifier</key>
        <string>MENU-GROUP-UUID</string>
        <key>WFControlFlowMode</key>
        <integer>2</integer>
    </dict>
</dict>
```

### Important Notes

1. **Case order must match WFMenuItems order** - Each case (mode 1) must appear in the same order as the items in WFMenuItems array
2. **WFMenuItemTitle must exactly match** - The case title must exactly match the corresponding item in WFMenuItems
3. **One case per item** - You need exactly one case action for each menu item

---

## Nesting Control Flow

Control flow blocks can be nested. Each nested block needs its own unique GroupingIdentifier:

```xml
<!-- Outer Repeat -->
<dict>
    <key>WFWorkflowActionIdentifier</key>
    <string>is.workflow.actions.repeat.count</string>
    <key>WFWorkflowActionParameters</key>
    <dict>
        <key>GroupingIdentifier</key>
        <string>OUTER-LOOP-UUID</string>
        <key>WFControlFlowMode</key>
        <integer>0</integer>
        <key>WFRepeatCount</key>
        <integer>3</integer>
    </dict>
</dict>

    <!-- Inner Conditional -->
    <dict>
        <key>WFWorkflowActionIdentifier</key>
        <string>is.workflow.actions.conditional</string>
        <key>WFWorkflowActionParameters</key>
        <dict>
            <key>GroupingIdentifier</key>
            <string>INNER-IF-UUID</string>
            <key>WFControlFlowMode</key>
            <integer>0</integer>
            <!-- condition params -->
        </dict>
    </dict>

    <!-- Inner Otherwise -->
    <dict>
        <key>WFWorkflowActionIdentifier</key>
        <string>is.workflow.actions.conditional</string>
        <key>WFWorkflowActionParameters</key>
        <dict>
            <key>GroupingIdentifier</key>
            <string>INNER-IF-UUID</string>
            <key>WFControlFlowMode</key>
            <integer>1</integer>
        </dict>
    </dict>

    <!-- Inner End If -->
    <dict>
        <key>WFWorkflowActionIdentifier</key>
        <string>is.workflow.actions.conditional</string>
        <key>WFWorkflowActionParameters</key>
        <dict>
            <key>GroupingIdentifier</key>
            <string>INNER-IF-UUID</string>
            <key>WFControlFlowMode</key>
            <integer>2</integer>
        </dict>
    </dict>

<!-- Outer End Repeat -->
<dict>
    <key>WFWorkflowActionIdentifier</key>
    <string>is.workflow.actions.repeat.count</string>
    <key>WFWorkflowActionParameters</key>
    <dict>
        <key>GroupingIdentifier</key>
        <string>OUTER-LOOP-UUID</string>
        <key>WFControlFlowMode</key>
        <integer>2</integer>
    </dict>
</dict>
```

---

## Common Mistakes

1. **Using string instead of integer for WFControlFlowMode**
   - Wrong: `<string>0</string>`
   - Right: `<integer>0</integer>`

2. **Mismatched GroupingIdentifier**
   - All parts of a control flow block must share the same GroupingIdentifier

3. **Missing End action**
   - Every start (mode 0) must have a corresponding end (mode 2)

4. **Wrong order in menu cases**
   - Cases must appear in the same order as WFMenuItems

5. **Referencing wrong UUID for loop items**
   - Repeat Item uses the **start** action's UUID
   - Repeat Index uses the **end** action's UUID

```

### FILTERS.md

```markdown
# Content Item Filters Reference

Documentation for `WFContentItemFilter` used in Find/Filter actions like FindPhotos, FindFiles, FindReminders, etc.

## Filter Structure

Filters are used in actions like `is.workflow.actions.filter.photos` to specify criteria for finding content.

### Basic Filter Template

```xml
<key>WFContentItemFilter</key>
<dict>
    <key>Value</key>
    <dict>
        <key>WFActionParameterFilterPrefix</key>
        <integer>1</integer>
        <key>WFContentPredicateBoundedDate</key>
        <false/>
        <key>WFActionParameterFilterTemplates</key>
        <array>
            <!-- Filter conditions go here -->
        </array>
    </dict>
    <key>WFSerializationType</key>
    <string>WFContentPredicateTableTemplate</string>
</dict>
```

---

## Operator Reference

Operators define the comparison type. These were discovered from Shortcuts internal JavaScript:

| Operator | Meaning | Use Case |
|----------|---------|----------|
| 3 | `>=` | Greater than or equal |
| 4 | `is` | Exact match |
| 5 | `is not` | Not equal |
| 8 | `begins with` | String prefix |
| 9 | `ends with` | String suffix |
| 99 | `contains` | String contains |
| 100 | `has any value` | Not empty |
| 101 | `does not have any value` | Is empty |
| 999 | `does not contain` | String not contains |
| 1000 | `is in the next` | Future date range |
| 1001 | `is in the last` | Past date range |
| 1002 | `is today` | Date is today |
| 1003 | `is between` | Date range |

---

## Unit Reference

Units are used with date/time and enumeration filters:

### Date Units (for operators 1000, 1001)

| Unit | Meaning |
|------|---------|
| 4 | years |
| 8 | months |
| 8192 | weeks |
| (TBD) | days |

### Boolean/Enum Unit

| Unit | Context |
|------|---------|
| 4 | Standard unit for boolean and enumeration values |

---

## Filter Templates by Type

### Boolean Filter (e.g., Is a Screenshot)

```xml
<dict>
    <key>Operator</key>
    <integer>4</integer>
    <key>Property</key>
    <string>Is a Screenshot</string>
    <key>Removable</key>
    <true/>
    <key>Values</key>
    <dict>
        <key>Bool</key>
        <true/>
        <key>Unit</key>
        <integer>4</integer>
    </dict>
</dict>
```

### "Is Today" Date Filter

The `is today` operator (1002) does NOT require Values:

```xml
<dict>
    <key>Operator</key>
    <integer>1002</integer>
    <key>Property</key>
    <string>Date Taken</string>
    <key>Removable</key>
    <true/>
</dict>
```

### "Is in the Last X" Date Filter

The `is in the last` operator (1001) requires Number and Unit:

```xml
<dict>
    <key>Operator</key>
    <integer>1001</integer>
    <key>Property</key>
    <string>Date Taken</string>
    <key>Removable</key>
    <true/>
    <key>Values</key>
    <dict>
        <key>Number</key>
        <integer>1</integer>
        <key>Unit</key>
        <integer>8192</integer>  <!-- weeks -->
    </dict>
</dict>
```

### Enumeration Filter (e.g., Media Type)

**IMPORTANT**: Media Type only accepts: `Image`, `Video`, `Live Photo`
Do NOT use `Screenshot` - use the `Is a Screenshot` boolean filter instead.

```xml
<dict>
    <key>Operator</key>
    <integer>4</integer>
    <key>Property</key>
    <string>Media Type</string>
    <key>Removable</key>
    <true/>
    <key>Values</key>
    <dict>
        <key>Unit</key>
        <integer>4</integer>
        <key>Enumeration</key>
        <dict>
            <key>Value</key>
            <string>Image</string>
            <key>WFSerializationType</key>
            <string>WFStringSubstitutableState</string>
        </dict>
    </dict>
</dict>
```

### String Filter (e.g., Album name)

```xml
<dict>
    <key>Operator</key>
    <integer>4</integer>
    <key>Property</key>
    <string>Album</string>
    <key>Removable</key>
    <true/>
    <key>Values</key>
    <dict>
        <key>String</key>
        <string>Favorites</string>
        <key>Unit</key>
        <integer>4</integer>
    </dict>
</dict>
```

---

## FindPhotos Complete Example

Find screenshots taken today:

```xml
<dict>
    <key>WFWorkflowActionIdentifier</key>
    <string>is.workflow.actions.filter.photos</string>
    <key>WFWorkflowActionParameters</key>
    <dict>
        <key>UUID</key>
        <string>FIND-PHOTOS-UUID</string>
        <key>WFContentItemFilter</key>
        <dict>
            <key>Value</key>
            <dict>
                <key>WFActionParameterFilterPrefix</key>
                <integer>1</integer>
                <key>WFContentPredicateBoundedDate</key>
                <false/>
                <key>WFActionParameterFilterTemplates</key>
                <array>
                    <!-- Is a Screenshot = true -->
                    <dict>
                        <key>Operator</key>
                        <integer>4</integer>
                        <key>Property</key>
                        <string>Is a Screenshot</string>
                        <key>Removable</key>
                        <true/>
                        <key>Values</key>
                        <dict>
                            <key>Bool</key>
                            <true/>
                            <key>Unit</key>
                            <integer>4</integer>
                        </dict>
                    </dict>
                    <!-- Date Taken is today -->
                    <dict>
                        <key>Operator</key>
                        <integer>1002</integer>
                        <key>Property</key>
                        <string>Date Taken</string>
                        <key>Removable</key>
                        <true/>
                    </dict>
                </array>
            </dict>
            <key>WFSerializationType</key>
            <string>WFContentPredicateTableTemplate</string>
        </dict>
        <key>WFContentItemSortProperty</key>
        <string>Date Taken</string>
        <key>WFContentItemSortOrder</key>
        <string>Latest First</string>
    </dict>
</dict>
```

---

## DeletePhotos Action

**CRITICAL**: DeletePhotos uses `photos` as the parameter key, NOT `WFInput`:

```xml
<dict>
    <key>WFWorkflowActionIdentifier</key>
    <string>is.workflow.actions.deletephotos</string>
    <key>WFWorkflowActionParameters</key>
    <dict>
        <key>UUID</key>
        <string>DELETE-UUID</string>
        <key>photos</key>
        <dict>
            <key>Value</key>
            <dict>
                <key>OutputName</key>
                <string>Photos</string>
                <key>OutputUUID</key>
                <string>FIND-PHOTOS-UUID</string>
                <key>Type</key>
                <string>ActionOutput</string>
            </dict>
            <key>WFSerializationType</key>
            <string>WFTextTokenAttachment</string>
        </dict>
    </dict>
</dict>
```

---

## Available Filter Properties by Content Type

### Photos (WFPhotoMediaContentItem)

| Property | Type | Values |
|----------|------|--------|
| `Album` | Enumeration | Album names |
| `Media Type` | Enumeration | `Image`, `Video`, `Live Photo` |
| `Is a Screenshot` | Boolean | true/false |
| `Is Hidden` | Boolean | true/false |
| `Is Favorite` | Boolean | true/false |
| `Date Taken` | Date | Use date operators |
| `Creation Date` | Date | Use date operators |
| `Width` | Number | Pixels |
| `Height` | Number | Pixels |
| `Orientation` | Enumeration | `Up`, `Down`, `Left`, `Right` |
| `Photo Type` | Enumeration | `HDR`, `Panorama`, etc. |
| `Frame Rate` | Number | FPS (for videos) |
| `Duration` | Number | Seconds (for videos) |
| `Camera Make` | String | Camera manufacturer |
| `Camera Model` | String | Camera model |
| `File Extension` | String | e.g., `png`, `jpg` |

### Files (WFGenericFileContentItem)

| Property | Type | Values |
|----------|------|--------|
| `Name` | String | Filename |
| `File Extension` | String | Extension without dot |
| `Creation Date` | Date | Use date operators |
| `File Size` | Number | Bytes |
| `Last Modified Date` | Date | Use date operators |

### Reminders (WFReminderContentItem)

| Property | Type | Values |
|----------|------|--------|
| `Title` | String | Reminder title |
| `Is Completed` | Boolean | true/false |
| `Priority` | Enumeration | `None`, `Low`, `Medium`, `High` |
| `Due Date` | Date | Use date operators |
| `Creation Date` | Date | Use date operators |
| `List` | Enumeration | List names |

---

## Common Mistakes to Avoid

1. **Using `media_type="Screenshot"`** - This is WRONG. Use `Is a Screenshot` boolean filter instead.

2. **Using Operator 4 for "is today"** - WRONG. Use Operator 1002.

3. **Using `WFInput` for DeletePhotos** - WRONG. Use `photos` (lowercase).

4. **Adding Values to "is today" filter** - WRONG. Operator 1002 doesn't need Values.

5. **Forgetting OutputUUID reference** - When passing results between actions, you must reference the source action's UUID.

```

### EXAMPLES.md

```markdown
# Complete Working Examples

Copy-paste ready examples that can be signed and imported.

## Example 1: Hello World

The simplest shortcut - displays "Hello World!".

```xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>WFWorkflowActions</key>
    <array>
        <dict>
            <key>WFWorkflowActionIdentifier</key>
            <string>is.workflow.actions.gettext</string>
            <key>WFWorkflowActionParameters</key>
            <dict>
                <key>UUID</key>
                <string>11111111-1111-1111-1111-111111111111</string>
                <key>WFTextActionText</key>
                <string>Hello World!</string>
            </dict>
        </dict>
        <dict>
            <key>WFWorkflowActionIdentifier</key>
            <string>is.workflow.actions.showresult</string>
            <key>WFWorkflowActionParameters</key>
            <dict>
                <key>Text</key>
                <dict>
                    <key>Value</key>
                    <dict>
                        <key>attachmentsByRange</key>
                        <dict>
                            <key>{0, 1}</key>
                            <dict>
                                <key>OutputName</key>
                                <string>Text</string>
                                <key>OutputUUID</key>
                                <string>11111111-1111-1111-1111-111111111111</string>
                                <key>Type</key>
                                <string>ActionOutput</string>
                            </dict>
                        </dict>
                        <key>string</key>
                        <string></string>
                    </dict>
                    <key>WFSerializationType</key>
                    <string>WFTextTokenString</string>
                </dict>
            </dict>
        </dict>
    </array>
    <key>WFWorkflowClientVersion</key>
    <string>2700.0.4</string>
    <key>WFWorkflowHasOutputFallback</key>
    <false/>
    <key>WFWorkflowIcon</key>
    <dict>
        <key>WFWorkflowIconGlyphNumber</key>
        <integer>59511</integer>
        <key>WFWorkflowIconStartColor</key>
        <integer>4282601983</integer>
    </dict>
    <key>WFWorkflowImportQuestions</key>
    <array/>
    <key>WFWorkflowMinimumClientVersion</key>
    <integer>900</integer>
    <key>WFWorkflowMinimumClientVersionString</key>
    <string>900</string>
    <key>WFWorkflowName</key>
    <string>Hello World</string>
    <key>WFWorkflowOutputContentItemClasses</key>
    <array/>
    <key>WFWorkflowTypes</key>
    <array/>
</dict>
</plist>
```

---

## Example 2: Ask User for Input

Asks user for their name and displays a greeting.

```xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>WFWorkflowActions</key>
    <array>
        <dict>
            <key>WFWorkflowActionIdentifier</key>
            <string>is.workflow.actions.ask</string>
            <key>WFWorkflowActionParameters</key>
            <dict>
                <key>UUID</key>
                <string>AAAAAAAA-AAAA-AAAA-AAAA-AAAAAAAAAAAA</string>
                <key>WFAskActionPrompt</key>
                <string>What is your name?</string>
                <key>WFInputType</key>
                <string>Text</string>
            </dict>
        </dict>
        <dict>
            <key>WFWorkflowActionIdentifier</key>
            <string>is.workflow.actions.showresult</string>
            <key>WFWorkflowActionParameters</key>
            <dict>
                <key>Text</key>
                <dict>
                    <key>Value</key>
                    <dict>
                        <key>attachmentsByRange</key>
                        <dict>
                            <key>{7, 1}</key>
                            <dict>
                                <key>OutputName</key>
                                <string>Provided Input</string>
                                <key>OutputUUID</key>
                                <string>AAAAAAAA-AAAA-AAAA-AAAA-AAAAAAAAAAAA</string>
                                <key>Type</key>
                                <string>ActionOutput</string>
                            </dict>
                        </dict>
                        <key>string</key>
                        <string>Hello, !</string>
                    </dict>
                    <key>WFSerializationType</key>
                    <string>WFTextTokenString</string>
                </dict>
            </dict>
        </dict>
    </array>
    <key>WFWorkflowClientVersion</key>
    <string>2700.0.4</string>
    <key>WFWorkflowHasOutputFallback</key>
    <false/>
    <key>WFWorkflowIcon</key>
    <dict>
        <key>WFWorkflowIconGlyphNumber</key>
        <integer>59511</integer>
        <key>WFWorkflowIconStartColor</key>
        <integer>4282601983</integer>
    </dict>
    <key>WFWorkflowImportQuestions</key>
    <array/>
    <key>WFWorkflowMinimumClientVersion</key>
    <integer>900</integer>
    <key>WFWorkflowMinimumClientVersionString</key>
    <string>900</string>
    <key>WFWorkflowName</key>
    <string>Greeting</string>
    <key>WFWorkflowOutputContentItemClasses</key>
    <array/>
    <key>WFWorkflowTypes</key>
    <array/>
</dict>
</plist>
```

---

## Example 3: AI Query

Asks user for a question, sends it to Apple Intelligence, and displays the response.

```xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>WFWorkflowActions</key>
    <array>
        <dict>
            <key>WFWorkflowActionIdentifier</key>
            <string>is.workflow.actions.ask</string>
            <key>WFWorkflowActionParameters</key>
            <dict>
                <key>UUID</key>
                <string>BBBBBBBB-BBBB-BBBB-BBBB-BBBBBBBBBBBB</string>
                <key>WFAskActionPrompt</key>
                <string>What would you like to ask?</string>
                <key>WFInputType</key>
                <string>Text</string>
            </dict>
        </dict>
        <dict>
            <key>WFWorkflowActionIdentifier</key>
            <string>is.workflow.actions.askllm</string>
            <key>WFWorkflowActionParameters</key>
            <dict>
                <key>UUID</key>
                <string>CCCCCCCC-CCCC-CCCC-CCCC-CCCCCCCCCCCC</string>
                <key>WFLLMModel</key>
                <string>Apple Intelligence</string>
                <key>WFGenerativeResultType</key>
                <string>Text</string>
                <key>WFLLMPrompt</key>
                <dict>
                    <key>Value</key>
                    <dict>
                        <key>attachmentsByRange</key>
                        <dict>
                            <key>{0, 1}</key>
                            <dict>
                                <key>OutputName</key>
                                <string>Provided Input</string>
                                <key>OutputUUID</key>
                                <string>BBBBBBBB-BBBB-BBBB-BBBB-BBBBBBBBBBBB</string>
                                <key>Type</key>
                                <string>ActionOutput</string>
                            </dict>
                        </dict>
                        <key>string</key>
                        <string></string>
                    </dict>
                    <key>WFSerializationType</key>
                    <string>WFTextTokenString</string>
                </dict>
            </dict>
        </dict>
        <dict>
            <key>WFWorkflowActionIdentifier</key>
            <string>is.workflow.actions.showresult</string>
            <key>WFWorkflowActionParameters</key>
            <dict>
                <key>Text</key>
                <dict>
                    <key>Value</key>
                    <dict>
                        <key>attachmentsByRange</key>
                        <dict>
                            <key>{0, 1}</key>
                            <dict>
                                <key>OutputName</key>
                                <string>Response</string>
                                <key>OutputUUID</key>
                                <string>CCCCCCCC-CCCC-CCCC-CCCC-CCCCCCCCCCCC</string>
                                <key>Type</key>
                                <string>ActionOutput</string>
                            </dict>
                        </dict>
                        <key>string</key>
                        <string></string>
                    </dict>
                    <key>WFSerializationType</key>
                    <string>WFTextTokenString</string>
                </dict>
            </dict>
        </dict>
    </array>
    <key>WFWorkflowClientVersion</key>
    <string>2700.0.4</string>
    <key>WFWorkflowHasOutputFallback</key>
    <false/>
    <key>WFWorkflowIcon</key>
    <dict>
        <key>WFWorkflowIconGlyphNumber</key>
        <integer>59511</integer>
        <key>WFWorkflowIconStartColor</key>
        <integer>4282601983</integer>
    </dict>
    <key>WFWorkflowImportQuestions</key>
    <array/>
    <key>WFWorkflowMinimumClientVersion</key>
    <integer>900</integer>
    <key>WFWorkflowMinimumClientVersionString</key>
    <string>900</string>
    <key>WFWorkflowName</key>
    <string>Ask AI</string>
    <key>WFWorkflowOutputContentItemClasses</key>
    <array/>
    <key>WFWorkflowTypes</key>
    <array/>
</dict>
</plist>
```

---

## Example 4: Menu Demo

Presents a menu with three options, each displaying different text.

```xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>WFWorkflowActions</key>
    <array>
        <!-- Menu Start -->
        <dict>
            <key>WFWorkflowActionIdentifier</key>
            <string>is.workflow.actions.choosefrommenu</string>
            <key>WFWorkflowActionParameters</key>
            <dict>
                <key>GroupingIdentifier</key>
                <string>DDDDDDDD-DDDD-DDDD-DDDD-DDDDDDDDDDDD</string>
                <key>WFControlFlowMode</key>
                <integer>0</integer>
                <key>WFMenuPrompt</key>
                <string>What would you like to do?</string>
                <key>WFMenuItems</key>
                <array>
                    <string>Say Hello</string>
                    <string>Say Goodbye</string>
                    <string>Tell a Joke</string>
                </array>
            </dict>
        </dict>
        <!-- Case 1 -->
        <dict>
            <key>WFWorkflowActionIdentifier</key>
            <string>is.workflow.actions.choosefrommenu</string>
            <key>WFWorkflowActionParameters</key>
            <dict>
                <key>GroupingIdentifier</key>
                <string>DDDDDDDD-DDDD-DDDD-DDDD-DDDDDDDDDDDD</string>
                <key>WFControlFlowMode</key>
                <integer>1</integer>
                <key>WFMenuItemTitle</key>
                <string>Say Hello</string>
            </dict>
        </dict>
        <dict>
            <key>WFWorkflowActionIdentifier</key>
            <string>is.workflow.actions.showresult</string>
            <key>WFWorkflowActionParameters</key>
            <dict>
                <key>Text</key>
                <string>Hello there! Nice to meet you.</string>
            </dict>
        </dict>
        <!-- Case 2 -->
        <dict>
            <key>WFWorkflowActionIdentifier</key>
            <string>is.workflow.actions.choosefrommenu</string>
            <key>WFWorkflowActionParameters</key>
            <dict>
                <key>GroupingIdentifier</key>
                <string>DDDDDDDD-DDDD-DDDD-DDDD-DDDDDDDDDDDD</string>
                <key>WFControlFlowMode</key>
                <integer>1</integer>
                <key>WFMenuItemTitle</key>
                <string>Say Goodbye</string>
            </dict>
        </dict>
        <dict>
            <key>WFWorkflowActionIdentifier</key>
            <string>is.workflow.actions.showresult</string>
            <key>WFWorkflowActionParameters</key>
            <dict>
                <key>Text</key>
                <string>Goodbye! See you next time.</string>
            </dict>
        </dict>
        <!-- Case 3 -->
        <dict>
            <key>WFWorkflowActionIdentifier</key>
            <string>is.workflow.actions.choosefrommenu</string>
            <key>WFWorkflowActionParameters</key>
            <dict>
                <key>GroupingIdentifier</key>
                <string>DDDDDDDD-DDDD-DDDD-DDDD-DDDDDDDDDDDD</string>
                <key>WFControlFlowMode</key>
                <integer>1</integer>
                <key>WFMenuItemTitle</key>
                <string>Tell a Joke</string>
            </dict>
        </dict>
        <dict>
            <key>WFWorkflowActionIdentifier</key>
            <string>is.workflow.actions.showresult</string>
            <key>WFWorkflowActionParameters</key>
            <dict>
                <key>Text</key>
                <string>Why do programmers prefer dark mode? Because light attracts bugs!</string>
            </dict>
        </dict>
        <!-- Menu End -->
        <dict>
            <key>WFWorkflowActionIdentifier</key>
            <string>is.workflow.actions.choosefrommenu</string>
            <key>WFWorkflowActionParameters</key>
            <dict>
                <key>GroupingIdentifier</key>
                <string>DDDDDDDD-DDDD-DDDD-DDDD-DDDDDDDDDDDD</string>
                <key>WFControlFlowMode</key>
                <integer>2</integer>
            </dict>
        </dict>
    </array>
    <key>WFWorkflowClientVersion</key>
    <string>2700.0.4</string>
    <key>WFWorkflowHasOutputFallback</key>
    <false/>
    <key>WFWorkflowIcon</key>
    <dict>
        <key>WFWorkflowIconGlyphNumber</key>
        <integer>59511</integer>
        <key>WFWorkflowIconStartColor</key>
        <integer>4282601983</integer>
    </dict>
    <key>WFWorkflowImportQuestions</key>
    <array/>
    <key>WFWorkflowMinimumClientVersion</key>
    <integer>900</integer>
    <key>WFWorkflowMinimumClientVersionString</key>
    <string>900</string>
    <key>WFWorkflowName</key>
    <string>Menu Demo</string>
    <key>WFWorkflowOutputContentItemClasses</key>
    <array/>
    <key>WFWorkflowTypes</key>
    <array/>
</dict>
</plist>
```

---

## Example 5: Weather + AI Report

Gets current weather and uses AI to generate a friendly report.

```xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>WFWorkflowActions</key>
    <array>
        <!-- Get Weather -->
        <dict>
            <key>WFWorkflowActionIdentifier</key>
            <string>is.workflow.actions.weather.currentconditions</string>
            <key>WFWorkflowActionParameters</key>
            <dict>
                <key>UUID</key>
                <string>EEEEEEEE-EEEE-EEEE-EEEE-EEEEEEEEEEEE</string>
            </dict>
        </dict>
        <!-- Build Prompt -->
        <dict>
            <key>WFWorkflowActionIdentifier</key>
            <string>is.workflow.actions.gettext</string>
            <key>WFWorkflowActionParameters</key>
            <dict>
                <key>UUID</key>
                <string>FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF</string>
                <key>WFTextActionText</key>
                <dict>
                    <key>Value</key>
                    <dict>
                        <key>attachmentsByRange</key>
                        <dict>
                            <key>{56, 1}</key>
                            <dict>
                                <key>OutputName</key>
                                <string>Weather Conditions</string>
                                <key>OutputUUID</key>
                                <string>EEEEEEEE-EEEE-EEEE-EEEE-EEEEEEEEEEEE</string>
                                <key>Type</key>
                                <string>ActionOutput</string>
                            </dict>
                        </dict>
                        <key>string</key>
                        <string>Generate a friendly weather report based on this data:


Keep it brief and include clothing recommendations.</string>
                    </dict>
                    <key>WFSerializationType</key>
                    <string>WFTextTokenString</string>
                </dict>
            </dict>
        </dict>
        <!-- Ask AI -->
        <dict>
            <key>WFWorkflowActionIdentifier</key>
            <string>is.workflow.actions.askllm</string>
            <key>WFWorkflowActionParameters</key>
            <dict>
                <key>UUID</key>
                <string>GGGGGGGG-GGGG-GGGG-GGGG-GGGGGGGGGGGG</string>
                <key>WFLLMModel</key>
                <string>Apple Intelligence</string>
                <key>WFGenerativeResultType</key>
                <string>Text</string>
                <key>WFLLMPrompt</key>
                <dict>
                    <key>Value</key>
                    <dict>
                        <key>attachmentsByRange</key>
                        <dict>
                            <key>{0, 1}</key>
                            <dict>
                                <key>OutputName</key>
                                <string>Text</string>
                                <key>OutputUUID</key>
                                <string>FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF</string>
                                <key>Type</key>
                                <string>ActionOutput</string>
                            </dict>
                        </dict>
                        <key>string</key>
                        <string></string>
                    </dict>
                    <key>WFSerializationType</key>
                    <string>WFTextTokenString</string>
                </dict>
            </dict>
        </dict>
        <!-- Show Result -->
        <dict>
            <key>WFWorkflowActionIdentifier</key>
            <string>is.workflow.actions.showresult</string>
            <key>WFWorkflowActionParameters</key>
            <dict>
                <key>Text</key>
                <dict>
                    <key>Value</key>
                    <dict>
                        <key>attachmentsByRange</key>
                        <dict>
                            <key>{0, 1}</key>
                            <dict>
                                <key>OutputName</key>
                                <string>Response</string>
                                <key>OutputUUID</key>
                                <string>GGGGGGGG-GGGG-GGGG-GGGG-GGGGGGGGGGGG</string>
                                <key>Type</key>
                                <string>ActionOutput</string>
                            </dict>
                        </dict>
                        <key>string</key>
                        <string></string>
                    </dict>
                    <key>WFSerializationType</key>
                    <string>WFTextTokenString</string>
                </dict>
            </dict>
        </dict>
    </array>
    <key>WFWorkflowClientVersion</key>
    <string>2700.0.4</string>
    <key>WFWorkflowHasOutputFallback</key>
    <false/>
    <key>WFWorkflowIcon</key>
    <dict>
        <key>WFWorkflowIconGlyphNumber</key>
        <integer>59511</integer>
        <key>WFWorkflowIconStartColor</key>
        <integer>4282601983</integer>
    </dict>
    <key>WFWorkflowImportQuestions</key>
    <array/>
    <key>WFWorkflowMinimumClientVersion</key>
    <integer>900</integer>
    <key>WFWorkflowMinimumClientVersionString</key>
    <string>900</string>
    <key>WFWorkflowName</key>
    <string>Weather Report</string>
    <key>WFWorkflowOutputContentItemClasses</key>
    <array/>
    <key>WFWorkflowTypes</key>
    <array/>
</dict>
</plist>
```

---

## How to Use These Examples

1. **Copy** the XML content
2. **Save** to a file with `.shortcut` extension (e.g., `HelloWorld.shortcut`)
3. **Sign** using the shortcuts CLI:
   ```bash
   shortcuts sign --mode anyone --input HelloWorld.shortcut --output HelloWorld_signed.shortcut
   ```
4. **Import** by double-clicking the signed file or dragging to Shortcuts.app

```



---

## Skill Companion Files

> Additional files collected from the skill directory layout.

### _meta.json

```json
{
  "owner": "erik-agens",
  "slug": "shortcuts-skill",
  "displayName": "Shortcuts Generator",
  "latest": {
    "version": "0.1.0",
    "publishedAt": 1768474518850,
    "commit": "https://github.com/clawdbot/skills/commit/368c358abd65c03116f0864fd77b92af9a5cfe31"
  },
  "history": []
}

```