Skip to main content
This example demonstrates how to develop iOS apps without a Mac using Limrun’s Xcode sandbox. Code changes are automatically synced and you can trigger builds that install directly to the connected iOS Simulator.

Overview

The Xcode sandbox enables:
  • Cloud-based iOS development without macOS
  • Automatic code synchronization with delta patching
  • Remote xcodebuild execution
  • Hot reload workflow for rapid iteration
  • MCP server integration for AI agents

Complete Example

import { Limrun, createXCodeSandboxClient } from '@limrun/api';

const lim = new Limrun({ apiKey: process.env['LIM_API_KEY'] });

// Create an iOS instance with Xcode sandbox enabled
console.log('Creating iOS instance with Xcode sandbox...');
const instance = await lim.iosInstances.create({
  wait: true,
  reuseIfExists: true,
  metadata: {
    labels: { name: 'ios-native-build-example' },
  },
  spec: {
    sandbox: {
      xcode: {
        enabled: true,
      },
    },
  },
});

const sandboxUrl = instance.status.sandbox?.xcode?.url;
if (!sandboxUrl) {
  throw new Error('Xcode sandbox URL not available');
}

// Connect to the sandbox
const sandbox = await createXCodeSandboxClient({
  apiUrl: sandboxUrl,
  token: instance.status.token,
});

// Sync code with watch mode enabled
console.log('Syncing code...');
await sandbox.sync('./my-ios-app', { watch: true });

// Trigger a build
console.log('Starting xcodebuild...');
const build = sandbox.xcodebuild();

// Stream build output
build.stdout.on('data', (line) => {
  console.log(line.toString());
});

build.stderr.on('data', (line) => {
  console.error(line.toString());
});

// Wait for completion
const result = await build;
console.log(`Build finished with exit code: ${result.exitCode}`);

console.log(`View instance: https://console.limrun.com/stream/${instance.metadata.id}`);

How It Works

1. Code Synchronization

The sync() method uses delta patching (xdelta3) for efficient synchronization:
// One-time sync
await sandbox.sync('./my-ios-app');

// Watch mode - auto-sync on file changes
await sandbox.sync('./my-ios-app', { watch: true });

// Custom filter to exclude files
await sandbox.sync('./my-ios-app', {
  watch: true,
  filter: (path) => {
    // Exclude build artifacts
    return !path.startsWith('build/') && 
           !path.includes('.xcodeproj/xcuserdata');
  }
});

2. Building

Trigger builds programmatically:
// Start build
const build = sandbox.xcodebuild({
  scheme: 'MyApp',
  workspace: 'MyApp.xcworkspace'
});

// Stream output
build.stdout.on('data', (line) => console.log(line));
build.stderr.on('data', (line) => console.error(line));

// Wait for completion
const { exitCode, stdout, stderr } = await build;

if (exitCode === 0) {
  console.log('Build succeeded!');
} else {
  console.error('Build failed:', stderr);
}

3. Watch Mode Workflow

With watch mode enabled, your development cycle becomes:
1

Edit code locally

Make changes to your iOS app source files
2

Automatic sync

Changes are automatically detected and synced to the sandbox
3

Trigger build

Run xcodebuild when ready to test
4

App updates

The app is automatically installed on the connected iOS Simulator

MCP Server Integration

The example includes an MCP server for AI agent integration:
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';

const mcp = new McpServer({ name: 'xcodebuild', version: '1.0.0' });

mcp.registerTool(
  'build',
  {
    title: 'xcodebuild',
    description: 'Runs xcodebuild and installs the app on the remote simulator',
  },
  async () => {
    let buffer: string[] = [];
    await runBuild((line) => buffer.push(line));
    return { 
      content: [{ 
        type: 'text', 
        text: buffer.join('\n') 
      }] 
    };
  },
);

Configure AI Agent

Add to your MCP configuration:
{
  "mcpServers": {
    "xcode": {
      "url": "http://localhost:3000/"
    }
  }
}
Or with Claude CLI:
claude mcp add xcode --transport http http://localhost:3000

HTTP Endpoint

The example exposes an HTTP endpoint for manual builds:
# Trigger a build via HTTP
curl http://localhost:3000/xcodebuild

# Build output is streamed in real-time

Prerequisites

Install xdelta3 for delta patching:
brew install xdelta

Performance

The sync mechanism is highly efficient:
  • Initial sync: Full file upload (~10-30 seconds for typical iOS project)
  • Incremental sync: Only changed bytes are sent (~100ms-1s)
  • Watch mode overhead: Minimal CPU and memory usage
  • Build time: Same as local xcodebuild (varies by project)

Use Cases

Cloud Development

Develop iOS apps on Linux, Windows, or any platform

CI/CD

Automated builds and tests without Mac infrastructure

AI Agents

Let AI agents build and test iOS apps autonomously

Team Collaboration

Share development environments instantly

Limitations

The Xcode sandbox currently supports:
  • iOS Simulator builds only (not device builds)
  • Standard xcodebuild commands
  • Swift Package Manager dependencies
  • CocoaPods (if committed)

Next Steps

Xcode Sandbox API

Complete API reference for the sandbox

Folder Sync

Learn about the sync mechanism

Build docs developers (and LLMs) love