A CLI for driving Mac applications via the Accessibility API. Designed for automated testing and AI agent control.
Or with Homebrew:
brew tap mikker/tap
brew install steve
All commands output structured text to stdout by default, except screenshot which outputs PNG to stdout unless -o/--output is provided.
Use --format json (or -j) for compact JSON output. Errors go to stderr and return a non-zero exit code.
Text:
...
Example:
- Extensions
frame: x=837 y=157 w=885 h=814
JSON:
{"ok":true,"data":...}
{"ok":false,"error":"message"}
steve apps
steve focus "AppName"
steve focus --pid 1234
steve focus --bundle "com.example.app"
steve launch "com.example.app" --wait
steve quit "AppName" --force
steve elements
steve elements --depth 5
steve elements --window "Settings"
steve find "Button"
steve find --title "Submit"
steve find --text "Dictation Mode"
steve find --text "Dictation Mode" --window "Settings" --ancestor-role AXRow --click
steve find --role AXButton --title "OK"
steve find --identifier "loginButton"
steve element-at 100 200
steve click "ax://1234/0.2.5"
steve click --title "Submit"
steve click --text "Dictation Mode"
steve click --window "Settings" --text "Dictation Mode"
steve click-at 100 200 --double
steve type "hello world" --delay 50
steve key cmd+shift+p
steve key f12
steve key fn+f12
steve key --raw 122
steve key --list
steve set-value "ax://1234/0.1" "new text"
steve scroll down --amount 5
steve scroll --element "ax://1234/0.4" up
--textmatches visible text viaAXValue,AXDescription, andAXStaticTexttitle (case-insensitive substring).--window "Title"scopesfind,elements, andclickto a specific window title.--ancestor-role AXRow|AXCell|AXButton --clickclicks the nearest ancestor role after a text match.
steve exists --title "Welcome"
steve exists --text "Ready" --window "Settings"
steve wait --title "Results" --timeout 5
steve wait --title "Loading..." --gone --timeout 10
steve wait --text "Loading..." --window "Settings" --timeout 10
steve assert --title "Submit" --enabled
steve assert --title "Checkbox" --checked
steve assert --title "Input" --value "expected text"
steve windows
steve window focus "ax://win/123"
steve window resize "ax://win/123" 800 600
steve window move "ax://win/123" 100 100
steve menus
steve menu "File" "New"
steve menu --contains --case-insensitive "settings..."
steve menu --list "File"
steve statusbar --list
steve statusbar "Wi-Fi"
steve statusbar --menu --contains "Battery"
steve screenshot
steve screenshot --app "AppName" -o screenshot.png
steve screenshot --element "ax://1234/0.2" -o element.png
--app "Name"
--pid 1234
--bundle "id"
--timeout 5
--verbose
--quiet
--format text|json
-j
| Code | Meaning |
|---|---|
| 0 | Success |
| 1 | Element not found |
| 2 | App not found / not running |
| 3 | Timeout |
| 4 | Permission denied (accessibility) |
| 5 | Invalid arguments |
- Coordinates are in screen space (0,0 = top-left of main display). Multiple monitors extend rightward/downward.
- Element IDs are stable within a session but not across app restarts.
swift build -c release
MIT
