AppleScript Runtime
macOS app automation for Notes, Mail, Safari, and Finder via NSAppleScript and osascript.
On this page (6 sections)
The AppleScript action runtime (AppleScriptAction) allows OpenClip to automate macOS system applications (such as Safari, Finder, Mail, Notes, and Messages).
Execution Architecture#
Selection Context ---> AppleScriptAction.perform(_:)
|
v
AppleScriptRunner (osascript subprocess)
| ShellProcessRunner.run (watchdog only when a timeout is set)
v
ActionResult (.text / .success / .failure)- Environment Setup: The selected text string is sanitized by escaping double quotes (
"$\rightarrow$\"). - Variable Injection: OpenClip prepends top-level
propertydeclarations to the script before execution:
property OPENCLIP_TEXT : "<escaped_selected_text>"
property OPENCLIP_HTML : "<escaped_selected_html>"
property OPENCLIP_RTF : "<escaped_selected_rtf>"- Subprocess Execution: The script runs as an
/usr/bin/osascriptsubprocess throughAppleScriptRunner, which delegates to the sharedShellProcessRunner(the same runner used by shell actions, with instant cancellation support).
Why a subprocess (bounded off-main strategy)#
In-process NSAppleScript.executeAndReturnError() blocks the calling thread until the target
application answers over Apple Events — it cannot be cancelled, has no timeout, and a hung
tell application permanently parks a cooperative-pool thread. NSAppleScript is also not
thread-safe across instances. Running each script as a killable subprocess keeps the
cooperative-thread pool free, and a stuck script never wedges a thread forever: callers that want a
bound pass an explicit timeout that arms the subprocess watchdog, and without one the script runs
until it exits or the user cancels the loading toast.
AppleScriptAction and custom AppleScript actions route through the shared subprocess runner.
The deadline-capped AX inspect in SelectionRetrievalCoordinator uses OnceResume to guarantee
exactly-once continuation resume between the worker and the deadline. Web selection itself runs
directly over native Accessibility APIs without touching AppleScript.
Example AppleScript Snippets#
Example 1: Create New Note in macOS Notes App#
tell application "Notes"
activate
make new note at folder "Notes" with data OPENCLIP_TEXT
end tellExample 2: Transform Selected Text to Uppercase#
use framework "Foundation"
use scripting additions
set currentText to NSString's stringWithString:OPENCLIP_TEXT
set upperText to currentText's uppercaseString()
return (upperText as text)Return Values & Side Effects#
AppleScriptAction reads the script's stdout (the value osascript prints for the last statement):
- String Return Value: If the script returns a non-empty string value,
AppleScriptActionreturnsActionResult.text(str)— implicitly returned text, delivered per the user's per-click preference (preview/paste/copy; a secondary click derives copy via delivery). - No Return Value (empty): If the script executes without returning text, it returns
ActionResult.success. - Error Handling: On a non-zero subprocess exit (the AppleScript error text goes to stderr), the runtime returns
ActionResult.failure(error)with the error message. - Timeout: Only when the invocation carries an explicit budget. Past it the watchdog terminates
osascript, the process group when it is the leader, and remaining descendants. Execution surfaces as a timeout failure. With no budget (the default) there is no watchdog; the subprocess runs until it exits or the loading toast cancels it.