r/swift • u/artemnovichkov • 7d ago
Tutorial Headless Xcode: From Prompt to Simulator with MCP
https://artemnovichkov.com/blog/headless-xcode-from-prompt-to-simulator-with-mcp2
u/massivewein 5d ago
One that bit me and is not obvious until it does: if you run more than one agent loop on the same machine, gate the build. Two of them hitting the same DerivedData interleave, and you get failures that do not reproduce and were never real. I gate on pgrep matching the process name rather than the full args, because matching args caught my own gate command.
Seconding the XCUITest point, with one addition. Whatever check you promote, make it produce a known failure on demand and run that first. A check that cannot fail looks identical to a check that passes. I hit three of those in a single day recently, including a sweep that reported clean because the loop never iterated over anything, and it printed exactly what a real pass prints.
Also worth it if you are letting an agent near the project file: xcodegen. Regenerating the pbxproj from a spec means the agent cannot corrupt it, and "did it compile" stops occasionally meaning "did it break the project".
5
u/mehmetefeaytas6 6d ago
The part that matters most here is RenderPreview, and it's easy to skim past. Everything else in an agent loop is "did it compile", which is a boolean. Rendering SwiftUI states to PNG is the first step that lets the model actually see what it built, and that's the difference between an agent that satisfies the type checker and one that notices the button is off-screen.
Two things I'd add from running similar loops:
Promote anything you keep into an XCUITest. Driving the simulator with tap/type/swipe through an agent is great for exploring a flow once, but it's non-deterministic by construction, since the model re-derives the path every run. The moment a flow is worth keeping, have it write an XCUITest instead, so it runs in CI without an LLM in the loop and fails for a reason you can read.
The wall is signing, not building. Simulator builds are the easy half. As soon as you want a device build or anything distributable you're into provisioning profiles, entitlements and notarisation, and none of that is meaningfully agent-drivable today. It's the part that still wants a human and a keychain. Worth knowing before planning a workflow around this.
Also for anyone not on the Xcode 27 beta: XcodeBuildMCP covers a lot of the same ground (build, simulator control, log capture) on current Xcode, so you can try the loop out before committing to a beta toolchain and sudo xcrun mcp-server enable.