Llim.run

Concepts

Limrun has a small model: you create instances, each instance gets its own endpoints and token, and instances live until you delete them or a timeout fires. Read this page once and the guides will make sense in any order.

Instances

An instance is anything you create through Limrun. There are four kinds, each with its own CLI topic and SDK resource:

InstanceCLITypeScript SDK resource
iOS simulatorlim iosiosInstances
Android emulatorlim androidandroidInstances
Xcode sandboxlim xcodexcodeInstances
Gradle sandboxlim gradlegradleInstances

Each instance has an ID, a state, and a status block with the URLs you use to reach it. Instances are single-tenant: only one client should drive a simulator or emulator at a time, so scope them per user, per pull request, or per agent session.

Build instances and device instances are separate on purpose. You create an Xcode sandbox, build on it, and attach a simulator when you want to run the result. Attaching installs the latest successful build, and every later successful build installs and relaunches on the attached simulator. You pay only for what is running: drop the simulator between test runs and keep the sandbox, or the other way around. Building before the simulator exists also keeps an idle simulator from reaching its inactivity timeout during a long build.

Control plane and instance endpoints

Limrun has one control plane and a set of endpoints per instance.

The full list of status fields is in Instance spec and status.

Credentials

Five credentials show up in Limrun integrations. Hand each one only to the party that needs it.

CredentialWhat it can doWho should hold it
API key (LIM_API_KEY)Create, list, and delete every instance in the organization, and manage assets.Your machine, your CI secrets, your backend. Never a browser.
Instance token (status.token)Drive one instance through its endpoints, only while it is running. Returned only to credentials that can control the instance.Whoever drives that instance: a device client, <RemoteControl />, an MCP client, or a sandboxed agent.
Stream token (status.streamToken)Open the instance's streaming WebSocket (status.endpointWebSocketUrl) and nothing else.A browser that only streams the device, while the instance token stays on your backend.
Signed stream URL (status.signedStreamUrl)Open the instance in the Limrun console's streaming view, with the instance token in the URL fragment.Anyone you want to watch or use the device: a reviewer, a teammate, a Slack thread.
Scoped tokenReach specific registry endpoints, such as device installs or the Apple relay, for a limited time.A browser session started by your backend. See scoped tokens.

Create API keys in the console under Settings, API Keys. The CLI reads LIM_API_KEY from the environment or a .env file in the working directory, or uses the key stored in ~/.lim/config.yaml.

Lifecycle and timeouts

Every instance moves through the same states:

creating ──► assigned ──► ready ──► terminated

creating means hardware is being provisioned, assigned means it is booting, and ready means every URL in status works. An instance ends in terminated when you delete it, when a timeout fires, or when it fails; a failure sets status.errorMessage. Pass wait: true in the SDK (the CLI always waits) to get the instance back only once it is ready.

Two timeouts bound an instance's life:

Delete instances explicitly when the work is done. The timeouts are the safety net for crashed jobs and forgotten sessions.

Labels and reuse

Labels are free-form key=value pairs you attach at create time. They do three jobs:

Reuse matching runs in the region that handles the create call. Placement follows the caller's location and capacity, so a create from a different network can land in another region, miss the match, and start a fresh instance. Give each task its own label, such as --label issue=<id>. Reuse needs at least one label: without labels, --reuse-if-exists is ignored and every call creates a new instance.

Useful label keys are tenant, user, session, pr, repo, agent, and managed_by.

The CLI's default instance

When you omit --id, CLI commands target the instance of that type you created last. The CLI records it per workspace in ~/.lim/last-instances.json. A workspace is the current git repository or worktree by default, so agents working in separate worktrees never drive each other's instances. Assign any other directory its own workspace with lim set-workspace-dir, or set one explicitly with --workspace or LIM_WORKSPACE. On lim xcode build and lim xcode test, --workspace names the .xcworkspace instead, so use LIM_WORKSPACE.

Scripts and agents that create several instances should pass --id every time.

Placement

Limrun schedules each instance into a region. You influence placement three ways:

Details and payloads are in Instance spec and status.

Assets

Asset Storage holds the binaries instances install: iOS simulator builds (.app folders zipped or tarballed), signed IPAs, Android APKs and AABs, and encrypted keychain snapshots. Upload once, then install an asset by name when an instance boots, push it to a running instance, or share it as a browser preview. Build commands upload to Asset Storage with --upload.

Next steps

bot

Set up a coding agent

Give an agent the CLI and skills to build and run your app.

smartphone

Run a simulator

Create a simulator and drive it from the CLI or SDK.

monitor-play

Embed a device

Stream a live device into your own product.

book-open

Instance spec and status

Every create field, status field, and state.