GuidesCLI Reference

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 --force

Create 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 -- whoami

SSH 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 scripts

Inside 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> -f

Templates

# 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" -f

Images 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 token

Other 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 ~/Downloads

macOS installation

# Install macOS on a VM
cider install myvm --latest
cider install myvm --ipsw /path/to/restore.ipsw

Trial 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 deactivate

JSON 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 --json

Example 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_EXIT

Wait 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

CodeMeaning
0Success
1General error
2VM not found
3VM already running
4VM not running
5Snapshot not found
64Usage error (bad arguments)

Environment variables

CIDER_QUIET=1 cider vm list
CIDER_DEBUG=1 cider vm start myvm
NO_COLOR=1 cider vm list

More help

cider --help
cider <command> --help
cider examples

cider examples prints common usage snippets (create, push/pull, snapshot, SSH).


See also