Turn Claude Code into a full-stack macOS/iOS Shortcuts author. This plugin bundles a comprehensive Shortcuts knowledge base, a specialized build agent, automatic plist validation on every write, and wrapper commands that handle icon selection, validation, and the archive-and-sign pipeline.
Ask Claude to build a shortcut. Get back a signed .shortcut you can import.
Writing valid Shortcuts plists by hand — even with an LLM — is miserable. The XML format is under-documented, action identifiers change between OS releases, variable wiring breaks in silent ways, and half the rules you need are only documented in Apple's ToolKit binaries. The standalone shortcuts-generator skill that this plugin grew out of fixed most of that, but it only ran on the author's machine because every path was hardcoded.
shortcuts-playground packages the same knowledge base as a distributable Claude Code plugin. The model-only workflow becomes a model + agent + hook + bin workflow. The Craig Loop (validate → fix → revalidate) happens automatically via a PostToolUse hook. The bin/ wrappers work from any directory. The archive path is configurable per user.
| Component | Path | Purpose |
|---|---|---|
| Skill | skills/shortcuts-playground/ |
The complete Shortcuts knowledge base: action identifiers, wiring rules, curated BEST_PRACTICES.md guidance, golden example XMLs, ToolKit v63 and target-gated macOS/iOS 27 v78 ID snapshots, plus reviewed static Apple-derived macOS 27 grounding, parameter-key, enum-case, trigger metadata, and exported WFWorkflowTriggers samples for all 42 ToolKit trigger variants. Current Mac-specific External Drive, File Modified, and Folder Changed exports are documented as lossy picker carriers rather than copyable automation headers. Claude loads it automatically when you ask for a shortcut. |
| Build agent | agents/shortcut-builder.md |
shortcut-builder — specialized agent that owns the full design → build → validate → sign → archive loop for new shortcuts. |
| Remix agent | agents/shortcut-remixer.md |
shortcut-remixer — specialized agent that applies a surgical natural-language diff to an existing unsigned XML shortcut. Preserves UUIDs, icon, metadata, and every action the user didn't ask to touch. |
| Hook | hooks/hooks.json + hooks/auto-validate.sh |
PostToolUse hook that runs the Craig Loop validator on every Write/Edit producing a Shortcuts plist — applies to BOTH agents. Exit code 2 + stderr feeds validator output back into Claude's context so the model can iterate. |
| CLI | bin/validate-shortcut, bin/resolve-icon, bin/sign-shortcut, bin/shortcuts-playground-selftest |
Bare commands added to Claude's Bash PATH whenever the plugin is enabled. Work from any working directory. |
| Slash commands | commands/build.md, commands/remix.md |
/shortcuts-playground:build <brief> — create from scratch. /shortcuts-playground:remix <path> <idea> — diff an existing unsigned .xml file. |
| User config | plugin.json → userConfig |
output_dir (archive root), signing_mode (anyone or people-who-know-me), target_macos (auto, 26, 27, or latest), and target_platform (macos, ios, or all). See Configuration for how to set these. |
- macOS with the built-in
shortcutsCLI (signing only works on macOS). - Claude Code recent enough to support plugins (
/plugincommand). - Python 3.10+. The validator uses PEP 604 union syntax (
int | None) which requires 3.10 or later./usr/bin/python3on older macOS ships Python 3.9.6 and will fail — install Python 3.10+ via Homebrew (brew install python3) or python.org, or point the plugin at a specific interpreter withSHORTCUTS_PLAYGROUND_PYTHON=/opt/homebrew/bin/python3. Theshortcuts-playground-selftestcommand (below) will tell you immediately if your interpreter is too old.
This repository contains both Claude and Codex packages. The Claude Code plugin lives in claude/, and the repository root includes a Claude marketplace that points to that folder. Three install options, ordered from quickest to most-durable:
claude --plugin-dir /path/to/shortcuts-playground-plugin/claudeInside the session, ask for a shortcut or run /shortcuts-playground:build <brief>. Run /reload-plugins after source edits. The plugin only exists for the life of that session.
Create a separate marketplace directory that references this repository via a symlink. The marketplace is its own git repo and points at ./shortcuts-playground-plugin, whose root .claude-plugin/marketplace.json installs the Claude plugin from ./claude:
mkdir -p ~/Projects/shortcuts-playground-dev-marketplace/.claude-plugin
cd ~/Projects/shortcuts-playground-dev-marketplace
# Symlink the plugin into the marketplace directory
ln -s /path/to/shortcuts-playground-plugin shortcuts-playground-plugin
# Write marketplace.json
cat > .claude-plugin/marketplace.json <<'JSON'
{
"name": "shortcuts-playground-dev",
"owner": { "name": "Your Name" },
"metadata": {
"description": "Local dev marketplace for the Shortcuts Playground plugin.",
"version": "1.0.0"
},
"plugins": [
{ "source": "./shortcuts-playground-plugin/claude" }
]
}
JSON
# Register + install
claude plugin marketplace add ~/Projects/shortcuts-playground-dev-marketplace
claude plugin install shortcuts-playground@shortcuts-playground-devSource edits propagate through the symlink — Claude Code reads files in-place for directory-sourced marketplaces, so iteration is instant. Run claude plugin update shortcuts-playground@shortcuts-playground-dev only when you want the cache to resync (e.g., after a version bump).
Once a marketplace referencing this plugin is published (e.g., as a separate git repo):
claude plugin marketplace add https://github.com/<owner>/<marketplace-repo>
claude plugin install shortcuts-playground@<marketplace-name>Installation scopes (for either Option B or C):
--scope user(default): install for your user, available across every project.--scope project: install for the current project (shared with teammates via.claude/settings.json).--scope local: install for the current project only, gitignored.
After install, run the health check below to confirm everything's wired up.
python3 --version # expect 3.10+
which shortcuts # expect /usr/bin/shortcuts
claude plugin list | grep shortcuts-playground # expect "✔ enabled"
shortcuts-playground-selftest # expect "✔ All checks passed."shortcuts-playground-selftest is a bundled bin command that runs six checks in order: Python version, shortcuts CLI presence, plugin-root resolution, bundled data files, validator-on-golden, and a full archive + sign round trip to a temporary directory. It exits 0 on pass and prints a specific error message for every failure. Run it once after install and any time you update the plugin.
For CI environments without the macOS shortcuts CLI, set SHORTCUTS_PLAYGROUND_SELFTEST_SKIP_SIGN=1 to skip the sign round trip and only run the validator checks.
The plugin exposes four userConfig values in plugin.json:
| Key | Type | Default | Purpose |
|---|---|---|---|
output_dir |
directory |
~/Documents/Shortcuts Playground |
Root directory where unsigned XML archives and signed .shortcut files are written. |
signing_mode |
string |
anyone |
Passed to shortcuts sign. Use anyone for public distribution or people-who-know-me for contacts only. |
target_macos |
string |
auto |
Validator OS availability target. Use auto for host detection, 27 for OS 27-era shortcuts that need v78 snapshots, or latest to include every packaged OS snapshot. If the host cannot be detected, auto falls back to macOS 26. |
target_platform |
string |
macos |
Validator platform availability target. Use macos for Mac shortcuts, ios for iPhone/iPad-only authoring, or all only for cross-platform metadata audits. |
You can set these in three ways, from most to least explicit:
- Interactive plugin TUI. Inside a live Claude Code session, run
/pluginand pickshortcuts-playground. If prompts are available in your Claude Code build, they'll appear here. settings.json. Edit~/.claude/settings.jsondirectly. Non-sensitive values live underpluginConfigs:Claude Code substitutes non-sensitive values into plugin skill/agent content as{ "pluginConfigs": { "shortcuts-playground@shortcuts-playground": { "options": { "output_dir": "/Users/you/Documents/Shortcuts Playground", "signing_mode": "anyone", "target_macos": "auto", "target_platform": "macos" } } } }${user_config.<key>}and exports each value asCLAUDE_PLUGIN_OPTION_<KEY_UPPERCASED>(e.g.CLAUDE_PLUGIN_OPTION_OUTPUT_DIR) for plugin subprocesses. The bundled agents resolve${user_config.output_dir}first and pass the resulting path tosign-shortcut --output-dir, so this setting controls both draft and signed output paths.target_macosandtarget_platformare read by the validator asCLAUDE_PLUGIN_OPTION_TARGET_MACOSandCLAUDE_PLUGIN_OPTION_TARGET_PLATFORM.- Environment variable override. If both above fail, you can always set the env var directly for a one-off build:
Or pass
CLAUDE_PLUGIN_OPTION_OUTPUT_DIR=/custom/dir sign-shortcut draft.xml --name "My Shortcut"--output-dir/--modeflags directly tosign-shortcutto bypass config entirely.
If none of these are set, the plugin falls back to ~/Documents/Shortcuts Playground/, anyone, and auto. Those defaults exist so first-time install just works.
For best results, store output_dir as an absolute path such as /Users/you/Developer/Shortcuts. The agents also expand leading ~/ and literal $HOME/ values, but absolute paths avoid ambiguity across shells and plugin subprocesses.
Two workflows, two commands: build (from scratch) and remix (diff an existing XML).
Natural language (auto-invocation). Just describe what you want:
Build me a shortcut that asks for a city, fetches the current weather, and shows a notification.
Claude's skill auto-invocation picks up the Shortcuts intent and delegates to the shortcut-builder agent.
Explicit slash command. For a deterministic entry point:
/shortcuts-playground:build weather lookup that asks for a city and shows a notification
Everything after :build becomes the brief passed to the agent. Useful when you want to make sure the agent is invoked (for example, inside a long conversation where Claude might not auto-route).
Either path does the same thing — the shortcut-builder agent:
- Reads the skill's
SKILL.mdand the relevant reference files. - Designs the action list and picks UUIDs.
- Runs
resolve-icon --prompt "<your request>"to choose a glyph + color. - Writes the plist XML to your
output_dir/drafts/folder. - The
PostToolUsehook auto-validates the file and feeds any errors back. - The agent edits until the validator passes (max 5 fix iterations).
- Runs
sign-shortcutto archive the unsigned XML and produce a signed.shortcut. - Returns the paths so you can open the signed file in Shortcuts.app.
When you already have a shortcut and want to apply small changes, use /shortcuts-playground:remix. Pass an absolute path to an unsigned .xml file (NOT a signed .shortcut — those are AEA1 encrypted archives) plus a natural-language description of what to change:
/shortcuts-playground:remix /Users/you/Documents/Shortcuts Playground/drafts/Weather.xml add a notification at the start saying "Fetching weather"
The shortcut-remixer agent:
- Parses the command input into a source path + a remix idea.
- Validates the source (exists,
.xmlnot.shortcut, first bytes aren'tAEA1, containsWFWorkflowActions). If any check fails, it escalates with a specific reason — it never guesses. - Reads the full source and baselines it against the validator (pre-existing issues in the source are informational, not fixed unless they block signing).
- Loads relevant skill reference files for the diff you asked for.
- Plans a surgical diff: which actions to add, modify, or remove. Preserves every other action verbatim. Preserves UUIDs,
WFWorkflowIcon, client-version fields, andWFWorkflowName(unless you explicitly renamed it). - Writes the draft to
output_dir/drafts/<source stem> Remix.xml(or your explicit name). - Runs the Craig Loop via the same
PostToolUsehook that the builder uses. - Archives + signs via
sign-shortcut, then verifies the signed file exists. - Reports: signed path, archive path, source path, and a one-paragraph diff summary of what changed.
Key remix rules:
- The source is never overwritten. The remix writes to a new name so your original stays intact.
- Signed
.shortcutfiles cannot be remixed directly — export them as unsigned XML first (Shortcuts.app → Share → Copy → paste into a.xmlfile). - If you don't provide an absolute path, the agent immediately escalates with instructions on how to provide one. It doesn't search your filesystem for "a shortcut that looks like" your intent.
- The remix output carries the "Shortcuts generated by Shortcuts Playground" disclaimer Comment in its leading actions — your source's existing top-level comments are preserved below.
When you want to invoke a single step yourself:
# Validate an existing .xml or .shortcut
validate-shortcut /path/to/MyShortcut.xml
# Resolve an icon + color from free-text
resolve-icon --prompt "a calendar shortcut that pulls today's meetings"
# Archive + sign in one step
sign-shortcut /path/to/MyShortcut.xml --name "My Shortcut"
# End-to-end post-install self test
shortcuts-playground-selftestshortcuts-playground-plugin/
├── .claude-plugin/
│ └── plugin.json # Claude plugin manifest (name, version, userConfig)
├── skills/
│ └── shortcuts-playground/ # complete Shortcuts knowledge base
│ ├── SKILL.md
│ ├── BEST_PRACTICES.md
│ ├── ACTIONS.md
│ ├── APPINTENTS.md
│ ├── PARAMETER_TYPES.md
│ ├── ... # reference markdown files
│ ├── data/ # ToolKit ID snapshots + glyph/color JSON
│ ├── golden-shortcuts/ # 19 curated example XMLs
│ └── scripts/ # Python implementations
├── agents/
│ ├── shortcut-builder.md # build-from-scratch agent
│ └── shortcut-remixer.md # diff-an-existing-XML agent
├── commands/
│ ├── build.md # /shortcuts-playground:build slash command
│ └── remix.md # /shortcuts-playground:remix slash command
├── hooks/
│ ├── hooks.json # PostToolUse config
│ └── auto-validate.sh # Craig Loop hook runner
├── bin/
│ ├── validate-shortcut
│ ├── resolve-icon
│ ├── sign-shortcut
│ └── shortcuts-playground-selftest
├── CHANGELOG.md
├── LICENSE # MIT
└── README.md
This matters when you're iterating on the source:
- Directory-sourced marketplaces (added via
claude plugin marketplace add /local/path) read plugin files directly from the source directory. Edits tohooks/auto-validate.sh,agents/shortcut-builder.md,bin/*,commands/build.md, or anything underskills/propagate immediately to the next session — noclaude plugin updateneeded. Verified by tracing hook execution paths. - Git-sourced marketplaces (added via
claude plugin marketplace add https://github.com/owner/repo) copy the plugin to~/.claude/plugins/cache/<marketplace>/<plugin>/<version>/at install time and read from there. After pushing a source change to the git remote, runclaude plugin update shortcuts-playgroundto sync the cache.
Both variants expose ${CLAUDE_PLUGIN_ROOT} as the absolute path to whichever location Claude Code is reading from. All bundled commands and hooks use that variable (with a self-resolution fallback) so source-directory and cache installs behave identically from the script's point of view.
# 1. Edit source files under ~/Projects/shortcuts-playground-plugin/claude/
# 2. Re-run the self test to catch regressions
shortcuts-playground-selftest
# 3. Re-run manifest validation
claude plugin validate ~/Projects/shortcuts-playground-plugin/claude
# 4. Run a real build in a headless Claude session
claude -p --dangerously-skip-permissions "/shortcuts-playground:build a test shortcut that shows the current date"Inside an interactive Claude Code session, use /reload-plugins after each change to pick up edits without restarting the session.
Run these when touching validator logic, wiring rules, or action coverage:
python3 skills/shortcuts-playground/scripts/test_wiring_regressions.py --write-fixtures /tmp/wiring-regressions
python3 skills/shortcuts-playground/scripts/test_random_mixed_shortcuts.py --count 20 --min-actions 10The first covers 40 Weather Detail cases, 40 Location parameter cases, and 12 Set Name cases. The second generates random multi-action shortcuts and runs the validator against each.
- Built at MacStories, with Claude.
- Grew out of the standalone
shortcuts-generatorClaude Code skill, which bundles action identifiers, validator heuristics, and wiring rules derived from Apple's ToolKit snapshots.
MIT.