CLI Reference
The CiderStack CLI (cider) lets you create, manage, and automate macOS virtual machines from the terminal — ideal for scripting and CI/CD.
Important: Apple allows only 2 macOS VMs running simultaneously per Mac. This is a platform limit, not a CiderStack limit.
Installing the CLI
After installing CiderStack via the .pkg, the cider command is available in your terminal (the installer adds it to your PATH).
Global flags (work with most commands): --json, -q / --quiet, --debug, --no-color
VM lifecycle
# List all VMs
cider vm list
cider vm list --json
# Create a VM
cider vm create myvm
cider vm create myvm --cpu 4 --memory 8 --disk-size 64
cider vm create myvm --intent ci --ttl 2h
cider vm create myvm --template "CI Runner Base"
cider vm create myvm --image sonoma-arm64
# Start / stop / suspend
cider vm start myvm
cider vm start myvm --headless
cider vm stop myvm
cider vm suspend myvm
# Info and status
cider vm info myvm
cider vm info myvm --json
cider vm status myvm
# Clone, rename, delete
cider vm clone source-vm new-vm
cider vm rename old-name new-name
cider vm destroy myvm
cider vm destroy myvm -f
# Recovery mode
cider vm start-recovery myvm
# Intent and TTL (for disposable/CI VMs)
cider vm set-intent myvm ci
cider vm ttl myvm 30m
cider vm ttl myvm off
# Clean up retired VMs (TTL expired)
cider vm cleanup
cider vm cleanup --forceCreate options: --template / -t, --intent (interactive | disposable | ci | persistent), --image, --cpu, --memory (GB or MB if ≥1024), --disk-size (GB), --ttl (e.g. 30m, 2h, off)
VM IP and SSH
# Get VM IP
cider vm ip myvm
cider vm ip myvm --wait 60
cider vm ip --all
# SSH into a VM (auto-detects IP)
cider ssh myvm
# Run a command on the VM
cider ssh myvm -- whoami
cider ssh myvm -- "ls -la /tmp"
cider ssh myvm -- bash -c "echo hello > /tmp/test.txt"
# Options: IP, user, port, identity, timeout
cider ssh myvm --ip 192.168.64.2
cider ssh myvm --user admin --port 22
cider ssh myvm --identity ~/.ssh/id_ed25519 -- whoami
cider ssh myvm --timeout 30 -- whoami
# Target by IP (no VM name)
cider ssh 192.168.64.2 --user admin -- whoamiSSH must be enabled in the VM (System Settings → Sharing → Remote Login).
Shared folders
# Add a shared folder
cider vm share add myvm ~/scripts --name scripts
cider vm share add myvm /path/to/code --name code
cider vm share add myvm /path --name data --read-only
cider vm share add myvm /path --name data --mount-tag MyTag
# List / remove / enable / disable
cider vm share list myvm
cider vm share remove myvm scripts
cider vm share enable myvm scripts
cider vm share disable myvm scriptsInside the VM, shared folders appear at /Volumes/<name>.
Snapshots
# List snapshots
cider snapshot list myvm
cider snapshot list myvm --json
# Create a snapshot
cider snapshot create myvm "clean-state"
cider snapshot create myvm "before-test" -d "Pre-MDM enrollment"
# Restore a snapshot
cider snapshot restore myvm <snapshot-id>
cider snapshot restore myvm <snapshot-id> -f
# Delete a snapshot
cider snapshot delete myvm <snapshot-id>
cider snapshot delete myvm <snapshot-id> -fTemplates
# List templates
cider template list
cider template list --built-in
cider template list --custom
# Create a template from a VM
cider template create "My Template" --vm myvm
cider template create "My Template" --vm myvm -d "Base image for CI"
# Template details
cider template info "My Template"
cider template info <template-id>
# Delete
cider template delete "My Template"
cider template delete "My Template" -fImages and OCI
# List local images
cider image list
# Pull from OCI registry
cider pull ghcr.io/myorg/macos-base:latest
cider pull ghcr.io/myorg/image:tag --username user --password token
cider pull ghcr.io/myorg/image:tag --insecure
# Import an IPSW as an OCI image
cider image import /path/to/restore.ipsw
# Remove a local image
cider image rm <digest-or-ref>Pushing a VM to a registry
# Push VM as OCI image
cider vm push myvm ghcr.io/myorg/image:tag
cider vm push myvm ghcr.io/myorg/image:tag --username user --password tokenOther hosts can then cider pull ghcr.io/myorg/image:tag and create VMs from it.
IPSW
# List local IPSW files
cider ipsw list
cider ipsw list --scan /path/to/dir
# Show IPSW info
cider ipsw info /path/to/restore.ipsw
# Download from Apple
cider ipsw download --latest
cider ipsw download --version 15.2
cider ipsw download --latest --output ~/DownloadsmacOS installation
# Install macOS on a VM
cider install myvm --latest
cider install myvm --ipsw /path/to/restore.ipswTrial and license
# Start 14-day trial
cider trial start
# Trial status
cider trial status
# License
cider license status
cider license activate CIDER-XXXX-XXXX-...
cider license deactivateJSON output
Most commands support --json for scripting:
cider vm list --json
cider vm info myvm --json
cider vm ip myvm --json
cider vm ip --all --json
cider snapshot list myvm --json
cider template list --jsonExample cider vm list --json:
[
{
"id": "abc-123",
"name": "myvm",
"state": "stopped",
"cpuCount": 4,
"memoryGB": 8,
"diskSizeGB": 64
}
]Example scripts
Create and start a CI runner VM
#!/bin/bash
set -e
VM_NAME="ci-runner"
cider vm create "$VM_NAME" --intent ci --cpu 4 --memory 8
cider install "$VM_NAME" --latest
# Wait for installation to finish (can take 20–40 minutes)
while ! cider vm info "$VM_NAME" --json | jq -e '.state == "stopped"' >/dev/null 2>&1; do
sleep 60
done
cider vm start "$VM_NAME" --headless
sleep 30
IP=$(cider vm ip "$VM_NAME" --wait 120)
echo "VM IP: $IP"
cider ssh "$VM_NAME" -- "sudo systemsetup -setremotelogin on"
cider ssh "$VM_NAME" -- "mkdir -p ~/actions-runner"Snapshot-based testing
#!/bin/bash
set -e
VM_NAME="test-vm"
SNAPSHOT_NAME="clean-state"
SNAPSHOT_ID=$(cider snapshot list "$VM_NAME" --json | jq -r '.[] | select(.name=="'$SNAPSHOT_NAME'") | .id')
cider snapshot restore "$VM_NAME" "$SNAPSHOT_ID" -f
cider vm start "$VM_NAME" --headless
sleep 30
cider ssh "$VM_NAME" -- "./run-tests.sh"
TEST_EXIT=$?
cider vm stop "$VM_NAME"
exit $TEST_EXITWait for VM to be ready
#!/bin/bash
VM_NAME="$1"
TIMEOUT=300
STATE=$(cider vm info "$VM_NAME" --json | jq -r '.state // "notfound"')
if [ "$STATE" != "running" ]; then
cider vm start "$VM_NAME" --headless
fi
IP=$(cider vm ip "$VM_NAME" --wait "$TIMEOUT")
if [ -z "$IP" ]; then
echo "Failed to get IP after ${TIMEOUT}s"
exit 1
fi
ELAPSED=0
while ! cider ssh "$VM_NAME" -- "echo ready" 2>/dev/null; do
sleep 5
ELAPSED=$((ELAPSED + 5))
[ $ELAPSED -ge $TIMEOUT ] && { echo "SSH not ready"; exit 1; }
done
echo "VM $VM_NAME ready at $IP"Exit codes
| Code | Meaning |
|---|---|
| 0 | Success |
| 1 | General error |
| 2 | VM not found |
| 3 | VM already running |
| 4 | VM not running |
| 5 | Snapshot not found |
| 64 | Usage error (bad arguments) |
Environment variables
CIDER_QUIET=1 cider vm list
CIDER_DEBUG=1 cider vm start myvm
NO_COLOR=1 cider vm listMore help
cider --help
cider <command> --help
cider examplescider examples prints common usage snippets (create, push/pull, snapshot, SSH).
See also
- Image system (IPSW + OCI) — Pull, import, tagging, registries
- Local GitHub runners — Self-hosted runners on macOS VMs
- Key Concepts — Host, VM, snapshot, clone