@limrun/cli
The official command-line interface for Limrun — create and control cloud mobile sandboxes for Android, iOS, and Xcode.
Installation
npm install -g @limrun/cli
npx @limrun/cli <command>
Authentication
lim login
lim --api-key <YOUR_KEY> android list
export LIM_API_KEY=<YOUR_KEY>
lim android list
lim logout
The CLI stores configuration in ~/.lim/config.yaml. This file is compatible with the Go-based lim CLI — if you've already logged in with the Go version, the TypeScript CLI will use the same credentials.
Global Flags
Every command supports these flags:
--api-key <value> | API key (also reads LIM_API_KEY env var) |
--json | Output as JSON instead of human-readable tables |
--help | Show help for any command |
Command Structure
Commands are organized by resource (noun-first), so you can discover everything available for a platform with --help:
lim ios --help
lim android --help
lim xcode --help
lim asset --help
Instance ID is optional on interaction commands. When omitted, the CLI uses the last created instance of the matching type:
lim ios create
lim ios screenshot -o test.png
lim ios tap 100 200
lim session start
You can always provide an ID explicitly to target a specific instance:
lim ios screenshot ios_def456 -o test.png
Top-level shortcuts are available for common actions — the platform is auto-detected from the instance ID prefix:
lim screenshot ios_abc123
lim tap 100 200 ios_abc123
lim delete ios_abc123
Commands
- iOS — Create, manage, and interact with iOS instances
- Android — Create, manage, and interact with Android instances
- Xcode — Create and manage Xcode sandbox instances
- Assets — Upload and download files (APKs, IPAs, etc.)
- Sessions — Persistent connections for fast, interactive device control
- Xcode Build Pipeline — Sync code and run xcodebuild remotely
iOS
lim ios create
lim ios list
lim ios list <ID>
lim ios delete <ID>
Create Options
lim ios create
lim ios create --model ipad --rm
lim ios create --install-asset my-app.ipa
lim ios create --xcode
lim ios create --region us-west --display-name "CI Test" --label env=ci --rm
Flags for ios create:
--rm | Auto-delete the instance on exit (Ctrl+C) |
--model <iphone|ipad|watch> | Simulator device model |
--xcode | Attach a Xcode build sandbox to the iOS instance |
--region <value> | Region for the instance (e.g. us-west) |
--display-name <value> | Human-readable name |
--label <key=value> | Labels (repeatable). Used for filtering and reuse |
--hard-timeout <duration> | Max lifetime (e.g. 1m, 10m, 3h). Default: none |
--inactivity-timeout <duration> | Idle timeout. Default: 3m |
--reuse-if-exists | Reuse an existing instance with matching labels/region |
--install <file> | Local file to install (auto-uploads, repeatable) |
--install-asset <name> | Asset name to install (repeatable) |
List and Filter
lim ios list
lim ios list --all
lim ios list --state creating
lim ios list --region us-west
lim ios list --label-selector env=prod
lim ios list --json
Device Interaction
All interaction commands accept an optional [ID] as the last argument. When omitted, the last created iOS instance is used.
lim ios screenshot -o screenshot.png
lim ios screenshot
lim ios tap 100 200
lim ios tap-element --label "Submit"
lim ios tap-element --accessibility-id btn_ok
lim ios type "Hello World"
lim ios type "search query" --press-enter
lim ios press-key enter
lim ios press-key a --modifier shift
lim ios scroll down --amount 500
lim ios element-tree
lim ios element-tree | jq '.'
lim ios open-url https://example.com
lim ios open-url myapp://settings
App Management (iOS only)
lim ios install-app ./MyApp.ipa
lim ios install-app https://example.com/app.ipa
lim ios launch-app com.example.myapp
lim ios launch-app com.example.myapp --mode RelaunchIfRunning
lim ios terminate-app com.example.myapp
lim ios list-apps
Log Streaming (iOS only)
lim ios log com.example.myapp --lines 50
lim ios log com.example.myapp -f
Video Recording
lim ios record start
lim ios record start --quality 8
lim ios record stop -o recording.mp4
Xcode Integration
lim ios sync ./MyProject
lim ios build --scheme MyApp --workspace MyApp.xcworkspace
Android
lim android create
lim android list
lim android list <ID>
lim android delete <ID>
Create Options
lim android create
lim android create --install ./my-app.apk --install ./another.apk
lim android create --no-stream
lim android create --region us-west --display-name "CI Test" --label env=ci --rm
Android-specific flags:
--[no-]connect | Start ADB tunnel (default: true) |
--[no-]stream | Launch scrcpy for visual control (default: true) |
--adb-path <path> | Path to adb binary (default: adb) |
Device Interaction
All interaction commands accept an optional [ID] as the last argument. When omitted, the last created Android instance is used.
lim android screenshot -o screenshot.png
lim android tap 100 200
lim android tap-element --resource-id com.example:id/button
lim android tap-element --text "Sign In"
lim android type "Hello World"
lim android press-key enter
lim android scroll down --amount 500
lim android element-tree
lim android install-app ./app.apk
lim android open-url https://example.com
lim android record start
lim android record stop -o recording.mp4
ADB Tunnel
Connect to a running Android instance for direct adb access:
lim android connect
lim android connect android_abc123 --adb-path /usr/local/bin/adb
The tunnel stays open until you press Ctrl+C. While connected, you can use adb commands in another terminal.
Xcode
Standalone Xcode build sandboxes for remote compilation.
lim xcode create
lim xcode list
lim xcode list <ID>
lim xcode delete <ID>
lim xcode create --rm --region us-west --hard-timeout 1h
lim xcode sync ./MyProject
lim xcode build --scheme MyApp --workspace MyApp.xcworkspace
lim xcode build --scheme MyApp --upload my-app-build
Assets
Assets are files (APKs, IPAs, configs, etc.) stored in Limrun's cloud storage for use with instances.
lim asset push ./my-app.apk
lim asset push ./my-app.ipa -n custom-name
lim asset pull asset_abc123
lim asset pull my-app.apk
lim asset pull asset_abc123 -o ./downloads
lim asset list
lim asset list --name my-app
lim asset list --download-url
lim asset list asset_abc123
lim asset delete asset_abc123
Sessions
Sessions keep a persistent WebSocket connection to an instance in the background, making all interaction commands near-instant (~50ms instead of ~2s per command).
Why Sessions?
Without a session, every command creates a new connection:
lim ios screenshot # ~2s (connect + auth + screenshot + disconnect)
lim ios tap 100 200 # ~2s (connect + auth + tap + disconnect)
lim ios element-tree # ~2s (connect + auth + fetch + disconnect)
# Total: ~6s for 3 commands
With a session, the connection is created once and reused:
lim session start # ~2s (one-time connection setup)
lim ios screenshot # ~50ms (reuses connection)
lim ios tap 100 200 # ~50ms (reuses connection)
lim ios element-tree # ~50ms (reuses connection)
lim session stop # instant cleanup
# Total: ~2.15s for 3 commands
This makes sessions essential for interactive workflows, AI agent loops, and any scenario where you run multiple commands against the same instance.
Session Commands
lim session start
lim session start ios_abc123
lim session start ios_abc123
lim session start android_def456
lim session status
lim session status --json
lim session stop ios_abc123
lim session stop --all
If only one session is active, lim session stop (no ID) stops it automatically.
How It Works
Each lim session start spawns an independent background daemon that:
- Holds a persistent WebSocket connection to that specific instance
- Listens on its own Unix socket at
/tmp/lim-sessions/<instance-id>/
- All interaction commands automatically detect the matching session and route through it
- Multiple sessions run in parallel with no shared state
Example: Interactive Testing
lim ios create --model iphone
lim session start
lim ios launch-app com.example.myapp
lim ios element-tree | jq '.tree'
lim ios tap-element --label "Login"
lim ios type "user@example.com"
lim ios tap-element --label "Submit"
lim ios screenshot -o after-login.png
lim session stop
lim ios delete ios_abc123
Example: Multi-Device AI Agent
lim ios create --model iphone
lim ios create --model ipad
lim session start ios_phone_123
lim session start ios_tablet_456
lim ios launch-app com.example.myapp ios_phone_123
lim ios launch-app com.example.myapp ios_tablet_456
lim ios screenshot ios_phone_123 -o phone.png
lim ios screenshot ios_tablet_456 -o tablet.png
lim ios tap 200 400 ios_phone_123
lim ios element-tree ios_tablet_456 --json > tablet-tree.json
lim session stop --all
lim ios delete ios_phone_123
lim ios delete ios_tablet_456
Example: Automated Test Matrix
DEVICES=("iphone" "ipad")
IDS=()
for model in "${DEVICES[@]}"; do
ID=$(lim ios create --model $model --json | jq -r '.metadata.id')
lim session start $ID
IDS+=($ID)
done
for ID in "${IDS[@]}"; do
lim ios launch-app com.example.myapp $ID
lim ios screenshot $ID -o "test_${ID}.png"
done
lim session stop --all
for ID in "${IDS[@]}"; do
lim delete $ID
done
Xcode Build Pipeline
Build and test iOS apps remotely using cloud Xcode sandboxes. The sync and build commands work with both standalone Xcode instances and iOS instances that have Xcode sandbox enabled.
Option A: iOS Instance with Xcode Sandbox (Recommended)
This gives you a simulator and a build environment in one instance — the built app is automatically installed on the simulator.
lim ios create --xcode
lim ios sync ./MyProject
lim ios build --scheme MyApp --workspace MyApp.xcworkspace
lim session start
lim ios launch-app com.example.myapp
lim ios element-tree | jq '.'
lim ios screenshot -o built-app.png
lim session stop
lim ios delete ios_abc123
Note: The Xcode sandbox URL is only returned when the instance is created — not on subsequent list calls. The CLI caches it locally at ~/.lim/instances/ so that sync and build can find it. This means sync/build must run on the same machine where ios create --xcode was executed.
Option B: Standalone Xcode Instance
Use this when you only need to build (no simulator needed), or when you want to attach a simulator separately.
lim xcode create --rm
lim xcode sync ./MyProject
lim xcode build --scheme MyApp --workspace MyApp.xcworkspace
lim xcode build --scheme MyApp --upload my-app-build
lim asset pull my-app-build -o ./build-output
Sync Options
lim ios sync
lim ios sync ./MyProject --watch
lim ios sync ./MyProject
lim ios sync ./MyProject --no-watch
lim ios sync ./MyProject --no-install
The sync automatically ignores build artifacts (build/, DerivedData/, .build/), dependency folders (Pods/, Carthage/Build/, .swiftpm/), and user-specific files (xcuserdata/, .dSYM/).
Configuration
The CLI reads configuration from multiple sources (in order of precedence):
- Command-line flags (
--api-key)
- Environment variables (
LIM_API_KEY, LIM_API_ENDPOINT, LIM_CONSOLE_ENDPOINT)
- Config file (
~/.lim/config.yaml)
Config file keys:
api-key | — | Your Limrun API key |
api-endpoint | https://api.limrun.com | API base URL |
console-endpoint | https://console.limrun.com | Console URL (for login) |
JSON Output
All commands support --json for machine-readable output, making the CLI suitable for scripting and AI agent automation:
lim ios list ios_abc123 --json
lim android list --json | jq '.[].metadata.id'
INSTANCE_ID=$(lim ios create --json | jq -r '.metadata.id')
lim ios screenshot -o test.png
lim delete $INSTANCE_ID
Workflows
CI Testing: Install and Verify an App
lim ios create --install ./build/MyApp.ipa
lim session start
lim ios launch-app com.example.myapp
sleep 2
lim ios element-tree | grep "Welcome"
lim ios screenshot -o test-result.png
lim session stop
lim delete ios_abc123
AI Agent Automation
INSTANCE=$(lim ios create --model iphone --json)
ID=$(echo $INSTANCE | jq -r '.metadata.id')
lim session start
lim ios tap 200 400
lim ios type "test@example.com"
lim ios tap-element --label "Sign In"
lim ios screenshot -o result.png
lim ios element-tree --json > ui-state.json
lim ios log com.example.myapp --lines 20
lim session stop
lim delete $ID
Remote Build + Test on iOS Simulator
ID=$(lim ios create --xcode --json | jq -r '.metadata.id')
lim ios sync ./MyiOSProject
lim ios build --scheme MyApp --workspace MyApp.xcworkspace
lim session start
lim ios launch-app com.example.myapp
sleep 2
lim ios element-tree | grep "Welcome"
lim ios screenshot -o test-result.png
lim session stop
lim delete $ID
Build-Only with Artifact Upload
lim xcode create --rm --reuse-if-exists --label project=myapp
lim xcode sync ./MyiOSProject
lim xcode build --scheme MyApp --workspace MyApp.xcworkspace --upload myapp-latest
lim asset pull myapp-latest -o ./build-output
Development
Setup
cd packages/cli
npm install
npm run build
Run commands during development
npm run build && node bin/run.js <command>
npx tsc --watch
node bin/run.js ios list
Link globally
npm link
lim --help
lim android list
npm unlink -g @limrun/cli