macOS VMs in seconds.

Install macOS once into a shared base image. Every virtual machine after that is a copy-on-write layer on top, created in seconds, turning one EC2 Mac Dedicated Host, or any Mac in your rack, into a pool that resets clean between jobs.

$ spook create ci-runner-02

Requires macOS 27 or later on Apple silicon. MIT licensed.

ci-runner-02 + 40 MB ci-runner-01 + 12 MB dev + 96 MB three overlays. Each stores only its own writes base.asif 40 GB one macOS install · read-only · never booted
Fig 1, one shared base image, one thin overlay per VM.
30 ms to clone a 5 GB VM, measured on an M-series Mac
0 bytes of extra disk for that clone: APFS shares the blocks
1 install of macOS per build, not one per virtual machine
865 tests in 222 suites, run on every change

Host operating system

macOS 27 or later

Required for macOS guests: the shared base image and its copy-on-write overlays are built on DiskImageKit, which shipped in macOS 27. Linux guests run on older hosts.

Hardware

Apple silicon

M1 or newer, including the Apple silicon EC2 Mac families. Intel Macs. And the mac1 EC2 family, cannot run macOS guests at all.

To build from source

Xcode 27

The macOS 27 SDK is needed to compile. Roughly 40 GB of free disk covers the first base image, plus whatever each VM writes on top of it.

Creating a macOS VM used to mean installing macOS.

Every VM meant its own 10–20 minute install and its own privileged write into the guest disk. Spooktacular does both once per macOS build, then shares the result.

Per virtual machine, before
  • Download a restore image
  • Run Apple's installer, 10 to 20 minutes
  • Write the provisioner into the guest disk, as root
  • Pay the full disk cost of another macOS
Per virtual machine, now
  • Add an overlay layer to the shared base
  • Clone the auxiliary storage. An APFS clone, so instant
  • Reserve an address and install any published ports
  • Boot, and let the guest report when it is ready

The base image in Fig 1 is sealed read-only and never booted, so its layer identity cannot drift and a warm pool can prove its base is pristine rather than assume it. How instant create works has the full picture.

Built for the two jobs Macs get bought for.

CI runners that reset to a known-clean state, and desktops you can reach. Each is one command.

GitHub Actions

Ephemeral runners

A registration token is minted seconds before boot from a token in the Keychain, so no long-lived credential reaches the guest. The runner takes one job, then the VM resets to the base.

$ spook create runner --github-runner --ephemeral

Screen Sharing

Remote desktops

An admin account is provisioned, Setup Assistant is skipped, and Screen Sharing plus Remote Login come up on first boot. Connect with the credentials you set.

$ spook create desktop --remote-desktop

Published ports

Guest services on the host

Every VM gets a private subnet and a reserved address, so a guest port can be published to the host the way a container's would be, and spook ip is a lookup, not a probe.

$ spook create web --publish 8080:80

One engine, two front doors.

A native Mac app and a 27-command CLI over one core. A VM made in either is a first-class citizen of the other.

The Spooktacular Mac app: a sidebar listing two Linux virtual machines with their vCPU and memory allocations, above the downloaded Fedora and macOS images.
Fig 2: the app, managing a small fleet.

The app is where you watch a fleet and open a screen; the CLI is what your automation calls. Neither wraps the other. Both sit on the same Swift core, so behaviour cannot drift between them.

  • Create, clone, snapshot and reset from either side
  • A live event stream per VM over a Unix socket
  • An HTTP control plane with signed requests, for fleets
  • Roles and Secure-Enclave-bound keys for who may do what

A real session, replayed.

Every line below was captured from a terminal on an M-series Mac, commands, timings and all. Only the generated password is masked.

zsh: spook
spook create ci-runner-01 --os linux --from-image fedora✓ Linux VM 'ci-runner-01' created (cloud-init provisioned).  Bundle           ~/.spooktacular/vms/ED27407A-FBBA-4F12-878A-C26C041F8BBE.vm  Image            Fedora-Cloud-Base-AmazonEC2-44-1.7.aarch64.raw.xz ⚠ Save these credentials — you need them to connect (shown only once):  Account          admin  Password         ························  Applied by cloud-init on the first 'spook start'. No sudo needed. spook clone ci-runner-01 ci-runner-02⤢ Cloning 'ci-runner-01' → 'ci-runner-02'…✓ Clone 'ci-runner-02' created.  Machine ID       inherited (paired with auxiliary storage)  MAC              regenerated (unique) spook listNAME          STATE      CPU      MEM    DISK    NET  ♪  STATUS────────────  ─────────  ───────  ─────  ──────  ───  ─  ───────ci-runner-01  ○ stopped  8 cores  16 GB  100 GB  nat  ♪  pendingci-runner-02  ○ stopped  8 cores  16 GB  100 GB  nat  ♪  pending 2 virtual machines, 0 running

The first macOS create is the one that costs anything: it installs macOS into the shared base image, printing Building the macOS base image — one time, 10-20 minutes. and then Sealing the base image read-only… before the VM appears. Every create after that skips straight to ✓ VM created from the cached base image.

Apple permits two macOS guests per host, and Spooktacular enforces that rather than letting you find out later. Linux guests, like the ones above, are unlimited and need no base image at all.

Stop paying for the same macOS install twice.

Open source under MIT, built on Apple's own Virtualization and DiskImageKit frameworks. No agent on your guests, no license server, nothing phoning home.