Agent skill

Verify On Device

by woocommerce in woocommerce/woocommerce-android

Build, install, and visually verify the app on an Android emulator or device.

GPL-2.0Auto-check: notesMobile

Install Verify On Device

skills CLI
$ npx skills add woocommerce/woocommerce-android --skill verify-on-device -a claude-code

Project install by default; add -g for ~/.claude/skills/.

GitHub CLI
$ gh skill install woocommerce/woocommerce-android verify-on-device --agent claude-code

Project scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).

Manual copy
$ git clone --depth 1 https://github.com/woocommerce/woocommerce-android.git skills-src && mkdir -p .claude/skills && cp -r skills-src/.agents/skills/verify-on-device .claude/skills/verify-on-device && rm -rf skills-src

Use ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.

Claude Code skills documentation · loads skills from .claude/skills/

Facts

Skill name
verify-on-device
GitHub stars
319
Token cost
~10k tokens
SKILL.md length
4,287 words
Files
9 (incl. references)
Skills in repo
8
Repo updated
First seen
Licence
GPL-2.0

At a glance

Build, install, and visually verify the app on an Android emulator or device.

  • Works in 12 steps: Provision an Emulator (Optional,… → Discover Devices → Prepare the Device → …
  • Tasks that involve Mobile testing and debugging
  • SKILL.md covers Detect the Android CLI Once…, Verification Status of…, Critical Rule: Default to Main… and Critical Rule: Always Restart…, plus 8 more sections
  • Calls adb

What it does

Verify On Device is an agent skill from woocommerce/woocommerce-android. Build, install, and visually verify the app on an Android emulator or device. Uses the Android CLI for agents (android) when available with a full mobile-mcp/adb fallback.

Its SKILL.md is about 10k tokens, which your agent loads only when the skill is triggered. The skill folder holds 9 other files, including reference files (for example `references/agent-auto-login.md`, `references/main-app-dashboard.md` and `references/main-app-login.md`).

It sits in Mobile, covering Mobile testing and debugging. It works with Android, Model Context Protocol and WooCommerce. The repository describes itself as: WooCommerce Android app. The licence is GPL-2.0.

When your agent uses it

  • Tasks that involve Mobile testing and debugging

Example prompts

  • “/verify-on-device”

Requirements

  • Node.js
  • Pre-approved tools (allowed-tools): Bash, Read, Grep, Glob, mcp__mobile-mcp__*

Workflow steps

12 steps, taken from the step headings in SKILL.md.

  1. Provision an Emulator (Optional, macOS/Linux only — Experimental)
  2. Discover Devices
  3. Prepare the Device
  4. Disable LeakCanary
  5. Build the Debug APK
  6. Install the APK
  7. Set Up API Mocks (Optional)
  8. Restart and Launch the App
  9. Handle Authentication and Post-Launch Dialogs
  10. Start Screen Recording (Optional)
  11. Navigate and Verify
  12. Stop Recording and Save Evidence

What it can do on your machine

Read from SKILL.md and the folder at commit 0fb14b0. It shows what the files ask for, not the result of running them.

  • Tool permissions

    Pre-approves these tools, so the agent can use them without asking each time:

    • Bash
    • Read
    • Grep
    • Glob
    • mcp__mobile-mcp__*

    From allowed-tools in the SKILL.md frontmatter.

  • Runs code

    Shell commands in SKILL.md call:

    • adb

    From the folder's file list and the shell code blocks in SKILL.md.

  • Network

    No URLs in SKILL.md.

    From URLs in SKILL.md, links to its own repository left out.

  • Credentials

    Names no API keys, tokens, secrets or passwords.

    From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.

Context cost

Verify On Device loads about 10k tokens when it runs, and up to ~20k if it reads all its reference files. Until then it costs about 47 tokens; SKILL.md has 4,287 words of instructions outside code blocks.

Always · name and description, kept in context so the agent knows when to use it
~47
When it runs · the whole SKILL.md, loaded when a task matches
~10k
With references · SKILL.md plus every file in references/, read only if the agent opens them
~20k

Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.

Safety

Auto-check: notes

The automated check noted patterns worth knowing about, such as sudo or a known installer.

  • NotePre-approves every shell command (allowed-tools: Bash)SKILL.md
    allowed-tools: Bash, Read, Grep, Glob, mcp__mobile-mcp__*

Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.

SKILL.md

The full file from woocommerce/woocommerce-android at commit 0fb14b0, republished under its GPL-2.0 licence (© woocommerce). 4,287 words, ~10,124 tokens.

Download SKILL.mdSave it as .claude/skills/verify-on-device/SKILL.md (or your agent's skills folder). This skill also uses 8 other files; get the full folder from GitHub.
name
verify-on-device
description
Build, install, and visually verify the app on an Android emulator or device. Uses the Android CLI for agents (android) when available with a full mobile-mcp/adb fallback.
allowed-tools
Bash, Read, Grep, Glob, mcp__mobile-mcp__*
user-invocable
true
context
fork

Verify on Device

Build, install, and visually verify the app on an Android emulator or physical device. The skill prefers the Android CLI for agents (android) when installed and falls back to mobile-mcp + adb otherwise.

Prerequisites: Node.js v22+, Android SDK with platform-tools, and an emulator or device to target (step 0 can provision one when the Android CLI is installed).

Optional: Google's Android CLI for agents (android). When present, the skill uses android run for combined install+launch, android layout --diff for low-token screen-transition polling, and android docs for platform-API lookups. If not installed, every step falls back to the mobile-mcp / adb path with no behavior change.

Detect the Android CLI Once Per Session

Run this probe once at the start of a verification task and cache the result. Every CLI-based block in this skill is gated on USE_ANDROID_CLI=1.

The probe validates that android on PATH is Google's agent CLI (prints a semver like 0.7.15232955) and not the deprecated Android SDK android tool from tools/, which shadows it whenever the legacy SDK tools dir is on PATH. The probe only detects — it does not mutate PATH or create symlinks, since an in-script export PATH would not survive subsequent shell invocations in this skill. If android is missing, shadowed, or broken, it sets USE_ANDROID_CLI=0 and prints a hint pointing at the canonical install location (~/.android/bin/android-cli) when present. Exact PATH/symlink fix depends on the user's environment — the goal is to make android --version resolve to the agent CLI; the user applies the fix once in their shell rc so it persists.

The probe also writes USE_ANDROID_CLI to /tmp/.verify_on_device.env. Each subsequent Bash tool call starts a fresh shell, so a plain shell variable would be lost between invocations — every gated block in this skill begins by sourcing that file to restore the cached result.

bash
_android_is_agent_cli() {
  android --version 2>&1 | grep -qE '^[0-9]+\.[0-9]+\.'
}

if command -v android >/dev/null 2>&1 && _android_is_agent_cli; then
  USE_ANDROID_CLI=1
  android --version   # log for reproducibility
else
  USE_ANDROID_CLI=0
  if [ -x "$HOME/.android/bin/android-cli" ]; then
    echo 'NOTE: Agent CLI binary is at ~/.android/bin/android-cli but `android` does not resolve to it (likely missing symlink or shadowed by the legacy Android SDK tool).'
    echo 'Fix: update your PATH/symlinks until `android --version` prints a semver (e.g. symlink android-cli to a name `android` on a directory earlier in PATH than the legacy Android SDK tools), then restart the session.'
  fi
fi

# Persist for subsequent Bash invocations (shell state does not survive
# across separate Bash tool calls). Subsequent gated blocks `source` this.
echo "USE_ANDROID_CLI=$USE_ANDROID_CLI" > /tmp/.verify_on_device.env

If USE_ANDROID_CLI=0, follow the fallback blocks (labelled "Fallback") throughout this skill.

Verification Status of Agent-CLI Blocks

The USE_ANDROID_CLI=0 fallback paths in this skill (mobile-mcp + adb) have been exercised end-to-end against this repo. The USE_ANDROID_CLI=1 blocks were all re-run against agent CLI 0.7.15232955 on 2026-04-21 against this repo. Results:

CLI blockStatus
android run (step 7 install + launch)Verified — installs and launches in one call.
android layout --diff (screen-transition polling)Verified — captured the orders-list transition on a tab switch; diff JSON is a small fraction of a full layout dump. Note: --device=<device_id> was added to the documented invocation post-verification (multi-device fix); the flag is documented by the CLI but the new combination has not been re-run end-to-end.
android screen capture --annotate + screen resolve (Option B tap)Verified — both short (-a/-o) and long (--annotate/--output=…) flag forms work.
android docs search / docs fetchVerified — first invocation auto-downloads a knowledge-base zip (~one-time, a few seconds).
android emulator list (step 0 lifecycle)Partial — list runs end-to-end. create/start/stop shape confirmed via --help only; no AVD was created during verification, so step 0 is flagged Experimental in its heading.
android describeRejected. Output is multi-line plain text (not JSON, not paths-to-JSON). Requires ANDROID_HOME set; produces listings only after a build. Replaced with find in step 7.

If a CLI block fails in practice, do not assume the docs are right. Fall back to the USE_ANDROID_CLI=0 path for that step, file the discrepancy as a skill issue, and fix it in the skill before the next run.

Critical Rule: Default to Main App (Store Management)

Unless the task explicitly mentions POS, Point of Sale, or WooPos, always operate in the main app (store management) context — MainActivity with bottom navigation tabs. This applies to all workflows: creating orders, viewing products, collecting payments, etc. The main app is the default; POS is only used when specifically requested.

Critical Rule: Always Restart the App

Do NOT attempt to recover from the current screen state when you start a task. Always force-stop the app and relaunch it to start from a known state (the dashboard or POS). This avoids wasted time navigating out of unknown screens.

Restarting is not resetting. Preserve and reuse a coherent authenticated session whenever one exists. Never uninstall the app or clear its data merely to begin verification, and install APK updates without clearing app data.

bash
adb -s <device_id> shell am force-stop com.woocommerce.android.dev
adb -s <device_id> shell am start -n com.woocommerce.android.dev/com.woocommerce.android.ui.main.MainActivity

For POS tasks (only when explicitly requested):

bash
adb -s <device_id> shell am force-stop com.woocommerce.android.dev
adb -s <device_id> shell am start -n com.woocommerce.android.dev/com.woocommerce.android.ui.woopos.root.WooPosActivity

Critical Rule: Never Estimate Tap Coordinates From Raw Screenshots

NEVER estimate tap coordinates directly from a raw (un-annotated) screenshot. Screenshots are scaled down from the actual device resolution (e.g., a 1080x2400 device produces a ~480x1065 screenshot). Coordinates derived from raw screenshots will be systematically wrong.

Use one of the two workflows below. Both translate a human-readable target (an accessibility label, a visual element) into exact device-pixel coordinates — neither relies on pixel-measuring a screenshot.

Option A — Accessibility-tree workflow (default)
  1. Call mobile_list_elements_on_screen to get elements with their device-pixel coordinates
  2. Compute tap target as the center of the element's bounding rect: tap_x = x + width/2, tap_y = y + height/2
  3. Call mobile_click_on_screen_at_coordinates with those computed coordinates
  4. Call mobile_take_screenshot AFTER tapping to visually confirm the result

Only use mobile_take_screenshot for visual verification — never for deriving coordinates.

Option B — Visual-label workflow (USE_ANDROID_CLI=1)

Useful when an element lacks an accessibility label or test tag, or when you already have an annotated screenshot in context. android screen capture --annotate overlays numeric labels (#1, #2, ...) on every interactive element; android screen resolve substitutes #N placeholders in a template string with the element's device-pixel x y coordinates.

The android screen ... commands do not support --device, so use this workflow only when the CLI's default device is the same device you intend to tap.

bash
# Capture an annotated screenshot — each interactive element gets a number.
android screen capture --annotate --output=/tmp/ui.png

# Idiomatic: let resolve produce a complete `input tap X Y` command and pipe
# it straight to `adb shell`. The CLI replaces `#5` with the resolved coords.
android screen resolve --screenshot=/tmp/ui.png --string="input tap #5" \
  | adb -s <device_id> shell

# Alternative: capture just the coordinates and feed mobile-mcp's tap tool.
COORDS=$(android screen resolve --screenshot=/tmp/ui.png --string="#5")
# $COORDS is now "<x> <y>"; call mobile_click_on_screen_at_coordinates with those.

Option A remains the default — accessibility-tree coordinates are stable and don't require visual inspection. Reach for Option B when Option A does not surface the element you need.

Waiting for Screen Transitions

After every navigation action (tap, BACK press, app launch, swipe), the screen may be animating or loading data. ALWAYS follow one of the two stabilization protocols below.

Preferred: Diff-Based Polling (USE_ANDROID_CLI=1)

android layout --diff returns only the elements that changed since the last snapshot, instead of re-reading the entire accessibility tree (50-200+ elements per call). This is the single biggest token-consumption win over repeated mobile_list_elements_on_screen calls — measure on your own flow to confirm the magnitude.

Always pass --device=<device_id> to keep these calls pinned to the same device chosen in step 1; without it, android layout may target a different connected device than the one the app was launched on.

bash
# `[[:space:]]*` around the colon makes the pattern tolerant of both
# compact and pretty-printed JSON, so a stray --pretty in the chain
# doesn't silently break the grep.
TARGET='"resource-id"[[:space:]]*:[[:space:]]*"order_list_screen"'

# Baseline snapshot immediately after the action — also greppable: if the
# transition was instantaneous, the target is already on screen and every
# subsequent --diff would return empty (diffs are delta-only).
android layout --device=<device_id> --pretty --output=/tmp/layout_t0.json
if ! grep -qE "$TARGET" /tmp/layout_t0.json; then
  # Poll diffs until the expected target appears (1 second between polls).
  for i in 1 2 3 4 5; do
    android layout --device=<device_id> --diff --output=/tmp/layout_diff.json
    grep -qE "$TARGET" /tmp/layout_diff.json && break
    sleep 1
  done
  # Safety net — one full-layout read in case the target arrived between
  # two diffs but didn't change after that (so no later diff mentions it).
  android layout --device=<device_id> --pretty --output=/tmp/layout_final.json
  grep -qE "$TARGET" /tmp/layout_final.json || echo "Target not found after polling."
fi

Replace the TARGET pattern with the resource-id, Compose test tag, or content-description of the screen you expect to land on (see the WooCommerce Navigation Reference). Compose test tags surface as resource-id because testTagsAsResourceId is on, but they appear verbatim (order_list_screen) while View IDs carry the package prefix (com.woocommerce.android.dev:id/toolbar) — use whichever form the target screen actually exposes. content-description lives under a different JSON key (typically content-desc), so swap the key, not just the value.

Fallback: Repeated Layout Reads (no android CLI)
  1. Call mobile_list_elements_on_screen after the action.
  2. If the expected target element is NOT present, call mobile_list_elements_on_screen again. Each tool round-trip takes ~1-2 seconds, which provides sufficient implicit delay.
  3. Repeat up to 5 times.
  4. If after 5 attempts the expected element is still missing, take a screenshot for diagnosis and report the issue.
Guidance That Applies to Both Paths

Loading indicators to watch for:

  • Skeleton/shimmer views (animated placeholder content) — the screen is loading data, keep waiting.
  • CircularProgressIndicator or ProgressBar elements — an operation is in progress, keep waiting.
  • Empty state views with text like "No orders yet" — the screen IS loaded, just empty. Do NOT keep waiting.

When NOT to retry: If the layout (full or diff) returns the same result 3 times in a row with no change, the screen is stable. The element you want is genuinely not present — consider scrolling or navigating differently.

Timing Guidelines
ActionExpected WaitMax Attempts
App launch to dashboard3-8 seconds5
Tab navigation (bottom bar)<1 second3
Opening a detail screen1-3 seconds4
Network data load (pull to refresh)2-10 seconds8
Dialog appearance after button tap<1 second3
Keyboard appearing after field tap<1 second2

Text Input Workflow

Typing text into a field requires a specific sequence:

  1. Find the input field using mobile_list_elements_on_screen. Look for elements with type EditText, TextField, or hint text like "Search".
  2. Tap the field using mobile_click_on_screen_at_coordinates at its center to give it focus. The soft keyboard will appear.
  3. Confirm focus — call mobile_list_elements_on_screen to verify the field is focused.
  4. Type the text using mobile_type_keys. Set submit: false unless you want to press Enter after typing.
  5. Dismiss the keyboard if needed: call mobile_press_button with BACK. On Android, the first BACK press while the keyboard is visible dismisses the keyboard only — it does NOT navigate back. A second BACK press would navigate back.

Common pitfall: Calling mobile_type_keys without first tapping the input field types into whatever element last had focus (or nothing).

Search fields: The orders and products lists use a toolbar search icon. Tap the magnifying glass icon first, wait for the search field to expand, then type into the expanded field.

Handling Unexpected Dialogs

WooCommerce may show dialogs automatically on launch or during navigation. Detect and dismiss these before proceeding.

After launching the app or navigating to a new screen, call mobile_list_elements_on_screen and check for:

Dialog TypeHow to DetectHow to Dismiss
Privacy BannerElements with text "Privacy Settings" or "Save" button on a bottom sheet. This is NOT cancellable — tapping outside won't work.Tap the "Save" button.
What's New / Feature AnnouncementElement with identifier containing closeFeatureAnnouncementButton or text "Close".Tap the close button.
App Rating DialogAlertDialog with text containing "rate" or "enjoy".Tap "No Thanks" or "Remind Me Later".
Android Permission DialogElements from com.android.permissioncontroller, or text containing "Allow" / "Don't allow".Tap "Allow" for testing purposes.
SnackbarElement with identifier containing snackbar_text near the bottom of the screen.Do NOT dismiss — auto-dismisses after a few seconds. May temporarily cover bottom nav tabs; if a bottom tab tap fails, wait 3-4 seconds and retry.
Store Name DialogText "Name your store" (id: nameYourStoreDialogFragment).Tap "Save" or dismiss.
Create Test Order DialogText related to test order creation.Tap "Dismiss" or "Create".

General dialog dismissal strategy: Look for a dismiss/close/cancel button and tap it. If none visible, try mobile_press_button with BACK. If BACK doesn't work (non-cancellable dialogs), look for any actionable button ("OK", "Save", "Got it") and tap it. After dismissing, call mobile_list_elements_on_screen to confirm the dialog is gone.

Finding Elements That Require Scrolling

When mobile_list_elements_on_screen does not return the element you expect, it may be off-screen:

  1. Call mobile_list_elements_on_screen and check for the target element.
  2. If not found, call mobile_swipe_on_screen with direction up (swipe up = scroll down) from the center of the screen.
  3. Call mobile_list_elements_on_screen again.
  4. Repeat up to 10 times. If the same elements keep appearing (no new content), you have reached the bottom of the list.
  5. If still not found, try scrolling back up (direction down) or try an alternative navigation path.

Tip: To scroll within a specific scrollable container (not the full screen), use the container's center coordinates as the swipe starting point.

Working with Element Lists

mobile_list_elements_on_screen can return 50-200+ elements. To find what you need:

  • By resource identifier (most reliable): Match the identifier field -- com.woocommerce.android.dev:id/toolbar for a View, order_list_screen for a Compose test tag. Resource IDs are stable across app versions.
  • By display text: Match the element's text or label field. Useful for finding specific list items (e.g., order "#1234").
  • By position: Elements are returned in document order (top to bottom, left to right). Toolbar/status bar elements appear first, list items in visual order.

Compose vs View elements: View-based screens have stable com.woocommerce.android.dev:id/* identifiers. Compose screens expose their Modifier.testTag() values as unprefixed resource IDs (testTagsAsResourceId is enabled in both app themes), so a tagged node such as order_list_screen is matchable the same way. Compose nodes without a test tag have no resource ID at all — rely on contentDescription or display text for those.

Authentication and Session Preservation

Prefer an already coherent, authenticated app session. Upgrade/reinstall the APK in place so app data is preserved; do not call mobile_uninstall_app or pm clear unless the task explicitly requires destructive clean-state testing.

After launch, inspect the screen:

  • If the dashboard for the expected target appears, preserve and reuse that session.
  • If login is required, the target is not the expected store, or the session cannot be confirmed, invoke tools/agent-login/agent-login.sh with the target flavor, selected serial, and Android user. It uses the deterministic default profile. Add --profile <name> only when the user or task explicitly supplies that nonsecret override. Do not list, open, read, or print profile files. Report only the script's sanitized outcome.
  • On PROFILE_ERROR, ask the user to complete the one-time profile setup documented in references/agent-auto-login.md, or to log in manually on the device. Never ask for credentials in chat.

ALREADY_ACTIVE means the selected session matches the requested target and connection. A different selected store or connection returns CONFLICT; auto-login never replaces it. The dev tool assumes the configured target is connected, the account has the correct role and eligibility, and WordPress.com does not require 2FA. The app may surface store configuration errors after login. Do not run agent auto-login concurrently with manual login or another login flow; it reuses production WordPress.com and Jetpack repositories, whose global auth events are not request-correlated. Never synthesize or modify a credential profile to work around a failure, and never retry OUTCOME_UNKNOWN automatically. See references/agent-auto-login.md and load references/main-app-login.md when login is encountered.

Steps

Shortcut: If the app is already installed with a coherent session, preserve it and skip to step 6 (Set Up API Mocks) when a mock response is required.

0. Provision an Emulator (Optional, macOS/Linux only — Experimental)

Only run this step when no physical device is attached, no emulator is running, and the task requires a clean-slate device. Skip otherwise.

Status: experimental. Of the three emulator subcommands used here, only android emulator list has been exercised end-to-end against this repo. android emulator create, start, and stop were shape-confirmed via --help only — no AVD was created during PR verification. Expect to iterate on this step the first time you actually use it; if it fails, fall back to booting the emulator manually via Android Studio or emulator -avd <name> and continue from step 1.

bash
. /tmp/.verify_on_device.env  # restore USE_ANDROID_CLI from the probe step

# `android emulator` is disabled on Windows per Google's docs — detect Git
# Bash / MSYS / Cygwin and skip there. macOS and Linux both reach the `then`.
case "$(uname -s)" in MINGW*|MSYS*|CYGWIN*) IS_WINDOWS=1 ;; *) IS_WINDOWS=0 ;; esac

if [ "$USE_ANDROID_CLI" = "1" ] && [ "$IS_WINDOWS" = "0" ]; then
  # List existing AVDs; reuse one if it already fits the task.
  android emulator list

  # Create a device from a profile. The CLI only accepts --profile and
  # --list-profiles — the profile name doubles as the device name.
  android emulator create --profile=medium_phone

  # Snapshot existing serials BEFORE start so we can pin every adb call
  # to the new emulator. The moment a second device is attached, plain
  # `adb shell ...` errors with "more than one device/emulator" and the
  # boot-completed loop spins forever.
  PRE_SERIALS=$(adb devices | awk 'NR>1 && $2=="device"{print $1}' | sort -u)

  # Start the device using that profile name. `android emulator start`
  # returns once the command is issued — use `adb wait-for-device` plus a
  # boot-completed check before step 1, or `mobile_list_available_devices`
  # will race the boot sequence.
  android emulator start medium_phone

  # Identify the new serial by diffing `adb devices` (give it up to 30s
  # to register).
  for _ in $(seq 1 30); do
    POST_SERIALS=$(adb devices | awk 'NR>1 && $2=="device"{print $1}' | sort -u)
    NEW_SERIAL=$(comm -13 <(echo "$PRE_SERIALS") <(echo "$POST_SERIALS") | head -n1)
    [ -n "$NEW_SERIAL" ] && break
    sleep 1
  done

  adb -s "$NEW_SERIAL" wait-for-device
  until [ "$(adb -s "$NEW_SERIAL" shell getprop sys.boot_completed | tr -d '\r')" = "1" ]; do sleep 2; done
fi

At the end of the task, if this session created the AVD, stop it using the device serial (adb devices or android emulator list will print it):

bash
. /tmp/.verify_on_device.env  # restore USE_ANDROID_CLI from the probe step

if [ "$USE_ANDROID_CLI" = "1" ]; then
  android emulator stop <device-serial-number>
fi

Fallback (no android CLI): continue to step 1 and assume a running device, as before.

1. Discover Devices

Call mobile_list_available_devices. If multiple devices are returned, ask the user which to use. If none are found, instruct the user to boot an emulator or connect a device.

2. Prepare the Device

Run these ADB commands to configure the device for reliable agent interaction:

bash
# Disable animations (prevents flaky element detection during transitions)
adb -s <device_id> shell settings put global animator_duration_scale 0
adb -s <device_id> shell settings put global transition_animation_scale 0
adb -s <device_id> shell settings put global window_animation_scale 0
3. Disable LeakCanary

LeakCanary shows leak detection notifications and dialogs that interfere with agent verification. Disable it before building by setting the flag in developer.properties (a git-ignored local config file):

bash
# Ensure developer.properties exists and has LeakCanary disabled
touch developer.properties
grep -q "enable_leak_canary" developer.properties && sed -i '' 's/enable_leak_canary=.*/enable_leak_canary=false/' developer.properties || echo "enable_leak_canary=false" >> developer.properties
4. Build the Debug APK
./gradlew assembleWasabiDebug

If the build fails with "SDK location not found", check that local.properties exists and contains the sdk.dir path. See the Error Recovery section below.

5. Install the APK

Preferred path (USE_ANDROID_CLI=1): skip this step. The single android run call in step 7 installs and launches in one shot — APK resolution and the install itself happen there.

Both paths must install in place without clearing app data. Do not uninstall first.

Fallback (no android CLI): install via mobile-mcp; its install operation must replace the APK while preserving the existing app data.

Use mobile_install_app with:

  • path: WooCommerce/build/outputs/apk/wasabi/debug/WooCommerce-wasabi-debug.apk

Optionally call mobile_list_apps first to check if the app is already installed.

Show full SKILL.md (1,692 more words)Show less
6. Set Up API Mocks (Optional)

If the user requests verification of a specific scenario (error states, empty data, custom responses), set up ApiFaker mock endpoints before launching the app. See the "API Mocking with ApiFaker" section and docs/api-faker-adb.md for commands and workflow.

7. Restart and Launch the App

Always force-stop the app first, then launch fresh. This ensures a clean starting state regardless of what screen was previously active — the "Always Restart the App" rule above applies to both paths.

Preferred path (USE_ANDROID_CLI=1, full flow): locate the APK produced by step 4, then one android run call reinstalls and launches the exact Activity. android run has no "launch-only" mode — it always reinstalls. When the app is already installed and the build hasn't changed (shortcut flow from the top of "Steps"), use the launch-only form further below to skip the reinstall — the CLI does not offer a launch-only equivalent, so both no-CLI users and CLI shortcut users land on the same am start block.

bash
# 1. Resolve the APK path. `android describe` was evaluated for this purpose but
#    its output is multi-line plain text (not JSON/paths-to-JSON) and the
#    underlying Gradle task requires ANDROID_HOME; a plain `find` is simpler and
#    works whether the CLI is installed or not.
APK=$(find WooCommerce/build -type f -name 'WooCommerce-wasabi-debug.apk' | head -n1)

# Persist for the POS variant below (each Bash tool call is a fresh shell, so
# a plain $APK does not survive between separate code blocks). %q shell-quotes
# the value so a path with spaces or other special chars survives sourcing.
printf 'APK=%q\n' "$APK" >> /tmp/.verify_on_device.env

# 2. Force-stop — android run does not guarantee a cold start.
adb -s <device_id> shell am force-stop com.woocommerce.android.dev

# 3. Combined install + launch.
android run --apks="$APK" \
  --activity=com.woocommerce.android.ui.main.MainActivity \
  --device=<device_id>

For POS tasks (only when explicitly requested) — sources $APK from the block above:

bash
. /tmp/.verify_on_device.env  # restore $APK persisted by the main launch block

adb -s <device_id> shell am force-stop com.woocommerce.android.dev
android run --apks="$APK" \
  --activity=com.woocommerce.android.ui.woopos.root.WooPosActivity \
  --device=<device_id>

Launch-only form (no reinstall): force-stop + am start. Use this when (a) the agent CLI is not available, or (b) the agent CLI is available but the app is already installed and the build hasn't changed (the CLI shortcut path).

bash
adb -s <device_id> shell am force-stop com.woocommerce.android.dev
adb -s <device_id> shell am start -n com.woocommerce.android.dev/com.woocommerce.android.ui.main.MainActivity

Do NOT use mobile_launch_app — it launches the default launcher intent which may not always resolve to MainActivity.

For POS (only when explicitly requested): Launch directly into POS with:

bash
adb -s <device_id> shell am force-stop com.woocommerce.android.dev
adb -s <device_id> shell am start -n com.woocommerce.android.dev/com.woocommerce.android.ui.woopos.root.WooPosActivity
8. Handle Authentication and Post-Launch Dialogs

Call mobile_list_elements_on_screen to check what appeared. If login is shown, follow "Authentication and Session Preservation" and references/agent-auto-login.md.

If a dialog or overlay is blocking the main UI, dismiss it using the guidance in "Handling Unexpected Dialogs" above. Repeat until you reach the dashboard or the expected screen.

9. Start Screen Recording (Optional)

If the user requests a recording or demo video, start an ADB screen recording before navigating:

bash
# Start recording in the background (max 180s, Android hard limit)
adb -s <device_id> shell "screenrecord --size 720x1280 /sdcard/_agent_rec.mp4" &

Use --size 720x1280 to keep the file small. The recording runs in the background while you perform navigation steps. See the Screen Recording section below for full details.

10. Navigate and Verify

Navigate as needed per the user's request. After each navigation action:

  1. Wait for the screen to stabilize (see "Waiting for Screen Transitions").
  2. Verify you arrived at the expected screen using the Key Screen Identifiers table.
  3. Take a screenshot with mobile_save_screenshot as evidence.

If the expected screen identifier is NOT present after retries:

  1. Take a screenshot with mobile_take_screenshot.
  2. Call mobile_list_elements_on_screen and identify which screen you are actually on.
  3. Report to the user: "Navigation to [target] failed. Currently on [detected screen]."
11. Stop Recording and Save Evidence

If recording: stop the recording, pull the file, and clean up:

bash
adb -s <device_id> shell "pkill -l SIGINT screenrecord"
sleep 2
adb -s <device_id> pull /sdcard/_agent_rec.mp4 ./verification_recording.mp4
adb -s <device_id> shell rm /sdcard/_agent_rec.mp4

Always: use mobile_save_screenshot at each verification step to save screenshots to disk.

12. Report Results

Summarize what was verified, include saved screenshot and recording paths, and flag any issues found.

Available MCP Tools Reference

Device Management
ToolPurpose
mobile_list_available_devicesDiscover emulators and physical devices
mobile_get_screen_sizeGet device resolution in pixels — useful to understand coordinate space
mobile_get_orientationCheck if device is in portrait or landscape
mobile_set_orientationSwitch between portrait and landscape (e.g., for tablet testing)
App Lifecycle
ToolPurpose
mobile_list_appsList installed apps — verify the app is installed before launching
mobile_install_appInstall an APK (.apk file) on the device
mobile_uninstall_appRemove the app for clean install testing
mobile_launch_appStart the app by package name
mobile_terminate_appForce-stop the app (useful for restart/recovery)
Screen Interaction
ToolPurpose
mobile_list_elements_on_screenPrimary interaction tool. Returns all UI elements with device-pixel coordinates. ALWAYS call this before tapping.
mobile_click_on_screen_at_coordinatesTap at exact device-pixel coordinates
mobile_double_tap_on_screenDouble-tap (e.g., zoom in on images)
mobile_long_press_on_screen_at_coordinatesLong-press for context menus or bulk actions
mobile_swipe_on_screenScroll content or swipe between pages
mobile_type_keysType text into the currently focused input field
mobile_press_buttonPress hardware/system buttons: BACK, HOME, ENTER, VOLUME_UP, VOLUME_DOWN
mobile_open_urlOpen a URL in the device browser (useful for deep link testing)
Screenshots
ToolPurpose
mobile_take_screenshotCapture screen for visual verification (do NOT use for coordinate extraction)
mobile_save_screenshotSave a screenshot to a file path for documentation

Screen Recording via ADB

Use adb shell screenrecord to capture video of navigation flows. This is useful for demo recordings, PR evidence, or reproducing bugs.

Start Recording

Run in the background so the agent can continue navigating while recording:

bash
adb -s <device_id> shell "screenrecord --size 720x1280 /sdcard/_agent_rec.mp4" &
OptionDefaultNotes
--size WxHDevice nativeUse 720x1280 to reduce file size
--time-limit N180Maximum seconds (Android hard limit is 180)
Stop Recording

CRITICAL: Always stop with SIGINT. Using SIGKILL or just killing the process leaves the MP4 unfinalized and unplayable.

bash
adb -s <device_id> shell "pkill -l SIGINT screenrecord"
sleep 2
adb -s <device_id> pull /sdcard/_agent_rec.mp4 ./recording.mp4
adb -s <device_id> shell rm /sdcard/_agent_rec.mp4
Flows Longer Than 3 Minutes

Android limits recordings to 180 seconds. For longer flows, chain recordings:

bash
# Record in segments
adb -s <device_id> shell "screenrecord --time-limit 180 /sdcard/_agent_rec_1.mp4"
adb -s <device_id> pull /sdcard/_agent_rec_1.mp4 ./segment_1.mp4
adb -s <device_id> shell rm /sdcard/_agent_rec_1.mp4
# Start next segment...

Note: with --time-limit, the command blocks until done, so navigation must happen from a parallel process or between segments.

Recording Failure Modes
SymptomCauseFix
MP4 unplayableStopped with SIGKILL or device disconnectedAlways use pkill -l SIGINT screenrecord
Recording stops after 3 minHit 180s Android limitUse chained recordings
Black screen in videoDRM-protected content on screenOS-level restriction, cannot be avoided
screenrecord: not foundAndroid < 4.4Not supported on very old devices

API Mocking with ApiFaker

ApiFaker intercepts API calls at the OkHttp layer and returns fake responses from a local database. Control it via ADB broadcast commands to test specific scenarios (error states, empty lists, custom data) during device verification. ApiFaker is available only in debug builds.

When the user requests verification of a specific scenario, follow this workflow:

  1. Clear any existing endpoints
  2. Add mock endpoint(s) for the scenario
  3. Enable ApiFaker
  4. Launch or navigate the app — mocked endpoints return fake responses
  5. Verify the UI shows the expected behavior
  6. Disable ApiFaker and clear endpoints when done

For all ADB commands, extras, API types, examples, and debugging tips, read docs/api-faker-adb.md.

Key tips:

  • All am broadcast commands must include -p com.woocommerce.android.dev — without it, Android 8.0+ silently drops the broadcast.
  • All actions log results to logcat under the WCApiFaker tag — use adb logcat -s WCApiFaker -d to check feedback.

WooCommerce Navigation Reference

View resource IDs below use the debug package prefix com.woocommerce.android.dev:id/. Compose test tags (applied via Modifier.testTag()) also appear as resource IDs in the accessibility tree because testTagsAsResourceId is enabled in the app's themes, but they appear verbatim with no prefix — order_list_screen, not com.woocommerce.android.dev:id/order_list_screen.

The app has two distinct navigation domains with different architectures. Only load the reference files you need for the task — each file adds significant context cost.

Always load first
  • Overview & Feature Tree -- lightweight index of all screens, bottom tabs, global elements. Read this first to orient yourself, then load only the detailed references you need.
Load on demand — match task keywords to the right reference
If the task involves…Load this reference
Login, authentication, store selection, credentialsLogin
Dashboard, stats, analytics, onboarding, date rangesDashboard
Orders, creating orders, adding products to orders, payment collection (cash/card/tap-to-pay), refunds, fulfillment, shipping labels, receiptsOrders
Product catalog management — creating, editing, deleting, searching products in the Products tabProducts
Settings, payments hub, reviews, coupons, customers, Blaze, Google AdsMore Menu
POS, Point of Sale, WooPos, landscape checkout, cash registerPOS

Key distinction: "Adding products to an order" is an Orders workflow (order creation screen), NOT a Products workflow. Only load the Products reference when the task is about the standalone product catalog (Products tab).

Common Navigation Patterns
  • Go back: Call mobile_press_button with button BACK. This is the most reliable way to navigate back.
  • Dismiss the soft keyboard: Call mobile_press_button with BACK. This only dismisses the keyboard; it does NOT navigate back. If you need to navigate back AND the keyboard is visible, press BACK twice: once to dismiss keyboard, once to navigate.
  • Pull to refresh: Use mobile_swipe_on_screen with direction down from the middle of the screen.
  • Scroll down a list: Use mobile_swipe_on_screen with direction up (swipe up to scroll down).
  • Open a list item: Find the item in mobile_list_elements_on_screen by its text or identifier, compute center coordinates, and tap.
  • Toolbar back arrow: Look for elements in the toolbar area (com.woocommerce.android.dev:id/toolbar). If the back arrow is not exposed as a separate element, use mobile_press_button with BACK instead.

Error Recovery

ProblemSolution
Build fails: "SDK location not found"Ensure local.properties exists at the repo root with sdk.dir=/path/to/Android/sdk. Copy from the main repo if working in a worktree.
Build fails: missing secrets.propertiesCopy from ~/.configure/woocommerce-android/secrets/ or use defaults.properties as a template.
App not responding / blank screenCall mobile_terminate_app then mobile_launch_app to restart.
Element not found on screenThe screen may still be loading — follow the "Waiting for Screen Transitions" protocol. If stable, try scrolling (see "Finding Elements That Require Scrolling").
Tap lands on wrong elementYou likely used screenshot coordinates instead of element coordinates. Always use mobile_list_elements_on_screen and compute the center of the bounding rect.
Login screen appearsFollow "Authentication and Session Preservation" and references/agent-auto-login.md.
App crashes on launchRun adb logcat -d *:E via Bash to check crash logs. Common cause: missing FluxC database migration.
No devices foundRun adb devices via Bash to check ADB connectivity. Ensure the emulator is booted or the physical device has USB debugging enabled.
Recording MP4 is unplayableStopped with SIGKILL instead of SIGINT. Always use pkill -l SIGINT screenrecord and wait 2s before pulling.
Recording cuts off at 3 minAndroid's hard 180s limit. Use chained recordings for longer flows.
Diagnostic ADB Commands (via Bash)

When mobile-mcp tools are not giving enough information:

CommandPurpose
adb -s <device> shell dumpsys activity top | head -20Identify the current foreground Activity/Fragment
adb -s <device> shell dumpsys window | grep mCurrentFocusGet the current window/dialog in focus
adb -s <device> logcat -d *:E | tail -30Check recent error logs
adb -s <device> shell am force-stop com.woocommerce.android.devForce kill the app
adb -s <device> shell pm clear com.woocommerce.android.devClear app data only for explicitly requested clean-state testing; it destroys the preserved session.
Android Knowledge Base (USE_ANDROID_CLI=1)

When a platform-behavior question comes up mid-task (intent flags, am start semantics, Activity launch modes, permissions, animation scales, settings put global keys), prefer the Android Knowledge Base over a web search — the answers are authoritative, local, and don't cost browsing tokens.

bash
# Search by free-form query, then fetch one of the kb:// URLs it returns.
android docs search "am start intent flags"
android docs fetch <kb-url-from-the-search-result>

If the CLI is not installed, fall back to the Android developer website as before.

© woocommerce, GPL-2.0. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file

Files

SKILL.md and 8 other files (references) in .agents/skills/verify-on-device of woocommerce/woocommerce-android.

  • SKILL.md
  • references/agent-auto-login.md
  • references/main-app-dashboard.md
  • references/main-app-login.md
  • references/main-app-more.md
  • references/main-app-navigation.md
  • references/main-app-orders.md
  • references/main-app-products.md
  • references/pos-navigation.md

Open the folder on GitHubat commit 0fb14b0

Compare with similar skills

Verify On Device next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.

Verify On Device compared with similar skills
SkillStarsUsed inTokensAuto-checkLicenceRepo updated
Verify On Device this skillwoocommerce/woocommerce-android319—~10kAutomated safety check: NotesGPL-2.0
Magicnet Device DebuggingLIghtJUNction/MagicNet185—~2.9kAutomated safety check: NotesMIT
Scrcpy GotchasJuanCF/scrcpy-mcp112—~5.8kAutomated safety check: PassMIT
Generate Appclaw Flowappclawhq/AppClaw116—~3.4kAutomated safety check: NotesApache-2.0
Spock AdbWahdanZ/SpockAdb114—~3.3kAutomated safety check: PassApache-2.0
Aaalice Runtime VerifyAaalice233/Aaalice_NAI_Launcher187—~963Automated safety check: PassMIT

Similar skills

  • Magicnet Device Debugging

    LIghtJUNction/MagicNet

    Debug and verify MagicNet on a real Android root device. An agent skill from LIghtJUNction/MagicNet.

    185 GitHub stars~2.9k tokensUpdated today
    MobileAuto-check: notes
  • Scrcpy Gotchas

    JuanCF/scrcpy-mcp

    A skill your agent uses when interacting with Android devices via scrcpy-mcp tools (tap, swipe, inputtext, keyevent, uidump, uifindelement, appstart, etc.).

    112 GitHub stars~5.8k tokensUpdated 15 days ago
    MobileAuto-check passed
  • Generate Appclaw Flow

    appclawhq/AppClaw

    Generate YAML flow files for AppClaw mobile automation. An agent skill from appclawhq/AppClaw.

    116 GitHub stars~3.4k tokensUpdated 1 mo ago
    MobileAuto-check: notes
  • Spock Adb

    WahdanZ/SpockAdb

    Debug Android apps on a connected device or emulator through the Spock ADB MCP server (tools named android).

    114 GitHub stars~3.3k tokensUpdated 3 days ago
    MobileAuto-check passed
  • Aaalice Runtime Verify

    Aaalice233/Aaalice_NAI_Launcher

    用户要求自动化运行验收、界面操作、截图检查或双端 UI 测试时,自动启动或复用 Aaalice NAI Launcher 热重载会话,通过项目级 Dart/Flutter MCP 验证应用;Android 系统界面按需使用 ADB。

    187 GitHub stars~963 tokensUpdated 3 days ago
    MobileAuto-check passed
  • Use Appclaw CLI

    appclawhq/AppClaw

    Use the AppClaw CLI to run YAML flows, start the interactive TUI shell, explore apps, record/replay sessions, configure devices, and troubleshoot.

    116 GitHub stars~4.6k tokensUpdated 1 mo ago
    MobileAuto-check: notes

More from woocommerce/woocommerce-android

All 8 skills in this repo
  • PR

    woocommerce/woocommerce-android

    Create a pull request following project conventions. An agent skill from woocommerce/woocommerce-android.

    319 GitHub stars~1.3k tokensUpdated yesterday
    Auto-check: notes
  • PR Feedback

    woocommerce/woocommerce-android

    Address PR reviewer feedback by evaluating comments, proposing fixes, and executing after user approval.

    319 GitHub stars~1.3k tokensUpdated yesterday
    Auto-check: notes
  • UI Review

    woocommerce/woocommerce-android

    Generate screenshot coverage for screen-level Compose previews from the current diff or a specific target, check required visual and data variations, and produce a compact visual report

    319 GitHub stars~3.1k tokensUpdated yesterday
    Auto-check passed
  • Review

    woocommerce/woocommerce-android

    Review code changes against project architecture, style, and conventions

    319 GitHub stars~600 tokensUpdated yesterday
    Auto-check: notes
  • Woo AI Smoke

    woocommerce/woocommerce-android

    Run the Android AI Assistant headless smoke regression harness without launching UI.

    319 GitHub stars~2.5k tokensUpdated yesterday
    Auto-check passed
  • Pos Tests

    woocommerce/woocommerce-android

    POS unit testing patterns (WooPosCoroutineTestRule, runTest, advanceUntilIdle, mockito-kotlin, event bus mocking, analytics verification).

    319 GitHub stars~216 tokensUpdated yesterday
    Auto-check: notes

Categories

Questions about Verify On Device

What does Verify On Device do?

Build, install, and visually verify the app on an Android emulator or device. Verify On Device is an agent skill from woocommerce/woocommerce-android. Build, install, and visually verify the app on an Android emulator or device.

When should I use Verify On Device?

Verify On Device fits situations like: tasks that involve Mobile testing and debugging.

How do I install Verify On Device in Claude Code?

Run `npx skills add woocommerce/woocommerce-android --skill verify-on-device -a claude-code`. Or copy the skill folder (.agents/skills/verify-on-device in woocommerce/woocommerce-android) into .claude/skills/verify-on-device in your project. Claude Code loads it when a task matches its description.

How do I install Verify On Device in Codex?

Run `npx skills add woocommerce/woocommerce-android --skill verify-on-device -a codex`. Or copy the skill folder (.agents/skills/verify-on-device in woocommerce/woocommerce-android) into .agents/skills/verify-on-device in your project. Codex loads it when a task matches its description.

Can I use Verify On Device in Cursor, Gemini CLI or GitHub Copilot?

Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add woocommerce/woocommerce-android --skill verify-on-device -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/verify-on-device, .gemini/skills/verify-on-device, .github/skills/verify-on-device and .opencode/skills/verify-on-device in your project.

What does Verify On Device need to run?

Going by SKILL.md and its folder, Verify On Device needs the command-line tools its instructions call (adb). Our summary lists: Node.js. Its frontmatter pre-approves these tools: Bash, Read, Grep, Glob, mcp__mobile-mcp__*.

Does Verify On Device access the network?

SKILL.md contains no URLs. Any network use would come from the scripts or tools the agent runs. This is read from the text; nothing was executed.

Is Verify On Device safe to install?

Our automated static check of SKILL.md found notes only (pre-approves every shell command (allowed-tools: bash)), nothing it rates as a warning. It is not a guarantee. Review the folder before installing.

What licence does Verify On Device use?

Verify On Device is published under the GPL-2.0 licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.

How many tokens does Verify On Device use?

About 10k tokens (SKILL.md is roughly 40k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full. Its references folder adds about 10k tokens, read only when the agent opens those files.

What are the alternatives to Verify On Device?

Skills that share tags, products or a category with Verify On Device: Magicnet Device Debugging (LIghtJUNction/MagicNet, 185 stars), Scrcpy Gotchas (JuanCF/scrcpy-mcp, 112 stars), Generate Appclaw Flow (appclawhq/AppClaw, 116 stars) and Spock Adb (WahdanZ/SpockAdb, 114 stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.

Who maintains Verify On Device?

woocommerce (a GitHub organization) maintains it in woocommerce/woocommerce-android, which has 319 GitHub stars. The repository holds 8 skills in this directory. The repository was last updated on October 7, 2026.

Source: woocommerce/woocommerce-android on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.