macOS + iOS Simulator setup
This is the toolchain checklist for the strongest CodeLoop mobile path: a macOS host driving the iOS Simulator (and optionally the Android emulator from the same machine). Once it is in place, a full codeloop_verify builds the app, boots a simulator, launches the app, drives it, and captures screenshots + video + logs with no manual steps.
One command tells you what is missing: npx codeloop doctor checks every item on this page (Xcode, simulator runtimes, CocoaPods, Java, Maestro, idb, adb, AVDs) and prints the exact install command for anything absent.
1. Xcode + iOS Simulator runtime
# Full Xcode from the Mac App Store (Command Line Tools alone don't ship simctl)
xcode-select --install
sudo xcodebuild -license accept
# Download an iOS Simulator runtime (Xcode 15+)
xcodebuild -downloadPlatform iOS
# Confirm: at least one iOS runtime and one iPhone device should appear
xcrun simctl list runtimes
xcrun simctl list devicesA fresh Xcode install can have zeroiOS runtimes downloaded — simulators then fail to boot with “no runtime available”. codeloop doctor flags this case explicitly.
2. CocoaPods (Flutter plugins / native pods)
brew install cocoapods
# Then, inside a Flutter project that uses plugins:
cd ios && pod installAny project with an ios/Podfile needs CocoaPods or the build fails at the pod-integration phase. CodeLoop builds Flutter iOS apps through flutter build ios --simulator --no-codesign (the Flutter toolchain handles pod integration), so a working pod binary is all you need.
3. Maestro (label-based mobile driving) + Java
# Maestro is a JVM CLI — install Java first
brew install --cask temurin
curl -Ls "https://get.maestro.mobile.dev" | bashMaestro is CodeLoop’s primary mobile interaction engine: the journey generates a Maestro flow from your app’s real labels and drives it. Without Maestro, CodeLoop falls back to the coordinate engine (real CGEvent input into the Simulator window) — it works, but label-based driving is more reliable on labeled UIs. The first iOS run installs Maestro’s XCTest driver and can take a couple of minutes; CodeLoop raises the driver-startup timeout automatically.
4. Optional: idb (precision input + accessibility tree)
brew tap facebook/fb
brew install idb-companion
pipx install fb-idb # or: pip install fb-idbWhen idb is on PATH, CodeLoop uses it for HID-precise taps/swipes that need no window focus, and unlocks real get_texton iOS via the accessibility tree. Auto-detected — never required.
5. macOS permissions (the step everyone forgets)
CodeLoop’s capture and input paths use macOS system APIs that require one-time consent. Grant both to the app that hosts the MCP server process — that is Cursor (or your terminal app when using Claude Code from a terminal):
- Screen Recording— System Settings → Privacy & Security → Screen Recording. Without it, screenshots and ffmpeg/avfoundation video come out black.
- Accessibility— System Settings → Privacy & Security → Accessibility. Without it, CGEvent clicks and keystrokes (desktop apps and the Simulator fallback path) are silently discarded by macOS.
macOS prompts on first use; if a capture ever comes back black or a click lands nowhere, these two panes are the first place to look. Restart Cursor after granting.
6. Wire it into the project
npx codeloop init
npx codeloop doctor # everything green?Useful .codeloop/config.jsonkeys for this host (all optional — see the e2e reference):
{
"e2e": {
"ios_device": "iPhone 16 Pro", // pin a simulator
"platforms": ["ios", "android"], // drive BOTH apps in one verify
"launch_stall_seconds": 180, // raise for quiet toolchains
"ios_scheme": "MyApp-Staging" // native multi-scheme workspaces
}
}From here, a plain codeloop_verify(or “verify the app” to your agent) runs the full loop. To test the Android app on the same Mac: codeloop_run_journey with target_type: "android_emulator", or set e2e.platformsas above — the gate then requires driven evidence from both platforms.
Physical devices
Physical Android phones work over USB (adb). Physical iPhones are detected and get a best-effort flutter runlaunch, but Apple provides no supported CLI path for screenshots/video/input on hardware — visual evidence requires the Simulator. The compatibility matrix spells out every boundary.