looktap v0.2.1

Agents

Agent guide (skill)

looktap drives iPhone and Android devices: simulators, emulators and real phones. Every command is one short shell call that prints a few lines of plain text. Nothing is installed on simulators, emulators or Android devices; a real iPhone gets a small test runner. The helper starts on first use.

Quick start

# check the toolchain and see what's booted
looktap doctor
# start the app (id from --app or looktap.config.json)
looktap launch com.example.myapp --ls
# act by label or by @ref from the last screen read, and read the new screen in the same call
looktap tap "Sign in" --ls
looktap fill "Email" sam@example.com --ls
looktap tap @8 --ls
# wait for what the next screen should show, instead of sleeping
looktap wait "Welcome"
# screenshot (only open it when you need to see layout or colours)
looktap shot home --scale 0.5

The loop

Look, act, read the result. ls prints one row per element:

@1   Button           16, 285 358x54  General
@2   Button           16, 339 358x54  Accessibility
@3   TextField        33, 773 324x38  Search  = Search

The columns are: ref, type, x,y, width×height (iOS points / Android dp), label, and = value for fields.

Add --ls to an action and it prints the screen once it has settled, so you don't need a separate ls. It works on tap, longpress, zoom, tapxy, fill, type, key, hidekb, swipe, back, open, launch, bio, rotate and scrollto. It waits for the screen to change (up to 1.5 s, 6 s for launch/open), then for it to stop changing.

--ls stops at a loading skeleton too. If it shows a heading but none of the content, run looktap wait "<text you expect>" rather than acting on the placeholder.

Commands

Look

looktap ls
# include elements without a label
looktap ls --all
# structured: {screen, elements: [{ref, label, type, x, y, w, h, value}]}
looktap ls --json
# until it's on screen (10 s by default; --wait 30 for longer), or until it's gone
looktap wait "Welcome"
looktap wait "Loading" --gone
# swipe until it's fully on screen; fails at the end of the list
looktap scrollto "Privacy & Security"
looktap scrollto "General" --up

Tap and press

# a label: exact first, else the one label that starts with / contains it (ambiguous is an error)
looktap tap "General"
looktap tap "Messages" --exact
# a row from the last ls on this device
looktap tap @7
# a point, in the units ls prints; for things ls doesn't list
looktap tapxy 205 874
# hold (default 800 ms): context menus, drag handles, edit modes
looktap longpress "Photo"
looktap longpress @4 1500
looktap longpress 120 470
# two-finger pinch around the centre or a point; --scale is how far the fingers travel (default 2.5)
looktap zoom in
looktap zoom out 200 400 --scale 4
# Android: system Back · iOS: the navigation bar's back button
looktap back

Type

# focus the field, clear it, type; empty text just clears
looktap fill "Email" sam@example.com
looktap fill @4 ""
# into the focused field
looktap type "@example.com"
# return escape delete tab space; Android also back home KEYCODE_*; iOS also selectall paste
looktap key return
looktap key selectall delete
# dismiss the keyboard; exits 2 if it's still up
looktap hidekb

Swipe and navigate

# scroll down: the finger moves up (optional 5th argument: duration in ms)
looktap swipe 200 700 200 250
# deep link
looktap open "myapp://orders/42"
# (re)start the app
looktap launch
looktap launch com.example.myapp
# Face ID / fingerprint
looktap bio match
looktap bio nomatch

Screenshots and video

# saves <out>/<name>.png and prints the path; --scale 0.5 is a quarter of the image tokens
looktap shot checkout
looktap shot checkout --scale 0.5
# Android emulators capture FLAG_SECURE screens by default; --plain shows them black, as on a device
looktap shot payment --plain
# a frame each time the screen changes, for 3 s; duplicates dropped (start it in the background)
looktap burst ./frames 3 &
# a video of everything between start and stop (Android: at most 3 min)
looktap record start checkout
looktap record stop

Logs and crashes

# the app's log since your last `logs` (first time: the last minute); at most 80 lines, newest kept
looktap logs
looktap logs --errors
looktap logs --grep checkout
looktap logs --since 5m --lines 200
# iOS: keep Apple-framework messages too
looktap logs --all
# crashes, ANRs and low-memory kills since your last `crashes` (first time: the last hour)
looktap crashes
looktap crashes com.example.myapp --since 1h
# which app is in front, and whether the given one is running
looktap app
looktap app com.example.myapp

App state

# a simulator .app or an .apk (keeps the app's data; --grant: every runtime permission); prints the app id
looktap install build/MyApp.app
looktap install app-debug.apk --grant
looktap uninstall com.example.myapp
# as if freshly installed: data and permissions cleared (iOS keeps the keychain)
looktap reset com.example.myapp
# camera microphone location location-always photos contacts calendar notifications motion all
# (Android also android.permission.*)
looktap permission grant location com.example.myapp
looktap permission revoke photos com.example.myapp
looktap permission reset camera com.example.myapp

Conditions

# simulated GPS (Android: emulators); `clear` on iOS
looktap location 51.5072 -0.1276
looktap location clear
# no argument prints the current value
looktap appearance dark
looktap appearance light
# xs s m l xl xxl xxxl ax1…ax5 (default l)
looktap textsize ax2
# 9:41, full battery and signal, for screenshots; `live` to undo
looktap statusbar clean
looktap statusbar live
# portrait landscape left right upsidedown; ls, taps and shots follow the turned screen
looktap rotate landscape --ls
# Android only: airplane mode
looktap network offline
looktap network online
# iOS only: a remote notification; plain text, '{json}', or a .json file
looktap push com.example.myapp "Your order has shipped"
looktap push com.example.myapp '{"aps":{"alert":"Hi"},"orderId":7}'

Batch

# several steps in one call; stops at the first failure and names it
looktap run 'tap General; tap About; wait "iOS Version"; ls'
# one step per line from stdin, # for comments
looktap run - < steps.txt

Devices and setup

looktap devices
looktap doctor
# start the helper ahead of time (Android: also adb reverse tcp:8081 for Metro); teardown undoes it
looktap setup
looktap teardown
# serve the same commands over MCP, for clients without a shell; --config prints a client config
looktap mcp --config
# print this guide, or install it to ~/.claude/skills/looktap/SKILL.md
looktap skill --install

Options and config

# with more than one booted device, name the platform (-p, --platform) and/or the device (-d, --device)
looktap -p android ls
looktap -p ios -d 42E41FA7-EA40-45C1-8C6E-13A70BAF1FD6 ls
# where screenshots and videos go (-o, --out; default ./shots)
looktap -o out/run1 shot home
# the app for launch / open / logs / crashes / reset …
looktap --app com.example.myapp launch
# how long tap / fill / back wait for their target (default 3 s)
looktap --wait 10 tap "Continue"
# every command and option: -h or --help · the version: -v or --version
looktap --help
looktap --version

Put the app id in looktap.config.json at the repo root, so you don't have to pass it every time. looktap uses the nearest one, walking up from the current folder:

{ "out": "shots", "wait": 3, "ios": { "app": "com.example.myapp" }, "android": { "app": "com.example.myapp" } }

Command-line options beat LOOKTAP_* environment variables, which beat the config file. Passing both -p and -d makes every command about 0.2 s faster.

Exit codes: 0 OK · 2 usage or not found (bad arguments, no such element, no device) · 1 anything else. On exit 2, read the message, run ls, adjust. Don't retry the same command blindly.

Targeting elements

Example: sign in and check the home screen

looktap launch --ls
looktap fill "Email" sam@example.com
looktap fill "Password" "$TEST_PASSWORD"
looktap tap "Sign in"
looktap wait "Home"
looktap shot home --scale 0.5

Only with a test account the user gave you. Never type real credentials (see Rules).

Example: reproduce a bug and collect the evidence

looktap open "myapp://cart" --ls
looktap tap "Pay" --ls
# right after the step that misbehaved: only what's new is shown
looktap logs --errors
# "warning: … is no longer running" after an action means it crashed or was killed
looktap crashes
looktap shot pay__error

On iOS the full crash report is written up to a minute later; run crashes again. On Android, LOW_MEMORY means the system killed the app, which isn't a bug in it.

Example: screenshots in dark mode with large text

looktap statusbar clean
looktap appearance dark
looktap textsize ax2
looktap launch --ls
looktap shot home__dark_ax2
# set back what you changed
looktap textsize l
looktap appearance light
looktap statusbar live

Example: start from a clean install

looktap install build/MyApp.app
looktap reset com.example.myapp
looktap permission grant location com.example.myapp
looktap launch --ls

Example: catch a toast or a spinner

looktap burst ./frames 5 &
looktap swipe 200 250 200 700
wait

Then look at the few frames that matter, not all of them.

Rules

Installation

If looktap isn't on the PATH, use npx @looktap/cli in every command (or npx -y @looktap/cli to skip the prompt). Installing a global package may need the user's approval:

npm install -g @looktap/cli
looktap doctor

Needs Node 18+. iOS: macOS with Xcode and a booted simulator. Android: adb, with an emulator or a device.

Generated from skills/looktap/SKILL.md. Edit it there.