Getting Started
From first download to a running CI pipeline in seven steps. No prior experience required.
Download & Install
Install Spooktacular on your Mac. Takes about 30 seconds.
Build Spooktacular from Source macOS 26+ · Apple Silicon · signed releases coming$ git clone https://github.com/Spooky-Labs/spooktacular.git $ cd spooktacular && ./build-app.sh release
Drag the built Spooktacular.app to your Applications folder and launch it.
spook command-line tool:brew install spooktacular (planned)
Create Your First VM
Create a fresh macOS virtual machine with one command. It pulls the latest IPSW and installs it automatically.
$ spook create my-first-vm --from-ipsw latest ✓ Fetching latest compatible macOS restore image... ✓ Downloading IPSW (this may take a while)... ✓ Installing macOS (10-20 minutes)... ✓ VM 'my-first-vm' created successfully. Run 'spook start my-first-vm' to boot the VM. # Total time: ~15-20 minutes (mostly IPSW download)
What just happened?
Spooktacular downloaded the latest macOS restore image (IPSW) from Apple and installed it into a Virtualization.framework VM. Run spook start my-first-vm to boot it and complete Setup Assistant yourself, same as a physical Mac's first boot -- no automation runs here. (GitHub Actions runner VMs are different: see Step 4, which uses native macOS 27+ guest provisioning to create the account and skip Setup Assistant with zero interaction.)
Clone a VM
Create an identical copy of your base VM. APFS copy-on-write makes this nearly instant.
$ spook clone my-first-vm runner-01 ✓ Cloned "my-first-vm" → "runner-01" (48ms) ✓ New machine identity assigned ✓ Disk: copy-on-write (shared blocks, ~0 bytes additional)
Why is it so fast?
APFS copy-on-write cloning shares disk blocks between the source and the clone. Only modified blocks consume additional storage. A fresh clone takes 48 milliseconds and starts at approximately zero additional disk usage. Each clone gets a unique machine identity so it appears as a distinct Mac.
Run Your CI Pipeline
Create a GitHub Actions runner VM with a single command. Store a personal access token (PAT) in the Keychain first -- Spooktacular mints a short-lived runner registration token from it automatically, seconds before the VM boots.
$ security add-generic-password -s com.spooktacular.github \ -a your-org -w <PAT> -U $ spook create runner-01 --github-runner \ --github-repo your-org/your-repo \ --github-token-keychain your-org --ephemeral ✓ Installing macOS (10-20 minutes)... ✓ VM "runner-01" created successfully ✓ Minting GitHub Actions runner registration token... ✓ Script injected. The provisioner runs it automatically on first boot. ✓ Starting "runner-01" headless for runner registration... ✓ Runner "runner-01" is online
What's happening inside?
One command creates the VM, installs macOS, injects the runner setup script, boots the VM without a display, and polls GitHub every 10 seconds (up to 10 minutes) until the runner reports online -- no separate registration step. The PAT never touches a CLI flag, environment variable, or file; only the Keychain.
Double Your Capacity
Apple Silicon supports 2 VMs per Mac. Create a second runner and run both simultaneously. Ephemeral mode auto-destroys after each job for a clean slate.
$ spook create runner-02 --github-runner \ --github-repo your-org/your-repo \ --github-token-keychain your-org --ephemeral ✓ VM "runner-02" created successfully ✓ Starting "runner-02" headless for runner registration... ✓ Runner "runner-02" is online
Why ephemeral?
Ephemeral runners auto-destroy the moment they stop, after completing a single job -- no leftover state, no cache poisoning, no stale artifacts from previous builds. Cloning doesn't yet carry forward the --github-runner template, so each new runner today is its own spook create --github-runner --ephemeral rather than a clone of an earlier runner.
Run as a Service
Make your runner survive reboots and run headless in the background. Install it as a system service and forget about it.
$ sudo spook service install runner-01 ✓ Created launchd service: com.spooky-labs.spooktacular.runner-01 ✓ Service enabled (starts on boot) ✓ Runner-01 is now a persistent service # Manage the service $ spook service status runner-01 # check status $ spook service stop runner-01 # stop service $ spook service uninstall runner-01 # remove service
What does this do?
This installs a launchd plist that starts your runner automatically when the Mac boots. The VM runs headless in the background -- no display, no logged-in user required. Your runner persists through power cycles and macOS updates.
Connect & Monitor
SSH into your running VM, stream live metrics, and share the clipboard via Guest Tools. Spooktacular handles all the plumbing.
# Resolve the VM's IP address $ spook ip runner-01 192.168.1.42 # SSH into the VM (requires Remote Login enabled on the guest) $ spook ssh runner-01 Connecting to admin@192.168.1.42... runner-01:~$ sw_vers ProductName: macOS ProductVersion: 15.4 # Stream live VM metrics (CPU, memory, load) $ spook stream runner-01 --topic metrics {"topic":"metrics","event":{"at":"2026-07-02T14:31:07Z","cpuUsage":0.15,"diskBytesRead":184320000,"diskBytesWritten":52428800,"energyNanoJoules":98765432100,"loadAverage1m":1.42,"memoryTotalBytes":17179869184,"memoryUsedBytes":7247757312,"pageIns":184203,"processCount":312,"uptime":41523.7}} {"topic":"metrics","event":{"at":"2026-07-02T14:31:12Z","cpuUsage":0.18,"diskBytesRead":184320000,"diskBytesWritten":52428800,"energyNanoJoules":98766210400,"loadAverage1m":1.39,"memoryTotalBytes":17179869184,"memoryUsedBytes":7268962304,"pageIns":184219,"processCount":312,"uptime":41528.7}}
How does this work?
Spooktacular creates each VM with Remote Login (SSH) enabled. spook ip resolves the VM's IP by matching its MAC address against the host's DHCP lease table. spook ssh wraps this lookup and opens an interactive shell. spook stream subscribes to the host-API Unix-domain socket for live metrics (CPU/memory/load/lifecycle events). Guest Tools, installed automatically, provides clipboard sharing via SPICE when the guest UI is in use.