Automating macOS Apps (Apple Events, AppleScript, JXA)
Technology Status
JXA and AppleScript are legacy (last major updates: 2015-2016). Modern alternatives:
- PyXA: Active Python automation (see installation below)
- Shortcuts App: Visual workflow builder
- Swift/Objective-C: Production-ready automation
macOS Sequoia 15 Notes
Test scripts on target macOS due to:
- Stricter TCC permissions
- Enhanced Apple Events security
- Sandbox improvements
Core framing (use this mental model)
- Apple Events: The underlying inter-process communication (IPC) transport for macOS automation.
- AppleScript: The original DSL (Domain-Specific Language) for Apple Events: best for discovery, dictionaries, and quick prototypes.
- JXA (JavaScript for Automation): A JavaScript binding to the Apple Events layer: best for data handling, JSON, and maintainable logic.
- ObjC Bridge: JavaScript access to Objective-C frameworks (Foundation, AppKit) for advanced macOS capabilities beyond app dictionaries.
When to use which
- Use AppleScript for discovery, dictionary exploration, UI scripting, and quick one-offs.
- Use JXA for robust logic, JSON pipelines, integration with Python/Node, and long-lived automation.
- Hybrid pattern (recommended): discover in AppleScript, implement in JXA for production use.
When to use this skill
- Foundation for app-specific skills (Calendar, Notes, Mail, Keynote, Excel, Reminders).
- Run the automation warm-up scripts before first automation to surface macOS permission prompts.
- Use as the base reference for permissions, shell integration, and UI scripting fallbacks.
Workflow (default)
- Identify target app + dictionary using Script Editor.
- Prototype a minimal command that works.
- Example:
tell application "Finder" to get name of first item in desktop
- Decide language using the rules above.
- Harden: add error handling, timeouts, and permission checks.
- JXA:
try { ... } catch (e) { console.log('Error:', e.message); }
- AppleScript:
try ... on error errMsg ... end try
- Validate: run a read-only command and check outputs.
- Example:
osascript -e 'tell application "Finder" to get name of home'
- Confirm: Output matches expected (e.g., user home folder name)
- Integrate via
osascript for CLI or pipeline use.
- UI scripting fallback only when the dictionary is missing/incomplete.
- Example UI Script:
tell application "System Events" to click button 1 of window 1 of process "App"
- Example JXA:
Application('System Events').processes.byName('App').windows[0].buttons[0].click()
Validation Checklist
Automation permission warm-up
- Use before first automation run or after macOS updates to surface prompts:
- All apps at once:
skills/automating-mac-apps/scripts/request_automation_permissions.sh (or .py).
- Per-app:
skills/automating-<app>/scripts/set_up_<app>_automation.{sh,py} (calendar, notes, mail, keynote, excel, reminders).
- Voice Memos (no dictionary):
skills/automating-voice-memos/scripts/set_up_voice_memos_automation.sh to activate app + check data paths; enable Accessibility + consider Full Disk Access.
- Run from the same host you intend to automate with (Terminal vs Python) so the correct app gets Automation approval.
- Each script runs read-only AppleScript calls (list accounts/calendars/folders, etc.) to request Terminal/Python control; click “Allow” when prompted.
Modern Python Alternatives to JXA
PyXA (Python for macOS Automation) - Preferred for new projects:
PyXA Features
- Active development (v0.2.3+), modern Python syntax
- App automation: Safari, Calendar, Reminders, Mail, Music
- UI scripting, clipboard, notifications, AppleScript integration
- Method chaining:
app.lists().reminders().title()
PyXA Installation {#pyxa-installation}
# Install PyXA
pip install mac-pyxa
# Or with pip3 explicitly
pip3 install mac-pyxa
# Requirements:
# - Python 3.10+ (check with: python3 --version)
# - macOS 12+ (Monterey or later recommended)
# - PyObjC is installed automatically as a dependency
# Verify installation
python3 -c "import PyXA; print(f'PyXA {PyXA.__version__} installed successfully')"
Note: All app-specific skills in this plugin that show PyXA examples assume PyXA is installed. See this section for installation.
PyXA Example (Safari Automation)
import PyXA
# Launch Safari and navigate
safari = PyXA.Safari()
safari.activate()
safari.open_location("https://example.com")
# Get current tab URL
current_url = safari.current_tab.url
print(f"Current URL: {current_url}")
PyXA Example (Reminders)
import PyXA
reminders = PyXA.Reminders()
work_list = reminders.lists().by_name("Work")
# Add new reminder
new_reminder = work_list.reminders().push({
"name": "Review PyXA documentation",
"body": "Explore modern macOS automation options"
})
PyXA Official Resources:
PyObjC (Python-Objective-C Bridge) - For Low-Level macOS Integration:
PyObjC Capabilities
- Direct Framework Access: AppKit, Foundation, and all macOS frameworks
- Apple Events: Send Apple Events via Scripting Bridge
- Script Execution: Run AppleScript or JXA from Python
- System APIs: Direct access to CalendarStore, AddressBook, SystemEvents
Installation
pip install pyobjc
# Installs bridges for major frameworks
PyObjC Example (AppleScript Execution)
from Foundation import NSAppleScript
# Execute AppleScript from Python
script_source = '''
tell application "Safari"
return URL of current tab
end tell
'''
script = NSAppleScript.alloc().initWithSource_(script_source)
result, error = script.executeAndReturnError_(None)
if error:
print(f"Error: {error}")
else:
print(f"Current Safari URL: {result.stringValue()}")
PyObjC Example (App Control via Scripting Bridge)
from ScriptingBridge import SBApplication
# Control Mail app
mail = SBApplication.applicationWithBundleIdentifier_("com.apple.Mail")
inbox = mail.inboxes()[0] # Access first inbox
# Get unread message count
unread_count = inbox.unreadCount()
print(f"Unread messages: {unread_count}")
PyObjC Official Resources:
JXA Status
JXA has no updates since 2016. Use PyXA for new projects when possible.
When Not to Use
- Cross-platform automation (use Selenium/Playwright for web)
- Full UI testing (use XCUITest or Appium)
- Environments blocking Automation/Accessibility permissions
- Non-macOS platforms
- Simple shell scripting tasks (use Bash directly)
Related Skills
- App-specific automation (create
automating-[app] skills as needed)
ci-cd-tcc for advanced permission management in automated environments
mastering-applescript for AppleScript-focused workflows
Security Best Practices
Permission Management:
- Request minimal required permissions to reduce security risks
- Use code signing for production scripts (Developer ID certificate)
- Store credentials securely (Keychain, not hardcoded)
- Validate all inputs to prevent injection attacks
Official Apple Security Guidance:
Output expectations
- Keep examples minimal and runnable.
- JSON Output: For CLI pipelines, use
JSON.stringify(result) in JXA.
- Example:
console.log(JSON.stringify({files: files, count: files.length}))
- Exit Codes: Ensure
osascript exits with 0 for success, non-zero for failure.
What to load
Tier 1: Essentials (Start Here)
- JXA Syntax & Patterns:
automating-mac-apps/references/basics.md
- AppleScript Basics:
automating-mac-apps/references/applescript-basics.md
- Cookbook (Common Recipes):
automating-mac-apps/references/recipes.md
Tier 2: Advanced & Production
- JXA Cookbook (Condensed):
automating-mac-apps/references/cookbook.md
- Performance Patterns:
automating-mac-apps/references/applescript-performance.md
- CI/CD & Permissions:
automating-mac-apps/references/ci-cd-tcc.md
- Shell Environment:
automating-mac-apps/references/shell-environment.md
- UI Scripting Inspector:
automating-mac-apps/references/ui-scripting-inspector.md
Tier 3: Specialized & Reference
- PyXA Core API Reference (complete class/method docs):
automating-mac-apps/references/pyxa-core-api-reference.md
- PyXA Basics:
automating-mac-apps/references/pyxa-basics.md (Modern Python automation fundamentals)
- AppleScript → PyXA Conversion:
automating-mac-apps/references/applescript-to-pyxa-conversion.md (Migration guide with examples)
- Translation Checklist (AppleScript → JXA):
automating-mac-apps/references/translation-checklist.md (Comprehensive guide with examples and pitfalls)
- JXA Helpers Library:
automating-mac-apps/references/helpers.js
whose Batching Patterns: automating-mac-apps/references/whos-batching.md
- Dictionary Strategies:
automating-mac-apps/references/dictionary-strategies.md
- ASObjC Helpers:
automating-mac-apps/references/applescript-asobjc.md
Related Skills:
web-browser-automation: Complete browser automation guide (Chrome, Edge, Brave, Arc)
1---2name: automating-mac-apps3description: Automates macOS apps via Apple Events using AppleScript (discovery), JXA (legacy), and PyXA (modern Python). Use when asked to "automate Mac apps", "write AppleScript", "JXA scripting", "osascript automation", or "PyXA Python automation". Foundation skill for all macOS app automation.4---5
6# Automating macOS Apps (Apple Events, AppleScript, JXA)
7
8## Technology Status
9
10JXA and AppleScript are legacy (last major updates: 2015-2016). Modern alternatives:
11- **PyXA**: Active Python automation (see installation below)
12- **Shortcuts App**: Visual workflow builder
13- **Swift/Objective-C**: Production-ready automation
14
15## macOS Sequoia 15 Notes
16
17Test scripts on target macOS due to:
18- Stricter TCC permissions
19- Enhanced Apple Events security
20- Sandbox improvements
21
22## Core framing (use this mental model)
23- **Apple Events**: The underlying inter-process communication (IPC) transport for macOS automation.
24- **AppleScript**: The original DSL (Domain-Specific Language) for Apple Events: best for discovery, dictionaries, and quick prototypes.
25- **JXA (JavaScript for Automation)**: A JavaScript binding to the Apple Events layer: best for data handling, JSON, and maintainable logic.
26- **ObjC Bridge**: JavaScript access to Objective-C frameworks (Foundation, AppKit) for advanced macOS capabilities beyond app dictionaries.
27
28## When to use which
29- Use **AppleScript** for discovery, dictionary exploration, UI scripting, and quick one-offs.
30- Use **JXA** for robust logic, JSON pipelines, integration with Python/Node, and long-lived automation.
31- Hybrid pattern (recommended): discover in AppleScript, implement in JXA for production use.
32
33## When to use this skill
34- Foundation for app-specific skills (Calendar, Notes, Mail, Keynote, Excel, Reminders).
35- Run the automation warm-up scripts before first automation to surface macOS permission prompts.
36- Use as the base reference for permissions, shell integration, and UI scripting fallbacks.
37
38## Workflow (default)
391) **Identify target app + dictionary** using Script Editor.
402) **Prototype** a minimal command that works.
41 - *Example*: `tell application "Finder" to get name of first item in desktop`
423) **Decide language** using the rules above.
434) **Harden**: add error handling, timeouts, and permission checks.
44 - *JXA*: `try { ... } catch (e) { console.log('Error:', e.message); }`
45 - *AppleScript*: `try ... on error errMsg ... end try`
465) **Validate**: run a read-only command and check outputs.
47 - *Example*: `osascript -e 'tell application "Finder" to get name of home'`
48 - Confirm: Output matches expected (e.g., user home folder name)
496) **Integrate** via `osascript` for CLI or pipeline use.
507) **UI scripting fallback** only when the dictionary is missing/incomplete.
51 - *Example UI Script*: `tell application "System Events" to click button 1 of window 1 of process "App"`
52 - *Example JXA*: `Application('System Events').processes.byName('App').windows[0].buttons[0].click()`
53
54## Validation Checklist
55- [ ] Automation/Accessibility permissions granted (System Settings > Privacy & Security)
56- [ ] App is running: `Application("App").running()` returns true
57- [ ] State checked before acting (e.g., folder exists)
58- [ ] Dictionary method used (not UI scripting)
59- [ ] Delays/retries added for UI operations
60- [ ] Read-only test command succeeds
61- [ ] Output matches expected values
62
63## Automation permission warm-up
64- Use before first automation run or after macOS updates to surface prompts:
65 - All apps at once: `skills/automating-mac-apps/scripts/request_automation_permissions.sh` (or `.py`).
66 - Per-app: `skills/automating-<app>/scripts/set_up_<app>_automation.{sh,py}` (calendar, notes, mail, keynote, excel, reminders).
67 - Voice Memos (no dictionary): `skills/automating-voice-memos/scripts/set_up_voice_memos_automation.sh` to activate app + check data paths; enable Accessibility + consider Full Disk Access.
68- Run from the same host you intend to automate with (Terminal vs Python) so the correct app gets Automation approval.
69- Each script runs read-only AppleScript calls (list accounts/calendars/folders, etc.) to request Terminal/Python control; click “Allow” when prompted.
70
71## Modern Python Alternatives to JXA
72
73**PyXA (Python for macOS Automation)** - Preferred for new projects:
74
75### PyXA Features
76- Active development (v0.2.3+), modern Python syntax
77- App automation: Safari, Calendar, Reminders, Mail, Music
78- UI scripting, clipboard, notifications, AppleScript integration
79- Method chaining: `app.lists().reminders().title()`
80
81### PyXA Installation {#pyxa-installation}
82
83```bash
84# Install PyXA
85pip install mac-pyxa
86
87# Or with pip3 explicitly
88pip3 install mac-pyxa
89
90# Requirements:
91# - Python 3.10+ (check with: python3 --version)
92# - macOS 12+ (Monterey or later recommended)
93# - PyObjC is installed automatically as a dependency
94
95# Verify installation
96python3 -c "import PyXA; print(f'PyXA {PyXA.__version__} installed successfully')"
97```
98
99> **Note:** All app-specific skills in this plugin that show PyXA examples assume PyXA is installed. See this section for installation.
100
101### PyXA Example (Safari Automation)
102```python
103import PyXA
104
105# Launch Safari and navigate
106safari = PyXA.Safari()
107safari.activate()
108safari.open_location("https://example.com")
109
110# Get current tab URL
111current_url = safari.current_tab.url
112print(f"Current URL: {current_url}")
113```
114
115### PyXA Example (Reminders)
116```python
117import PyXA
118
119reminders = PyXA.Reminders()
120work_list = reminders.lists().by_name("Work")
121
122# Add new reminder
123new_reminder = work_list.reminders().push({
124 "name": "Review PyXA documentation",
125 "body": "Explore modern macOS automation options"
126})
127```
128
129**PyXA Official Resources**:
130- Documentation: https://skaplanofficial.github.io/PyXA/
131- GitHub: https://github.com/SKaplanOfficial/PyXA
132- Community: Active Discord and GitHub discussions
133
134---
135
136**PyObjC (Python-Objective-C Bridge)** - For Low-Level macOS Integration:
137
138### PyObjC Capabilities
139- **Direct Framework Access**: AppKit, Foundation, and all macOS frameworks
140- **Apple Events**: Send Apple Events via Scripting Bridge
141- **Script Execution**: Run AppleScript or JXA from Python
142- **System APIs**: Direct access to CalendarStore, AddressBook, SystemEvents
143
144### Installation
145```bash
146pip install pyobjc
147# Installs bridges for major frameworks
148```
149
150### PyObjC Example (AppleScript Execution)
151```python
152from Foundation import NSAppleScript
153
154# Execute AppleScript from Python
155script_source = '''
156tell application "Safari"
157 return URL of current tab
158end tell
159'''
160
161script = NSAppleScript.alloc().initWithSource_(script_source)
162result, error = script.executeAndReturnError_(None)
163
164if error:
165 print(f"Error: {error}")
166else:
167 print(f"Current Safari URL: {result.stringValue()}")
168```
169
170### PyObjC Example (App Control via Scripting Bridge)
171```python
172from ScriptingBridge import SBApplication
173
174# Control Mail app
175mail = SBApplication.applicationWithBundleIdentifier_("com.apple.Mail")
176inbox = mail.inboxes()[0] # Access first inbox
177
178# Get unread message count
179unread_count = inbox.unreadCount()
180print(f"Unread messages: {unread_count}")
181```
182
183**PyObjC Official Resources**:
184- Documentation: https://pyobjc.readthedocs.io
185- Examples: Extensive GitHub repositories with code samples
186
187---
188
189### JXA Status
190JXA has no updates since 2016. Use PyXA for new projects when possible.
191
192## When Not to Use
193- Cross-platform automation (use Selenium/Playwright for web)
194- Full UI testing (use XCUITest or Appium)
195- Environments blocking Automation/Accessibility permissions
196- Non-macOS platforms
197- Simple shell scripting tasks (use Bash directly)
198
199## Related Skills
200- App-specific automation (create `automating-[app]` skills as needed)
201- `ci-cd-tcc` for advanced permission management in automated environments
202- `mastering-applescript` for AppleScript-focused workflows
203
204## Security Best Practices
205
206**Permission Management**:
207- Request minimal required permissions to reduce security risks
208- Use code signing for production scripts (Developer ID certificate)
209- Store credentials securely (Keychain, not hardcoded)
210- Validate all inputs to prevent injection attacks
211
212**Official Apple Security Guidance**:
213- [Apple Platform Security Guide](https://support.apple.com/guide/security/welcome/web)
214- [Scripting security considerations](https://support.apple.com/guide/security/secf202c9f70/web)
215- [App Sandbox Design Guide](https://developer.apple.com/library/archive/documentation/Security/Conceptual/AppSandboxDesignGuide/AboutAppSandbox/AboutAppSandbox.html)
216
217## Output expectations
218- Keep examples minimal and runnable.
219- **JSON Output**: For CLI pipelines, use `JSON.stringify(result)` in JXA.
220 - *Example*: `console.log(JSON.stringify({files: files, count: files.length}))`
221- **Exit Codes**: Ensure `osascript` exits with 0 for success, non-zero for failure.
222
223## What to load
224
225### Tier 1: Essentials (Start Here)
226- JXA Syntax & Patterns: `automating-mac-apps/references/basics.md`
227- AppleScript Basics: `automating-mac-apps/references/applescript-basics.md`
228- Cookbook (Common Recipes): `automating-mac-apps/references/recipes.md`
229
230### Tier 2: Advanced & Production
231- JXA Cookbook (Condensed): `automating-mac-apps/references/cookbook.md`
232- Performance Patterns: `automating-mac-apps/references/applescript-performance.md`
233- CI/CD & Permissions: `automating-mac-apps/references/ci-cd-tcc.md`
234- Shell Environment: `automating-mac-apps/references/shell-environment.md`
235- UI Scripting Inspector: `automating-mac-apps/references/ui-scripting-inspector.md`
236
237### Tier 3: Specialized & Reference
238- **PyXA Core API Reference** (complete class/method docs): `automating-mac-apps/references/pyxa-core-api-reference.md`
239- PyXA Basics: `automating-mac-apps/references/pyxa-basics.md` (Modern Python automation fundamentals)
240- AppleScript → PyXA Conversion: `automating-mac-apps/references/applescript-to-pyxa-conversion.md` (Migration guide with examples)
241- Translation Checklist (AppleScript → JXA): `automating-mac-apps/references/translation-checklist.md` (Comprehensive guide with examples and pitfalls)
242- JXA Helpers Library: `automating-mac-apps/references/helpers.js`
243- `whose` Batching Patterns: `automating-mac-apps/references/whos-batching.md`
244- Dictionary Strategies: `automating-mac-apps/references/dictionary-strategies.md`
245- ASObjC Helpers: `automating-mac-apps/references/applescript-asobjc.md`
246
247**Related Skills**:
248- `web-browser-automation`: Complete browser automation guide (Chrome, Edge, Brave, Arc)