# What Is a VM Bundle in vphone-cli? The Directory Structure Explained

> Understand vphone-cli VM bundles. Learn about the directory structure for virtual iPhone instances, including config files, APFS disk images, and firmware blobs.

- Repository: [Lakr/vphone-cli](https://github.com/Lakr233/vphone-cli)
- Tags: internals
- Published: 2026-09-12

---

**A VM bundle in vphone-cli is a self-contained directory that packages all configuration files, APFS disk images, and firmware blobs required to boot and run a virtual iPhone instance on macOS.**

In the `Lakr233/vphone-cli` ecosystem, the VM bundle serves as the fundamental unit of storage and portability for virtual iOS devices. Each bundle represents a complete virtual machine state—from CPU allocation to filesystem contents—organized as a single directory that the Virtualization.framework consumes to emulate iPhone hardware.

## Core Components of a VM Bundle

A VM bundle is simply a directory on disk containing several mandatory and optional items. According to the source code in [`sources/VPhoneCore/VPhoneBundle.swift`](https://github.com/Lakr233/vphone-cli/blob/main/sources/VPhoneCore/VPhoneBundle.swift), the directory name itself becomes the **bundle name** (e.g., `my-iPhone-vm`), while the contents define the virtual hardware.

### Configuration and Manifest

Every bundle contains a `config.plist` file at its root. This property list stores a serialized **VPhoneVirtualMachineManifest** that describes the virtual hardware configuration, including CPU count, memory size in megabytes, network settings, and the filename of the disk image. The CLI loads this manifest via `VPhoneVirtualMachineManifest.load` when initializing the bundle object.

### Disk Images and Firmware

The bundle houses the actual storage and boot components required by the guest OS:

- **Disk.img**: A raw APFS disk image containing the iOS filesystem. The bundle exposes the image size through the `VPhoneBundle.diskSizeBytes` property.
- **SEPStorage** and **AVPBooter.vresearch1.bin**: Firmware blobs required for Secure Enclave and virtual hardware emulation.
- **.vphoned.signed**: The signed host-side daemon binary that communicates with the guest iOS over a vsock transport channel.

### Snapshots and Resources

Additional files support state management and UI integration:

- **.snapshot files**: APFS snapshots used by the export and import commands to preserve exact VM state across transfers.
- **Resource bundles**: Optional application bundles (such as the bundled `vphone-cli.app` itself) and UI assets that can be staged into the VM environment.

## The VPhoneBundle Data Model

The `VPhoneBundle` struct in [`sources/VPhoneCore/VPhoneBundle.swift`](https://github.com/Lakr233/vphone-cli/blob/main/sources/VPhoneCore/VPhoneBundle.swift) provides the programmatic interface to these directories. It is a `Sendable` value type that encapsulates the bundle's location and configuration:

```swift
public struct VPhoneBundle: Sendable {
    public let url: URL                         // bundle directory
    public let manifest: VPhoneVirtualMachineManifest
    public var name: String { url.lastPathComponent }
    public var configURL: URL { url.appendingPathComponent("config.plist") }
}

```

This structure exposes the filesystem URL, the parsed hardware manifest, and computed properties for the bundle name and configuration file path.

## Creating VM Bundles with VPhoneBundleOps

The `VPhoneBundleOps` API in [`sources/VPhoneCore/VPhoneBundleOps.swift`](https://github.com/Lakr233/vphone-cli/blob/main/sources/VPhoneCore/VPhoneBundleOps.swift) provides factory methods for bundle lifecycle management. Creating a new VM requires specifying a `NewBundleSpec` with hardware parameters and firmware sources:

```swift
let spec = VPhoneBundleOps.NewBundleSpec(
    name: "my-iPhone-vm",
    romSource: VPhoneBundleOps.defaultROMSource(),
    sepromSource: VPhoneBundleOps.defaultSEPROMSource(),
    cpuCount: 8,
    memoryMB: 8192)
let bundle = try VPhoneBundleOps.create(spec, in: library)

```

This operation performs three critical steps: it creates the bundle directory, writes the default `config.plist` with the specified manifest, and copies the necessary ROM and SEP firmware files into the bundle structure.

## Launching and Transferring Bundles

Once instantiated, a bundle becomes the input for the virtualization engine. The CLI boots instances using `VPhoneVirtualMachine.start(with:)` as implemented in [`sources/vphone-cli/VPhoneVMLaunchCLI.swift`](https://github.com/Lakr233/vphone-cli/blob/main/sources/vphone-cli/VPhoneVMLaunchCLI.swift):

```swift
let bundle = try library.bundle(named: "my-iPhone-vm")
try VPhoneVirtualMachine.start(with: bundle)

```

The library validates the bundle's manifest integrity and delegates configuration to Apple's Virtualization.framework.

### Export and Import Workflows

Bundles support serialization for backup and migration via [`sources/vphone-cli/VPhoneVMTransferCLI.swift`](https://github.com/Lakr233/vphone-cli/blob/main/sources/vphone-cli/VPhoneVMTransferCLI.swift). The **export** operation creates a compressed archive containing the entire bundle state:

```swift
let archive = try VPhoneBundleOps.export(
    bundleNamed: "my-iPhone-vm",
    to: URL(fileURLWithPath: "/tmp/my-iPhone-vm.tgz"),
    includeIPSW: false,
    in: library)

```

The **import** operation reconstructs the bundle from an archive into a new library location, preserving APFS snapshots and firmware integrity:

```swift
let imported = try VPhoneBundleOps.importArchive(
    from: archiveURL,
    name: "imported-vm",
    in: newLibrary)

```

## Summary

- A **VM bundle** is a directory-based container that encapsulates all files required to run a virtual iPhone, including configuration, disk images, and firmware.
- The `VPhoneBundle` struct models the bundle's path and manifest, while `VPhoneBundleOps` handles creation, cloning, and destruction.
- Key files include `config.plist` (hardware settings), `Disk.img` (APFS filesystem), SEP firmware blobs, and `.vphoned.signed` (host daemon).
- Bundles support full lifecycle operations—create, launch, export, and import—enabling portable virtual device workflows across macOS systems.

## Frequently Asked Questions

### What file format does vphone-cli use for VM bundles?

vphone-cli uses a directory-based bundle format rather than a single file. The bundle is a standard filesystem directory containing a `config.plist` (Apple property list format), a raw `Disk.img` (APFS format), and binary firmware blobs. This structure allows the Virtualization.framework to memory-map disk images and access configuration directly without extraction overhead.

### How do I move a VM bundle to another Mac?

Use the built-in export and import commands. Call `VPhoneBundleOps.export(bundleNamed:to:includeIPSW:in:)` to generate a compressed `.tgz` archive containing the bundle directory and its snapshots. Transfer this archive to the target Mac, then use `VPhoneBundleOps.importArchive(from:name:in:)` to reconstruct the bundle in the new library. This preserves the exact VM state, including APFS snapshots and hardware configuration.

### Can I edit the VM configuration after creation?

Yes. Since the configuration is stored as `config.plist` inside the bundle directory, you can modify CPU count, memory size, or network settings by updating this property list. The `VPhoneBundle` struct provides the `configURL` property to locate this file programmatically. However, changes to hardware parameters typically require a VM reboot to take effect, and modifying the disk image filename requires the corresponding file to exist in the bundle directory.

### Where does vphone-cli store VM bundles by default?

vphone-cli organizes bundles within a **VPhoneLibrary**, which is a root directory containing a `Bundles/` subdirectory. When you create a bundle, it is placed as a subfolder named after the bundle inside this library path. The library path itself is configurable during initialization of the `VPhoneLibrary` object, allowing you to store VMs on external drives or specific volumes.