Apple Shortcuts As Code

Copied to clipboard! Copies a prompt to paste into ChatGPT, Claude, etc.

Apple Shortcuts are powerful, but building complex automations with the visual block interface quickly becomes painful. Enter Cherri - a programming language that compiles to Apple Shortcuts, giving you proper syntax, variables, control flow, and most importantly, version control.

I’ve been using Cherri to build iOS automations, and along the way I’ve discovered some powerful patterns - especially for integrating with third-party apps like Pythonista.

What is Cherri?

Cherri is a transpiler that converts human-readable code into the .shortcut binary format that iOS and macOS can run. Instead of dragging blocks around, you write code like this:

@name = askText("What's your name?")
alert("Hello, {name}!", "Greeting")

This compiles to a native Shortcut that prompts for input and shows an alert.

Vibecoding Shortcuts with LLMs

Here’s where it gets really interesting: I don’t write most of my Cherri code by hand anymore. I describe what I want to an LLM, and it generates the shortcut for me.

To make this work, I wrote a comprehensive guide that teaches LLMs the Cherri syntax - all the quirks, common mistakes, and patterns they need to know. The full guide is available as a gist:

LLM_GUIDE.md - Teaching AI to Write Apple Shortcuts

The workflow is simple:

  1. Include the LLM_GUIDE in your prompt context
  2. Describe the shortcut you want
  3. The LLM generates valid Cherri code
  4. Compile and run

This is “vibecoding” for iOS automation - you describe the behavior, the LLM handles the syntax.

Key Concepts from the Guide

The guide covers everything an LLM needs to know:

Variables and strings:

// Variables use @
@message = "Hello World"

// String interpolation with curly braces
alert("The message is: {message}")

Menus (note the colon syntax):

menu "Choose:" {
    item "Option 1":
        alert("You chose 1")
    item "Option 2":
        alert("You chose 2")
}

Loops:

repeat 3 {
    alert("Count: {RepeatIndex}")
}

for item in list {
    show(item)
}

Common gotchas the guide prevents:

  1. alert(message, title) not alert(title, message)
  2. Menu items use colon : not curly braces
  3. Variables need @ for assignment
  4. Cherri is case-sensitive

Discovering Third-Party App Actions

Here’s where it gets interesting. The Shortcuts app can interact with third-party apps through App Intents, but finding the exact action identifiers requires some detective work.

I wrote a script (analyze_apps.sh) that scans /Applications for apps with Shortcuts support:

# Find intent handlers
find /Applications -name "*IntentHandler.appex"

# Extract activity types from Info.plist
plutil -extract NSUserActivityTypes raw "/path/to/app/Info.plist"

# Find intent definitions
find "/Applications/App.app" -name "*.intentdefinition"

The script analyzes each app for:

  • NSUserActivityTypes in Info.plist
  • Intent Handler extensions
  • Action extensions

The APP_ACTIONS_REFERENCE

After running the analysis, I documented all the useful actions I found. Here are the most valuable ones:

Pythonista (Python on iOS)

This is the killer integration. Pythonista lets you run Python scripts on iOS, and Cherri can call it:

#define action 'PA3RunScriptIntent' runPythonistaScript(
    text scriptPath: 'scriptPath',
    text ?scriptArguments: 'scriptArguments'
)

// Call a Python script with arguments
runPythonistaScript("icloud/my_script.py", "arg1,arg2")

Logger (Debug Console)

Great for debugging complex shortcuts:

#define action 'LogMessageIntent' logMessage(text message: 'message')

logMessage("Checkpoint reached: processing started")
#define action 'QuickMenuIntent' showQuickMenu(text ?menuName: 'quickMenuStringDynamic')

showQuickMenu("Development Tools")

Real-World Example: Pythonista Reminder System

Here’s a practical shortcut I built that combines Cherri menus with Pythonista scripts:

/*
Pythonista Reminder Template System
Calls Pythonista to handle all reminder operations
*/

#include 'actions/calendar'

#define action 'PA3RunScriptIntent' runPythonistaScript(
    text scriptPath: 'scriptPath',
    text ?scriptArguments: 'scriptArguments'
)

// Get current date for the script
@today = currentDate()
@dateForScript = formatDate(today, "None", "yyyy-MM-dd")

// First run cleanup
runPythonistaScript("icloud/cleanup_automated_reminders.py", dateForScript)

// Show template menu
menu "Choose Daily Template:" {
    item "Morning Routine":
        @templateType = "morning"
    item "Evening Routine":
        @templateType = "evening"
    item "Driving Tasks":
        @templateType = "driving"
}

// Call Pythonista to create the reminders
runPythonistaScript("icloud/reminder_template_system.py", templateType)

The Shortcut handles the UI (menu selection), while Python handles the complex logic (reminder creation, date parsing, etc.).

Development Workflow

Fast iteration is key. I set up a Makefile for building shortcuts:

# Development build (no signing, fast)
make dev

# Production build (with signing)
make prod

# Clean all generated shortcuts
make clean

The --skip-sign flag is crucial for development - signing takes several seconds but isn’t needed for local testing.

My Workflow

  1. Write .cherri file (or have an LLM generate it)
  2. Run make dev (compiles without signing)
  3. Test the unsigned .shortcut locally
  4. Fix issues, repeat
  5. Run make prod for final signed version

Defining Custom Actions

The #define action syntax lets you wrap any app’s intent:

#define action 'IntentIdentifier' functionName(
    parameterType parameterName: 'internalName',
    parameterType ?optionalParam: 'internalName2'
)

The identifier comes from analyzing the app bundle. Parameters marked with ? are optional.

Why This Matters

Cherri + LLMs + third-party app integration enables:

  1. Vibecoding: Describe shortcuts in plain English, LLM generates the code
  2. Version Control: Your shortcuts live in git, not iCloud
  3. Code Reuse: Include files, define reusable actions
  4. Complex Logic: Real programming instead of block spaghetti
  5. Pythonista Bridge: iOS Python scripts triggered from anywhere
  6. Debugging: Logger integration for tracing execution

Getting Started

  1. Clone the Cherri repo
  2. Build with go build
  3. Write your first shortcut:
#define name "My First Shortcut"
#define color blue
#define glyph star

alert("Hello from Cherri!", "It works!")
  1. Compile: ./cherri my_shortcut.cherri --skip-sign
  2. Open the .shortcut file to install

Resources

  • LLM_GUIDE.md: Comprehensive syntax guide for teaching LLMs Cherri
  • APP_ACTIONS_REFERENCE.md: Third-party app action identifiers
  • analyze_apps.sh: Script to discover actions in installed apps

The combination of Cherri’s programming model, LLM code generation, and Pythonista’s Python runtime creates a surprisingly powerful automation platform on iOS - one where you can describe what you want and actually get working code.

Copied to clipboard!