Skip to content
Back to skills

Macos Harness

ASecurity

See and operate macOS apps, iOS Simulators and Android emulators and phones from the shell with the macos-harness CLI - list apps and windows, read an app's UI as refs, take screenshots, press buttons, type, choose menu items, drag, scroll, swipe and right-click; boot simulators and emulators, build and run apps on them. Use when a task needs a Mac, iOS or Android app's UI, such as checking an app you built or driving one of Apple's apps.

  • 4 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added October 10, 2026
ai-agentsgoshellaws

Works with

  • cursor
  • cli

Security analysis

A100/100

Scanned October 10, 2026

npx -y skills add TheRogue76/macos-harness --skill macos-harness --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Macos Harness?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Macos Harness
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/therogue76-macos-harness/badge)](https://www.skillsdirectory.com/skills/therogue76-macos-harness)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: macos-harness
description: See and operate macOS apps, iOS Simulators and Android emulators and phones from the shell with the macos-harness CLI - list apps and windows, read an app's UI as refs, take screenshots, press buttons, type, choose menu items, drag, scroll, swipe and right-click; boot simulators and emulators, build and run apps on them. Use when a task needs a Mac, iOS or Android app's UI, such as checking an app you built or driving one of Apple's apps.
license: MIT
compatibility: macOS 15 or later with the macOS Harness app installed (brew install --cask therogue76/tap/macos-harness).
---

# macOS Harness

`macos-harness` talks to the macOS Harness menu bar app, which holds the
Screen Recording and Accessibility permissions. The first time you use it,
the user approves you in a prompt; if a command waits, tell them to look at
the menu bar. Run `macos-harness doctor` if anything seems off.

## The loop

1. Find the app: `macos-harness apps`, `macos-harness windows -a Notes`.
2. Read it: `macos-harness snapshot -a Notes` prints the window as a tree of
   refs (`k12`) with roles, labels, state and `@x,y` click points.
   `macos-harness find "Save" -a TextEdit` searches, including scrolled-out
   elements. `macos-harness screenshot -a Notes --out /tmp/notes.png` saves a
   picture; add `--labels` to draw refs on it.
3. Act: `macos-harness press k12 -a Notes`. Every action prints what it did
   and what changed (`~ k6 text "79" → "797"`, `+ k45 sheet`), so you rarely
   need a new snapshot.
4. Wait for slow things: `macos-harness wait --text "Done" -a App`.

Refs last until the app or the helper restarts. Instead of a ref you can
select by `--text`, `--role` (`button`, `textfield`, `checkbox`, `tab`,
`popup`, `menuitem`, …) and `--id`; ambiguous selectors fail with the
candidates listed.

## Acting

Prefer these: they use accessibility and don't move the user's cursor.

- `press <ref>`, `set-value <ref> --value "…"`, `focus`, `select`,
  `increment`, `decrement`, `scroll-to`
- `type "text" -a App` types at the focused element (`--into <ref>` to
  choose one); `key cmd+s -a App` sends a shortcut.
- `menu-select -a TextEdit File "Save…"` chooses a menu item (it brings the
  app to the front). `menu -a App File` lists a menu first.
- `window activate|move|resize|minimize|close -a App`,
  `launch App [--open file]`, `quit App`.

Text fields often save only when editing ends: after `set-value` or `type`,
send `key tab` or `key return` if the change didn't show elsewhere.

Use the real mouse and keyboard only when accessibility can't do it: an
element with no actions, a drag, a hover, scrolling, a right-click, or an app
that ignores background keys. These bring the app to the front, wait until
the user stops typing or moving the mouse, and put the cursor back:

- `click <ref>` (`--right`, `--count 2`), or `click --x 40 --y 120 -a App`
  for window-relative points
- `hover <ref>`, `drag <ref> --to <ref>`, `scroll <ref> --down 300`
- `type "…" --real`, `key cmd+a --real`

A right-click lists the context menu's items as refs; `press` one to choose it.

## Apps with little or no tree

- Electron, Chrome and other Chromium apps hide their tree until asked; the
  first read switches it on (a `treeEnabled` notice). If a `treeHidden`
  notice appears, ask the user before relaunching their app with
  `launch "App" --arg=--force-renderer-accessibility`.
- For text the tree doesn't have, `find --ocr "Text" -a App` reads the
  window's pixels and gives click points; `click --ocr --text "Text"` clicks
  it. `screenshot --grid 100` draws window coordinates for canvases; then
  `click --x … --y …`.
- Need a browser of your own? `launch "Google Chrome" --new-instance
  --arg=--user-data-dir=/tmp/my-profile` and target it by the pid it prints;
  never drive the user's own browser profile without asking.

## iOS Simulators

Needs Xcode 27 or later. Give any `-a` command `sim:<device>` (a UDID, a
name, or `sim:booted`) and it works on that simulator's screen, in the
device's own points:

- `sim list`, then `sim boot "iPhone 18 Pro"` (waits for the home screen).
- `build --sim booted --run` builds the project here, installs and launches
  it; or `sim install booted App.app` and `sim launch booted com.example.app`.
- `snapshot -a sim:booted`, `press -a sim:booted --text "Sign in"`,
  `type "ada@example.com" -a sim:booted --into <ref>`, `key return -a sim:booted`.
- `scroll -a sim:booted --down 600` pages through a list; actions also
  scroll to find an element iOS hasn't listed yet. `swipe --left 200`,
  `long-press <ref>` and `click --x --y` use the mouse in the simulator's
  window.
- `sim button booted home` (also lock, siri, app-switcher, rotate-left…),
  `sim open-url booted <url>`, `sim privacy booted grant photos <bundle-id>`,
  `sim appearance booted dark`, `sim location booted 59.33,18.07`.
- `screenshot -a sim:booted` and `record start -a sim:booted` come straight
  from the simulator.

The simulator's tree lags its screen by a second or two; the commands wait
for it. If a snapshot stays empty, Device Hub has lost the simulator's
screen: tell the user, since the fix (quitting Device Hub) shuts down its
simulators. Never quit Device Hub, or boot, shut down or erase a simulator
the user is using, without asking.

## Android emulators and phones

Needs the Android SDK (adb). Give any `-a` command `android:<device>` (an
adb serial, an emulator's name, or `android:booted`); coordinates are the
screen's pixels and nothing touches the user's Mac:

- `android list`, then `android boot <emulator>` (`--headless` for no
  window).
- `android install booted app.apk`, `android launch booted <package>`,
  `android terminate booted <package>`.
- `snapshot -a android:booted`, `press -a android:booted --id sign_in`,
  `type "ada@example.com" -a android:booted --into <ref>`,
  `key enter -a android:booted`, `android button booted back`.
- `scroll`, `swipe`, `long-press` and `drag` work as on a simulator;
  actions scroll to find an element that isn't on screen yet.
- `android open-url`, `android permission booted grant <package> camera`,
  `android appearance booted dark`, `android rotate booted landscape`.

Each read takes 2–3 s: act on refs and read the change lists rather than
snapshotting after every step. Only plain ASCII can be typed. A connected
phone is the user's own: ask before acting on it, and never start, stop or
wipe the user's emulators without asking.

## Recording and repeatable checks

- `record start -a App --out /tmp/run.mov` records only that app's windows;
  `record stop` finishes the file. Useful to show the user what happened.
- `flow run checks.yaml` replays a YAML flow of steps and `expect`s, and
  `flow export last` turns your latest session into one (typed text becomes
  `${text_N}` variables). `macos-harness flow --help` has the details.

## When things go wrong

- **"The user stopped …"** (error 1004): the user paused you from the menu
  bar or with ⌃⌥⌘. Stop and ask them to resume. Never restart the helper or
  work around it.
- **"… policy blocks …" or "read-only"** (1005): the user's policy file
  doesn't allow this app or action. Tell them; don't look for another way.
- **"isn't allowed to use macOS Harness"** (1001): the user declined the
  pairing prompt.
- **Notices** (`!` lines) flag things like a system dialog, a sheet, Secure
  Input, or that the app isn't frontmost. Read them before acting.

Every command takes `--json`; errors then come back as
`{"error": {"code": …, "message": …}}`.

## Manners

You're sharing the user's Mac while they work. Do only what the task needs,
and ask before anything hard to undo: sending messages or email, deleting,
purchasing, or changing settings. Work in test files and folders when you
can.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…