/jxa
Reference for writing JXA (JavaScript for Automation) scripts run through `osascript -l JavaScript`. Covers the JavaScriptCore ES5 constraints, `run(argv)`, and the `Application()` bridge.
Claude Code
$ npx -y skills add bendrucker/claude --skill jxa --agent claude-code
Codex
$ npx skills add bendrucker/claude --skill jxa -a codex -y
Cursor
$ npx skills add bendrucker/claude --skill jxa -a cursor -y
Gemini CLI
$ npx skills add bendrucker/claude --skill jxa -a gemini-cli -y
GitHub Copilot
$ npx skills add bendrucker/claude --skill jxa -a github-copilot -y
OpenCode
$ npx skills add bendrucker/claude --skill jxa -a opencode -y
Windsurf
$ npx skills add bendrucker/claude --skill jxa -a windsurf -y
SKILL.md
jxa.SKILL.mdname: mac:jxa
disable-model-invocation: true
description: Reference for writing JXA (JavaScript for Automation) scripts run through `osascript -l JavaScript`. Covers the JavaScriptCore ES5 constraints, `run(argv)`, and the `Application()` bridge.
JXA
JavaScript for Automation (JXA) automates macOS apps via the `Application()` bridge. It runs on JavaScriptCore (ES5).
Language Constraints
- Use `var` (not `let`/`const`)
- Use for-loops (JXA arrays lack `.map()`, `.filter()`, `.forEach()`)
- Return a JSON string from `run()` (not an object)
// WRONG: JXA arrays don't have .map()
// var names = app.windows().map(function(w) { return w.name(); });
// CORRECT: use a for-loop
var windows = app.windows();
var names = [];
for (var i = 0; i < windows.length; i++) {
names.push(windows[i].name());
}Script Files
Script files define a `function run(argv)` entry point. `osascript` calls it and prints the return value. The function must be named `run`, not `_run`.
#!/usr/bin/env osascript -l JavaScript
function run(argv) {
var finder = Application("Finder");
var items = finder.desktop.items();
var names = [];
for (var i = 0; i < items.length; i++) {
names.push(items[i].name());
}
return JSON.stringify(names);
}Tips
- Use `properties()` for batch reads instead of individual getters
- Use `.whose()` for filtering when the app supports it (pushes work to the app)
- `Application.currentApplication()` accesses the current app context
- Extract sdef for any app: `sdef /Applications/AppName.app`
Read more
name: mac:jxa disable-model-invocation: true description: Reference for writing JXA (JavaScript for Automation) scripts run through `osascript -l JavaScript`. Covers the JavaScriptCore ES5 constraints, `run(argv)`, and the `Application()` bridge.
JXA
JavaScript for Automation (JXA) automates macOS apps via the `Application()` bridge. It runs on JavaScriptCore (ES5).
Language Constraints
- Use `var` (not `let`/`const`)
- Use for-loops (JXA arrays lack `.map()`, `.filter()`, `.forEach()`)
- Return a JSON string from `run()` (not an object)
// WRONG: JXA arrays don't have .map()
// var names = app.windows().map(function(w) { return w.name(); });
// CORRECT: use a for-loop
var windows = app.windows();
var names = [];
for (var i = 0; i < windows.length; i++) {
names.push(windows[i].name());
}Script Files
Script files define a `function run(argv)` entry point. `osascript` calls it and prints the return value. The function must be named `run`, not `_run`.
#!/usr/bin/env osascript -l JavaScript
function run(argv) {
var finder = Application("Finder");
var items = finder.desktop.items();
var names = [];
for (var i = 0; i < items.length; i++) {
names.push(items[i].name());
}
return JSON.stringify(names);
}Tips
- Use `properties()` for batch reads instead of individual getters
- Use `.whose()` for filtering when the app supports it (pushes work to the app)
- `Application.currentApplication()` accesses the current app context
- Extract sdef for any app: `sdef /Applications/AppName.app`
Other skills on claude.
cli
Type-safe CLI argument parsing with commander and @commander-js/extra-typings, the standard parser for this repo's Bun scripts.…
prose-lab
Turn the user's labels on repo prose, or their notes from reviewing a document in Plannotator, into calibrated Vale rules.
activity
Report real device usage from ActivityWatch. Covers per-app time, window titles, and active vs idle spans. Use when asked "what…
agent-team
Orchestrating Claude Code agent teams. Use when creating teams, spawning teammates, assigning tasks, configuring teammate modes,…
handoff
Hand the current conversation off to a fresh background agent that picks up the work immediately, so you can step away and track…
More skills from other plugins.
brainstorming
You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or…
ask-matt
Ask which skill or flow fits your situation. A router over the skills in this repo.
Questions about jxa.
- Which coding agents can use jxa?
- jxa installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.

