Offsider

A hand for your agent on the iOS Simulator and the Android Emulator.

A command-line tool that reads and drives iOS Simulators, Android Emulators, and iPhones, iPads and Android phones over USB. It's built for terminals, scripts and AI coding agents, and it runs entirely on your Mac.

brew install michael-palmes/tap/offsider

Open source under the MIT licence.

From install to first tap

It needs an Apple silicon Mac with macOS 26 or later and Xcode 26 or later. Android also needs the Android SDK.

# List simulators, emulators and USB devicesoffsider list-devices# Bind this shell to one deviceexport OFFSIDER_DEVICE=<ID># Check the host and the device before driving itoffsider doctor# One line per labelled element on screenoffsider describe-ui --summary# Tap, and exit 5 if nothing changesoffsider tap --id LoginButton --verifyoffsider screenshot --output screen.png

On Android

offsider boot Pixel_9 starts the emulator and prints its serial, such as emulator-5554. Bind that, and the same commands work.

export OFFSIDER_DEVICE=$(offsider boot Pixel_9)

For your agent

offsider init installs the bundled skill: add --client claude for Claude Code, or --client agents for ~/.agents/skills. offsider guide lists its topics, matched to the installed version.

Rather check the binary yourself? Each release also ships a tarball with SHA256SUMS and a build provenance attestation. Verify a release tarball

A hand that checks its work

Offsider reads the screen through accessibility, then taps, types, swipes, presses buttons and captures screenshots or video. Each step is careful enough to hand to an agent.

Checks the effect, not just the dispatch

Most input commands only confirm that the input was sent. Add --verify to tap, type, key or button and Offsider waits for the screen to change. If nothing changes, it exits 5.

Refuses taps that would land somewhere else

A tap by selector checks what a touch at its point would reach. When the target is off screen, covered by another view or under the keyboard, Offsider refuses and sends nothing.

Safe with more than one agent

Input commands lock the device while they run, so two agents can't interleave their input. A second command exits 8 at once, or waits its turn with --wait-lock. A lease marks a device as taken by one session.

Reads the screen compactly

describe-ui --summary prints one line per labelled element on screen, within a 16 KB budget by default. --diff prints only what changed since the last command.

# ios <ID> 402x874 @3x portrait 0°application "Playground" (0,0 402x874)  button "Save" id=save-button (170.7,313.3 61x34.3)  group id=rows (0,400 402x474)    button "Inbox, 3 unread" (0,400 402x56)    [off-screen below] 34 items: id=rows-item-9 to id=rows-end# folded 2 repeated labels

One set of commands

The same commands drive iOS Simulators, Android Emulators, and iPhones, iPads and Android phones over USB. list-devices shows each one with its ID, and --device or OFFSIDER_DEVICE picks one.

At home in React Native

In debug builds, rn open loads an Expo dev client's bundle from Metro, rn devmenu drives the dev menu and rn logbox reads and dismisses LogBox toasts. logs --rn prints console output, in release builds too.

Errors an agent can act on

Every exit code is documented, so a script can branch on it. With --json, a failure prints one object with a reason, a hint naming the next command to run, and whether any input was dispatched.

0
Success
2
Nothing matched the selector
5
A condition was not met
7
The device wasn't found or isn't booted
8
Another command holds the device
64
Invalid arguments

How it compares

Each tool takes its own route to the same screens, and some do more than Offsider. e2e is a test framework rather than a device tool, but it drives the same screens through agent-device. Offsider's column comes from its repo; the others come from each project's own documentation.

OffsiderAXeidbMaestroagent-devicee2e
iOS SimulatorYesYesYesYesYesYes
Android EmulatorYesNoNoYesYesYes
Physical devicesiPhones, iPads and Android phones, over USBNoiOS devices attached to the Mac, for some commandsAndroid phones; iPhones not yetiOS over USB or Wi-Fi; Android phones over adbiPhones and Android phones plugged into the machine
Host OSmacOS 26 or later, Apple siliconmacOS 14 or later, Apple silicon or IntelCompanion on Apple silicon macOS 15 or later; Python client on any OSmacOS, Linux or Windows; iOS needs a MacmacOS; Android also under WSLmacOS for iOS; Linux or WSL for Android
InterfaceCLI with an agent skill; no MCP server, by designCLI, batch step files and an agent skillCLI, Python client and gRPCCLI, YAML flows and an MCP serverCLI, MCP server and a Node.js APITypeScript tests, CLI and an MCP server
Checks that input took effectYes: --verify exits 5 when nothing changedOnly slider; other input is fire and forgetOnly before a tap, with --expected-valueWaits for the screen to settle; can retry a tap that changed nothingYes, with --verifyThrough the test's assertions, which retry until they pass
Refuses covered or off-screen tapsYes, and sends nothingNot documentedNo: a tap aims at the element's frame centreNot documentedYes, the tap fails at onceNot documented
Device lock for several agentsYes: a second command exits 8 or waits with --wait-lock; leasesNot documentedNot documentedNot documentedYes: device claims per workspaceWithin one run: workers never share a device
Installs and launches appsNo, by design: xcrun simctl and adb do thatNoYesLaunches apps that are already installedYesYes
Test flow filesNo: batch runs a whole case in one callBatch files, one step per lineNo; it runs XCTest bundlesYes, YAML flowsYes, .ad replay scriptsYes, TypeScript tests with plain-language steps
TelemetryNoneNot documentedHooks only; the open source build reports nothingOn by default; MAESTRO_CLI_NO_ANALYTICS turns it offNot documentedOn by default; E2E_TELEMETRY_DISABLED turns it off
LicenceMITMITMITApache 2.0MITApache 2.0

Checked October 2026.

Coming from idb, Maestro or agent-device? offsider guide migrate maps each command.

Nothing leaves your Mac

  • No telemetry, no accounts and no update checks.
  • It never connects to non-loopback addresses and never resolves hostnames. It may use Unix sockets and loopback to local developer daemons: the adb server, the Android Emulator and usbmuxd.
  • Password fields read as bullets, logs are redacted by default, and screenshots can mask password fields, labels, text, emails and regions.
  • Test credentials and unlock codes live in your login Keychain, never synchronised.
  • Physical devices connect over USB only. Offsider never pairs a device, accepts a prompt on one or types an iPhone passcode.
  • Releases are signed with a Developer ID and notarised, and ship with SHA256SUMS and a build provenance attestation.

One caveat. A device's screen reaches whatever your agent sends to its model provider. Offsider itself sends nothing.

Found a vulnerability? Report it privately through GitHub, as the security policy describes.

This site has no analytics, no cookies and no third-party requests.

Open source, on GitHub

Offsider is free and open source under the MIT licence. Read the code, open an issue or send a pull request.

github.com/michael-palmes/offsider

Offsider is a fork of AXe v1.8.0 by Cameron Cooke, used under the MIT licence, and is not endorsed by AXe's author. Its simulator frameworks are built from the michael-palmes/idb mirror at a pinned revision.