Android automation that fits in your context window.

u2-agent turns the Android view hierarchy into a ~250-token tree of @handles, then resolves every action from a hot daemon in under 15 ms.

Zero dependencies. Bun and TypeScript native APIs only.

u2-agent stdout
$ u2-agent ui snapshot

[App: com.google.android.youtube]
[@1] Input  "Search YouTube"
[@2] Button "Explore"
[@3] Item   "Live lo-fi hip hop radio"
[@4] Button "Subscribe"
[@5] Tab    "Home"
[@6] Tab    "Shorts"

6 handles · ~250 tokens · 14 ms

See it drive a real phone.

A recorded session of an agent driving a physical Android device — read a snapshot, act on a handle, verify the receipt. No mockups, no simulated taps.

AI agent drives a real Android phone youtu.be/UUP5fDA2C5w · player loads on click

Raw hierarchies choke an agent.

A single Android XML dump is 5,000–20,000 tokens of container noise. By step fifteen the context window is spent and the reasoning degrades — so the agent stalls exactly when the task gets long.

Raw UIAutomator XML ~15,000 tokens
<hierarchy rotation="0">
  <node index="0" class="android.widget.FrameLayout">
    <node index="0" class="android.widget.LinearLayout">
      <node index="0" class="android.view.ViewGroup">
        <node class="androidx.recyclerview.widget.RecyclerView">
          <node class="android.widget.FrameLayout">
            <node text="Search YouTube"
                  class="android.widget.EditText">
          ... 240 more nodes ...

Containers, indices and bounds the agent never needs.

u2-agent snapshot ~250 tokens
[App: com.google.android.youtube]
[@1] Input  "Search YouTube"
[@2] Button "Explore"
[@3] Item   "Live lo-fi hip hop radio"
[@4] Button "Subscribe"
[@5] Tab    "Home"
[@6] Tab    "Shorts"

Actionable handles only. This is the real shape the CLI prints.

The dump is measured, not argued: snapshot drops structural containers, collapses nodes with ≥85% bounding-box overlap, and normalizes roles to Input, Button, Tab, Toggle and Item.

Read, act, verify.

One loop, three commands. The agent reads the screen, acts on a handle, and gets a clean receipt — no re-dump, no disconnects, no reasoning poisoned by diagnostics.

A1 Agent issues ui snapshot
D1 Daemon keeps the session hot
U1 Device executes the action
@1 standing by idle
Loop halted — press run to energize the circuit.
  1. Read the screen

    Dump the hierarchy and index every interactive element with an ephemeral handle.

    u2-agent ui snapshot
  2. Act on a handle

    The daemon resolves coordinates for the handle from RAM — no cold re-dump on the wire.

    u2-agent ui tap --ref @1
  3. Read the receipt

    stdout carries only machine text. Diagnostics and recovery hints stay on stderr.

    u2-agent ui type --ref @1 --text "synthwave"

What you get.

Everything the loop above depends on, itemized. No browser stack, no Java wrapper, no WebDriver.

Component Specification
Core runtime Bun and TypeScript native APIs only — no external browser or device SDKs.
Background daemon Keep-alive ADB socket and an in-RAM @handle store; actions resolve in under 15 ms.
Snapshot engine Structural-noise filtering, ≥85% bounding-box deduplication, role normalization.
Tool schema export tools schema --format openai drops into Anthropic, OpenAI or Gemini tool catalogs.
Error contract Deterministic codes — SELECTOR_NOT_FOUND, DEVICE_OFFLINE, USAGE, TIMEOUT — with defined exit codes.
Agent compatibility Claude Code, OpenCode, Cursor, Antigravity, LangChain, AutoGen and custom orchestrators.

Install.

Prerequisites: Bun ≥ 1.1, adb on your PATH, and an Android device with USB debugging enabled.

  1. Clone and install

    git clone https://github.com/themikehage/u2-agent.git && cd u2-agent && bun install
  2. Provision the device

    Install the lightweight UIAutomator2 RPC server on the target device.

    bun run src/index.ts setup install
  3. Take the first snapshot

    bun run src/index.ts ui snapshot
  4. Compile a standalone binary optional

    bun run build

Four boundaries, under 15 milliseconds.

How a handle action crosses from the agent to the device.

A1 AI agent Claude · GPT · OpenCode
issues --ref @N
P1 u2-agent CLI Bun / TypeScript
parses and validates
D1 Background daemon keep-alive ADB socket
in-RAM handle store
U1 Android device UIAutomator2 JSON-RPC
clicks and types

Exit codes

Exit Codes Meaning
0 success command succeeded
1 USAGE invalid arguments
2 DEVICE_OFFLINE · DEVICE_NOT_FOUND · DEVICE_UNAUTHORIZED device layer failure
3 SELECTOR_NOT_FOUND · APP_NOT_FOUND element or app not found
4 PROVISION_BLOCKED provisioning failure
5 TIMEOUT · POSTCONDITION_FAILED timeout or postcondition failure
10 internal internal error

Give your agent hands on a real phone.

Star the repository, install the CLI, take a snapshot in under a minute.