301 lines
19 KiB
HTML
301 lines
19 KiB
HTML
<!doctype html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="utf-8" />
|
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
<title>macOS virtual machines: overview — Nucleic Support</title>
|
|
<meta name="description" content="Nucleic's macOS VMs give each agent session its own isolated Mac for Xcode, the simulators, and codesign — so parallel Mac builds never collide on your host." />
|
|
<meta name="theme-color" content="#faf7f3" />
|
|
<meta name="robots" content="index, follow" />
|
|
|
|
<!-- atom mark, reused as favicon -->
|
|
<link rel="icon" href="data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><g fill='none' stroke-width='7'><ellipse cx='50' cy='50' rx='17' ry='40' transform='rotate(80 50 50)' stroke='%237AA7DD'/><ellipse cx='50' cy='50' rx='17' ry='40' transform='rotate(20 50 50)' stroke='%23DF619B'/><ellipse cx='50' cy='50' rx='17' ry='40' transform='rotate(140 50 50)' stroke='%23C5826F'/></g></svg>" />
|
|
|
|
<link rel="preload" href="../fonts/space-grotesk.woff2" as="font" type="font/woff2" crossorigin />
|
|
<link rel="preload" href="../fonts/jetbrains-mono.woff2" as="font" type="font/woff2" crossorigin />
|
|
<style>
|
|
@font-face{font-family:'Space Grotesk';font-style:normal;font-weight:400 700;font-display:swap;src:url(../fonts/space-grotesk.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
|
@font-face{font-family:'JetBrains Mono';font-style:normal;font-weight:400 500;font-display:swap;src:url(../fonts/jetbrains-mono.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|
|
</style>
|
|
|
|
<style>
|
|
:root{
|
|
--ink:#181520;--ink-soft:#5b5560;--ink-faint:#8b8590;
|
|
--paper:#faf7f3;--panel:#fffdfb;--panel-2:#f3ede6;--line:#e6ded4;--line-2:#efe9e1;
|
|
--blue:#5e9bd8;--pink:#db5f97;--magenta:#c264ad;--rust:#c47e69;--green:#5fa775;--amber:#d7a23f;
|
|
--sans:"Space Grotesk", -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;
|
|
--mono:"JetBrains Mono", ui-monospace, SFMono-Regular, "SF Mono", Menlo, monospace;
|
|
--maxw:1080px;--prose:760px;
|
|
}
|
|
*{box-sizing:border-box}
|
|
html{scroll-behavior:smooth}
|
|
body{
|
|
margin:0;overflow-x:clip;font-family:var(--sans);color:var(--ink);background:var(--paper);
|
|
background-image:radial-gradient(var(--line) 1px, transparent 1px);
|
|
background-size:26px 26px;background-position:-13px -13px;
|
|
-webkit-font-smoothing:antialiased;line-height:1.5;
|
|
}
|
|
a{color:inherit}
|
|
.wrap{max-width:var(--maxw);margin:0 auto;padding:0 24px}
|
|
.mono{font-family:var(--mono)}
|
|
.kicker{font-family:var(--mono);font-size:11.5px;letter-spacing:.16em;text-transform:uppercase;color:var(--ink-faint)}
|
|
|
|
/* ---------- top bar ---------- */
|
|
header{position:sticky;top:0;z-index:20;backdrop-filter:saturate(1.1) blur(8px);background:color-mix(in srgb, var(--paper) 82%, transparent);border-bottom:1px solid var(--line-2)}
|
|
.bar{display:flex;align-items:center;justify-content:space-between;height:62px}
|
|
.brand{display:flex;align-items:center;gap:11px;font-weight:600;letter-spacing:-.01em;font-size:17px;text-decoration:none;color:var(--ink)}
|
|
.brand .mk{width:26px;height:26px;display:block}
|
|
.nav{display:flex;align-items:center;gap:22px;font-size:14px;color:var(--ink-soft)}
|
|
.nav a{text-decoration:none}
|
|
.nav .lk:hover{color:var(--ink)}
|
|
.btn{font-family:var(--sans);font-size:14px;font-weight:500;text-decoration:none;cursor:pointer;border:0;padding:9px 16px;border-radius:10px;color:#fff;background:var(--ink);transition:transform .12s ease, opacity .12s ease;white-space:nowrap;-webkit-tap-highlight-color:transparent}
|
|
.btn:link,.btn:visited,.btn:hover,.btn:focus,.btn:active{color:#fff}
|
|
.btn:hover{opacity:.9;transform:translateY(-1px)}
|
|
@media (max-width:600px){ .nav .lk{display:none} }
|
|
|
|
/* ---------- doc header ---------- */
|
|
.crumbs{max-width:var(--prose);margin:0 auto;padding:26px 0 0;font-family:var(--mono);font-size:12px;color:var(--ink-faint);letter-spacing:.02em}
|
|
.crumbs a{text-decoration:none;color:var(--ink-soft)}
|
|
.crumbs a:hover{color:var(--ink)}
|
|
.crumbs .sep{color:var(--line);margin:0 8px}
|
|
.doc-hero{padding:16px 0 22px}
|
|
.doc-hero .wrap{max-width:var(--prose)}
|
|
.doc-hero h1{font-size:clamp(30px,4.6vw,44px);line-height:1.05;letter-spacing:-.03em;font-weight:600;margin:12px 0 0}
|
|
.doc-hero h1 .em{background:linear-gradient(100deg,var(--rust),var(--pink) 45%,var(--magenta) 70%,var(--blue));-webkit-background-clip:text;background-clip:text;color:transparent}
|
|
.doc-hero .lede{max-width:var(--prose);margin:16px 0 0;font-size:17px;color:var(--ink-soft);line-height:1.62}
|
|
|
|
/* ---------- on this page ---------- */
|
|
.toc{max-width:var(--prose);margin:22px auto 0;border:1px solid var(--line);border-radius:14px;background:var(--panel);padding:16px 20px}
|
|
.toc h2{margin:0 0 10px;font-size:11px;letter-spacing:.12em;text-transform:uppercase;color:var(--ink-faint);font-weight:600;font-family:var(--mono)}
|
|
.toc ol{margin:0;padding-left:0;list-style:none;counter-reset:toc;display:grid;gap:7px}
|
|
.toc li{counter-increment:toc;position:relative;padding-left:28px;font-size:14.5px}
|
|
.toc li::before{content:counter(toc,decimal-leading-zero);position:absolute;left:0;top:1px;font-family:var(--mono);font-size:11px;color:var(--ink-faint)}
|
|
.toc a{text-decoration:none;color:var(--ink-soft)}
|
|
.toc a:hover{color:var(--ink)}
|
|
|
|
/* ---------- prose ---------- */
|
|
main{padding:10px 0 30px}
|
|
.prose{max-width:var(--prose);margin:0 auto}
|
|
.prose section{padding:28px 0;border-top:1px solid var(--line-2)}
|
|
.prose h2{font-size:22px;font-weight:600;letter-spacing:-.02em;margin:0 0 6px;scroll-margin-top:80px}
|
|
.prose h2 .n{font-family:var(--mono);font-size:13px;color:var(--ink-faint);margin-right:10px;font-weight:500}
|
|
.prose h3{font-size:16px;font-weight:600;letter-spacing:-.01em;margin:22px 0 6px;color:var(--ink)}
|
|
.prose p{margin:12px 0;color:var(--ink-soft);font-size:15.5px;line-height:1.65}
|
|
.prose ul{margin:12px 0;padding-left:22px;color:var(--ink-soft);font-size:15.5px;line-height:1.65}
|
|
.prose li{margin:7px 0}
|
|
.prose strong{color:var(--ink);font-weight:600}
|
|
.prose a{color:var(--ink);text-decoration:underline;text-decoration-color:var(--line);text-underline-offset:3px}
|
|
.prose a:hover{text-decoration-color:var(--magenta)}
|
|
.prose code{font-family:var(--mono);font-size:.86em;background:var(--panel-2);border:1px solid var(--line-2);border-radius:5px;padding:1px 6px}
|
|
.prose .lede{font-size:17px;color:var(--ink);line-height:1.6}
|
|
.kbd{font-family:var(--mono);font-size:.82em;background:var(--panel);border:1px solid var(--line);border-bottom-width:2px;border-radius:6px;padding:1px 7px;color:var(--ink);white-space:nowrap}
|
|
.ui{font-weight:600;color:var(--ink)}
|
|
|
|
/* two-path table */
|
|
.ftable{width:100%;border-collapse:collapse;margin:16px 0;font-size:14px}
|
|
.ftable th,.ftable td{text-align:left;padding:10px 12px;border-bottom:1px solid var(--line-2);vertical-align:top}
|
|
.ftable th{font-size:11px;letter-spacing:.08em;text-transform:uppercase;color:var(--ink-faint);font-weight:600}
|
|
.ftable td:first-child{font-weight:600;color:var(--ink);white-space:nowrap}
|
|
.ftable td:last-child{color:var(--ink-soft)}
|
|
|
|
/* callouts */
|
|
.callout{border-left:3px solid var(--line);border-radius:0 10px 10px 0;padding:14px 16px;margin:18px 0;font-size:14.5px;color:var(--ink-soft);line-height:1.6}
|
|
.callout strong{color:var(--ink)}
|
|
.callout code{font-family:var(--mono);font-size:.86em;background:var(--panel-2);border:1px solid var(--line-2);border-radius:5px;padding:1px 6px}
|
|
.callout.note{border-color:color-mix(in srgb,var(--blue) 60%,var(--line));background:color-mix(in srgb,var(--blue) 6%,var(--panel))}
|
|
.callout.tip{border-color:color-mix(in srgb,var(--green) 60%,var(--line));background:color-mix(in srgb,var(--green) 6%,var(--panel))}
|
|
.callout.warn{border-color:color-mix(in srgb,var(--amber) 70%,var(--line));background:color-mix(in srgb,var(--amber) 8%,var(--panel))}
|
|
.callout .lbl{display:block;font-size:11px;letter-spacing:.1em;text-transform:uppercase;font-family:var(--mono);margin-bottom:4px}
|
|
.callout.note .lbl{color:var(--blue)}
|
|
.callout.tip .lbl{color:var(--green)}
|
|
.callout.warn .lbl{color:color-mix(in srgb,var(--amber) 80%,var(--ink))}
|
|
|
|
/* numbered steps */
|
|
.steps{counter-reset:step;list-style:none;padding:0;margin:16px 0}
|
|
.steps>li{counter-increment:step;position:relative;padding:0 0 20px 46px;margin:0}
|
|
.steps>li::before{content:counter(step);position:absolute;left:0;top:-2px;width:30px;height:30px;border-radius:9px;background:var(--ink);color:#fff;font-family:var(--mono);font-size:13px;display:flex;align-items:center;justify-content:center}
|
|
.steps>li:not(:last-child)::after{content:"";position:absolute;left:14px;top:32px;bottom:6px;width:2px;background:var(--line)}
|
|
.steps>li h3{margin:4px 0 4px;font-size:16px}
|
|
.steps>li p{margin:6px 0}
|
|
|
|
/* code block */
|
|
pre{background:var(--panel);border:1px solid var(--line);border-radius:12px;padding:14px 16px;overflow-x:auto;margin:14px 0}
|
|
pre code{font-family:var(--mono);font-size:13px;color:var(--ink);line-height:1.7;background:none;border:0;padding:0}
|
|
pre code .c{color:var(--ink-faint)}
|
|
|
|
/* next / related */
|
|
.related{max-width:var(--prose);margin:0 auto;padding:26px 0 0;border-top:1px solid var(--line-2)}
|
|
.related h2{font-size:12px;letter-spacing:.12em;text-transform:uppercase;color:var(--ink-faint);font-weight:600;font-family:var(--mono);margin:0 0 12px}
|
|
.related a{display:flex;align-items:center;gap:9px;text-decoration:none;color:var(--ink);border:1px solid var(--line);border-radius:12px;padding:13px 16px;margin:8px 0;font-weight:500;font-size:15px;transition:border-color .14s ease}
|
|
.related a:hover{border-color:color-mix(in srgb,var(--magenta) 45%,var(--line))}
|
|
.related a .arw{margin-left:auto;color:var(--ink-faint)}
|
|
|
|
footer{border-top:1px solid var(--line-2);padding:30px 0 50px;margin-top:24px}
|
|
.foot{display:flex;align-items:center;justify-content:space-between;gap:18px;flex-wrap:wrap;color:var(--ink-faint);font-size:13px}
|
|
.foot .mono{font-size:12px}
|
|
.foot-links{display:flex;gap:18px;flex-wrap:wrap}
|
|
.foot-links a{text-decoration:none;color:var(--ink-soft)}
|
|
.foot-links a:hover{color:var(--ink)}
|
|
.dotsep{color:var(--line)}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
|
|
<!-- ===== top bar ===== -->
|
|
<header>
|
|
<div class="wrap bar">
|
|
<a class="brand" href="/">
|
|
<svg class="mk" viewBox="0 0 100 100" aria-hidden="true">
|
|
<g fill="none" stroke-width="7">
|
|
<ellipse cx="50" cy="50" rx="17" ry="40" transform="rotate(80 50 50)" stroke="#7AA7DD"/>
|
|
<ellipse cx="50" cy="50" rx="17" ry="40" transform="rotate(20 50 50)" stroke="#DF619B"/>
|
|
<ellipse cx="50" cy="50" rx="17" ry="40" transform="rotate(140 50 50)" stroke="#C5826F"/>
|
|
</g>
|
|
</svg>
|
|
Nucleic
|
|
</a>
|
|
<nav class="nav">
|
|
<a class="lk" href="/support.html">Support</a>
|
|
<a class="btn" href="/">Home</a>
|
|
</nav>
|
|
</div>
|
|
</header>
|
|
|
|
<div class="wrap">
|
|
<nav class="crumbs" aria-label="Breadcrumb">
|
|
<a href="/support.html">Support</a><span class="sep">/</span>
|
|
Virtual Machines
|
|
</nav>
|
|
</div>
|
|
|
|
<!-- ===== title ===== -->
|
|
<section class="doc-hero">
|
|
<div class="wrap">
|
|
<div class="kicker">Virtual Machines</div>
|
|
<h1>macOS <span class="em">virtual machines</span></h1>
|
|
<p class="lede">Give an agent a whole Mac of its own — a per-session macOS VM for Xcode, the simulators, and codesign, so parallel Mac builds never collide on your host.</p>
|
|
</div>
|
|
</section>
|
|
|
|
<div class="wrap">
|
|
<nav class="toc" aria-label="On this page">
|
|
<h2>On this page</h2>
|
|
<ol>
|
|
<li><a href="#what">What they are & why</a></li>
|
|
<li><a href="#requirements">Requirements</a></li>
|
|
<li><a href="#turn-on">Turning it on</a></li>
|
|
<li><a href="#lifecycle">How a per-session VM works</a></li>
|
|
<li><a href="#concurrency">Concurrency & resources</a></li>
|
|
<li><a href="#next">What's next</a></li>
|
|
</ol>
|
|
</nav>
|
|
</div>
|
|
|
|
<main>
|
|
<div class="wrap prose">
|
|
|
|
<section id="what">
|
|
<h2><span class="n">01</span>What they are & why</h2>
|
|
<p class="lede">Each macOS VM is a per-session, isolated Mac running on Apple's Virtualization framework — a real, disposable macOS instance where <code>xcodebuild</code>, the simulators (<code>xcrun simctl</code>), and <code>codesign</code> run end-to-end without ever touching your host.</p>
|
|
<p>They exist to remove shared-host toolchain thrash. Two agents building on the same host collide and corrupt each other's derived-data build output — one clobbers the other's intermediate files mid-compile, and both builds fail in confusing ways. When each agent gets its own isolated Mac, concurrent builds never collide: every session compiles, simulates, and signs in its own clean environment.</p>
|
|
<p>This is exposed to agents as the <code>mac_vm_exec</code> tool — the per-agent alternative to the shared-host <code>host_exec</code>. Where <code>host_exec</code> runs commands directly on your Mac (shared by every session), <code>mac_vm_exec</code> runs them inside that session's own VM.</p>
|
|
</section>
|
|
|
|
<section id="requirements">
|
|
<h2><span class="n">02</span>Requirements</h2>
|
|
<p>Before you turn this on, make sure the machine can carry it:</p>
|
|
<ul>
|
|
<li><strong>Apple silicon Mac.</strong> Running macOS guests requires Apple silicon — Intel Macs can't host a macOS VM.</li>
|
|
<li><strong>Plenty of RAM.</strong> It's heavy: expect several GB of RAM per running VM, on top of a one-time base-image install.</li>
|
|
<li><strong>Free disk space.</strong> The golden base image, its downloaded restore image, and each per-session VM disk add up fast.</li>
|
|
<li><strong>Host ≥ guest.</strong> The host macOS version must be greater than or equal to the guest — a macOS 26 host can't install a macOS 27 guest.</li>
|
|
</ul>
|
|
<div class="callout warn"><span class="lbl">Disk space</span>Keep at least <strong>64 GB free</strong> before enabling macOS VMs. Between the golden base image, its restore image, and every per-session VM disk, space disappears quickly — and running low can stall builds or corrupt a VM mid-run.</div>
|
|
</section>
|
|
|
|
<section id="turn-on">
|
|
<h2><span class="n">03</span>Turning it on</h2>
|
|
<ol class="steps">
|
|
<li>
|
|
<h3>Enable the service</h3>
|
|
<p>In <span class="ui">Settings ▸ Virtual Machines</span>, turn on <span class="ui">Enable macOS VM service</span>.</p>
|
|
</li>
|
|
<li>
|
|
<h3>Optionally expose it to sessions</h3>
|
|
<p>Turn on <span class="ui">Expose to sandboxed sessions by default</span> so sessions get the <code>mac_vm_exec</code> tool automatically, without opting in per session.</p>
|
|
</li>
|
|
<li>
|
|
<h3>Build the one-time base image</h3>
|
|
<p>Before any VM can boot, you must build the golden base image once — this installs macOS and provisions the dev toolchain. See <a href="/support/macos-vm-base-image.html">Building the base image</a> for the full walkthrough.</p>
|
|
</li>
|
|
</ol>
|
|
<div class="callout note"><span class="lbl">Good to know</span>The base image is a one-time build. Every per-session VM is cloned from it, so you only pay the macOS install cost once — not on every session.</div>
|
|
</section>
|
|
|
|
<section id="lifecycle">
|
|
<h2><span class="n">04</span>How a per-session VM works</h2>
|
|
<p>The first time a session calls <code>mac_vm_exec</code>, Nucleic spins up a VM just for that session:</p>
|
|
<ul>
|
|
<li><strong>Clone the golden base.</strong> Nucleic makes a copy-on-write clone of the base image — fast and space-efficient, since unchanged blocks are shared with the base rather than copied.</li>
|
|
<li><strong>Boot and connect.</strong> It boots the clone and connects to it over SSH.</li>
|
|
<li><strong>Share the repo.</strong> That session's repository is shared into the VM over virtiofs at <code>/Volumes/My Shared Files/workspace</code>, so the agent builds the exact working tree it's editing.</li>
|
|
</ul>
|
|
<p>When the VM goes idle (default <strong>15 minutes</strong>), it stops to free RAM — but its disk persists, so the next turn reboots quickly instead of re-cloning from scratch. When the session ends or is interrupted, the clone is deleted. Any orphaned clones left behind by a crash are cleaned up on the next app launch.</p>
|
|
</section>
|
|
|
|
<section id="concurrency">
|
|
<h2><span class="n">05</span>Concurrency & resources</h2>
|
|
<p>macOS caps how many macOS guests can run at once — about <strong>2</strong> on recent releases. Nucleic works within that limit rather than fighting it:</p>
|
|
<ul>
|
|
<li><strong>Max concurrent VMs.</strong> When the cap is reached, extra agents <em>queue</em> for a VM rather than failing — a session waits its turn for a slot instead of erroring out.</li>
|
|
<li><strong>CPUs.</strong> A per-session ceiling on virtual CPUs (default <strong>4</strong>).</li>
|
|
<li><strong>Memory.</strong> A per-session memory ceiling (default <strong>8 GB</strong>).</li>
|
|
</ul>
|
|
<div class="callout tip"><span class="lbl">Tuning</span>Raise <span class="ui">CPUs</span> and <span class="ui">Memory</span> for heavier builds, but remember each running VM holds that memory for as long as it's booted — balance the per-VM ceilings against how many run at once.</div>
|
|
</section>
|
|
|
|
<section id="next">
|
|
<h2><span class="n">06</span>What's next</h2>
|
|
<p>Now that you know what macOS VMs are, these guides take you the rest of the way:</p>
|
|
<ul>
|
|
<li><strong><a href="/support/macos-vm-base-image.html">Building the base image</a></strong> — the required one-time build that every per-session VM is cloned from.</li>
|
|
<li><strong><a href="/support/macos-vm-computer-use.html">Computer use for macOS VMs</a></strong> — letting an agent see and drive the VM's screen with screenshots, clicks, and typing.</li>
|
|
<li><strong><a href="/support/macos-vm-ax-agent.html">Setting up AX-based computer use</a></strong> — the advanced, semantic accessibility agent for by-identity control of the guest.</li>
|
|
</ul>
|
|
</section>
|
|
|
|
</div>
|
|
|
|
<div class="wrap related">
|
|
<h2>Related guides</h2>
|
|
<a href="/support/macos-vm-base-image.html">Building the base image<span class="arw" aria-hidden="true">→</span></a>
|
|
<a href="/support/macos-vm-computer-use.html">Computer use for macOS VMs<span class="arw" aria-hidden="true">→</span></a>
|
|
<a href="/support/macos-vm-ax-agent.html">Setting up AX-based computer use<span class="arw" aria-hidden="true">→</span></a>
|
|
</div>
|
|
</main>
|
|
|
|
<footer>
|
|
<div class="wrap foot">
|
|
<div class="brand" style="font-size:15px">
|
|
<svg class="mk" viewBox="0 0 100 100" aria-hidden="true">
|
|
<g fill="none" stroke-width="7">
|
|
<ellipse cx="50" cy="50" rx="17" ry="40" transform="rotate(80 50 50)" stroke="#7AA7DD"/>
|
|
<ellipse cx="50" cy="50" rx="17" ry="40" transform="rotate(20 50 50)" stroke="#DF619B"/>
|
|
<ellipse cx="50" cy="50" rx="17" ry="40" transform="rotate(140 50 50)" stroke="#C5826F"/>
|
|
</g>
|
|
</svg>
|
|
Nucleic
|
|
</div>
|
|
<div class="foot-links">
|
|
<a href="/">Home</a>
|
|
<a href="/support.html">Support</a>
|
|
<a href="/privacy.html">Privacy</a>
|
|
<a href="/terms.html">Terms</a>
|
|
</div>
|
|
<div class="mono">© 2026 Andrew Blakeslee Moore · Made with Nucleic</div>
|
|
</div>
|
|
</footer>
|
|
|
|
</body>
|
|
</html>
|