VM management · Managing VMs

Managing VMs

Everything past the first boot — multi-window sessions, the macOS guest install path, the bundle on disk, and how to clean up.

The VM Library

The VM Library window is SecVF's main surface. The center pane is a table of every VM SecVF knows about — the source of truth is ~/.avf/<family>/*.bundle/metadata.json, scanned on launch.

ColumnSourceNotes
Statusruntime● running, ◉ paused, ○ stopped, ◌ booting.
Namemetadata.jsonAlso the bundle directory name. Lowercase + hyphens recommended.
OSmetadata.jsonLinux distro or macOS version.
Networkmetadata.jsonNAT / Virtual / Router / FakeNet — see Network modes.
RAMmetadata.jsonBytes, displayed in MB/GB.
Last startedfilesystem mtimeUseful when the list grows.

The right-click menu has the operations you'll use most: Start, Stop, Pause, Edit configuration, Reveal bundle in Finder, Duplicate, Delete.

Lifecycle

VMs go through five states. SecVF posts NotificationCenter events at every transition — useful if you're scripting.

  ┌────────┐  start   ┌─────────┐         ┌─────────┐
  │stopped │ ──────▶ │ booting │ ──────▶ │ running │
  └────────┘          └─────────┘         └────┬────┘
       ▲                                       │
       │ stop / shutdown          pause/resume ▼
       │                                  ┌─────────┐
       └─────────────── stop ◀────────── │ paused  │
                                          └─────────┘
  • Start reads metadata.json, builds a VZVirtualMachineConfiguration on a background thread, then transitions to running on the main actor.
  • Stop requests a clean ACPI shutdown; force stop calls VZVirtualMachine.stop() — equivalent to pulling the plug.
  • Pause calls VZVirtualMachine.pause() — RAM stays allocated, no CPU cycles. Resume restores exactly.

Multi-window sessions

Every running VM gets its own window. The Window menu lists them all; ~ cycles between them.

  • Closing a window does not stop the VM. Reopen from the VM Library by selecting and clicking Show window.
  • Each window has its own toolbar: pause/resume, fullscreen, scale-to-fit, send CtrlAltDel.
  • The Active VMs sidebar in the Library updates in real time — green dot = running, yellow = paused.

Editing configuration

VM config is editable from Edit configuration… in the right-click menu. The VM must be stopped.

Editable fields:

  • CPU cores
  • RAM
  • Network mode (see Switching modes)
  • Display resolution (Linux guests)
  • VirtioFS shared folders (off by default — opt-in)

Non-editable, baked at creation:

  • OS family
  • Disk size — to grow a disk, add a second one or rebuild the VM
  • Machine identifier — changing it breaks any guest software bound to it (e.g. macOS Activation)

Editing writes through to metadata.json. The file is stable JSON — version-control-friendly, diff-friendly.

Installing a macOS guest

Apple Silicon only. macOS guest VMs require the M1+ implementation of the Virtualization framework. They will not run on Intel Macs.

The macOS install path is different from Linux because Apple distributes macOS as a restorable IPSW, not an ISO.

  1. VM Library → + New VM → OS family macOS.
  2. SecVF queries Apple's CDN for available IPSWs and shows the latest. Pick a version (typically the matching macOS or one minor below).
  3. Click Create. SecVF downloads the IPSW (~12–14 GB) directly from *.cdn-apple.com over TLS 1.2+. The download is validated against a hardcoded domain allowlist; downloads from anywhere else are refused.
  4. The installer transitions the IPSW into a virtual disk, then boots it. macOS Setup Assistant runs inside the VM — go through Apple ID setup if you plan to use FaceTime/iCloud, otherwise skip with Set up later.
  5. After install, take a snapshot (see Snapshots) so you can roll back to a clean macOS state.

The macOS bundle structure adds auxiliary.bin and hardwareModel.bin alongside the regular files — these are required by the framework and shouldn't be modified.

Inside the VM bundle

A VM bundle is just a directory. Everything the VM needs is inside it; the bundle is fully portable across SecVF installs.

~/.avf/Linux/ubuntu-test.bundle/
├── Disk.img             # Sparse virtual disk (qcow-ish but framework-native)
├── NVRAM                # EFI variables, boot order
├── MachineIdentifier    # Stable VZ machine ID (binary)
├── metadata.json        # Human-editable config
└── (optional) iso/      # ISO file when first-boot install pending

For macOS:

~/.avf/MacOS/macos-14.bundle/
├── Disk.img
├── NVRAM
├── MachineIdentifier
├── auxiliary.bin        # macOS-specific firmware data
├── hardwareModel.bin    # Frozen machine model descriptor
├── <version>.ipsw       # Original installer (kept for re-restore)
└── metadata.json

Metadata schema

{
  "name": "ubuntu-test",
  "osFamily": "linux",
  "distroId": "ubuntu",
  "distroVersion": "24.04",
  "cpu": 2,
  "memory": 4294967296,
  "diskBytes": 21474836480,
  "networkMode": "nat",
  "createdAt": "2026-05-01T14:22:11Z",
  "schemaVersion": 1
}

Fields are Codable in Swift — any addition needs a schema bump. VMConfiguration in the source is the reference.

Snapshots & cloning

The Apple Virtualization framework doesn't yet expose first-class snapshots, so SecVF does it at the file level — duplicate the bundle while the VM is stopped, give the copy a new name and a new MachineIdentifier.

From the GUI: right-click → Duplicate. Give the copy a name; SecVF rewrites metadata.json, regenerates MachineIdentifier, and copies Disk.img.

APFS clone trick. If ~/.avf is on APFS (it is, on any modern Mac), the duplicate uses copy-on-write — it's instant and takes no disk until you start writing. The AI sandbox uses this same primitive for its sub-millisecond session clones (see AI sandbox).

Deleting a VM

Right-click a stopped VM → Delete. SecVF asks for confirmation, then moves the bundle to the trash (Finder trash, not rm) — recoverable until the trash is emptied.

  • If the VM is running, Delete is disabled. Stop it first.
  • If the bundle is open in Finder or another app holds a file inside it, the move can fail. Close those, retry.
  • Force-deleting the bundle from the shell is fine: rm -rf ~/.avf/Linux/<name>.bundle. SecVF re-scans and the row drops out.
Logs survive deletion. Security and error logs at ~/.avf/logs/ retain entries for deleted VMs by name. If you're rotating bundles for sensitive analyses, also clear or rotate the logs.