
An API-backed coding agent needs an always-on Mac: a place to keep a cloned repo, run git, call an LLM API, write files, and commit results on a schedule. A laptop that sleeps or an ephemeral CI runner that is torn down after each job cannot hold that state. A hosted Mac can.
This guide gives the direct recommendation, the runtime components to verify, a tool-permission matrix, and a launchd loop you can copy. Start a plan at /mac-hosting/start.
The right plan is the smallest one that runs your agent's actual binaries.
| Agent workload | Plan | Why |
|---|---|---|
Call LLM API, run git, write files, commit | Figment virtual Intel macOS — $29/mo | 2 vCPU, 8 GiB RAM, 80 GiB disk; browser-console access; Intel toolchain |
| Cross-compile an arm64 app or a universal binary | Virtual Intel macOS — $29/mo | Xcode 26 or earlier on Intel can cross-compile arm64 and sign supported targets |
| Execute ARM-only binaries, Xcode 27, or visionOS work | Physical M-series — from $95/mo entry | Apple silicon required; exact chip/RAM/disk confirmed in the quote |
| CI setup, backups and monitoring included | Managed Build Mac — $249/mo | One M-series Mac, CI setup, backups, monitoring, 30 minutes monthly support |
| Two Macs, two runners, one hour monthly support | Managed Mac Team — $999/mo | Two M-series Macs, two CI runners, team setup, backups, monitoring |
Recommendation. For a pure "fetch a task, call an LLM, write a patch, open a PR" agent, the $29 virtual Intel macOS is the right starting plan. It is a real macOS environment that runs compatible Intel Mac toolchains in the VM itself, including supported Xcode 26-or-earlier versions, reached through a browser console. It has no GPU acceleration and no audio, and it will not execute ARM-only binaries. If your agent runs ARM-only tools, Xcode 27, visionOS simulators, or heavy local model inference, request an M-series configuration — the $95 entry is a starting price, and the specific chip, RAM and disk are set in the quote. Physical Intel $49 and physical M-series offers currently collect requests until supply is confirmed.
Entry-price context from a primary source: CloudMac pricing lists an M4 / 16 GB / 256 GB mini at $99.99/month, with 512 GB and 1 TB storage rows marked fully reserved. Per the coordinator check on 2026-11-10, cloudmac.org also publishes a $999/year option, which is $83.25 effective monthly — cheaper than 12 × $95 at Figment's M-series entry. Figment's $95 is an M-series entry price, not a specified M4/16 GB build, so treat this as an entry-price comparison, not equal hardware. What Figment adds at the Managed Build and Team tiers is the specific managed CI work: CI setup, backups, monitoring, and support minutes.
Before launching the agent, verify every component is present. Run this once from the browser-console terminal on first login:
#!/usr/bin/env bash
# agent-bom-check.sh — verify runtime components on first login
set -euo pipefail
check() {
local name="$1" cmd="$2"
if eval "$cmd" >/dev/null 2>&1; then
echo "OK $name"
else
echo "MISSING $name"
MISSING=1
fi
}
MISSING=0
check "git" "git --version"
check "python3" "python3 --version"
check "node" "node --version"
check "curl" "curl --version"
check "jq" "jq --version"
check "LLM key" "security find-generic-password -a \"$USER\" -s llm-api-key -w"
check "workspace" "[ -d \"$HOME/agent-workspace\" ]"
exit "$MISSING"
Any MISSING line stops the agent before it runs a bad cycle. Install the missing tool, re-check, then proceed.
Every tool the agent uses needs an explicit, minimal grant. Over-permissioned agents are harder to audit and easier to exploit.
| Tool / capability | Credential | Scope | Where it lives |
|---|---|---|---|
git clone / push | Machine-user token or deploy key | Single repo, write | Keychain generic password |
| LLM API call | Bearer token | One project / one key | Keychain generic password |
| Task queue fetch | Bearer token | Read-only task endpoint | Keychain generic password |
| File writes | None special | ~/agent-workspace/ only | Run as a non-admin user |
| Outbound HTTPS | None | 443 to LLM + git host + queue | Update your own egress allowlist if you run one |
| Scheduled execution | User launchd agent | ~/Library/LaunchAgents/ | No root; user-only |
Store secrets in the login keychain, not in a dotfile:
# one-time, interactive
security add-generic-password -a "$USER" -s llm-api-key -w
# runtime
LLM_API_KEY=$(security find-generic-password -a "$USER" -s llm-api-key -w)
export LLM_API_KEY
Do not export every secret into a plain-text file and source it — that file will be read by every process the agent spawns and backed up by anything that touches the home directory. Transfer secret names between hosts and re-enter values through the keychain on the new host.
A minimal loop: fetch a task, call the LLM, apply the patch, commit, push. Run it under launchd so it survives crashes and restarts at login.
#!/usr/bin/env bash
# agent-loop.sh — one iteration; launchd re-runs it on StartInterval
set -euo pipefail
WORKSPACE="$HOME/agent-workspace"
LOG="$WORKSPACE/agent.log"
TASK_API="https://your-task-queue.example.com/tasks/next"
log() { printf '[%s] %s\n' "$(date -u +%FT%TZ)" "$*" >> "$LOG"; }
LLM_API_KEY=$(security find-generic-password -a "$USER" -s llm-api-key -w)
TASK_TOKEN=$(security find-generic-password -a "$USER" -s task-token -w)
export LLM_API_KEY TASK_TOKEN
cd "$WORKSPACE"
git fetch --quiet origin
git checkout --quiet main
git reset --quiet --hard origin/main
TASK=$(curl --silent --show-error --fail --max-time 15 \
-H "Authorization: Bearer $TASK_TOKEN" "$TASK_API") \
|| { log "task fetch failed"; exit 1; }
[ -z "$TASK" ] && { log "queue empty"; exit 0; }
TASK_ID=$(printf '%s' "$TASK" | jq -r '.id')
PROMPT=$(printf '%s' "$TASK" | jq -r '.prompt')
log "start $TASK_ID"
PATCH=$(python3 agent_client.py --prompt "$PROMPT") \
|| { log "llm failed $TASK_ID"; exit 1; }
printf '%s' "$PATCH" | git apply - \
|| { log "patch failed $TASK_ID"; exit 1; }
git add -A
git commit -m "agent: task $TASK_ID"
git push origin HEAD:refs/heads/agent/"$TASK_ID"
log "done $TASK_ID"
Install as a user launchd agent — see Apple's launchd agent guide and the launchd.plist(5) reference:
<!-- ~/Library/LaunchAgents/com.yourteam.agent.plist -->
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key><string>com.yourteam.agent</string>
<key>ProgramArguments</key>
<array>
<string>/bin/bash</string>
<string>/Users/agent/agent-workspace/agent-loop.sh</string>
</array>
<key>StartInterval</key><integer>60</integer>
<key>KeepAlive</key>
<dict>
<key>SuccessfulExit</key><false/>
</dict>
<key>StandardOutPath</key>
<string>/Users/agent/agent-workspace/agent.log</string>
<key>StandardErrorPath</key>
<string>/Users/agent/agent-workspace/agent-err.log</string>
</dict>
</plist>
KeepAlive with SuccessfulExit: false restarts the script only on non-zero exit, so a clean "queue empty" exit stays quiet. StartInterval: 60 schedules a fresh poll each minute regardless. Load it with launchctl bootstrap gui/$UID ~/Library/LaunchAgents/com.yourteam.agent.plist.
Before leaving the agent unattended, verify each of these:
agent-bom-check.sh prints OK for every line.agent/<id>.pkill -f agent-loop.sh; within 60 seconds confirm launchctl list | grep yourteam.agent shows a new PID.grep -Ei 'fail|error|denied' agent.log agent-err.log returns nothing unexpected.security add-generic-password, and run one task to prove rotation.The $29/month virtual Intel macOS is the entry price for one continuously-running agent. It is a monthly plan — a two-week run still costs the full month; there is no published daily rate at this tier. Plan around these limits:
git gc --aggressive and workspace-cleanup step.git. Local model inference, Xcode device builds, or large simulator runs want an M-series plan.When the job grows into multi-step compilation, signing, or simulator testing, move to an M-series plan (from $95/mo entry) or the Managed Build Mac ($249/mo) if you want CI setup, backups, and monitoring handled.
To start fresh, request your hosted Mac, log in via the browser console, and run agent-bom-check.sh. To migrate an existing agent:
llm-api-key, task-token, deploy key passphrase). Do not export values to a file.security add-generic-password each entry interactively. Clone the repo into ~/agent-workspace.launchctl bootstrap gui/$UID it.More in this cluster: Mac agent API polling · Mac agent signed webhooks · GitHub Actions self-hosted runner on Mac. Full plan details and the start form are at /mac-hosting.