Headless agents were launching lim xcode build in a background shell and
ending their turn before it finished, killing the build mid-flight. Observed
as the dominant failure mode in skill evals (baseline iterate 3/5); with this
paragraph the same eval scores 5/5 (see limrun/test/skill-evals/scorecards/
2026-08-18-foreground-build.*, verdict ADOPT).
The install check and the expo verify step both pointed at a bare
launch-app, which blocks watching the app until it exits and would hang
an agent on a healthy app; use --detach for the install check and frame
the watched relaunch as a backgrounded crash-diagnosis step. Show the
asset list prefix per platform instead of prose describing the Android
variant.
limrun-expo-development was iOS-only, and limrun-gradle routed all Expo
dev-loop intent to it, so Android users had no documented Metro/hot
reload path. Extend the expo skill with per-step Android variants in the
same flow: package/asset derivation (including the missing
android.package placeholder trap), gradle Debug builds as assets, the
adb reverse tunnel on Metro's default 8081 (no port range or packager
hostname override needed, unlike iOS), dev-client deep links via
open-url, screenshot-first verification (Expo apps expose no
accessibility nodes on Android), and assembleRelease preview assets
with platform=android links.
Update limrun-android-emulator for the new lim android launch-app and
terminate-app commands: app lifecycle moves out of the adb section into
its own Launching the app section with the watch-until-exit crash
report; adb keeps logcat, files, shell, and package discovery. Route
gradle's Expo pointers to the expo skill.
Every command verified live against production e2e-org emulators: full
dev loop with hot reload observed on sample-expo56-app, both reverse
tunnel and deep-link paths, and a standalone assembleRelease APK
(debug-keystore signed by the Expo template) running without Metro.
lim 0.28.4 prints the tunnel address in the connect started message,
so the serial no longer needs to be parsed out of adb devices. Verified
against the released CLI.
Ran the skill as the sole documentation for 8 subagent sessions (haiku,
sonnet, opus) against production emulators in the e2e org: basic install,
web interaction, adb lane, multi-instance targeting, non-git resolution,
and record/microphone/bandwidth scenarios. All 8 completed their tasks
with no leaked instances, so the changes are refinements, not rescues.
Recurring friction fixed:
- element-tree is one line, so plain grep echoes the whole document;
document the sed newline split every agent had to invent (works on
both BSD and GNU sed)
- verifying installs via the launcher fails because new apps land in
the app drawer; point to pm list packages or launching the app
- page loads after open-url are async; an empty WebView subtree means
still loading, not a broken tree
- web pages expose DOM ids, not pkg:id/... resource ids; select by
text plus class-name there
- type takes the same selectors as tap-element, useful for fields
with no resource id
- lim android list filters with --label-selector; four of eight agents
guessed --label first
- create blocks until the instance is ready; recorded video frames are
half the screenshot resolution; monkey exits nonzero on success
Mirror the iOS skill's install subsection names (Build and install /
Install app from local) and fold sync iteration into the local-install
flow like iOS does. Move the create --no-open/--no-connect defaults note
from Auth and CLI into Installing an app, match the signed stream URL
sharing wording, rename the microphone section to the iOS 'Simulate the
X' pattern, and repeat the element-tree check block after interactions.
Fix the logcat example: the previous line passed a package name where
logcat expects a tag filter; replace it with the verified
logcat --pid=$(pidof -s <pkg>) recipe for app-scoped logs.
Android emulators had no device-driving skill; the only guidance was a
4-line aside in limrun-gradle. Add limrun-android-emulator as the Android
counterpart of limrun-ios-simulator, covering install paths (install-asset,
install-app by URL, sync), the exact-match selector model, the adb tunnel
escape hatch for app lifecycle/logcat/files/shell, microphone audio
injection, bandwidth shaping, preview URLs, and fleet gotchas (x86_64 ABI,
RN empty element trees, background installs, session-bound tunnels).
Every command was verified against a live production instance. Slim the
gradle skill's emulator section to a cross-reference and route its
description to the new skill.
Teach agents to list an app data container before pulling generated files and to reuse the same container flags across file operations.
Co-authored-by: Cursor <cursoragent@cursor.com>
type now sends real key events and errors without focus; set-text is the
verbatim path. tap-element scrolls off-screen elements into view. Also fix
a tap-element flag that does not exist (--text -> --ax-label).
Adds the new `lim ios camera-video play|clear` commands so agents can
drive QR-scan and other camera flows with deterministic frames.
Co-authored-by: Cursor <cursoragent@cursor.com>
Prefer ASC-key-driven signing, document supported export methods, and surface the Apple permission and team errors agents can act on.
Co-authored-by: Cursor <cursoragent@cursor.com>
An external coding agent (Devin) ran the skills on a headless VM against prod.
Accepted the generic findings: --no-open guidance wherever an instance is
created (only the Maestro skill had it), @expo/ngrok as an explicit tunnel
prerequisite since Expo's interactive install fails in non-interactive
environments, the dev-menu onboarding sheet consuming the first deep link, a
pointer from the Maestro skill to the dev-client URL shape, and reading exact
accessibility labels with element-tree before writing text selectors.
Idle tunnels do not stop the inactivity timeout, and ports from dead
sessions free automatically within about two minutes, so agents should
retry on 'already in use' instead of switching ports.
Two live gate runs by agents that only saw the skill text: added a
self-contained Settings verify flow, machine-readable instance id capture,
explicit --id placement, --no-open for headless machines, runner asset
version-agnosticism, recording and screenshot semantics, and benign JDK
warning note. Second run completed with zero failed commands.