cua-desktop-automation-skills
Cua Desktop Automation — 7 executable skills with a self-learning task router for reliable macOS GUI automation.
📸 Demo
A collection of battle-tested skills and examples for building computer-use agents that control macOS desktops via Cua Driver — with an intelligent task router that learns from past executions.
💡 Why This Project?
Desktop automation is fragile. A single pixel shift, a renamed button, or a browser update can break an entire automation script. Most tools rely on hard-coded selectors, fixed coordinates, or brittle accessibility tree crawls — and when they break, they break silently.
AI agents need a router that learns from failure. Instead of guessing which tool to use, the router records what worked (and what didn't) across four execution tiers — CLI commands, browser CDP, pixel-level clicks, and vision-based fallback. Over time, it gets faster, smarter, and more resilient, automatically skipping strategies that have failed before and prioritizing the ones that actually work.
The result: automation that survives UI changes and improves with every run — no manual retraining required.
🌟 Star Feature: Router Learning System
The examples/router.py is a self-improving task routing engine that decides what tool to use based on past success:
Tier 1 — CLI/Git (fastest, no GUI needed)
Tier 2 — CDP WebSocket (direct browser DOM manipulation)
Tier 3 — Cua Driver (pixel clicks, keystrokes, AX tree)
Tier 4 — Vision AI (screenshot analysis for fallback)
How it works
from examples.router import do
# Route + auto-learn — the more you use it, the smarter it gets
result = do("git_commit", args={"message": "feat: ..."})
# → Router checks history, picks best path, records result
Key capabilities:
- 🧠 Dynamic path sorting — reorders tiers by historical success rate + execution time
- 📊 SQLite history (
~/.hermes/data/router_history.db) — persistent learning across sessions - 🔄 Context-aware fallback — auto-escalates through Tier 1 → 2 → 3 → 4 on failure
- ⏭️ Consecutive failure skip — skips paths that failed 3+ times in a row
- 🏆 Cold start → warm — static tier order initially, self-optimizes after 5+ samples
Built-in task routes
| Task | Available paths |
|---|---|
create_github_token |
Device code flow → CDP browser → Safari AX |
browser_navigate |
Cua hotkey (Cmd+L) |
browser_fill_input |
CDP JS → Cua type_text |
browser_click_button |
CDP JS → Cua pixel click |
app_hotkey |
Cua hotkey |
app_type |
Cua type_text |
app_click |
Cua pixel click |
app_screenshot |
screencapture |
git_commit |
git CLI |
git_push |
git CLI |
📋 Real-World Scenarios
These scenarios show how the Router Learning System picks the optimal path — and escalates intelligently when things go wrong.
Scenario 1: Automated GitHub Release
Pain point: Releasing software involves multiple steps — version bump, changelog update, git tag, push, and GitHub Release creation. One failed credential or network hiccup and the whole pipeline stalls.
# Router decides: Tier 1 (CLI git) first — fastest path
do("git_commit", args={"message": "chore: bump v1.2.3"}) # ✅ CLI succeeds
# But if git push fails due to auth...
do("git_push") # ❌ CLI auth error
# Router auto-escalates: Tier 3 (Cua click → Safari browser)
# → Opens GitHub.com in Safari, fills credentials, clicks "New Release"
do("create_github_token") # ✅ Cua Driver fallback
| Step | Chosen path | Why |
|---|---|---|
git_commit |
Tier 1 — git CLI |
Fastest, no GUI needed |
git_push |
Tier 1 — git CLI |
Preferred, but fails (auth) |
create_github_token |
Tier 3 — Cua Driver | Escalates on failure |
Scenario 2: Browser Fill + Submit
Pain point: Filling web forms and clicking submit buttons should be simple — but many sites use dynamic JS-rendered fields that static selectors can't reach.
# Router decides: Tier 2 (CDP JS) for DOM access
do("browser_fill_input", args={
"field": "#email",
"value": "[email protected]"
}) # ✅ CDP directly sets input.value
# Submit button is outside React's virtual DOM — CDP can't trigger it
do("browser_click_button", args={"button": "submit"})
# ❌ CDP JS fails — button not in accessible DOM tree
# Router escalates: Tier 3 (Cua pixel click)
# → Finds button coordinates via AX tree, clicks at pixel position
# ✅ Success!
| Step | Chosen path | Why |
|---|---|---|
browser_fill_input |
Tier 2 — CDP JS | Direct DOM access, fast |
browser_click_button |
Tier 2 → Tier 3 | CDP fails → pixel/AX fallback |
Scenario 3: Mac App Automation
Pain point: Native macOS apps (Finder, Calendar, Mail) have no web inspector, no CDP, no CLI interface for complex operations. You need full GUI control.
# Router decides: Tier 3 (Cua Driver) for native app interaction
do("app_click", args={
"app": "Finder",
"target": "Documents folder"
}) # ✅ Cua AX tree locates and clicks
# Button not found in AX tree (custom renderer)...
do("app_click", args={
"app": "Preview",
"target": "Export button"
}) # ❌ Tier 3 fails — no AX match
# Router escalates: Tier 4 (Vision AI)
# → Takes screenshot, runs vision model, finds button coordinates
# → Clicks at detected pixel position
# ✅ Success!
| Step | Chosen path | Why |
|---|---|---|
app_click (Finder) |
Tier 3 — Cua Driver | Native app, AX tree works |
app_click (Preview) |
Tier 3 → Tier 4 | AX fails → vision screenshot fallback |
Skills
| Skill | What it does |
|---|---|
auto-gui-debug-loop |
General-purpose GUI debugging loop — capture screen, analyze with vision AI, click UI, verify result. Works with any desktop app |
cua-browser-github-oauth |
Complete GitHub OAuth flow via browser automation — bypasses Chrome's URL bar search issue during device code auth |
cua-driver-install-macos |
Install, configure, and integrate Cua Driver on macOS — permission granting, MCP setup, Hermes integration |
cua-driver-macos-automation |
Launch apps, click UI elements, type text, and control web pages via Cua Driver's Accessibility API and JS injection |
cua-vision-hybrid-control |
Hybrid control loop: Accessibility tree + Vision AI screenshot analysis for reliable fallback when AX can't find elements |
cua-wechat-devtools-ui-inspection |
Inspect and navigate WeChat DevTools simulator for Mini Program UI visual review — covers AX quirks and pixel-click strategies |
desktop-browser-automation-cua |
Automate desktop browsers (Chrome/Safari) — open pages, type, click, execute JS. Includes React SPA workaround for X.com etc. |
Quick Start
# Clone
git clone https://github.com/ChrisLamDev/cua-desktop-automation-skills.git
cd cua-desktop-automation-skills
# Try the Router
python3 examples/router.py stats
python3 examples/router.py git_commit
For Cua Driver Contributors
This repo demonstrates real-world patterns for building computer-use agents with Cua Driver:
- Task routing with fallback — the key architectural pattern for reliable desktop automation
- Self-learning from history — essential for production agents that improve over time
- Multi-tier escalation — CLI → CDP → Cua Driver → Vision — handles all failure modes
Platform Compatibility
- macOS (primary target — tested on Apple Silicon)
- Requires Cua Driver:
brew install trycua/tap/cua
🧬 Skill Anatomy
Each skill in this repo follows a standard structure that the Router Learning System understands:
skills/cua-driver-install-macos/
├── SKILL.md # Human-readable: what this skill does, prerequisites, usage
└── router.py # Machine-readable: execution logic for the router
SKILL.md — The documentation layer. Contains a clear description, environment prerequisites (e.g., "requires macOS 14+"), step-by-step usage instructions, and any notes on common failure modes. This is what contributors read and what AI agents can parse for context.
router.py — The execution layer. Exports one or more functions that align with the built-in task routes (e.g., install(), verify()). The router imports these functions dynamically and calls them with the appropriate tier strategy. Each function should return a (success: bool, result: str) tuple so the router can record the outcome and learn from it.
How the router uses a skill:
# The router discovers and invokes a skill dynamically
from skills.cua_driver_install_macos.router import install
success, result = install()
# Router records: {skill_name, tier, success, duration_ms}
# Next time: router prioritizes this path if it worked
To add a new skill: create skills/<your-skill>/SKILL.md and skills/<your-skill>/router.py, then register the task route in the router's configuration table.
License
MIT — use freely, improve openly.
No comments yet
Be the first to share your take.