Skip to main content
llm-adb logo

llm-adb

Token-efficient ADB wrapper for LLM agents.

Python 3.9+ Android 7 to 17 Requires adb Built for LLM agents License GitHub stars Version

Why  ·  Benchmarks  ·  Install  ·  Quick start  ·  Commands  ·  Errors


llm-adb (CLI binary: llmadb) is a drop-in command-line wrapper around Android Debug Bridge (adb) built specifically for autonomous LLM coding and testing agents. Instead of forcing models to chain raw adb shell commands, parse multi-thousand-line uiautomator XML dumps, guess screen coordinates from full-resolution screenshots, or hang on 60fps animations, llm-adb collapses multi-step device interactions into single, deterministic calls with compact line-based output.

Any subcommand not owned by llm-adb passes through transparently to adb (llmadb shell ..., llmadb install ..., llmadb logcat ...), allowing agents to use llmadb as a complete replacement for adb.

At a glance

Raw adb llm-adb
Reading the screen 15,000–50,000 byte XML dump 15–40 line indexed tree (~100–250 tokens)
Custom views, WebViews, games Guessing coordinates from full-resolution screenshots Downscaled screenshot with a 100px device-coordinate grid
Animations and overlays Dump hangs or fails; overlays missing Fails fast, surfaces ! overlay warnings
Actions input tap returns nothing; extra turns to re-dump Every action returns the settled UI
Everything else adb Transparent passthrough to adb

Why llm-adb?

When controlling an Android device with raw adb, LLM agents waste 30–60% of their tokens and turns on boilerplate plumbing:

  • Massive XML Dumps: A single adb shell uiautomator dump produces 15,000–50,000 bytes of deeply nested XML. llmadb ui filters out invisible/zero-area containers, merges redundant single-child wrappers, strips repetitive package prefixes, and emits a 15–40 line indexed accessibility tree (~100–250 tokens).
  • Blind Coordinate Guessing: When elements live inside custom Canvas views, games, or unexposed WebViews, models fail to guess pixel coordinates on 1080x2400 screenshots. llmadb screen downscales screenshots (default max-edge 960px) while burning a crisp 100px device-coordinate grid with interior + crosshairs directly onto the image so vision models can read exact device coordinates (llmadb tap x,y) in one shot.
  • Animation & Overlay Blindness: Standard uiautomator dump hangs for up to 30 seconds or fails with could not get idle state when a countdown timer, progress spinner, or 60fps animation is active. Furthermore, floating system overlays (incoming calls, heads-up notifications, OxygenOS Dynamic Island / SeedlingCard capsules) are omitted when another window holds input focus. llm-adb fails fast on non-idle trees and cross-checks dumpsys window across Android 7 through Android 17 (InputWindowHandle and InputDispatcher) to surface ! overlay window="..." @cx,cy warnings automatically.
  • Multi-Turn Action Loops: Raw adb shell input tap returns nothing, requiring extra turns to sleep and re-dump the screen. Every llmadb action (tap, type, swipe, key) automatically waits for the UI to settle and returns the updated UI snapshot in a single tool call.

How llm-adb Accelerates App Development & QA

llm-adb turns any tool-using LLM (Claude Code, Codex, Antigravity CLI, Cursor, Windsurf / Devin, or local coding agents) into an autonomous Android QA and debugging engineer:

  1. Automated UI & Feature Verification: After building and installing an APK (llmadb install -r app-debug.apk), an agent can launch the app (llmadb launch com.example.app), navigate onboarding flows (llmadb tap --text "Get Started"), fill forms (llmadb type "user@example.com" --clear --enter), and test long-press context menus (llmadb tap --text "Item" --hold).
  2. Deterministic Crash Reproduction & Log Triage: Instead of sifting through thousands of noisy system logcat lines, agents run a tight reproduction loop:
    llmadb mark                                      # Save current device timestamp
    llmadb tap --id submit_btn                       # Trigger the bug
    llmadb log --pkg com.example.app --since-mark    # Inspect deduplicated app logs (xN)
    llmadb log --crash --since-mark                  # Extract fatal exception stack traces
    
  3. Orientation & Responsive Layout Testing: Agents can toggle or lock screen orientation (llmadb rotate landscape, llmadb rotate portrait, or llmadb rotate to flip the current state) and immediately inspect llmadb ui or llmadb screen to verify that state survives configuration changes without layout clipping.
  4. Device Environment & Connectivity Auditing: With llmadb status and llmadb hardware, agents instantly verify battery levels, Wi-Fi/Cellular connectivity, Bluetooth/NFC/Airplane states, DPI scaling, available RAM/storage, and SELinux/root status before running integration tests.
  5. Cross-Generation Compatibility (Android 7 to Android 17): Tested across legacy OEM skins (Samsung Experience / Grace UX (Android 7.0), modern OEM skins (OnePlus OxygenOS 16 / Android 16), and stock AOSP (Google Pixel / Android 17), automatically handling edge-to-edge bottom navigation insets and OEM-specific window dumps.

Performance & Benchmark Results

llm-adb was evaluated in a Zero-Context ("Clueless") Autonomous Agent Benchmark on a physical Android 16 device (1080x2412, 480 DPI) across frontier multimodal models and a local 35B MoE model. Agents were given zero prior documentation - learning llm-adb strictly via llmadb --help-llm at runtime - and compared against an unassisted Raw adb baseline under strict on-device UI rules (no host web scraping or deep-link shortcuts).

1. End-to-End Agent Benchmark Summary

Task Model Raw adb Baseline llm-adb (llmadb) Improvement with llm-adb
Launcher Navigation & Web Search (TC-02) Local 35B-A3B MoE (Text-Only) 208.8s (25 turns)
12,545 uncached tokens
166,071 total context
110.3s (17 turns)
8,565 uncached tokens
103,056 total context
47.2% faster
31.7% fewer uncached tokens
50.5% fewer output tokens
Launcher Navigation & Web Search (TC-02) Claude Sonnet 5.5 40.6s
106,764 total context
1,875 output tokens
31.3s
83,376 total context
1,224 output tokens
22.9% faster
21.9% fewer total tokens
34.7% fewer output tokens
Launcher Navigation & Web Search (TC-02) Gemini 3.8 Flash 66.6s
221,262 total context
1,251 output tokens
63.2s
159,175 total context
635 output tokens
28.1% fewer total tokens
49.2% fewer output tokens
7-Stage Multi-App Flow (TC-06)
(Quick Settings -> Web Search -> APK Download & Install -> 20s Timer -> Dynamic Island Dismiss)
Gemini 3.8 Flash FAILED (723.2s T/O)
364,506 uncached tokens
(Mis-tapped link without grid; hung on Play Protect)
PASSED (7/7 stages)
441.3s
254,405 uncached tokens
Passed vs. Failed
39.0% faster
30.2% fewer uncached tokens
65.3% fewer output tokens
7-Stage Multi-App Flow (TC-06) Claude Sonnet 5.5 PASSED (695.4s)
163,746 uncached tokens
(2 failed pm install calls + mis-tap)
PASSED (7/7 stages)
498.8s
109,023 uncached tokens
28.3% faster (-3m 16s)
33.4% fewer uncached tokens
34.8% fewer input tokens

Each cell is a single trial (TC-02 was run 1–3 times per model and TC-06 1–2 times, against one Raw adb baseline run), so treat the percentages as indicative, not statistical. Every run, including the ones not shown here, is logged in AGENT_TESTS.md. Every test can be found at TEST_SUITE.md

2. Host CLI Execution Latency

llm-adb batches multiple shell queries into single delimited adb shell invocations, keeping host-side command overhead minimal:

Command Operation Typical Latency
llmadb current Batched focus, activity, rotation, and keyboard visibility ~180–350 ms
llmadb rotate Read/toggle system rotation and verify orientation ~200–400 ms
llmadb status Batched battery, Wi-Fi, cellular, BT, NFC, and airplane status ~250–450 ms
llmadb info <pkg> Package version, SDK, permissions, launcher, and PID ~250–500 ms
llmadb log --since-mark Timestamp mark lookup + deduplicated PID logcat ~200–450 ms
llmadb list apps Package path classification (user, system, vendor, product) ~400–800 ms
llmadb screen Screencap + 960px downscale + 100px coordinate grid ~800–1400 ms
llmadb ui Accessibility dump + reduction + overlay check + cache ~1.0–2.2 s
llmadb tap <target> Input tap/hold + animation pause + settled UI dump ~1.2–2.4 s

Installation

Requires adb on your system PATH (or set via the LLMADB_ADB environment variable).

From PyPI (Python 3.9+)

pip install llm-adb

# Or install globally in an isolated environment via pipx
pipx install llm-adb

Standalone Binaries

Prebuilt standalone executables (llmadb) for Windows (x86_64, arm64), Linux (x86_64, arm64), and macOS (arm64, x86_64) are available on the Releases page - no Python runtime required.

From Source

git clone https://github.com/codefl0w/llm-adb.git
cd llm-adb
pip install .

# Editable install with test dependencies
pip install -e ".[dev]"

Verify installation:

llmadb --version
llmadb devices

Quick Start for LLM Agents

Add the output of llmadb --help-llm to your agent's system prompt or CLAUDE.md / AGENTS.md, or instruct your agent to run llmadb --help-llm at the start of a session:

llmadb --help-llm

Typical Agent Workflow

# 1. Inspect connected device and status
llmadb devices
llmadb hardware
llmadb status

# 2. Dump compact UI hierarchy
llmadb ui
# Output:
# screen 1080x2400 app=com.google.android.apps.nexuslauncher rot=0 snap=1
# 1 text "Search" id=search_box @540,2180
# 2 text "YouTube" @200,1450
# 3 text "Chrome" @540,1450

# 3. Tap or long-press by element index, text, resource-id, or coordinates
llmadb tap 3                              # Tap element #3 (Chrome) and print settled UI
llmadb tap --text "YouTube" --hold        # Long-press YouTube (default 500ms) to open shortcut menu
llmadb tap --text "YouTube" --hold 1000   # Long-press YouTube for 1000ms

# 4. Type into focused input field
llmadb type "https://example.com" --clear --enter

# 5. Capture screenshot with 100px device coordinate grid (for WebViews/Canvas/games)
llmadb screen

# 6. Toggle or set screen rotation
llmadb rotate                             # Toggle between portrait (0) and landscape (1)
llmadb rotate portrait                    # Explicitly lock portrait

# 7. Clean up cached screenshots and snapshots
llmadb clear-cache

Command Reference

Global Options

llmadb [--device SERIAL] [--timeout SECONDS] [--max-lines N] <command> [args...]
llmadb -- <adb-command> [args...]
  • -s, --device SERIAL: Target device serial (also reads LLMADB_SERIAL or ANDROID_SERIAL).
  • --timeout SECONDS: Command execution timeout in seconds.
  • --max-lines N: Truncate stdout to N lines (appends [truncated: M more lines]).
  • --help-llm: Print compact rules and command cheat-sheet for LLM context windows.
  • -h, --help: Show CLI help.
  • -v, --version: Show version.

Device & System State

llmadb devices

List connected devices in clean TSV format (serial, state, model, transport).

llmadb hardware [--json]

Single-call batched hardware specification report: manufacturer, model, Android version, SDK level, security patch, CPU ABIs, SoC/platform, physical and effective resolution, DPI, RAM (total_mb, available_mb), /data storage, SELinux state, and root availability. Outputs compact key: value lines by default; pass --json for structured JSON.

llmadb status [--json]

Single-call device connectivity and power status report:

  • battery: percentage and charging state (e.g. 85% (charging, ac))
  • wifi: enabled/connected state and SSID
  • cellular: SIM/radio state and network operator
  • bluetooth, nfc, airplane_mode: on / off

llmadb current

Report foreground package/activity, display rotation (0–3), and software keyboard state (visible or hidden):

com.android.chrome/com.google.android.apps.chrome.Main rot=0 keyboard=hidden

llmadb rotate [0|1|portrait|landscape|auto]

Control screen orientation and return the current rotation state (rotation: 0 (portrait) or rotation: 1 (landscape)):

  • llmadb rotate (no args): Check current rotation and toggle to the opposite orientation (0 <-> 1), disabling accelerometer_rotation.
  • llmadb rotate 0 / llmadb rotate portrait: Lock to portrait (user_rotation=0).
  • llmadb rotate 1 / llmadb rotate landscape: Lock to landscape (user_rotation=1).
  • llmadb rotate auto: Re-enable sensor auto-rotation (accelerometer_rotation=1).

llmadb clear-cache [--all]

Delete cached screenshots (screens/*.png), UI snapshots (snap.json), and logcat marks stored in the host user cache directory (~/.cache/llmadb or %LOCALAPPDATA%\llmadb\Cache). By default clears the active device's cache; pass --all to purge all device caches.


Perception (ui & screen)

llmadb ui [--full] [--bounds] [--compressed] [--raw]

Dump and reduce the current accessibility hierarchy into indexed interactive/labeled elements:

screen 1080x2400 app=com.android.settings rot=0 snap=4
! overlay window="NotificationShade" bounds=[42,96][1038,348] @540,222
1 text "Network & internet" @412,560
2 switch "Wi-Fi" id=switchWidget [checked] @948,560
  • --full: Do not truncate long element labels at 120 characters.
  • --bounds: Display full [x1,y1][x2,y2] bounding boxes instead of @cx,cy centers.
  • --compressed: Pass --compressed to uiautomator dump.
  • --raw: Output raw unparsed XML for debugging.

llmadb screen [options]

Capture a downscaled screenshot with a 100px device-coordinate grid by default:

  • --grid N: Draw device-pixel coordinate grid every N pixels (default: 100).
  • --no-grid: Disable grid overlay and draw numbered element bounding boxes from the UI tree instead.
  • --max-edge N: Maximum long-edge resolution in pixels (default: 960).
  • --element N: Crop and 2x-upscale around element index N from the latest snapshot.
  • --region x1,y1,x2,y2: Crop and 2x-upscale a specific device-coordinate rectangle.
  • --raw: Save downscaled screenshot without any annotations or UI dump.
  • --no-ui: Skip refreshing the UI snapshot before annotating.

Interaction (tap, type, swipe, key, wait-for)

All interaction commands wait for the UI to settle after execution and print the updated ui output automatically (pass --no-ui to suppress, or --diff to print only + added and - removed elements).

llmadb tap <target> [--hold [TIME]] [--snap N] [--diff] [--no-ui] [--wait-settle]

Tap or long-press a target element:

  • llmadb tap 5: Tap element #5 from the latest cached snapshot.
  • llmadb tap --text "Sign in": Match element by exact text first, then case-insensitive substring.
  • llmadb tap --id login_button: Match element by resource ID (short_id or full pkg:id/name).
  • llmadb tap 540,1200: Tap explicit device pixel coordinates (always device space, never scaled image space).
  • --hold [TIME]: Perform a long-press at the target coordinates (input swipe x y x y <ms>). TIME is optional and specified in milliseconds (defaults to 500 ms when omitted).
  • --snap N: Guard against stale state by failing if the cached snapshot ID is not N.
  • --wait-settle: Poll up to 3s for animations to finish before resolving --text or --id.

llmadb type "<text>" [--clear] [--enter] [--diff] [--no-ui]

Type ASCII text into the focused input field with automatic shell/metacharacter escaping:

  • --clear: Select all (CTRL+A) and delete existing text in the focused field before typing.
  • --enter: Send KEYCODE_ENTER (66) after typing.

llmadb swipe <up|down|left|right|x1,y1 x2,y2> [--dist F] [--dur MS] [--diff] [--no-ui]

Perform a directional or coordinate swipe gesture. Directional swipes automatically clamp start/end coordinates away from Android 10–17 system gesture insets.

llmadb key <name|code> [--diff] [--no-ui]

Send a hardware or navigation keyevent (home, back, enter, tab, menu, power, volup, voldown, recents, delete, or numeric Android keycode).

llmadb wait-for <--text X|--id Y|--gone X> [--timeout S]

Poll the UI hierarchy every 500ms until matching text/ID appears or --gone text disappears (default timeout: 10s).


App Management & Logcat

llmadb list apps [user|system|vendor|product|all] [--grep S] [--disabled] [--enabled]

List installed packages classified by partition path (default scope: user).

llmadb info <pkg>

Condensed package metadata: version name/code, minSdk/targetSdk, installer, debuggable flag, enabled state, running status with PID, main launcher component, and granted/denied runtime permissions.

llmadb launch <pkg> | llmadb stop <pkg> | llmadb clear <pkg>

Start an app's main launcher activity, force-stop a package (am force-stop), or wipe app data (pm clear).

llmadb mark & llmadb log [--pkg P] [--level V|D|I|W|E|F] [-n 200] [--since-mark] [--crash] [--full]

  • llmadb mark: Record the device's current timestamp in the host cache.
  • llmadb log: Query logcat with consecutive duplicate collapsing (... x37), PID filtering (--pkg), minimum severity (--level, default W), --since-mark filtering, and --crash buffer inspection.

Transparent adb Passthrough

Any subcommand not listed above is forwarded directly to adb with automatic device serial resolution:

llmadb shell getprop ro.build.version.release
llmadb install -r app-debug.apk
llmadb pull /sdcard/Download/report.json .
llmadb -- devices   # Force raw 'adb devices' via '--' escape hatch

Structured Error Model & Exit Codes

Errors are written exclusively to stderr in a single-line machine-parseable format with an actionable recovery hint:

error: <CODE> <message> | hint: <recovery hint>
Exit Code Error Code(s) Meaning
0 - Success
1 E_GENERIC Unexpected internal error
2 E_USAGE, E_UNSUPPORTED Invalid CLI arguments or unsupported input (e.g., non-ASCII type)
3 E_NO_DEVICE, E_MULTI_DEVICE No device connected, or multiple devices connected without -s
4 E_DEVICE_STATE Device is unauthorized or offline
5 E_TIMEOUT Command or wait-for condition timed out
6 E_NOT_FOUND, E_AMBIGUOUS Target UI element or package not found, or multiple elements matched
7 E_SECURE_OR_EMPTY FLAG_SECURE window or empty accessibility hierarchy
8 E_ADB Underlying adb binary missing or failed

Running Tests

pytest

License

See LICENSE for details.

Donate

If my tools have been useful to you, please consider supporting their development via Buy Me a Coffee or GitHub Sponsors.

yellow-button

Metadata

Release files for llm-adb 0.1.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for llm-adb 0.1.1
File Size Uploaded Provenance Actions
llm_adb-0.1.1.tar.gz 81.9 kB With provenance Details for llm_adb-0.1.1.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for llm-adb 0.1.1
File Interpreter ABI Platform Actions
llm_adb-0.1.1-py3-none-any.whl Python 3 none any Details for llm_adb-0.1.1-py3-none-any.whl

Total release size: 159.5 kB

Release files / llm_adb-0.1.1.tar.gz

Download URL llm_adb-0.1.1.tar.gz
Size 81.9 kB
Tags Source
SHA-256 checksum
How to use checksums
d2eac5d9c75502602311dcb90978520d31e24930d5421a98fb08a70849f65391
BLAKE2b-256 checksum
How to use checksums
c1cef5ad98128e1a34d9e3dd1bb342cd7bfd6d649bd9b73fa45c626a1a1081b8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 27, 2026.

Transparency log

Release files / llm_adb-0.1.1-py3-none-any.whl

Download URL llm_adb-0.1.1-py3-none-any.whl
Size 77.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
4cc68beb216de916cef28e64be4cba77b75037ffebc492c5633a1f349c5c3f55
BLAKE2b-256 checksum
How to use checksums
e76f1c4c01d09676092d33ead5efadc9343877d9a7e6f3cfbd7da6b173fe704f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 27, 2026.

Transparency log

Security for llm-adb 0.1.1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for llm_adb-0.1.1.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 27, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1.1 This release

2 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page