Migrating Existing Shortcuts to Cherri
This guide will help you convert your existing Shortcuts into Cherri code, making them easier to maintain, version control, and scale.
Table of contents
- Why Migrate?
 - Migration Process Overview
 - Step 1: Decompile Your Shortcut
 - Step 2: Understanding Decompiled Code
 - Refactoring to Idiomatic Cherri
 - Testing Your Migrated Shortcut
 - Advanced Migration Techniques
 - Troubleshooting Migration Issues
 - Migration Best Practices
 - When NOT to Decompile
 - Resources
 
Why Migrate?
Converting your existing Shortcuts to Cherri offers several benefits:
- 📝 Version Control - Track changes with Git, collaborate with others
 - 🔍 Code Review - Review changes in pull requests before deploying
 - 🧩 Modularity - Split large Shortcuts into multiple files with 
#include - 🔄 Reusability - Create functions to eliminate duplicate actions
 - 🐛 Easier Debugging - Read and understand code faster than visual blocks
 - 📏 Code Style - Enforce consistent formatting and patterns
 - 🤝 Team Collaboration - Multiple people can work on the same Shortcut
 
Migration Process Overview
The migration process consists of four main steps:
- Decompile - Convert your 
.shortcutfile to Cherri code - Review - Understand the generated code and identify improvement areas
 - Refactor - Apply Cherri best practices and idioms
 - Test - Compile and verify the migrated Shortcut works correctly
 
Step 1: Decompile Your Shortcut
Cherri can automatically convert existing Shortcuts into Cherri code using the --import flag.
Get the Shortcut URL
First, you need an iCloud link to your shortcut:
- Open the Shortcuts app on your device
 - Find the shortcut you want to migrate
 - Tap the info icon (ⓘ) on the shortcut
 - Tap Share
 - Choose Copy iCloud Link
 
The link will look like: https://www.icloud.com/shortcuts/abc123def456
Decompile with Cherri
Use the --import flag with the iCloud URL:
cherri --import=https://www.icloud.com/shortcuts/abc123def456
This will:
- Download the shortcut from iCloud
 - Parse the 
.plistformat - Generate Cherri code
 - Save it as a 
.cherrifile 
If the decompilation is successful, you’ll see no output (following Unix conventions). The decompiled .cherri file will be created in your current directory.
Review the Generated Code
Open the generated .cherri file in your editor:
code "My Shortcut_decompiled.cherri"  # VS Code
# or
open "My Shortcut_decompiled.cherri"  # Default editor
The decompiled code will contain:
- Metadata (
#definestatements for name, color, glyph) - All actions from your shortcut
 - Raw actions for any actions not in Cherri’s standard library
 - Comments indicating action names
 
Step 2: Understanding Decompiled Code
Decompiled code is functional but not idiomatic. Let’s look at what you might see.
Example: Simple Shortcut
Original Shortcut:
- Show alert “Hello, World!”
 
Decompiled Code:
#define color yellow
#define glyph smileyFace
alert("Hello, World!")
What to Notice
- Standard Actions Matched - Most standard actions are automatically matched to their Cherri equivalents
 - Third-Party Actions - Only 3rd party actions not defined in Cherri will appear as 
rawAction(...) - Missing Includes - Action includes may not be automatically added (this is a known issue), so you may need to add them manually
 - No Variables - Magic variables may appear as raw variable references
 - No Functions - Duplicate action sequences aren’t consolidated
 - Verbose - The code may be longer than necessary
 
The decompiler generates functional code that matches most standard actions correctly, but it’s your job to make it idiomatic Cherri by adding includes, using better variable patterns, and consolidating duplicate code.
Refactoring to Idiomatic Cherri
Now let’s transform the decompiled code into clean, maintainable Cherri.
3.1 Add Missing Action Includes
Standard actions are usually decompiled correctly, but the action includes may not be automatically added. Add the necessary includes at the top of your file:
Before (fails):
// #define name My Shortcut
#define color blue
#define glyph hand
const location = getCurrentLocation()
const weather = getCurrentWeather(location)
After (succeeeds):
#include 'actions/location'
// #define name My Shortcut
#define color blue
#define glyph hand
const location = getCurrentLocation()
const weather = getCurrentWeather(location)
Check the Standard Library documentation to find which include file contains each action.
If you encounter rawAction(...) for a standard Shortcuts action, it may be missing from Cherri’s standard library. Consider defining it as a custom action or reporting it as an issue.
3.2 Use Constants for Immutable Values
Before:
@number = 42
show("{number}")
After:
const number = 42
show("{number}")
Why? If a value never changes, use const instead of @variable for smaller shortcuts and better performance.
3.3 Consolidate Duplicate Code into Functions
Before:
// Calculate total for item 1
@price1 = 10
@tax1 = price1 * 0.08
@total1 = price1 + tax1
// Calculate total for item 2
@price2 = 20
@tax2 = price2 * 0.08
@total2 = price2 + tax2
After:
#include 'actions/scripting'
function calculateTotal(number price): number {
    const tax = price * 0.08
    const total = price + tax
    output("{total}")
}
const total1 = calculateTotal(10)
const total2 = calculateTotal(20)
3.4 Use Control Flow Output
Before:
const condition = true
@result
if condition {
    @result = "Yes"
} else {
    @result = "No"
}
show("{result}")
After:
const condition = true
const result = if condition {
    text("Yes")
} else {
    text("No")
}
show("{result}")
3.5 Split Large Shortcuts with Includes
If your shortcut has distinct sections, split them into separate files:
main.cherri:
#include 'config.cherri'
#include 'helpers.cherri'
#include 'actions/network'
// Main logic here
config.cherri:
#define name My Shortcut
#define color yellow
#define glyph smileyFace
// Configuration constants
const API_URL = "https://api.example.com"
const TIMEOUT = 30
helpers.cherri:
#include 'actions/scripting'
function formatDate(date input): text {
    // Date formatting logic
    output("{formattedDate}")
}
function validateInput(text input): boolean {
    // Validation logic
    output("{isValid}")
}
Testing Your Migrated Shortcut
After refactoring, it’s crucial to test that your shortcut still works correctly.
Step 1: Compile
cherri my-shortcut.cherri
Fix any compilation errors.
Step 2: Compare Actions
If you want to compare the actions:
Before: Note the actions in your original Shortcut
After: Compile with debug mode to output a plist file for comparison with the original plist file.
cherri my-shortcut.cherri --debug
Step 3: Test on Device
Transfer the compiled Shortcut to your device and test all functionality:
- ✅ Test with valid inputs
 - ✅ Test with edge cases (empty values, large numbers, etc.)
 - ✅ Test all conditional branches
 - ✅ Test all menu options
 - ✅ Compare output with original Shortcut
 
Step 4: Debug Issues
If something doesn’t work:
- Compare outputs: Run both Shortcuts with the same input and compare results
 - Add debug statements: Insert 
show("{variable}")to inspect values - Check the .plist: Compile with 
--debugor-dand inspect the generated.plist - Review raw actions: Ensure raw action parameters match the original
 
Advanced Migration Techniques
Handling Third-Party Actions
If your shortcut uses third-party app actions not in Cherri’s standard library, you have two options:
Option 1: Keep as Raw Action
const content = "My note"
// Third-party action for "Bear" app
rawAction("net.shinyfrog.bear.create-note", {
    "title": "My Note",
    "text": "{content}"
})
Option 2: Define Custom Action
// Define once, reuse many times
action 'net.shinyfrog.bear.create-note' createBearNote(
    text title: 'title',
    text content: 'text'
)
// Use it
const content = "My note"
createBearNote("My Note", "{content}")
See Action Definitions for more details.
Optimizing Memory Usage
During migration, you can optimize for runtime memory:
Before:
@temp1 = heavyAction()
@temp2 = anotherAction()
// temp1 is never used again but stays in memory
After:
const temp1 = heavyAction()
nothing()  // Clear output
@temp2 = anotherAction()
Or better yet, only make variables you actually need:
const result = heavyAction()
// Use result where needed
or add nothing() after to make sure output is not loaded into memory if never used.
heavyAction()
// Output is never used, so we clear it.
nothing()
Troubleshooting Migration Issues
Issue: Raw Actions for Standard Actions
Problem: After decompiling, a standard Shortcuts action appears as rawAction(...) instead of its Cherri equivalent.
Solution: This is rare but can happen if the action is missing from Cherri’s standard library. You can either define it as a custom action using action definitions or keep it as a raw action. Consider reporting it as an issue on GitHub.
Issue: Variables Not Working
Problem: Variables from the original Shortcut don’t work in Cherri code.
Solution: Ensure you’re using @variable for mutable variables and const for constants. Check variable names for typos.
Issue: Control Flow Broken
Problem: If/else or loops don’t work as expected.
Solution: Review the control flow structure. Cherri’s syntax differs slightly from Shortcuts’ visual representation. See Control Flow documentation.
Issue: Type Errors
Problem: Compilation fails with type mismatch errors.
Solution: Add explicit type annotations or check that action inputs match expected types:
@myVar: text  // Explicitly declare type
Issue: Shortcut Won’t Import on Device
Problem: The compiled Shortcut won’t import into the Shortcuts app.
Solution: Ensure it’s signed. On non-macOS platforms, use --hubsign:
cherri my-shortcut.cherri --hubsign
Migration Best Practices
- Start with Simple Shortcuts - Migrate simple Shortcuts first to learn the patterns
 - Keep the Original - Don’t delete your original Shortcut until you’ve fully tested the migrated version
 - Migrate Incrementally - For large Shortcuts, migrate section by section
 - Document Changes - Add comments explaining non-obvious refactorings
 - Use Version Control - Commit after each refactoring step so you can revert if needed
 - Test Thoroughly - Test all code paths and edge cases
 - Refactor Gradually - First make it work (decompiled code), then make it better (refactored)
 - Learn the Standard Library - Familiarize yourself with available actions to avoid raw actions
 
When NOT to Decompile
Consider simply rewriting your Shortcuts in Cherri instead if:
- The shortcut is very simple (fewer than 30 actions)
 - It uses third-party actions not in Cherri that will need to be replaced in a decompilation.
 
Resources
- Decompilation Documentation - Technical details on the decompilation process
 - Standard Library Reference - All available actions
 - Action Definitions - Define your own actions
 - Best Practices - Writing efficient Cherri code
 
Ready to migrate? Start with a simple Shortcut, follow the refactoring checklist, and gradually work your way up to more complex migrations.
If you need help, check the FAQ or open an issue on GitHub. Happy migrating! 🍒