← Plugin catalog
Developer Tools

Limrun

Limrun, Inc. v1.1.0

Test apps on cloud simulators

Create a free account to save this plugin.

From the developer

Not specified in the available declarations: capabilities, limitations, pricing & account requirements.

Onboarding example

Create an iOS simulator and show me a screenshot of the home screen
Sources & dates

Developer declarations; not independently tested. Listing last checked Nov 9, 2026. Package observed Nov 9, 2026.

View package source →

Description

From the marketplace listing

Limrun gives your agent iOS simulators and Android emulators in the cloud. Ask for a device and it is ready in seconds, with your app pre-installed if you want.

Language: English · Automatically detected from descriptions.

Matches for “apps”

Exact text from the indicated source. A mention alone does not establish support for your task.

Publisher subtitle

Test apps on cloud simulators

What changed

Files & skills

File archives

Plugin package12 files · 37.6 KBBrowse files →
Skill instructions
limrun-android-emulator17.4 KB

View saved version →

---
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, 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', 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.

## Auth and CLI

Install if needed: `npm install --global lim`. Auth is `lim login` or
`LIM_API_KEY` (it may be set outside the project, so don't ask for it just
because it's missing from `.env` or the shell). 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 <subcommand> --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

Upload the APK built by **limrun-gradle** as a named asset, then create an
emulator with it pre-installed:

```bash
lim gradle build . --upload myapp.apk
lim android create --install-asset myapp.apk --no-open --no-connect
```

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](<signed-stream-url>)`. 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.

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 <package> --detach` (without `--detach`
it blocks watching the app until it exits), or confirm with
`lim android adb-shell -- sh -c "pm list packages | grep <name>"`.

Every time y

Preview of the first 4,000 characters. Read full instructions →

limrun-detox-testing5.83 KB

View saved version →

---
name: limrun-detox-testing
description: Configure, run, or debug Detox on Limrun iOS simulators. Use when attaching the Limrun Detox runtime to an app, wiring Detox mediator connectivity, or validating app/tester connections over destination tunnels.
user-invocable: true
---

# Limrun Detox

Use this for Detox runtime work on Limrun iOS. Keep build concerns separate
unless the user explicitly asks for a native build.

## Components

- Tester: local Node/Jest/Detox process.
- Mediator: `detox run-server`, usually local to the agent machine.
- App client: injected by limulator through `lim ios launch-app --runtime detox`.

## CLI Flow

Check current help before running commands you have not used in this session:

```bash
lim ios tunnel --help
lim ios launch-app --help
```

Run the long-lived mediator, tester, and tunnel from separate terminals.
Before using this quick path, ensure the project's `.detoxrc` reads the session
environment. Detox does not consume these variables automatically:

```js
session: {
  server: process.env.DETOX_SERVER || 'ws://localhost:8099',
  sessionId: process.env.DETOX_SESSION_ID || 'limrun-detox',
}
```

The complete configuration appears under **Detox Test Setup** below.

Terminal 1:

```bash
npx detox run-server -p 8099 -l verbose
```

Terminal 2:

```bash
lim ios tunnel \
  --selector localhost:8099 \
  --detach \
  --id <ios-id>
DETOX_SERVER_URL="ws://localhost:8099"
```

Terminal 3 starts the tester before the app connects:

```bash
DETOX_SERVER="ws://localhost:8099" \
DETOX_SESSION_ID=<session-id> \
  npx detox test --no-start
```

Then relaunch the app from Terminal 2. `--detox-version` is optional when
running from the project with `node_modules/detox`.

```bash
lim ios launch-app <bundle-id> \
  --id <ios-id> \
  --runtime detox \
  --detox-server-url "$DETOX_SERVER_URL" \
  --detox-session-id <session-id> \
  --detox-version <detox-version>
```

Prefer starting the tester before the app connects, or use the maintained orchestration in [limrun-inc/typescript-sdk `examples/detox-ios`](https://github.com/limrun-inc/typescript-sdk/tree/main/examples/detox-ios), to avoid benign mediator "cannot forward" noise.
If you manually launch the app before `npx detox test --no-start`, that mediator message is expected until the tester connects.

If tunnel start reports an active session, inspect it with `lim ios tunnel status --id <ios-id> --json`. Stop an obsolete session with `lim ios tunnel stop --id <ios-id>`, then start the declared mediator selector again.
An open idle tunnel does not count as instance activity, so it does not prevent
the simulator's inactivity timeout between test runs.

## Detox Test Setup

`npx detox test --no-start` still needs the normal Detox project configuration:

- Pass the Detox config file and configuration name from your project (see [`examples/detox-ios/.detoxrc.cjs` in limrun-inc/typescript-sdk](https://github.com/limrun-inc/typescript-sdk/blob/main/examples/detox-ios/.detoxrc.cjs) for a reference layout).
- Use the Limrun third-party driver: `type: '@limrun/detox/driver'`.
- Keep `DETOX_SERVER` and `DETOX_SESSION_ID` aligned with the mediator and launch command.
- Provide Limrun driver env such as `LIMRUN_IOS_ID`, `LIMRUN_IOS_API_URL`, and `LIMRUN_IOS_TOKEN` when screenshots or driver calls need the instance API.

Use [limrun-inc/typescript-sdk `examples/detox-ios`](https://github.com/limrun-inc/typescript-sdk/tree/main/examples/detox-ios) as the maintained happy path for exact config/env wiring. Use `-l trace` on `detox run-server` only when verbose logs are not enough.

For native SwiftUI apps, a minimal Detox configuration usually looks like:

```js
const server = process.env.DETOX_SERVER || 'ws://localhost:8099';
const sessionId = process.env.DETOX_SESSION_ID || 'limrun-detox';

module.exports = {
  testRunner: { args: { $0: 'jest' }, jest: { setupTimeout: 120000 } },
  session: {
    server,
    sessionId,
    debugSynchronization: 0,
  },
  apps: { ios: { t

Preview of the first 4,000 characters. Read full instructions →

limrun-expo-development13.9 KB

View saved version →

---
name: limrun-expo-development
description: "Prepare and run Expo / React Native apps on Limrun with Expo dev-client iteration. Use when the user wants an Expo dev build, Metro tunnel, hot reload, JS/TS iteration without repeated native rebuilds, or to run/test an Expo app on a remote iOS simulator or Android emulator."
user-invocable: true
effort: high
---

# Developing Expo Apps on Limrun

Use this skill for Expo / React Native-specific setup and dev-client iteration, on iOS simulators and Android emulators. Use **limrun-ios-simulator** and **limrun-android-emulator** for command details, device interaction, screenshots, recordings, and cleanup, and the build skills (**limrun-xcode**, **limrun-gradle**) for build flag details and non-Expo workflows.

All builds and device operations must run on Limrun. Do not use local Xcode, local simulators, a local Android SDK, or local emulators; local `adb` is used only to talk to the remote emulator through the CLI's tunnel.

## Expo Readiness

Before changing Expo dependencies or app config, check the app's Expo SDK version and use the matching Expo versioned docs.

Verify this is an Expo app:

```bash
npx expo config --type introspect --json
```

Derive:

- `BUNDLE_ID` from `ios.bundleIdentifier` (iOS) and `PACKAGE` from `android.package` (Android). When `android.package` is missing, introspect reports a placeholder (like `com.placeholder.appid`) while the build generates a different real applicationId; set `android.package` in `app.json` before building so `$PACKAGE` matches the installed app.
- `SLUG` from `slug`
- `SCHEME` from `scheme`, falling back to `exp+${SLUG}`
- `BRANCH` from `git branch --show-current`, falling back to `main`
- `ASSET_NAME="${BUNDLE_ID}/${BRANCH}-debug.zip"` on iOS, `ASSET_NAME="${PACKAGE}/${BRANCH}-debug.apk"` on Android

## Ensure Dev Client

Expo development builds require `expo-dev-client`. If it is missing from `package.json`, install it automatically:

```bash
npx expo install expo-dev-client
```

Installing `expo-dev-client`, adding/removing/updating native dependencies, or changing native app config means the uploaded Debug asset is stale. Build a fresh Debug app before starting the dev loop. Do not merely warn the user that a rebuild may be needed; perform the rebuild.

## Debug Build Asset

First check whether a reusable Debug dev-client asset already exists:

```bash
lim asset list --name-prefix "$BUNDLE_ID/"   # iOS
lim asset list --name-prefix "$PACKAGE/"     # Android
```

Reuse the exact `$ASSET_NAME` only when:

- it exists, and
- no native dependency or native config changed in this session.

If the current task changed native dependencies or native config, skip asset reuse even if `$ASSET_NAME` exists.

When reusing the asset, create or reuse a device and install it:

```bash
lim ios create \
  --reuse-if-exists \
  --install-asset "$ASSET_NAME" \
  --label repo=<repo> \
  --label agent=<agent>

lim android create \
  --reuse-if-exists \
  --install-asset "$ASSET_NAME" \
  --no-open \
  --label repo=<repo> \
  --label agent=<agent>
```

Android note: keep the tunnel that `create` opens by default (do not pass
`--no-connect` here, unlike plain driving sessions); the Metro reverse
tunnel below runs over it. Note the instance ID from the output and pass
`--id` to every later `lim android` call: Metro and Expo run from the app
directory, and instance resolution is per git worktree, so commands run from
elsewhere will not find the instance on their own.

### Fresh build on Android

Build the Debug APK remotely and upload it as the asset (Expo prebuild,
`--expo-app-dir`, and other build flags belong to **limrun-gradle**; the
default `assembleDebug` task is the right dev-client build):

```bash
lim gradle build . --upload "$ASSET_NAME"
lim android create --reuse-if-exists --install-asset "$ASSET_NAME" --no-open --label repo=<repo> --label agent=<agent>
```

For a later native rebuild on a running emulator, rebuild with `--upload` and
install 

Preview of the first 4,000 characters. Read full instructions →

limrun-gradle10.9 KB

View saved version →

---
name: limrun-gradle
description: "Build an Android app on a remote Gradle sandbox with `lim gradle build` instead of local Gradle or Android Studio, from any environment (Linux, Windows, macOS, VM, container). Use when the user wants to build an APK or AAB, sign a release with an upload key, prepare a Play Store publish, inspect build logs, or select sandbox tools and run shell commands, for native Android projects, React Native, and Expo. To run, tap, screenshot, or otherwise interact with the built APK on an emulator, use limrun-android-emulator. For iOS builds, use limrun-xcode or limrun-expo-development."
user-invocable: true
effort: high
---

# Remote Gradle build

Build Android projects on Limrun's remote Gradle sandboxes, from any
environment (Linux, Windows, macOS, VM, container). `lim gradle build` syncs
your sources to a remote instance, runs the project's own Gradle wrapper
there, and streams the build output. Never fall back to local Gradle, a local
Android SDK, or a local emulator. Your job doesn't end at a green build: get
the app running or the artifact delivered, and iterate until the user is
satisfied.

For iOS builds, use **`limrun-xcode`** instead of this skill. For the Expo
dev-client loop (Metro, hot reload) on either platform, use
**`limrun-expo-development`**; it comes back here for the Android Debug
build.

## Auth and CLI

Install if needed: `npm install --global lim`. Auth is `lim login` or
`LIM_API_KEY` (it may be set outside the project, so don't ask for it just
because it's missing from `.env` or the shell). 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 `--help` instead of guessing:

```bash
lim gradle --help
lim gradle build --help
```

## Build an APK

Instead of `./gradlew`, build with:

```bash
lim gradle build .
```

This creates or reuses the remembered Gradle instance, syncs the current
directory, and runs `assembleDebug` by default. Pick tasks explicitly with
`--task` (repeatable):

```bash
lim gradle build . --task :app:assembleRelease
```

Use `--project-path` when the Gradle root is nested and auto-discovery is
ambiguous (for example a bare React Native repo where Gradle lives in
`android/`; the server usually finds it on its own):

```bash
lim gradle build . --project-path android
```

Expo managed-workflow projects (no `android/` directory) are detected
automatically: the sandbox installs dependencies and runs `expo prebuild`
before Gradle. Setting `--expo-app-dir` (monorepos) or `--abi` forces that
pipeline and errors when no Expo app is detected:

```bash
lim gradle build ./my-monorepo --expo-app-dir apps/mobile
```

For iterating on an Expo app with Metro and hot reload rather than plain
builds, use **`limrun-expo-development`**.

## Detached builds and logs

Use `--detach` to return once the build is accepted; a webhook is optional.
`logs` reads the latest build without an exec ID, including persisted logs after
instance deletion; add `--follow` to wait for completion.

```bash
lim gradle build . --detach
lim gradle logs
lim gradle logs --follow
```

## Tool versions and shell commands

After syncing, `lim gradle use` selects tools in the sandbox and installs missing versions.
Run `lim gradle tools install` for synced project tool selections ([details](https://docs.limrun.com/docs/android/build-with-gradle)). Builds keep the project's `gradlew`; Android SDK/NDK/CMake use `sdkmanager`.

```bash
lim gradle tools
# Node includes npm/npx.
lim gradle use node@24 pnpm@10 yarn@4 bun@1 java@temurin-17 bundletool@1
lim gradle tools install
lim gradle run -- mise use --pin node@24.5.0
lim gradle run --env APP_ENV=staging -- npm run generate
lim gradle build . --env APP_ENV=staging
```

## Run it on an emulator

Upload the built APK as a named asset, then install it on an Android instance:

```bash
lim gradle build . --upload myapp.apk
lim android create --install-asset=myapp.apk
```

Build uploads defau

Preview of the first 4,000 characters. Read full instructions →

limrun-ios-simulator14.4 KB

View saved version →

---
name: limrun-ios-simulator
description: "Drive an app running on a Limrun cloud iOS simulator: launch, tap, type, read the accessibility element tree, screenshot, record video, connect the app to local services, play a video file as the camera, and run timed action chains. Use after a build (from any builder) when the user wants to see, test, or interact with their app on a simulator, or says 'show me a screenshot', 'tap', 'run the UI test', 'record a video', 'connect localhost', 'reach my local server from the simulator', 'mock the camera', or 'launch on simulator'. To build the app first, use limrun-xcode-bazel (Bazel workspaces) or limrun-xcode (xcodebuild projects)."
user-invocable: true
effort: high
---

# Limrun iOS Simulator

Interact with an app running on a Limrun cloud iOS simulator, from any
environment (Linux, Windows, macOS, VM, container). This skill is build-agnostic:
it assumes the app was already built and installed by a build skill
(`limrun-xcode-bazel` for Bazel, `limrun-xcode` for xcodebuild). Keep build
concerns in those skills; this one is about driving the running simulator.

Never use local Xcode, local simulators, or local macOS tools.

## Auth and CLI

Install if needed: `npm install --global lim`. Auth is `lim login` or
`LIM_API_KEY` (it may be set outside the project, so don't ask for it just
because it's missing from `.env` or the shell). 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 ios <subcommand> --help` instead of guessing.

## Installing an app bundle

You can either use Limrun remote Bazel or Xcode services to build the app bundle and have
it installed to the simulator automatically or you can sync a pre-built local `.ipa`
file or `.app` folder to the simulator. The main requirement is that it must be
built for simulator.

### Build and install

A build skill usually attaches the simulator for you (`lim xcode rbe --ios`, or
`lim xcode build .` then attach). Check what's already there:

```bash
lim xcode get      # is a simulator attached to the current build target?
lim ios list       # all running iOS instances
```

If none is attached, create one. It installs the last build immediately, so you
don't need to rebuild:

```bash
lim ios create --attach
```

If the create (or `lim xcode rbe --ios`) output includes a signed stream URL,
share it with the user as a Markdown link, like
`[Live simulator](<signed-stream-url>)`. If you have a browser the user can see,
open the URL there and tell them. Otherwise pass `--no-open` to `create`: it
skips opening the URL locally and still prints it for sharing.

`lim xcode get` prints a Limrun console URL instead. It opens the same live
view but requires a console login, so prefer the signed stream URL for sharing.
If the console URL is all you have, share it and mention it needs login.

### Install app from local

Create a new simulator:

```bash
lim ios create
```

Share the signed stream URL with the user as a Markdown link, like
`[Live simulator](<signed-stream-url>)`. If you have a browser the user can see,
open the URL there and tell them.

You can then run the following command to upload a bundle from local:

```bash
lim ios sync <path to .ipa file or .app folder>
```

You can run the same command every time you need to install a new version of the
bundle. It will patch with the difference and reload it in the simulator.

## Targeting the right instance

Most `lim ios` commands default to the last created instance and resolve the
"current" one from the **git repo / worktree** of your cwd. So even when a
simulator is attached and `lim xcode get` shows it, a `lim ios` command can still
report `No instance ID provided and no recent ios instance found`, because your
cwd isn't the git worktree where the instance was created (or isn't a git repo at
all). This bites most often right after `lim xcode rbe --ios` in a fresh project.

The reliable recipe when that hap

Preview of the first 4,000 characters. Read full instructions →

limrun-maestro-testing6.67 KB

View saved version →

---
name: limrun-maestro-testing
description: "Run Maestro YAML flows against a Limrun cloud iOS simulator with `lim ios maestro`, from any environment (Linux, Windows, macOS, VM, container). Use when the user wants to run, write, or debug Maestro flows or `maestro test` on iOS, migrate an existing Maestro suite to remote simulators, or asks for UI testing with Maestro. iOS simulators only today. For Detox suites use limrun-detox-testing; for driving the simulator without a test framework use limrun-ios-simulator."
user-invocable: true
---

# Maestro on Limrun iOS

Run the stock upstream Maestro CLI against a remote Limrun iOS simulator.
`lim ios maestro` wires `maestro test` to the instance transparently: it
installs and launches the Maestro XCTest runner on the simulator when needed,
then routes the driver traffic to it. No fork of Maestro, no local simulator,
no local Xcode.

## Prerequisites

- `lim` CLI 0.22.0 or newer: `npm install --global lim`. Auth is `lim login` or
  `LIM_API_KEY` (it may be set outside the project, so don't ask for it just
  because it's missing from `.env` or the shell).
- Maestro CLI on PATH: `curl -fsSL https://get.maestro.mobile.dev | bash`.
  Maestro needs Java 17+ (`java -version` to check). Both Maestro 2.5.x and
  2.6+ work; `lim` adapts to the installed version automatically.

The CLI is the source of truth: if a flag errors or you need one not shown
here, check `lim ios <subcommand> --help` instead of guessing.

## Verify the setup

Before touching the user's app, prove the whole pipeline with a flow against
the built-in Settings app; it needs no app install, tunnel, or build:

```bash
ID=$(lim ios create --install-asset appstore/maestro-ios-runner-2.5.1.tar.gz \
  --no-open --quiet --json | jq -r .metadata.id)

cat > hello-flow.yaml <<'EOF'
appId: com.apple.Preferences
---
- launchApp
- assertVisible: General
- takeScreenshot: settings-check
EOF

lim ios maestro --id "$ID" test hello-flow.yaml
```

All three steps reporting `COMPLETED` means Maestro, the runner, and the
remote wiring all work; anything failing after this point is about the app or
the flow, not the setup.

## Run a flow

```bash
lim ios maestro test flow.yaml
lim ios maestro test flows/
lim ios maestro --id <ios-id> test flow.yaml
```

Without `--id` this targets the most recently created iOS instance in the
current workspace (workspaces follow the git repo or worktree you run from);
pass `--id <ios-id>` (before `test`) in scripts, agents, or when running from
a different directory. The first run on an instance takes a few extra seconds
to launch the runner (plus the install when it wasn't preinstalled); later
runs skip that. Extra Maestro flags go after
`--`:

```bash
lim ios maestro -- test flow.yaml --include-tags smoke --test-output-dir artifacts
```

Do not pass `--platform`, `--device`, `--udid`, `--no-reinstall-driver`, or
`--driver-host-port`; `lim` sets those itself and rejects duplicates.
Real Maestro exit codes and reports are preserved, so CI wiring works as with
local Maestro.

## Instance setup

Any running iOS instance works; the runner is installed on first use. Creating
the instance with the runner preinstalled skips that step:

```bash
lim ios create --install-asset appstore/maestro-ios-runner-2.5.1.tar.gz --no-open
```

`--no-open` skips opening the stream URL in a browser (important on headless
and CI machines). The runner asset name above is the only published one and it
is version-agnostic: the same runner serves Maestro 2.5.x through 2.7.x, so do
not look for an asset matching your Maestro version.

Install the app under test as usual (`lim ios create --install app.ipa`,
`lim ios install-app`, or a build skill), then reference its bundle id via
`appId:` in the flow. For Expo Go testing, also preinstall
`appstore/Expo-Go-54.0.6.tar.gz` and open the project URL with `openLink`
(env vars must be prefixed `MAESTRO_` to be visible in flows):

```bash
MAESTRO_EXPO_URL='exp://<tunnel-host>' lim ios maestro 

Preview of the first 4,000 characters. Read full instructions →

limrun-xcode20.5 KB

View saved version →

---
name: limrun-xcode
description: "Build an iOS / Apple app on remote Xcode with `lim xcode build` instead of local xcodebuild, or run its XCTest suites with `lim xcode test`, from any environment (Linux, Windows, macOS, VM, container). Use for non-Bazel projects (an `.xcodeproj` / `.xcworkspace`, an XcodeGen `project.yml` with a gitignored project, React Native / Expo native build) when the user wants to build, compile, test, inspect build logs, reload, produce a preview build, or ship a signed device IPA. To run, tap, screenshot, or otherwise interact with the result on a simulator, use limrun-ios-simulator. For Bazel workspaces, use limrun-xcode-bazel."
user-invocable: true
effort: high
---

# Remote Xcode build

Build Apple projects on Limrun's remote Xcode, from any environment (Linux,
Windows, macOS, VM, container). `lim xcode build` syncs your sources to a remote
Xcode instance, builds there, and (when a simulator is attached) installs and
relaunches the app. Never fall back to local Xcode, local simulators, or local
build tools. Your job doesn't end at a green build: get the app running, verify
it works, and iterate until the user is satisfied.

For driving the app once it's running (tap, type, element tree, screenshot,
record), use the **`limrun-ios-simulator`** skill. For Bazel workspaces, use
**`limrun-xcode-bazel`** instead of this skill.

## Auth and CLI

Install if needed: `npm install --global lim`. Auth is `lim login` or
`LIM_API_KEY` (it may be set outside the project, so don't ask for it just
because it's missing from `.env` or the shell). 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 `--help` instead of guessing:

```bash
lim xcode --help
lim xcode build --help
```

## Build

Instead of `xcodebuild`, build with:

```bash
lim xcode build .
```

This creates or reuses the remembered Xcode target, syncs the current directory,
and streams the build logs through stdout and stderr.

Use `--scheme` and `--workspace` if the project has multiple schemes or uses a
workspace file:

```bash
lim xcode build . --scheme MyApp --workspace MyApp.xcworkspace
```

Use `--configuration Debug` or `--configuration Release` for a specific Xcode
configuration. If omitted, Limrun uses limbuild's project-type default: `Debug`
for native Xcode builds, `Release` for React Native / Expo builds.

```bash
lim xcode build . --configuration Debug
```

### Detached builds and logs

Use `--detach` to return once the build is accepted; a webhook is optional.
`logs` reads the latest build without an exec ID, including persisted logs after
instance deletion; add `--follow` to wait for completion.

```bash
lim xcode build . --detach
lim xcode logs
lim xcode logs --follow
```

### Pick the Xcode version

A sandbox builds with its node's default Xcode. To build with another installed
major (Xcode 27 beta is available beside the default), set a preference once
for the workspace; every later build, test, RBE session and new sandbox follows
it, and the flag overrides it for one command:

```bash
lim xcode version list      # versions the sandbox can build with; * marks the one in use
lim xcode use xcode@27      # prefer 27 for this workspace; switches the remembered sandbox now
lim xcode build .           # builds with 27
lim xcode version           # "27.0 (27A5252f)" shows the sandbox's current Xcode
lim xcode build . --xcode-version 26   # one-off override, not remembered
lim xcode version unset     # forget the preference; the sandbox goes back to the node default
```

Combine Xcode and mise selections with `lim xcode use xcode@27 node@24`.

For scripting, `lim xcode version list --quiet` prints one selectable major per
line and `--json` returns `{ installed, bound, preferred }` (`installed[].betaSeed`
carries the beta seed). The table marks the Xcode in use with `*`.
`lim xcode version set` does not record a major the node lacks (the error lists
the available 

Preview of the first 4,000 characters. Read full instructions →

limrun-xcode-bazel7.27 KB

View saved version →

---
name: limrun-xcode-bazel
description: "Build a Bazel-based iOS / macOS / Apple app on Limrun's remote build execution (RBE) instead of a local Mac, and install it on a remote iOS simulator. Use when the project is a Bazel workspace (MODULE.bazel / WORKSPACE) building rules_apple / rules_swift targets and the user wants to `bazel build` it or run it on a simulator, or when a `--config=limrun` build or install misbehaves. To then tap, type, screenshot, or otherwise interact with the running app, use limrun-ios-simulator. For non-Bazel (plain xcodebuild) projects use limrun-xcode instead."
user-invocable: true
effort: high
---

# Bazel iOS builds on Limrun RBE

Build Bazel Apple projects on Limrun's remote Mac workers — from any environment
(Linux, Windows, macOS, VM, container), no local Xcode. `lim xcode rbe` brings up
a remote RBE stack, tunnels it to a local port, and writes a `.limrun/` config so
`bazelisk build --config=limrun` runs Apple actions remotely. Never fall back to
local Xcode or build tools.

## Auth and CLI

Install if needed: `npm install --global lim`. Auth is `lim login` or
`LIM_API_KEY` (may be set outside the project — don't ask for it just because
it's absent). 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 xcode rbe --help` instead of guessing.

## Build

1. From the **Bazel workspace root** (has `MODULE.bazel` / `WORKSPACE`), run
   `lim xcode rbe`. It sets up the instance + `.limrun/` config and **prints the
   exact build command**. The tunnel runs in the background (prints a PID);
   `--no-daemon` keeps it foreground.
2. Run the printed command, e.g.
   `bazelisk --digest_function=sha256 build --config=limrun //App`.

Don't hand-write `.limrun/` or the flags — the CLI generates them for the
sandbox's Xcode and your OS. `lim xcode version set 27` (or the one-off
`lim xcode rbe --xcode-version 27`) builds with another installed major. Re-run
`lim xcode rbe` (after `--stop`) to refresh after a fleet Xcode upgrade or an
Xcode switch.

To add your own Bazel flags to the limrun path without editing the generated
config, put them in **`user.limrun.bazelrc`** at the workspace root. The
generated config try-imports it last, so your `build:limrun --…` lines win, and
it survives `lim xcode rbe` regeneration (`.limrun/` does not).

## Run on a simulator

`lim xcode rbe` is build-only; attach a simulator when the user wants to see or
run the app. Check or attach (it installs the last build immediately, so no
rebuild is needed):

```bash
lim xcode get             # is a simulator already attached?
lim ios create --attach   # attach one
```

Add `--no-open` when you have no browser to show the user; it skips opening
the stream URL locally and still prints it for sharing.

If the attach output includes a signed stream URL, share it with the user as a
Markdown link, such as `[Live simulator](<signed-stream-url>)`.

With a simulator attached, every successful `--config=limrun` build automatically
reinstalls and relaunches the app, no separate install step:

```bash
bazelisk --digest_function=sha256 build --config=limrun //App
```

Notes:
- **Attach upfront** if you already know you want a sim: `lim xcode rbe --ios`
  (attaches at startup, removed on `--stop`).
- Auto-install happens server-side from the build's events; there is no
  `lim xcode rbe install` subcommand or `--target` flag. To force a reinstall,
  rebuild (a cache-hit rebuild is seconds).
- It fires when the successful invocation produced a single app, so in a
  multi-app workspace build one app target per invocation (`//App`, not
  `//...`); a multi-app build succeeds but installs nothing.

To tap, type, read the element tree, screenshot, or record the running app,
switch to the **`limrun-ios-simulator`** skill.

## Upload builds as assets

To publish a build as a Limrun asset (preview links, installing on other
simulators, CI artifacts), arm uploads at tunnel st

Preview of the first 4,000 characters. Read full instructions →

Referenced files: 2 — file references are metadata, not package contents.

Package details

Publisher declarations from the archived package. These are separate from our research and the live service's terms.

Package author
Limrun, Inc.

Package observed Nov 9, 2026.

Technical details
First seen
Sep 30, 2026 · 22:02 UTC
Last seen
Nov 9, 2026 · 06:00 UTC
Collection status
Collected

plugin_asdk_app_6aa95107d094819192324cfe1acf2985

Download plugin data (JSON)

Plugin details: served from cache. Prepared . Refreshed when plugin data changes or after 6 hours. Your account and Follow status are live.