Officialexpo/skillsMIT5 files

Eas Simulator

EAS service (paid). Run and control a user's app on a remote iOS/Android simulator hosted on EAS cloud. Read before running any `eas simulator:*` commands - it has the current syntax for this experimental API. Use whenever the user needs a simulator they can't run locally - 'run my app on a cloud simulator', 'use eas simulator to run/install/screenshot my app', 'I'm on Linux/Cursor and need an iOS device', 'no sim on this box / headless CI', 'let an agent click through my app and screenshot it', 'test my dev build on a remote sim with live reload', 'stream a sim to my browser' - even when they don't say 'EAS Simulator' or 'cloud'. On a host WITHOUT a local simulator (Linux, CI, cloud sandbox) it's the default; on macOS, do NOT auto-trigger for a plain 'run on the simulator' - use it only for a cloud/remote/shareable sim, an iOS version they lack, or an agent-driven session. NOT for local sims (expo run:ios, Xcode, Android Studio), EAS Build/Update, web preview, or physical devices.

Specification
Skill ID
expo/skills/eas-simulator
Publisher
expo
Repository
skills
Installs
228
Files
5
License
MIT
Synced
Sep 16, 2026
How to use it

Open any RiverX project, open the Skills panel in the chat, and search for this identifier. The files are fetched from the source repository at install time.

expo/skills/eas-simulatorInstalls these files
  • SKILL.md
  • agents/openai.yaml
  • references/controllers.md
  • references/run-your-app.md
  • references/troubleshooting.md

What this skill tells the agent

EAS Simulator

EAS service - costs apply. EAS Simulator is a hosted EAS service. Session usage is subject to your account's pricing and limits. See https://expo.dev/pricing for current terms.

EAS Simulator runs a remote iOS simulator or Android emulator on EAS infrastructure that you drive from your machine — from the CLI, from an AI agent (via agent-device), and from a browser preview. It's the unlock for environments that can't run a simulator locally (Linux boxes, cloud/background agents like Cursor Cloud), and for letting an agent verify a change on a real device instead of only reasoning about code.

The simulator:* commands are experimental and hidden, and need a recent eas-cli (≥ 20.3.0 as of writing) — which is why this skill runs everything via npx --yes eas-cli@latest. Flags and verbs may change; the relevant subcommand's `--help` output is authoritative.

When to use

The frontmatter description carries the trigger phrases. In short: use this to get a user's app onto a cloud simulator and interact with it — especially from a Mac-less or cloud/sandbox agent. Not for local sims (expo run:ios, Xcode, Android Studio), store builds/signing (that's EAS Build), or physical devices. For the macOS case, see Cloud vs local next.

Cloud vs local: decide this first

  • Explicit cloud/remote/shareable request: use EAS Simulator after checking access, on any host.
  • Generic simulator request: use a suitable local simulator when available. If the host cannot run the requested simulator (for example, iOS on Linux or a cloud sandbox), use EAS Simulator after checking access. A non-macOS host may still support a local Android emulator.
  • Honor an explicit local choice; hand off to expo run:ios / Xcode / Android Studio as appropriate. Clarify only when the requested environment remains ambiguous and affects the task.

When the user requests EAS Simulator or a cloud simulator, proceed within that request and any stated budget. Explain applicable usage once and carry existing authorization through the session. Ask before exceeding a stated budget or expanding beyond the requested work.

Prerequisites

  • Run every `eas` command via `npx --yes eas-cli@latest …` — guarantees a CLI new enough to have simulator:* (a global eas is often too old), and --yes skips npx's prompt. (Bare eas is fine if eas --version is current.)
  • Authenticated. Interactive machine → npx --yes eas-cli@latest login. Cloud sandbox / CI / headless agent has no browser login — set `EXPO_TOKEN` (expo.dev → Account → Access Tokens) in the env instead. Verify either way with npx --yes eas-cli@latest whoami.
  • Run from an Expo project directory. A fresh app needs one-time setup: npx --yes eas-cli@latest init to create/link the project (when there's no projectId), and set `ios.bundleIdentifier` in app config if it's missing — a fresh create-expo-app often has none, and prebuild/eas build need it (they prompt or fail without it; e.g. dev.<owner>.<slug>). Read current config with npx expo config --json (it may live in app.config.js). The first Mode-C run is slow (native build); later runs reuse it.
  • A controller to drive the device. This skill uses agent-device (open source, MIT), run on demand via npx agent-device@latest — nothing globally installed. Appium and argent are alternative automation interfaces; web-preview-only has no automation interface. See references/controllers.md.
  • `.env.eas-simulator` is written/managed by eas-cli (not this skill): it holds the session id (EAS_SIMULATOR_SESSION_ID) + the daemon URL/token, so get/stop/exec default to that session (usually omit `--id`; pass --id <id> to target another). It carries a token → keep it gitignored (eas-cli marks it "do not commit" but may not add the ignore rule, and a fresh app's .gitignore won't cover it — add .env.eas-simulator if missing).
  • The command blocks assume a POSIX shell (bash/zsh) — printf, lsof, $(seq …) loops won't run in cmd/PowerShell. On Windows, run them in WSL or Git Bash, or translate as you go (the eas-cli/agent-device invocations themselves are cross-platform).

Session lifetime

  • --max-duration-minutes N is the hard automatic-stop deadline. Customize it when supported by the account; otherwise use the service's default session limit.
  • --max-idle-time-minutes N stops a session after that many inactive minutes. Omitted means no idle timeout: the session runs until its maximum duration or an explicit stop.
  • Only activity reported through `agent-device` and `argent` resets the idle timer. Appium commands and browser-preview activity do not reset it. For Appium or a user-driven browser preview, rely on the maximum duration—not idle time—to bound the session; customize it with --max-duration-minutes when supported by the account.

Check availability first

EAS Simulator is a limited-access EAS feature that is still rolling out, so it isn't enabled on every account. Check access before starting a session; this read-only command does not create a session.

npx --yes eas-cli@latest simulator:availability --json
# → {"available": true, ...}  enabled → continue to the core loop
# → {"available": false, ...} not enabled → do NOT start a session

If it's not available, don't call simulator:start (it will fail). Instead, hand off gracefully so you keep making progress without this skill:

  • Tell the user EAS Simulator isn't available on their account yet — it's coming soon.
  • Fall back to their normal local path for the actual goal — expo run:ios / Xcode / Android Studio for a local sim/emulator, an EAS Build, or whatever else fits. Don't dead-end on the cloud sim; the request was almost never "use EAS Simulator specifically."

(If simulator:availability isn't recognized, the CLI is too old — upgrade, or treat a not enabled for this account error from simulator:start the same way: stop and fall back.)

The core loop (always the same)

A session is: start → (install your app) → drive → stop. eas-cli owns the session; the device verbs (open/tap/screenshot) come from the controller, which npx --yes eas-cli@latest simulator:exec runs for you with the session's connection env loaded.

# 1. Start a session (boots the remote sim + agent-device daemon; writes .env.eas-simulator).
# If the dotenv names a session, inspect it with simulator:get --json first. Reuse it when it
# belongs to this run; stop it only when it is in scope and no longer needed. An IN_PROGRESS
# session may be intentionally concurrent, so preserve its id/config before resetting the dotenv.
# Continue below only after choosing how to handle that existing session.
printf '# managed by eas-cli\n' > .env.eas-simulator   # clear only after resolving any live session
npx --yes eas-cli@latest simulator:start --platform ios --type agent-device --non-interactive \
  --name "Checkout flow screenshots"   # always name it — see 'Always name the session'
#    Then confirm it's live: simulator:get --json → status IN_PROGRESS (bounded poll in run-your-app.md).

# 2. Drive it through `exec` (loads the session env, then runs the command you give it).
#    agent-device runs on demand via npx — nothing installed globally.
npx --yes eas-cli@latest simulator:exec npx agent-device@latest open <app-or-url> --platform ios
npx --yes eas-cli@latest simulator:exec npx agent-device@latest snapshot -i          # interactive UI tree → @e1, @e2 refs
npx --yes eas-cli@latest simulator:exec npx agent-device@latest press @e2            # tap a ref (NOTE: 'press', not 'tap')
npx --yes eas-cli@latest simulator:exec npx agent-device@latest screenshot ./shot.png

# 3. Stop the session and reset the dotenv. Omit --id to target the dotenv session.
npx --yes eas-cli@latest simulator:stop