Tapium
A single-file, AI-agent-friendly controller for driving a real Android device (or emulator) over USB/ADB — built for letting an LLM agent (or any script) operate an app the way a human tester would: read the screen, tap things, type things, wait for things to load.
Built on top of uiautomator2.
Why
Most UI-automation tooling is built for deterministic test scripts: you know in advance exactly which element you want, and you write a selector for it. Driving a device from an LLM agent is different — the agent needs to see the screen as structured data, decide what to do, act, and see the result, in a tight loop, with minimal round-trips.
tapium.py is a thin JSON-in/JSON-out CLI wrapping uiautomator2 with
that loop in mind:
- Every action returns a compact list of on-screen elements (text, content-description, bounds, clickable/scrollable flags) — enough for an agent to decide its next move without a screenshot.
- Every mutating action waits for the UI to settle before returning, so the response already reflects the new screen — no extra "dump" call needed in the common case.
- Actions are addressed by visible text/description first, with explicit coordinate and structured-selector fallbacks for elements that don't expose text (SVGs, canvases, custom views).
Install
pip install tapium
tapium setup
tapium setup checks Python, adb, and a connected device, tells you
exactly how to install anything missing (no Android Studio — just the
~10MB platform-tools binary), and installs the on-device automation agent.
Run tapium doctor any time afterward to re-check the environment without
reinstalling anything.
Full first-run walkthrough, including enabling USB debugging on the phone: see AGENTS.md.
Requires:
- A device with USB debugging enabled, connected and authorized (
adb devicesshould list it) - Python 3.8+
Installing from this repo instead of PyPI: pip install -e ., or the
older pip install -r requirements.txt + running tapium.py directly
still works identically.
Usage
tapium '{"action":"dump_ui"}'
tapium '{"action":"tap","text":"Sign in"}'
tapium '{"action":"input_text","field":"Email","text":"hello@example.com"}'
tapium '{"action":"swipe","direction":"up"}'
tapium '{"action":"wait_for","text":"Welcome back","timeout":15}'
(Running from source instead of the installed command: swap tapium for
python tapium.py in the examples above.)
Every call prints one JSON object to stdout and exits 0 on success
("ok": true) or 1 on failure ("ok": false, "error": "...").
See the module docstring in tapium.py for the full action reference,
and examples/ for a worked example of wiring this into an agent loop.
Pairing with a backend API
api.py shows the intended pattern for combining tapium.py with a
backend API client in agent-driven testing — using the API for setup/
verification that's slow or flaky to reach purely through the UI (seed an
account, check a record landed, tear down test data), while
tapium.py drives the app itself.
Every request in api.py is mocked — there's no real backend wired
up, just an in-memory store and canned responses, so you can run it
out of the box and see the shape of the integration:
python3 api.py '{"command":"get_user","id":"user_123","env":"staging"}'
python3 api.py '{"command":"create_user","email":"demo@example.com","env":"staging"}'
python3 api.py '{"command":"list_orders","user_id":"user_123","env":"staging"}'
To point this at a real API: replace _mock_request() with actual HTTP
calls (e.g. via requests) against env["base_url"], authenticated with
env["token"]. Copy environments.example.json to environments.json
and fill in real tokens — that file is gitignored so secrets never get
committed.
Design notes
- No app-specific defaults. Package names, landmark screen text, and APK paths are always passed in by the caller — this tool knows nothing about any particular app.
- Text/description first, coordinates as fallback. Tapping by visible
label is far more robust to minor layout shifts than fixed coordinates,
but
tapandinput_sequenceboth support coordinate fallbacks for the cases where an element genuinely has no usable label. tap_selectorfor non-text elements. SVG/canvas/custom-rendered UI often has notextorcontent-descat all —tap_selectorexposes the underlying uiautomator2Selectorkwargs (className,instance,resourceId, etc.) for those cases.set_locationis necessarily a bit app-specific. Mock-location apps all have different UIs, so this action drives a fairly common "menu → search → lat/lon fields → OK → Start" shape and exposes the parts likely to need adjusting (menu_coords, package names) as arguments rather than hardcoding them. You may need to adapt the field labels for whichever mock-location app you use — see the docstring.
What this is not
This isn't a full test framework — there's no assertion library, test
runner, or reporting built in. It's the device-control layer you'd build
one on top of. If you're looking for that, this plays well alongside
pytest (treat each action's "ok" field and "screen" contents as your
assertions) or an agent framework that can shell out and parse JSON.
Testing
The test suite runs against a fake in-memory device — no real Android device or emulator required:
pip install -r requirements-dev.txt
pytest tests/ -v
See CONTRIBUTING.md for the full development workflow.
Contributing
Issues and PRs welcome — see CONTRIBUTING.md.
License
MIT — see LICENSE.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file tapium-0.1.0.tar.gz.
File metadata
- Download URL: tapium-0.1.0.tar.gz
- Upload date:
- Size: 20.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
dbe80428cd2a102e698aec7eaffc35f4c743177f0511f21c7168e7de48555f3c
|
|
| MD5 |
3a7ece8d4760eed697c612d413f6813e
|
|
| BLAKE2b-256 |
c578e6d399d9e7581083ccf3c9b1f17f0fa8778c3df0be19a895d8a9a678e4ec
|
Provenance
The following attestation bundles were made for tapium-0.1.0.tar.gz:
Publisher:
publish.yml on alesav/tapium
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
tapium-0.1.0.tar.gz -
Subject digest:
dbe80428cd2a102e698aec7eaffc35f4c743177f0511f21c7168e7de48555f3c - Sigstore transparency entry: 2219983220
- Sigstore integration time:
-
Permalink:
alesav/tapium@df2a8f7e177878e8373e6740bb55b66223508d03 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/alesav
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@df2a8f7e177878e8373e6740bb55b66223508d03 -
Trigger Event:
push
-
Statement type:
File details
Details for the file tapium-0.1.0-py3-none-any.whl.
File metadata
- Download URL: tapium-0.1.0-py3-none-any.whl
- Upload date:
- Size: 17.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1fc2f9f7a2a6189f2fab08d9cb99627a054dd3fefa639422c8d26586335c3665
|
|
| MD5 |
c70748112c17cc2e949cb7b082c7fc72
|
|
| BLAKE2b-256 |
3706ba761a52a1bbfe3c7436cf7c4f38c64f3f0ad49659e709c3283f34b700fd
|
Provenance
The following attestation bundles were made for tapium-0.1.0-py3-none-any.whl:
Publisher:
publish.yml on alesav/tapium
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
tapium-0.1.0-py3-none-any.whl -
Subject digest:
1fc2f9f7a2a6189f2fab08d9cb99627a054dd3fefa639422c8d26586335c3665 - Sigstore transparency entry: 2219983263
- Sigstore integration time:
-
Permalink:
alesav/tapium@df2a8f7e177878e8373e6740bb55b66223508d03 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/alesav
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@df2a8f7e177878e8373e6740bb55b66223508d03 -
Trigger Event:
push
-
Statement type: