What Is Handsets?
Handsets is one of the best Android Automation CLI tools for developers automating Android apps from the terminal. Built by Elliot Gao (elliotgao2), it drives Android UI state over a tiny on-device daemon and reports single-call latency in the 2–7 ms range in the published benchmark, which is far below the typical adb shell path. It is designed for engineers who want a shell-first workflow, not a heavyweight mobile test stack.
Handsets focuses on tapping, filling, waiting, and inspecting by label instead of brittle screen coordinates. That makes it a strong fit for CLI automation, agent loops, and scripts that need predictable selectors without installing a full mobile test framework.
Quick Overview
| Attribute | Details |
|---|---|
| Type | Android Automation CLI |
| Best For | Developers automating Android apps from the terminal |
| Language/Stack | Android accessibility APIs, adb forward, Java daemon, Python bindings |
| License | MIT |
| GitHub Stars | N/A (not shown on the scraped page) |
| Pricing | Open-Source |
| Last Release | v0.1.26 — date not shown on the scraped page |
Who Should Use Handsets?
- Android engineers writing terminal-driven flows who want to validate app states with
tap,fill, andwaitwithout launching Android Studio or a GUI recorder. - Indie hackers building agents or scripts that need fast UI control loops, because Handsets keeps interaction latency low enough for repeated action/observe cycles.
- Platform or QA teams that already depend on ADB and want a slimmer alternative to heavier harnesses for smoke checks, regression checks, or demo automation.
- Python or polyglot developers who want a subprocess or SDK workflow instead of being locked into one test runner.
Not ideal for:
- Teams that need iOS support, rich reporting, or recorder-based test generation.
- Teams that need pytest plugins, HTML reports, or full device farm orchestration out of the box.
- UI automation that depends on pixel-perfect coordinates only and has no stable accessibility labels.
Key Features of Handsets
- Millisecond command latency — The benchmark in the repo shows 2–7 ms single-call latency, which is much lower than the 40–700 ms range shown for
adb shell. That matters when a script or agent performs dozens of UI actions per minute. - Label-first selectors — Handsets uses CSS-like, Playwright-inspired selectors such as
Button:has-text("Continue")andEditText[hint~=Email]. This is a better fit than coordinate tapping when views shift, animate, or reflow. - Persistent on-device daemon —
hs usestarts a daemon on the phone and keeps a socket open, so each command does not pay a cold-start penalty. The page describes this as a one-jar setup with no app and no root. - Live terminal inspector —
hs tuirenders the accessibility tree in aratatui+crossterminterface at roughly 10–20 fps. You can drive the device from the keyboard and watch the screen state update without manual refreshes. - Binary wire protocol — The host and device talk over
adb forwardusing length-prefixed binary frames on TCP9008. That design keeps the protocol small and makes it easy to expose the CLI from any language via subprocess. - Native screenshot and export paths —
screenshotdefaults to a 768px long-edge JPEG for fast agent loops, whilehs see out.jpgcan save native-resolution output. The repo also calls out WebP for compact lossy exports and PNG for debug or lossless capture. - Structured failures and exit codes — Handsets emits explicit exit codes for
NOT_FOUND,TIMEOUT, andAMBIGUOUS, and the JSON mode exposes a structurederror.code. That is useful when a calling process needs deterministic branching instead of parsing human text.
Handsets vs Alternatives
| Tool | Best For | Key Differentiator | Pricing |
|---|---|---|---|
| Handsets | Shell-first Android automation with low latency | Persistent daemon, label-based selectors, and ms-level command calls | Open-Source |
adb shell | Direct device commands and ad hoc debugging | Built-in ADB access, but UI automation is slow and coordinate-heavy | Free |
| uiautomator2 | Python-centric Android automation | Mature Python API and test ecosystem, but heavier than Handsets | Open-Source |
| Appium | Cross-platform mobile test suites | WebDriver abstraction, broader ecosystem, but much heavier runtime overhead | Open-Source |
For adjacent shell-first workflows, compare browse all CLI Tools with browse all DevOps Automation tools. Handsets beats adb shell when the task is repeated UI driving rather than one-off device commands. uiautomator2 is still the better fit if your whole team lives inside Python and wants the surrounding test tooling.
Pick Appium when you need a broader mobile testing platform, especially if cross-platform coverage and existing WebDriver infrastructure matter more than raw call latency. Pick uiautomator2 when the workflow is Python-only and you want the established Android automation ecosystem with its higher-level helpers.
How Handsets Works
Handsets splits the system into a thin host CLI and a tiny device-side server. The host binary forwards a TCP socket over adb forward to tcp:9008, and the device process runs as a shell-UID Java server via app_process. That server exposes accessibility tree dumps, binder reflection helpers, screenshots, and state mirroring without requiring an installed app package.
The data path is intentionally simple: a host command becomes a length-prefixed binary frame, the device executes the verb, and the response returns either an ok body, an empty end-of-stream marker, or a structured error payload. That is why the CLI can stay fast while still being language-agnostic through subprocesses and JSON output.
hs use
hs ui
hs tap 'Button:has-text("Continue")' --visible --unique
hs wait 'Welcome' --timeout 15s
The first command connects to the device and starts the daemon. The second command dumps tappable nodes as a table, and the last two commands show the selector model: match by text, constrain by visibility, then wait on a success condition. That flow is the core Handsets tutorial pattern and is the shortest path from inspection to automation.
Pros and Cons of Handsets
Pros:
- Very low per-call overhead compared with
adb shell, which is the main reason to choose Handsets for repeated UI actions. - Stable selectors based on labels, text, and accessibility properties, which are less brittle than coordinates.
- No root and no companion app install beyond a tiny jar, which simplifies device setup.
- CLI-first design that works well with shell scripts, CI jobs, and agent loops.
- Useful interactive TUI for manual exploration, especially when debugging selectors or screen changes.
- Python support plus subprocess mode make it easy to integrate into larger automation systems without rewriting everything.
Cons:
- No iOS support, so teams with cross-platform mobile needs still need another tool.
- Smaller ecosystem than Appium or uiautomator2, with no recorder, pytest plugin, or built-in HTML report layer.
- Accessibility-dependent automation can fail on apps with poor labels or intentionally hidden UI metadata.
- Pre-1.0 surface means the project is stable by its own claim since v0.1.0, but teams should still pin versions for production use.
- Not a full test farm product; orchestration, retries, and dashboards still need to be supplied by your own tooling.
Getting Started with Handsets
curl -fsSL https://raw.githubusercontent.com/elliotgao2/handsets/main/install.sh | bash
export HANDSETS_VERSION=v0.1.26
hs use
hs ui
After installation, make sure adb is available on your PATH and that your Android device or emulator is already visible to ADB. hs use starts the on-device daemon, and hs ui confirms that the accessibility tree can be read before you begin scripting tap, fill, or wait calls.
If you want a Python integration, install the package with pip install handsets and use the Session API. For other languages, the repo recommends driving hs --json as a subprocess and parsing one JSON line per call, which keeps the integration simple and portable.
Verdict
Handsets is the strongest option for shell-first Android UI automation when you care more about per-call latency than rich test reporting. Its biggest strength is the persistent daemon and label-based selector model; its main caveat is the smaller ecosystem compared with Appium or uiautomator2. Use it when speed and scriptability matter most.


