Skip to content

applescript-forge

Use when generating, validating, or testing AppleScript/JXA scripts from natural language descriptions. Also use when looking up app dictionaries or creating macos-automator KB-compatible scripts with placeholders.

ModelSource
sonnetpack: macos-automation
Full Reference

Script generation utility for macOS automation. Translates natural language into working AppleScript or JXA scripts with proper error handling, app targeting, and optional macos-automator KB compatibility.

Mandatory Announcement — FIRST OUTPUT before anything else:

┏━ 🔧 applescript-forge ━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ [one-line description of script being forged] ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛

No exceptions. Box frame first, then work.

  1. Parse intent — identify target app(s) + desired action(s)
  2. Check KB — search macos-automator knowledge base for similar existing scripts (get_scripting_tips with relevant search terms)
  3. Load references — read applescript-reference docs for target app patterns
  4. Choose language — AppleScript vs JXA based on task requirements (see Language Selection Guide)
  5. Generate script — with error handling, timeouts, cleanup
  6. Validate — syntax check via osascript -e 'tell application "System Events" to return ""' pattern
  7. Present — script with explanation + usage instructions
Use AppleScript whenUse JXA when
Automating apps via dictionariesJSON data handling
Showing user dialogs (display dialog, choose file)ObjC bridge needed ($.NS* classes)
Simple one-off automationHTTP requests
Team is familiar with AppleScriptComplex data structures (arrays, objects)
Script Editor debuggingRegex needed
String-heavy operations with text item delimitersFile I/O with binary data

Default: AppleScript — broader app support, simpler syntax for common tasks.

-- [Description of what this script does]
-- Usage: osascript script.applescript [args]
on run argv
try
-- Main logic here
tell application "TargetApp"
-- App-specific commands
end tell
on error errMsg number errNum
if errNum is -128 then
-- User cancelled
return "Cancelled"
end if
error "Script failed: " & errMsg & " (" & errNum & ")"
end try
end run
// [Description of what this script does]
// Usage: osascript -l JavaScript script.js [args]
function run(argv) {
const app = Application.currentApplication();
app.includeStandardAdditions = true;
try {
const target = Application("TargetApp");
// App-specific logic
} catch (e) {
if (e.errorNumber === -128) return "Cancelled";
throw new Error(`Script failed: ${e.message} (${e.errorNumber})`);
}
}
-- Retry pattern (for flaky operations like UI scripting)
set maxRetries to 3
repeat with attempt from 1 to maxRetries
try
-- Operation that might fail
exit repeat
on error errMsg
if attempt = maxRetries then error errMsg
delay 0.5
end try
end repeat
-- Timeout pattern
with timeout of 30 seconds
tell application "Slow App"
-- Long operation
end tell
end timeout

When creating scripts that should be added to the macos-automator knowledge base:

---
id: category_NNN
title: Short descriptive title
keywords: [keyword1, keyword2, keyword3]
category: category_name
description: What this script does in one line
---

Categories: intro, as_core, jxa_core, system, files, terminal, browsers, editors, productivity, creative, advanced, network, developer

For KB scripts that accept dynamic input, use macos-automator placeholders:

-- AppleScript placeholder syntax
set userName to "--MCP_INPUT:userName"
set filePath to "--MCP_INPUT:filePath"
set targetApp to "--MCP_ARG_1"
// JXA placeholder syntax
const userName = "${inputData.userName}";
const filePath = "${inputData.filePath}";
const targetApp = "${arguments[0]}";

Placeholder rules:

  • camelCase in placeholder → snake_case in input_data API key
  • --MCP_INPUT:firstName looks up first_name in input_data
  • --MCP_ARG_N is 1-indexed (matches positional arguments)

Before presenting a generated script:

  • Error handling present (try/on error)
  • Timeout set for app-targeting operations
  • Proper cleanup (restore text item delimiters, close file handles)
  • App name verified (bundle ID fallback for non-standard names)
  • Permissions noted (which macOS permissions the script needs)
  • Edge cases considered (app not running, file not found, empty input)

GOTCHA [runtime-crash]: as alias throws error -43 if file doesn’t exist. Use POSIX file for paths to files that may not exist yet.

GOTCHA [silent-bug]: set listB to listA creates a REFERENCE, not a copy. Changes to listB affect listA. Use copy for independent copies.

GOTCHA [dx-trap]: Text item delimiters are GLOBAL state. Always save and restore: set oldDelims to AppleScript's text item delimitersset AppleScript's text item delimiters to oldDelims.

GOTCHA [runtime-crash]: JXA ObjC bridge calls fail with macos-automator’s default output format. Set output_format_mode: 'direct' when running JXA with $.NS* classes.

GOTCHA [dx-trap]: AppleScript lists are 1-indexed. item 0 throws an error. Always start loops with from 1.

NeedUse
Language patternsLoad applescript-reference (applescript-core.md or jxa.md)
App-specific patternsLoad applescript-reference (app-dictionaries.md)
Similar existing scriptsSearch macos-automator KB (get_scripting_tips)
Run the generated scriptUse macos-automator (execute_script) or applescript-mcp
Multi-step workflowHand off to macos-workflow