Infrastructure for agentic iOS development.
AI agents can already write Swift and trigger builds, but they're still blind on iOS. Remo gives them the eyes and hands they need to discover real devices (USB) and simulators, invoke app capabilities, then verify the result visually through screenshots, live mirroring, or recorded video.
The result is a closed loop: write code → build → call capabilities → inspect the UI → decide if the change is correct → iterate. No human watching the simulator.
Watch the full demo video here:
# Agent writes code, triggers a build, then verifies via Remo:
remo devices # discover real devices (USB) & simulators
remo call -a <addr> counter.increment '{"amount":5}' # invoke a capability
remo screenshot -a <addr> -o after.jpg # capture the result
remo mirror -a <addr> --save recording.mp4 # or record video for animation review
# → Agent compares before/after screenshots to confirm the UI is correct
- Agent-first. Every API is designed for programmatic access. Agents discover real devices (USB) and simulators, invoke capabilities, and verify results — enabling fully autonomous write → test → fix cycles for iOS.
- Extensible capabilities. Developers register named handlers in Swift. Agents discover and call them at runtime — read CoreData, toggle feature flags, navigate routes, inject test data. If you can write it in Swift, an agent can call it.
- Visual verification. Screenshots and captured video let agents see what the user sees after every action. Screenshots for static UI checks; video recording for reviewing animations and transitions.
- Instant feedback. Capability call → UI update → screenshot capture in milliseconds, over USB or localhost.
- Debug-only by default. The SDK compiles to no-ops in Release builds (
#if DEBUG), so it never ships to production.
Add the SPM dependency in Xcode:
https://github.com/yi-jiang-applovin/remo-spm.git
import RemoSwift
// The server starts automatically on first API access.
// Simulator: random port (avoids collisions). Device: port 9930 (for USB tunnel).
Remo.register("myFeature.toggle") { params in
let enabled = params["enabled"] as? Bool ?? false
FeatureFlags.shared.myFeature = enabled
return ["toggled": enabled]
}# From source
cargo install --git https://github.com/yi-jiang-applovin/Remo.git remo-cli
# Or from a local clone
cargo install --path crates/remo-cliremo devices # discover real devices & simulators
remo call -a <addr> myFeature.toggle '{"enabled":true}' # invoke your capability
remo screenshot -a <addr> -o screen.jpg # verify the result
remo mirror -a <addr> --web # inspect animations in the browser
# or:
remo dashboard # open the multi-device web dashboard┌──────────────────────────────────────┐
│ macOS │
│ remo CLI / AI agent │
│ ├── USB discovery (usbmuxd) │
│ ├── Simulator discovery (Bonjour) │
│ └── RPC client │
└──────────┬───────────────────────────┘
│ TCP (USB tunnel / localhost)
┌──────────▼───────────────────────────┐
│ iOS │
│ remo-sdk (Rust static lib) │
│ ├── TCP server (tokio) │
│ ├── Capability registry │
│ ├── Bonjour advertisement │
│ ├── Built-in: view tree, screenshot │
│ └── ObjC bridge (objc2) │
│ ── FFI boundary ── │
│ RemoSwift (Swift wrapper) │
│ Your app registers capabilities │
└──────────────────────────────────────┘
The iOS SDK starts a TCP server inside your app. Real devices are discovered via USB (usbmuxd), simulators via Bonjour/mDNS. The macOS CLI (or any AI agent) sends JSON-RPC requests to invoke capabilities.
remo devices # Auto-discover devices (USB + Bonjour)
remo call -a <addr> <capability> [params] # Invoke a capability
remo list -a <addr> # List registered capabilities
remo screenshot -a <addr> -o out.jpg # Take a screenshot
remo tree -a <addr> # Dump view hierarchy
remo info -a <addr> # Show device & app info
remo mirror -a <addr> --web # Live screen mirror (H.264 → fMP4)
remo mirror -a <addr> --save out.mp4 # Record screen to file
remo watch -a <addr> # Stream events from device
remo dashboard # Web demo pageThese are registered automatically by the SDK — no setup required:
| Capability | Description |
|---|---|
__ping |
Connectivity check |
__list_capabilities |
List all registered capabilities |
__view_tree |
Snapshot the UIView hierarchy as JSON |
__screenshot |
Capture the screen (JPEG/PNG, configurable quality) |
__device_info |
Device model, OS version, screen dimensions |
__app_info |
Bundle ID, version, build number, display name |
__start_mirror |
Start H.264 screen mirror stream |
__stop_mirror |
Stop mirror stream |
Everything below is for contributing to Remo itself.
| Tool | Version | Notes |
|---|---|---|
| Rust | 1.82+ | Auto-installed via rust-toolchain.toml |
| Xcode | 16+ | iOS SDK + Swift 6.1 |
git clone https://github.com/yi-jiang-applovin/Remo.git && cd Remo
make setup # Configure git hooks
cargo build -p remo-cli # Build the CLI
./build-ios.sh sim # Build XCFramework (simulator)
./build-ios.sh device # Build XCFramework (real device)
./build-ios.sh release # Build all targets, optimized| Crate | Description |
|---|---|
remo-protocol |
Message types + length-prefixed JSON framing codec |
remo-transport |
Bidirectional connection over TCP or Unix socket |
remo-usbmuxd |
macOS usbmuxd client — device discovery + USB tunneling |
remo-bonjour |
Bonjour/mDNS service registration and discovery |
remo-sdk |
iOS embedded server + capability registry + C FFI |
remo-objc |
ObjC runtime bridge via objc2 (view tree, screenshot, device info) |
remo-desktop |
macOS library — device manager, RPC client, web dashboard, fMP4 muxer |
remo-cli |
CLI entry point |
v0.3.0 — See SPEC.md for the full architecture.
- Auto-reconnection on disconnect
- macOS GUI (SwiftUI device inspector)
- View property modification (
__view_set) - Protocol versioning / handshake
See CONTRIBUTING.md for development setup and guidelines.
