Open-source computer-use agent and MCP server for macOS: operates any app through the Accessibility API and native interfaces instead of screenshots.
MacWork defines 9 tools with reasonable descriptions (avg 180 chars) and input schemas. However, several critical gaps reduce quality: (1) Output schemas are undocumented, callers cannot predict response structure; (2) Parameter descriptions lack format/constraint details (e.g., 'max_steps' has no bounds, 'limit' defaults to 120 with no explanation); (3) Error handling is implicit, no guidance on recovery paths for 'blocked', 'need_input', 'ambiguous' states; (4) Tool names use 'mac_' prefix but lack clear verb-noun structure (mac_do, mac_act are vague); (5) No enum constraints on status values or choice IDs. Schemas are present but incomplete, most tools lack documented return types. Descriptions are adequate but could be more LLM-optimized with explicit constraints and examples of when to use each tool.
Execute one affordance from the latest mac_observe. Irreversible actions need confirm=true. remember=true keeps that confirmation as a standing grant — see mac_resume for who may give one.
Stop a running or pending task.
Accomplish a goal on this Mac. `inputs` carries any text the task needs (text, query, url, file…); `app` names the app to work in (default: the frontmost one). A long task may come back as `need_continue`: it is getting somewhere but this turn's budget is spent — call mac_resume.
Tell the engine whether a finished task really did what was asked; a wrong "done" is then not learned.
What can be done right now: affordances (menus, buttons, fields, apps, keys…) of `app` (default frontmost), in a fixed provider order (window, menus, keys, apps…), plus the readable screen text. `inputs` is what mac_do takes: a path in it is offered for opening, `controls` become holdable options. When `total` exceeds the page, `next_offset` continues the same listing.
Output schemas undocumented. Tools return dict[str, Any] with no documented field structure. LLMs cannot predict response shape, forcing them to guess at field names and types for downstream tool calls.
Vague tool names. 'mac_do' and 'mac_act' lack clear verb-noun structure. 'mac_do' could mean anything; 'mac_act' is ambiguous (execute? perform? react?). Names should be verb_noun (e.g., 'execute_goal', 'perform_action').
Parameter constraints missing. 'limit' (mac_observe) defaults to 120 with no min/max bounds documented. 'max_steps' (mac_revert) has no range. 'offset' has no validation. LLMs will pass invalid values without guidance.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-23 | D | 53 | 2026-07-28+ | v2 |
Continue a task that returned need_input (pass inputs), need_confirm (pass confirm) or ambiguous (pass choice). A chosen option still meets the safety floor — picking one says which, not whether — so pass confirm=true alongside choice to answer both at once. When `pending.remember` is present the person may have this confirmation remembered, so the same action in the same app is not asked about again.
Put back what a task changed, most recent change first, using each app's own undo command. Refuses while someone has been using the Mac, and stops at the first change it cannot put back.
Helper permissions, decider, cost so far, queue, dry-run state — or, with a task_id (from mac_submit or mac_do), that task: its status, result so far, and its place in the queue while it waits.
Hand in a goal and get its id back at once, without waiting for the Mac to be free. Tasks still run one at a time; this returns the queue position instead of blocking. Follow it with mac_status.
Error recovery guidance absent. Tools return status values like 'blocked', 'need_input', 'ambiguous' but descriptions do not explain what the LLM should do next. No enum constraints on status values.
Parameter descriptions lack actionable detail. 'inputs' is described as 'Any text the task needs' but does not specify expected keys, format, or examples. 'params' in mac_act is similarly vague.