Why cloud coding agents can't build your iOS app
Hosted coding agents run in Linux sandboxes, so xcodebuild is missing. How to hand the Apple steps to a Mac the agent can reach over HTTPS.
· 7 min read
Need a Mac for this? NoMac gives your agent full macOS with Xcode, from $9.99 a month, billed by the second. Start now →
You give a cloud coding agent an iOS task. It reads the Swift, writes a clean change, and then tries to prove it compiles:
$ xcodebuild -scheme MyApp build bash: xcodebuild: command not found
The agent is not broken. Hosted coding agents run in Linux sandboxes, and Xcode only runs on macOS. The agent can edit Swift all day, but it cannot compile SwiftUI, run XCTest, boot a simulator or sign an archive. Without those, “done” means “looks right,” which is not the same thing.
The fix is not a different agent. Keep the agent where it is and give it a Mac it can reach over HTTPS. The code stays in the sandbox; only the Apple steps travel.
What works in a Linux sandbox and what does not
- ·Works: reading and editing Swift, Git, portable Swift packages with the Linux toolchain, tests for pure logic, JSON and plist edits, most scripting.
- ·Does not work: anything that imports SwiftUI or UIKit, Xcode project builds, XCTest for app targets, the iOS simulator, code signing, archives, uploads to App Store Connect.
See what actually needs a Mac for the full list. The short version: anything Apple-flavoured beyond plain Swift.
Three ways to give a cloud agent a Mac
1. Push and let CI answer
The agent commits, pushes and waits for a macOS CI job. This works and needs no new tools, but each attempt is a commit and a queue. An agent fixing a stubborn build error can spend an hour producing a pile of “try again” commits. It is best as a final check, not as the development loop.
2. A hosted MCP server that runs commands on a Mac
The agent calls tools over HTTPS: start a Mac, run a command, read its output, stop. No SSH client or key is needed inside the sandbox, which matters because many sandboxes restrict outbound connections to web traffic. NoMac exposes this at https://mcp.nomac.app/mcp with a bearer API key.
3. SSH to a Mac, if the sandbox allows it
Where outbound SSH is allowed, the agent can install the NoMac CLI, run nomac start, nomac sync . and nomac ssh -- xcodebuild .... This is the most flexible option for long builds.
The loop, over MCP
With the hosted MCP server connected, the tools an agent uses are few and predictable:
get_mac_credits → check this week's remaining hours start_mac → request a Mac with a stable request_key get_mac_session → poll until ready (about a minute) exec_mac → start a job, e.g. ["/bin/bash","-lc","xcodebuild ..."] get_mac_job → check whether it finished read_mac_output → read stdout and stderr from a cursor stop_mac → delete the Mac when done
Over MCP, source gets onto the Mac the way it gets onto any fresh machine: the agent pushes a branch and the first job clones it. For a private repository, use a short-lived, read-only token scoped to that one repository; the VM and everything on it is deleted at stop. If the sandbox allows SSH, the CLI's nomac sync . uploads the working tree directly instead.
A prompt that works
You have NoMac MCP tools for a remote macOS machine with Xcode. 1. Check credits, then start one Mac with request_key "fix-build-001". 2. Clone this branch on the Mac and run: xcodebuild -scheme MyApp -destination 'generic/platform=iOS Simulator' build 3. Read the full error output. Fix the source here, push, pull on the Mac, rebuild. 4. Repeat until the build succeeds, then run the unit tests. 5. Stop the Mac and confirm cleanup before you finish. Reuse the same request_key if a response is lost. Never start a second Mac.
Things that trip agents up
- ·Network allowlists. Some hosted sandboxes block outbound traffic by default. The NoMac endpoints must be allowed. We do not assume every sandbox can reach them, so check your environment's network settings first.
- ·Timeouts. Managed commands default to 300 seconds and cap at 600. A first simulator boot takes about 90 seconds; a large first build can take longer than ten minutes, so split it or use SSH.
- ·Retries. If a response is lost, retry with the same request key and arguments. A new key means a new job.
- ·Forgetting to stop. Idle and session limits protect you, but a finished agent should always call
stop_macand wait for cleanup.
Setup for Claude Code specifically is in give Claude Code a Mac in five minutes. The machine-readable version of all of this is at nomac.app/llms.txt.