Skip to main content
ZICQ

Skills ZICQ category:Media limrun-android-emulator

Limrun Android Emulator

Drive an app running on a Limrun cloud Android emulator: install an APK, launch and terminate apps with crash reports, tap, type, read the UI element tree, screenshot, record video, inject microphone audio, shape network bandwidth, read app logs, run shell commands, transfer files, tunnel the app's network destinations through your machine with HTTP inspection and HAR capture, reach a private network through a private tunnel, send all traffic through the user's proxy, trust a custom CA certificate, and use adb over the CLI's tunnel for full logcat and interactive tools. Use after a build (from limrun-gradle or any builder) when the user wants to see, test, or interact with their app on an emulator, or says 'show me a screenshot', 'tap', 'run it on the emulator', 'check logcat', 'record a v

40024 installs

Official URL:skills.sh

What this skill does

Intro in this page language first. The official description stays in its original wording; we do not rewrite SKILL.md.

What it does

Drive an app running on a Limrun cloud Android emulator: install an APK, launch and terminate apps with crash reports, tap, type, read the UI element tree, screenshot, record video, inject microphone audio, shape network bandwidth, read app logs, run shell commands, transfer files, tunnel the app's network destinations through your machine with HTTP inspection and HAR capture, reach a private network through a private tunnel, send all traffic through the user's proxy, trust a custom CA certificate, and use adb over the CLI's tunnel for full logcat and interactive tools. Use after a build (from limrun-gradle or any builder) when the user wants to see, test, or interact with their app on an emulator, or says 'show me a screenshot', 'tap', 'run it on the emulator', 'check logcat', 'record a video', 'inspect network traffic', 'route all traffic through my proxy', or 'reach my local server from the emulator'. To build the APK or AAB first, use limrun-gradle.

When to use it

The official description does not include a separate “Use when”. Per the spec, agents activate this skill when the task matches keywords in that description.

How agents load it

Per Agent Skills progressive disclosure: name and description load at startup (~100 tokens); the full SKILL.md body loads when the skill activates; scripts/, references/, and assets/ load only as needed. This file's sections: Limrun Android Emulator; Auth and CLI; Installing an app; Build and install; Install app from local; Targeting the right instance.

File analysis

File analysis: instruction-only skill (SKILL.md). The agent loads the full body when activated.

Official description (original)

Drive an app running on a Limrun cloud Android emulator: install an APK, launch and terminate apps with crash reports, tap, type, read the UI element tree, screenshot, record video, inject microphone audio, shape network bandwidth, read app logs, run shell commands, transfer files, tunnel the app's network destinations through your machine with HTTP inspection and HAR capture, reach a private network through a private tunnel, send all traffic through the user's proxy, trust a custom CA certificate, and use adb over the CLI's tunnel for full logcat and interactive tools. Use after a build (from limrun-gradle or any builder) when the user wants to see, test, or interact with their app on an emulator, or says 'show me a screenshot', 'tap', 'run it on the emulator', 'check logcat', 'record a video', 'inspect network traffic', 'route all traffic through my proxy', or 'reach my local server from the emulator'. To build the APK or AAB first, use limrun-gradle.

Limrun Android EmulatorAuth and CLIInstalling an appBuild and installInstall app from localTargeting the right instanceLaunching the appApp logsShell and filesFull logcat and interactive adb over the tunnelTesting changesInteracting with the app

Source category:skills.sh agent-skill

SKILL.md & Agent activation

Official spec ↗
name
limrun-android-emulator
description
Drive an app running on a Limrun cloud Android emulator: install an APK, launch and terminate apps with crash reports, tap, type, read the UI element tree, screenshot, record video, inject microphone audio, shape network bandwidth, read app logs, run shell commands, transfer files, tunnel the app's network destinations through your machine with HTTP inspection and HAR capture, reach a private network through a private tunnel, send all traffic through the user's proxy, trust a custom CA certificate, and use adb over the CLI's tunnel for full logcat and interactive tools. Use after a build (from limrun-gradle or any builder) when the user wants to see, test, or interact with their app on an emulator, or says 'show me a screenshot', 'tap', 'run it on the emulator', 'check logcat', 'record a video', 'inspect network traffic', 'route all traffic through my proxy', or 'reach my local server from the emulator'. To build the APK or AAB first, use limrun-gradle.
  1. DiscoverThe client exposes names and descriptions to the agent.
  2. ActivateYour request or the task context selects the skill and loads its instructions.
  3. Load resourcesReferenced scripts, documentation and assets are used when needed.

Invocation syntax and available tools depend on your Agent client. Client integration guide ↗

Install this skill

Skills CLI ↗

Choose the target agent and installation scope, keep referenced package files, then verify the skill appears in the client's catalog.

Ask your Agent to install

Copy these instructions to a compatible agent and confirm the target directory matches your client.

Install the agent skill "limrun-android-emulator" into my project. The full SKILL.md and official description are at https://zicq.com/en/skills/skl-ae558d16d389ff4c-Limrun-Android-Emulator.html
Save it as .cursor/skills/limrun-android-emulator/SKILL.md or .claude/skills/limrun-android-emulator/SKILL.md and keep the frontmatter name and description exactly as-is.

Full package on GitHub ↗

Install from the terminal · Skills CLI

Requires Node.js and npx. First inspect the repository's skill list to confirm the name.

npx skills add 'https://github.com/limrun-inc/skills' --list

npx skills add 'https://github.com/limrun-inc/skills' --skill 'limrun-android-emulator'

The CLI lets you choose the agent interactively. The default scope is the project; use -g for user scope. Confirm package availability with the discovery command, then use npx skills list to inspect installed skills.

Readable layout
--- name: limrun-android-emulator description: "Drive an app running on a Limrun cloud Android emulator: install an APK, launch and terminate apps with crash reports, tap, type, read the UI element tree, screenshot, record video, inject microphone audio, shape network bandwidth, read app logs, run shell commands, transfer files, tunnel the app's network destinations through your machine with HTTP inspection and HAR capture, reach a private network through a private tunnel, send all traffic through the user's proxy, trust a custom CA certificate, and use adb over the CLI's tunnel for full logcat and interactive tools. Use after a build (from limrun-gradle or any builder) when the user wants to see, test, or interact with their app on an emulator, or says 'show me a screenshot', 'tap', 'run it on the emulator', 'check logcat', 'record a video', 'inspect network traffic', 'route all traffic through my proxy', or 'reach my local server from the emulator'. To build the APK or AAB first, use limrun-gradle." user-invocable: true effort: high --- # Limrun Android Emulator Interact with an app running on a Limrun cloud Android emulator, from any environment (Linux, Windows, macOS, VM, container). This skill is build-agnostic: it assumes the APK was already built, usually by **limrun-gradle**. Keep build concerns in that skill; this one is about driving the running emulator. Never use a local emulator, a local Android SDK, or Android Studio. To disconnect the emulator from its build sandbox and stop automatic installation, run `lim gradle detach-emulator --id `. Both instances, installed apps, and retained builds remain available. Repeated detach requests succeed. ## Auth and CLI Install if needed: `npm install --global lim`. Auth is `lim login` or `LIM_API_KEY` (it may already be set in the user's environment even when `.env` and the shell do not show it; check before asking for it). The CLI is the source of truth: the commands in this skill are verified, but if a flag errors or you need one not shown here, check `lim android --help` instead of guessing. ## Installing an app You can build with Limrun's remote Gradle service and have the APK installed on a fresh emulator automatically, or install a pre-built local APK or a URL. One default to know first: `lim android create` opens an ADB tunnel (`--connect`) and a browser tab with the live stream (`--open`) unless told otherwise. As an agent, pass `--no-open` always, and `--no-connect` unless you need adb right away. ### Build and install For APKs built with **limrun-gradle**, prefer attaching the emulator to the Gradle sandbox. After the first transfer, rebuilds reuse the previous APK and send a binary patch when smaller. Small rebuilds can be much faster than uploading the full APK to Asset Storage and downloading it to the emulator each time. Build once, create an emulator if needed, then attach it. Attachment installs the latest retained APK, and later successful APK builds install automatically: ```bash lim gradle build . lim android create --no-open --no-connect lim gradle attach-emulator --id ``` Reuse an existing emulator when one is already running. Use Asset Storage when you need a reusable APK for other instances. Create blocks until the instance is ready to drive; no boot wait is needed. The create output includes a signed stream URL; share it with the user as a Markdown link, like `[Live emulator]()`. If you have a browser the user can see, open the URL there and tell them. Create also prints a console URL: it opens the same live view but requires a console login, so prefer the signed stream URL for sharing. Signed links open the shared device workspace without login. Full instance tokens show Inspect, Connect, and the logs, events, and network inspector. Stream-only tokens show the screen and input controls without those tools. Stop and app selection require the authenticated console. Useful create flags: `--reuse-if-exists` (reuse a running instance with the same labels), `--rm` (delete when the CLI exits), `--jurisdiction us|eu|as` (where the instance runs; don't use `--region`, it is deprecated), `--inactivity-timeout` / `--hard-timeout`, `--display-name`, and `--label k=v` (find labeled instances later with `lim android list --label-selector k=v`). ### Install app from local Create a new emulator, then install a local file or a URL: ```bash lim android create --no-open --no-connect lim android install-app ./app-debug.apk lim android install-app https://example.com/app.apk ``` A local path is uploaded to Limrun Asset Storage first; a URL is fetched by the instance itself, which is much faster for large APKs than uploading from your machine. `install-app` returns as soon as the app is sent; the install finishes in the background within seconds. Newly installed apps land in the app drawer, not the home screen, so don't look for their icon; just launch the app with `lim android launch-app --detach` (without `--detach` it blocks watching the app until it exits), or confirm with `lim android adb-shell -- sh -c "pm list packages | grep "`. Every time you need to install a new version of the APK, sync it instead of reinstalling: ```bash lim android sync ./app-debug.apk ``` It sends only a delta against the APK already on the instance, then reinstalls. `--watch` keeps re-syncing on file changes, and `--launch-mode ForegroundIfRunning|RelaunchIfRunning` controls what happens to the running app after each install. ## Targeting the right instance Most `lim android` commands default to the last created instance and resolve the "current" one from the **git repo / worktree** of your cwd. In a different directory (or outside any git repo) a command can report that no recent instance was found even though one is running. The reliable recipe: ```bash lim android list # shows all instances and their IDs lim android element-tree --id # pass --id to EVERY lim android command ``` Once you have the ID (format `android__`), pass `--id ` to all `lim android` calls for the rest of the session. Alternatively, `git init` the project so the workspace resolves on its own. When controlling multiple instances, always pass `--id`. ## Launching the app Launch and stop installed apps by package name: ```bash lim android launch-app com.example.app --detach # launch and return lim android launch-app com.example.app # launch and watch until it exits lim android launch-app com.example.app --mode RelaunchIfRunning # restart for a clean state lim android terminate-app com.example.app # stop it, e.g. to reset app state ``` Without `--detach`, `launch-app` blocks watching the app: when it crashes, ANRs, or is stopped, the command prints the exit reason, crash details with the stack trace, and a recent app log tail, then returns. That report is the way to see why an app died without adb; for logs while the app is running, use `lim android app-log` (below). There is no `list-apps`; discover package names with `lim android adb-shell -- pm list packages`, or take the application ID from the build. ## App logs One app's logs need no tunnel: ```bash lim android app-log com.example.app --tail 100 # recent lines (app must be running) lim android app-log com.example.app --follow # stream live lines until Ctrl+C; don't stream into context ``` ## Shell and files One-shot shell commands and file transfer need no tunnel either: ```bash lim android adb-shell -- pm list packages -3 # like adb shell; args go after -- lim android adb-shell -- sh -c "dumpsys battery | grep level" # pipes need an explicit shell lim android push-file ./fixture.json /sdcard/Download/fixture.json lim android pull-file /sdcard/Download/out.json ./out.json ``` They run with the same permissions the adb shell user has, and `adb-shell` exits with the command's exit code. ## Full logcat and interactive adb over the tunnel Full-device logcat and anything interactive (Android Studio, scrcpy, streaming) go through plain `adb` over the CLI's tunnel. Start the tunnel in a background shell and keep it alive: ```bash lim android connect # prints "Tunnel started on 127.0.0.1:." ``` `connect` runs `adb connect` for you (use `--adb-path` if adb isn't on PATH). The printed `127.0.0.1:` is the device serial; pass it with `-s` to every adb call (`adb devices` also lists it): ```bash SERIAL=127.0.0.1: adb -s $SERIAL logcat -d | tail -100 # dump recent full-device logs, don't stream into context ``` The tunnel lives and dies with the process that started it: when that shell exits, `adb devices` shows the serial as `offline` while the instance keeps running. Just run `lim android connect` again to get a new tunnel (the port changes each time). Stale offline serials are harmless; `adb disconnect` clears them. ## Testing changes When emulator interaction is part of the task, test new or changed functionality with the interaction commands after each install or sync. Focus on what changed, plus a quick smoke test of core flows. Start by reading the element tree to see what's on screen before acting: ```bash lim android element-tree ``` The output is the raw UIAutomator XML hierarchy on a single line, so a plain grep echoes the whole document. Split it into one node per line first, then grep for the `text`, `resource-id`, `content-desc`, or `bounds` you need rather than dumping the whole tree into context: ```bash lim android element-tree | sed 's/>\n ``` Use the element tree for functional assertions (element existence, text, state changes) and screenshots only for visual properties. For anything involving motion (animations, gameplay, streaming UI), prefer video: ```bash lim android record start # non-blocking lim android record stop -o /tmp/recording.mp4 ``` `record stop` accepts `--quality 5-10`. Recorded frames are half the screenshot resolution, so read tap coordinates from screenshots, never from video frames. For UI changes, include a demo video in the pull request so the user can see it. ## Simulate the microphone with an audio file For voice-driven flows (assistants, speech-to-text, audio calls), play a local audio file as the emulator's microphone. The app hears the audio through its normal capture pipeline: ```bash lim android play-on-microphone ./fixtures/command.wav # loops by default lim android play-on-microphone ./fixtures/command.mp3 --once ``` WAV and MP3 work. The file is pushed over adb, so this command needs a local `adb` binary (`--adb-path` if it's not on PATH) and opens its own short-lived tunnel. Camera injection is iOS-only; for camera-driven test flows use **limrun-ios-simulator**. ## Shape network bandwidth Test slow-network behavior by capping the instance's Wi-Fi bandwidth: ```bash lim android set-wifi-bandwidth --down-kbps 1000 --up-kbps 500 lim android set-wifi-bandwidth --down-kbps 0 --up-kbps 0 # 0 clears the limit ``` ## Tunnel the app's traffic through your machine When the app must reach a service only your machine can reach (a local dev server, a VPN-only staging API), or you need to see its HTTP traffic, start a destination tunnel. Only the destinations you select are rerouted through the machine running `lim`; everything else leaves the instance directly. ```bash lim android tunnel --selector localhost:8080 --detach --id ``` - An exact selector (`localhost:port` or `IP:port`, port >= 1024) becomes a listener on the emulator, also reachable as `10.0.2.2:`; the app's connections to it land on your machine and are dialed there. - Domain selectors (`api.example.com`, `"*.corp.example"`) are intercepted on the emulator and dialed from your machine, so your DNS and VPN apply. Apps that resolve DNS themselves over HTTPS bypass domain interception. - Start the tunnel **before** launching the app: connections opened earlier keep their original route. One tunnel per instance; a second start fails. As an agent, always pass `--detach`: it returns once the tunnel is READY and keeps it alive in a background process. Manage it with: ```bash lim android tunnel status --id # state, per-selector binds, last dial failure lim android tunnel stop --id ``` ### Inspect HTTP traffic, capture HAR, persist a network log Inspection is on by default: every HTTP and HTTPS request through the tunnel is decoded, printed as one summary line per request (in the tunnel log file when detached), and shown live in the console's network panel. ```bash lim android tunnel --selector "*.api.example" --har ./traffic.har --detach # write HAR 1.2 with bodies lim android tunnel --selector "*.api.example" --persist --detach # network log survives the instance ``` `--persist` uploads a body-inclusive network log as a session artifact when the tunnel stops or the instance terminates; it appears on the instance's session page in the console with a HAR download (default lifetime 3 days, `--ttl ` up to 30 days). HTTPS is decoded with an emulator-trusted CA, so **apps with certificate pinning fail through inspected domain selectors**: leave the pinned host out of the selectors or pass `--no-inspect` to relay bytes opaquely (no summaries, HAR, or persistence). ## Reach services in a private network through a private tunnel An organization can run a private tunnel: a connector inside its network, created by an admin with `lim tunnel create` or in the console (Network) and run with `lim tunnel run`, that serves every instance naming it. When the user names one, pass it at create time instead of starting a tunnel yourself: ```bash lim android create --tunnel ``` The app reaches the tunnel's selectors at the addresses they name, and exact selectors are also reachable as `10.0.2.2:`. Selectors resolve on the connector's machine, not on yours. Android instances attach only when every exact selector uses port 1024 or higher. The tunnel takes the instance's one destination tunnel, so do not start or stop `lim android tunnel` on it. Creation checks the tunnel and fails when it is not usable: - `tunnel does not exist`: the name is wrong or the tunnel was not created. Ask the user for the right name. - `tunnel is offline`: no connector is running. Ask the user to start it. - `did not attach within 30s`: the connector cannot attach the instance, or an exact selector uses a port below 1024. Ask the user to check the connector's output, or to move the service to a port of 1024 or higher. Retrying the create in a loop does not help in any of these cases. The tunnel's token belongs on the connector's machine. Never ask the user to paste it into the conversation. ## Send all device traffic through a proxy Tunnels carry only declared destinations; there is no catch-all selector. When the user wants all traffic to leave through their proxy (for example a recording proxy), point the emulator's global HTTP proxy at a proxy the tunnel reaches. Tunnel inspection passes requests meant for the proxy through as sent. Use a port other than 8080 for a `localhost` proxy; the emulator already uses 8080. ```bash lim android tunnel --selector localhost:3128 --detach --id lim android proxy set localhost:3128 --id # later, before stopping the tunnel: lim android proxy clear --id ``` With a private tunnel whose selector is the proxy, only `lim android proxy set` is needed. A proxy elsewhere in the user's network works the same way: `--selector proxy.example.internal` and `lim android proxy set proxy.example.internal:3128`. While the proxy is set and the tunnel is down, Chrome's requests fail instead of going direct. To read HTTPS in the proxy, trust its CA (below). ## Trust a CA certificate Add a PEM CA certificate to the emulator's trust stores, for example the root of a private CA that signs the user's test servers: ```bash lim android ca add ./my-ca.pem --id ``` Apps, WebViews, and Chrome trust it on their next connection, with no restart, for the life of the instance. Only one CA certificate per file; leaf certificates are rejected. Apps that pin certificates still reject it. To look at the app's HTTP and HTTPS traffic, use tunnel inspection (above) instead: it needs no CA of the user's own. ## Preview URL for humans Upload the APK to Limrun Asset Storage and return a preview URL for the user to open and test the app manually in the browser: ```bash export ASSET_NAME=myapp.apk # can be any name lim asset push ./app-debug.apk -n ${ASSET_NAME} echo "https://console.limrun.com/preview?asset=${ASSET_NAME}&platform=android" ``` Opening the link in the Limrun console provisions an emulator and starts streaming while the console installs the APK. An `Installing ` overlay stays visible during installation. Add `openUrl` to open a URL or app deep link after launch, for example `&openUrl=myapp%3A%2F%2Fcheckout`. Use `URLSearchParams.set("openUrl", url)` to encode the full URL and its query string. The stream stays visible while the app installs, launches, and opens the URL. The overlay disappears when the preview is ready. ## Cleanup When the work is completed, you can delete the emulator. `delete` takes a **positional** ID (`--id` is not a valid flag here, unlike other commands): ```bash lim android delete ``` ## Gotchas - **Ship one ABI, not a mix.** Emulators are x86_64 hosts that report `x86_64,arm64-v8a` and run arm64 native libraries through translation. An APK with only `arm64-v8a` libs installs and runs; x86_64 libs run natively and fastest. An APK that mixes ABIs, some vendor SDK libs arm64-only and the rest x86_64, installs as x86_64 and then crashes with `UnsatisfiedLinkError` when the arm64-only code first loads. `armeabi-v7a`-only APKs are rejected with `INSTALL_FAILED_NO_MATCHING_ABIS`, and apps that exec their own bundled ARM command-line binaries are not supported under translation. - **Selectors match exactly.** `tap-element --text` and `find-element --text` need the full, exact string from `element-tree`; substrings match nothing. - **`install-app` returns before the install finishes.** The app lands a few seconds later; verify with `find-element` or `pm list packages` before launching. Prefer `install-app ` or `create --install-asset` over raw `adb install`: a big APK over `adb install` streams with zero progress output and looks hung for minutes, and killing it mid-stream corrupts the install. - **The ADB tunnel is session-bound.** It dies with the shell that started it while the instance keeps running; reconnect with `lim android connect` and re-read the port, it changes every time. - **Failed create pipes can still leak an instance.** If a `create` invocation errors client-side (broken pipe, JSON parse), check `lim android list`; the instance may exist anyway and should be deleted. - **Empty element tree usually means a React Native app**, not a broken instance. See "When the element tree is empty" above. - **`element-tree` can be large.** Pipe through `grep` to extract what you need rather than dumping the whole tree into context. - **Instance resolution can miss in a non-git dir.** See "Targeting the right instance" above; pass `--id` when in doubt. - **Build errors are the build skill's job.** If the APK isn't building, the failure is upstream; go back to **limrun-gradle**.

Related skills

Media

Nano Banana Pro

Generate/edit images with Nano Banana Pro (Gemini 3 Pro Image). Use for image create/modify requests incl. edits. Supports text-to-image + i…

Media

Youtube Watcher

Fetch and read transcripts from YouTube videos. Use when you need to summarize a video, answer questions about its content, or extract infor…

Media

Atxp

Access ATXP paid API tools for web search, AI image generation, music creation, video generation, X/Twitter search, email, and agent account…

Media

Youtube

YouTube Data API integration with managed OAuth. Search videos, manage playlists, access channel data, and interact with comments. Use this …