AgentStack
SKILL verified MIT Self-run

Cua Driver Macos Automation

skill-chrislamdev-cua-desktop-automation-skills-cua-driver-macos-automation · by ChrisLamDev

Use Cua Driver for macOS desktop automation — launching apps, clicking UI elements, and controlling web pages via Accessibility API and JavaScript injection.

No reviews yet
0 installs
9 views
0.0% view→install

Install

$ agentstack add skill-chrislamdev-cua-desktop-automation-skills-cua-driver-macos-automation

✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access Used
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

Are you the author of Cua Driver Macos Automation? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

Cua Driver macOS Desktop Automation

When to use

  • User wants to automate macOS desktop apps (browsers, dev tools, etc.)
  • Need to click buttons, type text, or interact with web pages programmatically
  • macOS native Automation (AppleScript/cliclick) is blocked by OS restrictions
  • Want background (non-focus-stealing) desktop control

Version Updates

v0.6.8 (2026-06-28)

  • Hermes 原生支援! 執行 cua-driver mcp-config --client hermes 可直接輸出 Hermes config.yaml
  • 更新後要 restart daemon:cua-driver stop && cua-driver serve
  • TCC grants 理論上保留,但 macOS 可能出一次性 re-grant prompt
  • 如果 permission gate 卡住:cua-driver serve --no-permissions-gate
  • 新增 mcp-config 指令,支援 claude/codex/openclaw/cursor/opencode/hermes 等 client
  • Update 方法:cua-driver update --apply

Installation

/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/trycua/cua/main/libs/cua-driver/scripts/install.sh)"

Permissions Setup

After installation, grant two macOS permissions:

  1. Accessibility — System Settings > Privacy & Security > Accessibility > tick CuaDriver
  2. Screen Recording — System Settings > Privacy & Security > Screen Recording > tick CuaDriver

Check status:

cua-driver permissions status

Trigger permission dialogs:

cua-driver permissions grant

Core Workflow

1. List running apps

cua-driver call list_apps

2. Launch app in background (no focus steal)

cua-driver call launch_app '{"bundle_id":"com.google.Chrome","urls":["https://gemini.google.com/app"]}'

Useful flags:

  • creates_new_application_instance: true — force new instance for concurrent sessions
  • urls — array of URLs/file paths to open

3. List windows to find window_id

cua-driver call list_windows '{"pid":}'
cua-driver call list_windows '{"on_screen_only":true}'

4. Snapshot + get UI tree (element_index)

cua-driver call get_window_state '{"pid":,"window_id":}'

Use query to filter large trees:

cua-driver call get_window_state '{"pid":,"window_id":,"query":"button|input|search"}'

5. Click by element_index

cua-driver call click '{"pid":,"window_id":,"element_index":}'

6. Type text

cua-driver call type_text '{"pid":,"text":"Hello world"}'

7. Keyboard shortcuts

cua-driver call press_key '{"pid":,"key":"return"}'
cua-driver call hotkey '{"pid":,"keys":["cmd","c"]}'

Web Page Automation (Critical Path)

For interacting with web pages, elementindex + typetext often fail due to web component shadow DOMs.

Enable JavaScript Apple Events (one-time per browser)

echo '{"action":"enable_javascript_apple_events","bundle_id":"com.google.Chrome","user_has_confirmed_enabling":true}' | cua-driver call page

This restarts the browser.

Execute JavaScript directly in the page

Method A — Short JS (inline):

echo '{"pid":,"window_id":,"action":"execute_javascript","javascript":"document.title"}' | cua-driver call page

Method B — Long JS (file → stdin pipe, preferred):

# Write JS to file first, then pipe via python for proper JSON escaping
cat /tmp/script.js | python3 -c "
import sys, json
js = sys.stdin.read()
payload = json.dumps({'pid': , 'window_id': , 'action': 'execute_javascript', 'javascript': js})
with open('/tmp/payload.json', 'w') as f:
    f.write(payload)
" && cat /tmp/payload.json | cua-driver call page

Method C — AppleScript fallback (for Safari when page tool times out):

osascript -e 'tell application "Safari" to do JavaScript (read posix file "/tmp/script.js") in current tab of window 1'

Other page actions

echo '{"pid":,"window_id":,"action":"get_text"}' | cua-driver call page
echo '{"pid":,"window_id":,"action":"query_dom","css_selector":"button"}' | cua-driver call page

React SPA Text Input Strategy (e.g. X.com, Medium)

For React controlled components, standard textContent assignment doesn't trigger React's state update. Use this 3-layer approach:

Layer 1 — execCommand('insertText'): Best for React Draft.js editors (X.com compose box).

const el = document.querySelector('[data-testid="tweetTextarea_0"]');
el.focus();
const sel = window.getSelection();
const range = document.createRange();
range.selectNodeContents(el);
sel.removeAllRanges();
sel.addRange(range);
document.execCommand('insertText', false, tweetText);

Layer 2 — Cua typetext (method='keyevents'): Cua's type_text tool synthesises CGEvent keystrokes. Works when JS execCommand fails but may cause character duplication on SPA inputs. Use delay_ms: 10 for stability.

# Step 1: Click the input area first (use screenshot+vision to find pixel coords)
cua-driver call click '{"pid":,"window_id":,"x":,"y":}'
# Step 2: Type text via keystroke synthesis
cua-driver call type_text '{"pid":,"text":"Your tweet content here","delay_ms":10}'

Layer 3 — ClipboardEvent paste: Dispatches a programmatic paste event that React Draft.js recognizes.

const dataTransfer = new DataTransfer();
dataTransfer.setData('text/plain', tweetText);
el.dispatchEvent(new ClipboardEvent('paste', {
  bubbles: true, cancelable: true, clipboardData: dataTransfer
}));

X.com specific:

  • Post button [data-testid="tweetButtonInline"] is disabled until React state has content
  • Pixel coordinates for clicking Post button typically ~(610, 420) on 1600×796 Safari window
  • After typing via typetext, use screenshot + visionanalyze to verify Post button state
  • If Safari shows "確定要離開此網頁嗎?" dialog, click "停留在網頁" to dismiss

Common Pitfalls

  1. Shell quoting: When passing JSON with long JS strings, prefer stdin piping.
  2. elementindex is per-snapshot: Always call get_window_state before using elementindex.
  3. Web apps ignore AX type_text: Chromium/Electron web inputs often don't implement kAXSelectedText.
  4. After "Allow JS Apple Events": Chrome restarts with a NEW pid.
  5. list_windows can return no windows: Some Electron apps report 0 windows on main PID but have windows on child Renderer process PID.
  6. hotkey vs press_key: Use hotkey for keyboard shortcuts (more reliable on Electron apps).
  7. Screenshot capture: v0.5.3 get_window_state does NOT include screenshot despite capture_mode. Use macOS screencapture -x /tmp/screen.png as fallback.

Verification

cua-driver status
cua-driver permissions status
cua-driver list-tools

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet — be the first.

Versions

  • v0.1.0 Imported from the upstream source.