The simplest, thinnest harness that gives an LLM complete freedom to control a Mac.
See the codeGive any coding agent the apps on your Mac. One shell command per step. It works in the background: your pointer does not move and your front app stays in front.
● agent: needs something only an app's UI can do
│
● macos-harness get_app_state --app "TextEdit" the window as numbered text
│
● macos-harness click --app "TextEdit" --element_index 12
│
● macos-harness get_app_state --app "TextEdit" only what changed
│
✓ task complete you kept working the whole time
Your agent now has a Mac.
Paste this into Claude Code, Codex, Pi or OpenCode:
Install or upgrade macOS Harness from https://github.com/browser-use/macos-harness with uv using Python 3.12. Then run `macos-harness install --agent NAME`, where NAME is the agent CLI you are (claude, codex, pi or opencode), and `macos-harness doctor`. Explain any missing macOS permission and ask before requesting it. Finally read one app that is already running, without bringing it to the front: `macos-harness get_app_state --app Finder`.
That is it. The agent installs the package, gets the skill, checks permissions and
reads its first app. Manual setup is available too. To go back to an
older release, run macos-harness uninstall --agent all first.
macos-harness get_app_state --app "TextEdit"
macos-harness click --app "TextEdit" --element_index 12
macos-harness type_text --app "TextEdit" --text "hello world"
macos-harness press_key --app "TextEdit" --key "super+s"
macos-harness set_value --app "TextEdit" --element_index 7 --value "report.txt"
macos-harness scroll --app "TextEdit" --element_index 3 --direction down --pages 1
macos-harness get_app_state --app "TextEdit"
Read, act, read again. get_app_state prints one line per thing on screen, each with
a number, and the path of a screenshot. Every other tool takes that number, or a pixel
of that screenshot. The rest of the eleven: list_apps, drag, paste,
select_text and perform_secondary_action.
There are no Spotify tools, Slack tools or Final Cut tools. The model gets the same eleven commands for every app. The skill is one page, and it is all an agent needs to read.
agent's shell helper (starts on the first call)
│ │
macos-harness click ... ── local socket ──▶ numbers, last state, sessions
│ │
text on stdout ◀────────────── accessibility tree + window screenshot
│
accessibility actions first, else events
sent to the app's own process
Raise, which the model asks for by name;
System Settings, opened when a permission is missing; and a menu-bar menu an app
fills only while it is open, which is opened for at most a quarter of a secondask_before_first_use = true in policy.toml in the state folder; strict = true
forbids terminal apps tooblocked_urls list of a policy file are noticed
when the page is read and before the action after one that may have changed it, not
while a page is loading; apps built on Electron or a plain web view give no URL to
check; one call clicks at most 10 times and types at most 20,000 charactersmacos-harness doctor reports the macOS permissions: Accessibility and Screen
Recording, which every call needs, and two optional ones, for the app that starts the
harness.
While paste runs, what was on your clipboard is kept in a file only you can read
(in the state folder) for about four seconds, so that it can be put back, also after
a crash.
Anonymous telemetry is enabled by default. It records only the CLI command category, success, duration, package version, OS/architecture, and detected agent client. It never records prompts, app names, screenshots, UI text, scripts, paths, or window titles.
macos-harness telemetry disable
Experimental. macOS only. MIT licensed.
(top 24 of 26)
450 followers · starred Aug 2026
165 followers · starred Aug 2026
234 followers · starred Aug 2026
155 followers · starred Aug 2026
The simplest, thinnest harness that gives an LLM complete freedom to control a Mac.
See the codeGive any coding agent the apps on your Mac. One shell command per step. It works in the background: your pointer does not move and your front app stays in front.
● agent: needs something only an app's UI can do
│
● macos-harness get_app_state --app "TextEdit" the window as numbered text
│
● macos-harness click --app "TextEdit" --element_index 12
│
● macos-harness get_app_state --app "TextEdit" only what changed
│
✓ task complete you kept working the whole time
Your agent now has a Mac.
Paste this into Claude Code, Codex, Pi or OpenCode:
Install or upgrade macOS Harness from https://github.com/browser-use/macos-harness with uv using Python 3.12. Then run `macos-harness install --agent NAME`, where NAME is the agent CLI you are (claude, codex, pi or opencode), and `macos-harness doctor`. Explain any missing macOS permission and ask before requesting it. Finally read one app that is already running, without bringing it to the front: `macos-harness get_app_state --app Finder`.
That is it. The agent installs the package, gets the skill, checks permissions and
reads its first app. Manual setup is available too. To go back to an
older release, run macos-harness uninstall --agent all first.
macos-harness get_app_state --app "TextEdit"
macos-harness click --app "TextEdit" --element_index 12
macos-harness type_text --app "TextEdit" --text "hello world"
macos-harness press_key --app "TextEdit" --key "super+s"
macos-harness set_value --app "TextEdit" --element_index 7 --value "report.txt"
macos-harness scroll --app "TextEdit" --element_index 3 --direction down --pages 1
macos-harness get_app_state --app "TextEdit"
Read, act, read again. get_app_state prints one line per thing on screen, each with
a number, and the path of a screenshot. Every other tool takes that number, or a pixel
of that screenshot. The rest of the eleven: list_apps, drag, paste,
select_text and perform_secondary_action.
There are no Spotify tools, Slack tools or Final Cut tools. The model gets the same eleven commands for every app. The skill is one page, and it is all an agent needs to read.
agent's shell helper (starts on the first call)
│ │
macos-harness click ... ── local socket ──▶ numbers, last state, sessions
│ │
text on stdout ◀────────────── accessibility tree + window screenshot
│
accessibility actions first, else events
sent to the app's own process
Raise, which the model asks for by name;
System Settings, opened when a permission is missing; and a menu-bar menu an app
fills only while it is open, which is opened for at most a quarter of a secondask_before_first_use = true in policy.toml in the state folder; strict = true
forbids terminal apps tooblocked_urls list of a policy file are noticed
when the page is read and before the action after one that may have changed it, not
while a page is loading; apps built on Electron or a plain web view give no URL to
check; one call clicks at most 10 times and types at most 20,000 charactersmacos-harness doctor reports the macOS permissions: Accessibility and Screen
Recording, which every call needs, and two optional ones, for the app that starts the
harness.
While paste runs, what was on your clipboard is kept in a file only you can read
(in the state folder) for about four seconds, so that it can be put back, also after
a crash.
Anonymous telemetry is enabled by default. It records only the CLI command category, success, duration, package version, OS/architecture, and detected agent client. It never records prompts, app names, screenshots, UI text, scripts, paths, or window titles.
macos-harness telemetry disable
Experimental. macOS only. MIT licensed.
(top 24 of 26)
450 followers · starred Aug 2026
165 followers · starred Aug 2026
234 followers · starred Aug 2026
155 followers · starred Aug 2026