A reference desktop
agent tool
A working CLI and MCP server for controlling native desktop apps through the accessibility tree — on macOS, Windows, and Linux. Use it as-is for automation and testing, or read the source to see how easy it is to build your own with xa11y.
What it looks like
# list running apps
agent-desktop apps
# read the accessibility tree
agent-desktop tree --app Safari
# find elements with CSS-like selectors
agent-desktop find "button[name='New Tab']" --app Safari
# interact
agent-desktop action press "button[name='New Tab']" --app Safari
agent-desktop action type-text "text_field[name='Address']" --app Safari --value "xa11y.dev"
# screenshot any app or element
agent-desktop screenshot --app Safari --output screen.png
Built on xa11y
agent-desktop is a thin layer over xa11y — a Playwright-style library for driving native apps via OS accessibility APIs. One unified API for AXUIElement (macOS), UI Automation (Windows), and AT-SPI2 (Linux). The same agent-desktop logic fits in ~50 lines in any supported language.
// cargo add xa11y
use xa11y::{App, InputSim};
async fn run() -> xa11y::Result<()> {
// connect to any running app by name
let app = App::by_name("Safari")?;
// CSS-like selectors, auto-waits for visible + enabled
let locator = app.locator("button[name='New Tab']");
locator.press().await?;
// screenshot any element or region
let shot = app.screenshot(None).await?;
shot.save_png("screen.png")?;
Ok(())
}# pip install xa11y
from xa11y import App
# connect to any running app by name
app = App.by_name("Safari")
# CSS-like selectors, auto-waits for visible + enabled
locator = app.locator("button[name='New Tab']")
locator.press()
# screenshot any element or region
shot = app.screenshot()
shot.save_png("screen.png")// npm install @crowecawcaw/xa11y
import { App } from '@crowecawcaw/xa11y';
// connect to any running app by name
const app = await App.byName('Safari');
// CSS-like selectors, auto-waits for visible + enabled
const locator = app.locator("button[name='New Tab']");
await locator.press();
// screenshot any element or region
const shot = await app.screenshot();
await shot.savePng('screen.png');Where to go from here
Use agent-desktop
Install the CLI or add the MCP server to your agent stack. Works out of the box on macOS, Windows, and Linux.
Install →Build your own with xa11y
Use agent-desktop as a reference and xa11y as your foundation. Rust, Python, or JavaScript bindings available.
xa11y.dev →Desktop testing
Looking for a cross-platform desktop testing framework? xa11y has a dedicated testing guide with CI setup for all three platforms.
Testing guide →Install
# via cargo (Rust)
cargo install agent-desktop
# verify
agent-desktop --version
Pre-built binaries for macOS, Linux, and Windows via GitHub Releases. MCP server config: see README.