
MacOS Shortcuts can reach work shell scripts cannot touch directly: PDF export, image processing through system frameworks, URL-scheme calls, and cross-app automation. Apple's shortcuts tool makes any of those shortcuts callable from a script, a CI step, or a launchd job. This page shows how to pick a hosted Mac plan for the job, pin an input/output contract per shortcut, and verify every run with an exit-status test before scheduling it.
Start on Figment's $29/month virtual Intel macOS environment (2 vCPU, 8 GiB RAM, 80 GiB disk) if your Shortcut only needs standard Intel-compatible actions: text handling, file transformation, PDF export, URL-scheme calls, and macOS framework actions all run there. Access is through the browser console; outbound network to your own services works, and you can drive shortcuts run from the desktop terminal.
Move to an M-series Mac (from $95/month, request-based) when the Shortcut:
The $29 VM is a real macOS environment, not a jump host — shortcuts run executes locally on it. It just will not execute ARM-only code. Confirm the exact chip, RAM, and disk for the M-series plan in the quote; stock on physical hardware is confirmed per order.
shortcuts CLI, verified against Apple's referenceApple documents the tool in Run shortcuts from the command line. The operations relevant to automation:
| Command | Purpose |
|---|---|
shortcuts run "Name" | Execute a shortcut by name |
shortcuts run "Name" -i /path/to/file | Pass one or more file paths as input |
shortcuts run "Name" -o /path/to/output | Write output to a file |
shortcuts run "Name" --output-type public.pdf | Pin the output format with a UTI |
shortcuts list | List installed shortcuts |
shortcuts list --folders | List shortcut folders |
shortcuts list -f FolderName | List shortcuts in a folder |
shortcuts view "Name" | Open the shortcut in the editor |
shortcuts sign --mode people-who-know-me --input in.shortcut --output out.shortcut | Sign a shortcut for sharing |
Exit code 0 means success; 1 means an action in the shortcut failed. Piping data into shortcuts run treats it as text input; use -i when you need the shortcut to receive file references. Check shortcuts --help on your installed macOS version to confirm current flags.
The common failure mode for scripted Shortcuts is assuming the shortcut handles inputs and errors the way it does when a human taps Run. Fill this in once per shortcut you plan to schedule:
| Field | Your shortcut's value |
|---|---|
| Shortcut name | Exact name as shown in Shortcuts.app |
| Input type | File path / text / none |
| Input format | e.g. .jpg, .txt, no input |
| Output type | File / stdout text / none |
| Output format | e.g. public.pdf, public.plain-text |
| Minimum output size | Bytes or character count you consider valid |
| Side effects | Files written, URLs opened, emails sent |
| Needs user session | Yes for UI-touching actions, otherwise no |
The last row matters most on a hosted Mac. The browser console gives you a logged-in session, so UI-touching actions work interactively, but a launchd daemon at system level is headless. Schedule UI-touching shortcuts as LaunchAgents that run in the user session, not as LaunchDaemons.
Run this once before wiring any shortcut into launchd or CI. It checks the exit code and the output size against the contract.
#!/usr/bin/env bash
# test-shortcut.sh — verify a shortcut's input/output contract
# Usage: ./test-shortcut.sh "My Shortcut" /path/to/input /tmp/out.pdf 1000
set -euo pipefail
SHORTCUT="${1:?name required}"
INPUT="${2:-}"
OUTPUT="${3:-}"
MIN_BYTES="${4:-1000}"
LOG=$(mktemp -t shortcut-test.XXXXXX)
echo "Testing: $SHORTCUT" | tee "$LOG"
CMD=(shortcuts run "$SHORTCUT")
[[ -n "$INPUT" ]] && CMD+=(-i "$INPUT")
[[ -n "$OUTPUT" ]] && CMD+=(-o "$OUTPUT")
if ! "${CMD[@]}" >>"$LOG" 2>&1; then
echo "FAIL: shortcuts run exited non-zero. See $LOG and Console.app." >&2
exit 1
fi
if [[ -n "$OUTPUT" ]]; then
[[ -f "$OUTPUT" ]] || { echo "FAIL: expected $OUTPUT not created" >&2; exit 1; }
BYTES=$(wc -c < "$OUTPUT" | tr -d ' ')
if (( BYTES < MIN_BYTES )); then
echo "FAIL: output $BYTES bytes, expected >= $MIN_BYTES" >&2
exit 1
fi
echo "PASS: $OUTPUT ($BYTES bytes)"
else
echo "PASS: no output file expected"
fi
This is an example, not a benchmark. Run it on your own input and tune MIN_BYTES to whatever "clearly not empty" means for the shortcut.
Once the contract test passes, put the plist at ~/Library/LaunchAgents/com.example.my-shortcut.plist so it runs in your user session:
<?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>Label</key><string>com.example.my-shortcut</string>
<key>ProgramArguments</key>
<array>
<string>/usr/bin/shortcuts</string>
<string>run</string>
<string>My Shortcut Name</string>
<string>-i</string><string>/Users/agent/inputs/source.jpg</string>
<string>-o</string><string>/Users/agent/outputs/result.pdf</string>
</array>
<key>StartCalendarInterval</key>
<dict>
<key>Hour</key><integer>6</integer>
<key>Minute</key><integer>30</integer>
</dict>
<key>StandardOutPath</key><string>/Users/agent/Library/Logs/my-shortcut.log</string>
<key>StandardErrorPath</key><string>/Users/agent/Library/Logs/my-shortcut-err.log</string>
</dict>
</plist>
Load it with launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.example.my-shortcut.plist. Each <string> in ProgramArguments is one argv entry, so a shortcut name with spaces needs no shell escaping — see Apple's Creating Launch Daemons and Agents. Confirm the binary path on your Mac with which shortcuts before pinning /usr/bin/shortcuts.
| Symptom | Likely cause | Fix |
|---|---|---|
| Exit 1, no output | A shortcut action errored | Open Console.app, filter shortcuts, find the action error |
| Exit 1, "not found" | Name mismatch or shortcut removed | Run shortcuts list and match the exact name |
| Exit 0, no output file | Shortcut has no save-file action | Add "Save File", or drop -o from the contract |
| Output exists but empty | Action produced no data | Re-run with the real input; check the shortcut's expected input UTI |
| Works interactively, fails under launchd | Action needs the user session | Use a LaunchAgent, not a LaunchDaemon |
For a specific action failure, drive the shortcut once from the browser-console terminal with Console.app open. The system log shows action-level detail the CLI exit code does not.
The $29 VM runs on shared Linux/KVM infrastructure, with no GPU acceleration and no audio pipeline, so image-processing shortcuts that rely on GPU encoders will be CPU-bound. If a scheduled shortcut uses several seconds of CPU and you plan to run it often, watch top from the terminal before adding more concurrent jobs. For GPU work, ARM-only code, or heavier parallelism, move the workload to an M-series plan and confirm the exact hardware in the quote.
New setup: open Mac hosting, pick the plan that matches your shortcut's requirements, connect through the browser console, build and import the shortcut in Shortcuts.app, run the contract test, write the plist, and bootstrap it.
Migration: export each shortcut from Shortcuts.app (File → Export, or shortcuts sign for a distributable file), import on the new Mac, re-run the contract test with the same inputs, and load the plist.
Related guides