Reproducible Developer Environment topologies, with Linux as the universal Machine target.
A Developer Environment is the primary vz product object: a named,
isolated realization of a project topology containing one or more target-native
Machines plus their storage, networks, DNS, endpoints, credentials, lifecycle,
and workload state. It is not a synonym for one VM or container. A project and
even one worktree may have several Environment instances; a single Environment
may contain Linux and native macOS Machines.
The target model is deliberately asymmetric:
- Linux is universal. Linux Machines run on macOS today and are planned for Linux and Windows hosts.
- Native targets follow the host. Native macOS Machines run on macOS; native Windows Machines are planned for Windows.
- Docker belongs to each Developer-profile Linux Machine. The complete Docker-compatible
workflow is in progress. Every Developer-profile Linux Machine will implicitly own its private
Docker Engine, containerd, BuildKit cache, image and volume state, networks,
endpoint, and Docker context. There is no Environment-global or global
vzDocker daemon and no Docker capability implied for native macOS/Windows Machines. - Networking can be realistic without being public. Machines use declared private paths or an Environment-local simulated-public DNS/TLS/ingress/NAT edge. Separate Environments are default-deny.
- Hardened environments are secondary. The constrained
containerkernel profile remains available for locked-down workloads, but it is not a peer product or the default Developer Environment.
Today, vz ships Linux VM/OCI/BuildKit primitives and native macOS VM automation
on Apple Silicon. Their convergence into the complete Developer Environment
contract—including topology and private per-Developer-Linux-Machine Docker—is in
development. Additional
host/Machine-target combinations below are roadmap work, not shipped functionality.
- Environment-first. A project definition creates isolated reproducible topology instances, each with one or more Machines.
- Linux everywhere. Keep the Linux target consistent while choosing the best isolation backend for macOS, Linux, or Windows.
- Native where it matters. Use native macOS environments on Apple hardware; native Windows is a later target for Windows hosts.
- Private by construction. Linux Docker state is scoped to one Machine; Environment routing, DNS, storage, credentials, and endpoints cannot leak into another instance.
- Script-friendly. Consistent command flows and
--jsonoutput support automation.
curl -sSf https://raw.githubusercontent.com/gpu-cli/vz/main/scripts/install.sh | shThis installs pre-built binaries (signed + notarized) and the Linux kernel to ~/.vz/bin/.
Requires macOS on Apple Silicon.
Options:
VZ_VERSION=0.3.0— pin a specific versionVZ_NO_LINUX=1— skip Linux kernel download
# Requires Rust 1.85+
cargo install --git https://github.com/gpu-cli/vz.git vz-cli
vz self-sign # apply Virtualization.framework entitlementscd linux && make docker-build # requires Docker
mkdir -p ~/.vz/linux && cp linux/out/{vmlinux,initramfs.img,youki,version.json} ~/.vz/linux/The default kernel profile is developer and keeps nested virtualization for
Virgil-style Firecracker host VMs. To build the constrained container sandbox
bundle, use:
cd linux && make docker-build KERNEL_PROFILE=containerRelease CI caches the developer/container kernel images by kernel inputs, then
rebuilds the initramfs and metadata for each vz release.
Status describes backend maturity, not complete product parity.
| Host | Linux target | Native macOS target | Native Windows target |
|---|---|---|---|
| macOS (Apple Silicon) | ACTIVE primitives: Virtualization.framework Linux VM, OCI, and BuildKit; unified lifecycle and private Docker are DEV | ACTIVE vz vm ... provisioning and automation; unified lifecycle is DEV |
Not applicable |
| Linux | DEV: partial linux-native backend; complete Developer Environment parity remains in progress |
Not applicable | Not applicable |
| Windows | PLANNED: Linux Developer Environments using the appropriate Windows virtualization backend | Not applicable | PLANNED later: native Windows Developer Environments |
Linux is the universal Machine target across all three hosts. Native macOS and native Windows Machines complement it; they do not replace it. On macOS, Linux and native macOS Machines may participate in the same declared Environment topology.
vz status is the first public lifecycle verb wired to the topology model. It
reads the nearest checked-in vz.json as a typed ProjectDefinition, connects
only to an already-running runtime daemon, and reports a persisted Project,
Environment, and Machine snapshot. JSON output distinguishes the host and
daemon backend from each Machine target and reports desired-versus-persisted
definition drift, requested and negotiated capabilities, and persisted
unsupported-capability reasons. These are persisted results, not a live health
probe. Status does not infer Docker availability from a Developer profile or
create a Docker context.
Bare vz now prints static top-level help without discovering or mutating
runtime state. The implicit create/continue/resume path and its root mutation
flags are removed, as is the --control-plane flag. Removed entries return
structured migration errors; they are not hidden aliases. Explicit legacy
command families remain except for the already-retired stack family.
The other four 0.4 lifecycle verbs and the final exactly-five-command surface
are still in development. The currently shipped vz init remains a legacy 0.3
authoring command and does not produce the topology ProjectDefinition required
by the new status path; no mutating fallback is performed. The repository does
not yet ship a stable schema/example authoring bundle.
The commands below document the shipped 0.3 single-Linux-VM surface. They are
being replaced for 0.4 by vz up, vz exec, vz status, vz stop, and
vz delete; they do not define the future product object model.
cd your-project
# Generate a vz.json config (auto-detects Rust, Node, Python, Go)
vz init
# Run any command inside the Linux VM
vz run echo "hello from Linux"
# Compile and run a Rust project
vz run cargo build
vz run cargo test
# Open an interactive shell
vz run -i bash
# Stop the VM when done
vz stopThe first vz run boots the environment's Linux VM (~3s), pulls the base
image, and runs setup commands from vz.json. Subsequent runs reuse that
environment and skip setup when the setup hash is unchanged.
This legacy sequence no longer includes vz status: that spelling now uses the
0.4 topology-backed behavior described above.
The intended Developer Environment UX will also start each declared Linux
Machine's private Docker service and report its managed context. Until the Docker roadmap is
complete, do not assume that host docker, Compose, or buildx commands have
full compatibility merely because the OCI workflows below are available.
{
"image": "ubuntu:24.04",
"workspace": "/workspace",
"mounts": [{ "source": ".", "target": "/workspace" }],
"setup": [
"apt-get update",
"apt-get install -y build-essential curl"
],
"env": { "PATH": "/root/.cargo/bin:/usr/local/bin:/usr/bin:/bin" },
"resources": { "cpus": 4, "memory": "8G" }
}The former vz stack ... command family is no longer executable. Calls fail
before daemon or state access with the structured legacy_command_removed
response and migration guidance. Multi-service topology belongs in vz.json;
lower-level topology operations remain available through typed APIs while the
five-verb 0.4 CLI is implemented.
Developer Environments do not expose the macOS host through an unconditional
gateway alias. In particular, an undeclared Machine must not receive
host.vz.internal in /etc/hosts, and external egress does not authorize host
access.
The 0.4 design requires an explicit Environment/Machine-owned host import for
one host-loopback protocol and port, carried over a private authenticated relay.
That relay is still under development; do not bind a host service to a wildcard
or LAN address as a substitute. See
docs/developer-environments.md for the
normative network contract.
# Create a pinned base image from the stable channel
vz vm init --base stable
# Provision account + guest agent after fingerprint verification (system mode is default)
sudo vz vm provision --image ~/.vz/images/base.img --base-id stable
# No-local-sudo local path (opt-in runtime policy)
vz vm provision --image ~/.vz/images/base.img --base-id stable --agent-mode user
# Verify a local image against the stable channel pin
vz vm base verify --image ~/.vz/images/base.img --base-id stable
# Start headless VM
vz vm run --image ~/.vz/images/base.img --name dev --headless &
# Execute in guest over vsock
vz vm exec dev -- sw_vers
# Save state and stop
vz vm save dev --stop
# Restore fast from saved state
vz vm run --image ~/.vz/images/base.img --name dev --restore ~/.vz/state/dev.vzsave --headless &vz vm init --base <selector>,vz vm provision --base-id <selector>, andvz vm base verify --base-id <selector>accept immutable base IDs plus channel aliases (stable,previous).- Base descriptors include support lifecycle metadata (
activeorretired); selecting a retired or unknown base fails with explicit fallback guidance. - Retirement guidance always includes
vz vm init --base stableand, when available, a concrete replacement selector/base. vz vm patch verifyandvz vm patch applyreject bundles targeting retired or unsupported base descriptors.- Unpinned flows require explicit
--allow-unpinned. - In CI (
CI=true), unpinned flows are blocked unlessVZ_ALLOW_UNPINNED_IN_CI=1is set. - Runtime policy:
--agent-mode systemis the default for reliability;--agent-mode useris opt-in for no-local-sudo workflows.
# Explicit unpinned local flow
vz vm init --allow-unpinned --ipsw ~/Downloads/restore.ipsw
sudo vz vm provision --image ~/.vz/images/base.img --allow-unpinned# Generate an Ed25519 signing key (PKCS#8 PEM)
openssl genpkey -algorithm Ed25519 -out /tmp/vz-patch-signing-key.pem
# One-command inline patch creation (no operations.json or payload directory required)
vz vm patch create \
--bundle /tmp/patch-1.vzpatch \
--base-id stable \
--mkdir /usr/local/libexec:755 \
--write-file /path/to/vz-agent:/usr/local/libexec/vz-agent:755 \
--symlink /usr/local/bin/vz-agent:/usr/local/libexec/vz-agent \
--set-owner /usr/local/libexec/vz-agent:0:0 \
--set-mode /usr/local/libexec/vz-agent:755 \
--signing-key /tmp/vz-patch-signing-key.pem
vz vm patch verify --bundle /tmp/patch-1.vzpatch
sudo vz vm patch apply --bundle /tmp/patch-1.vzpatch --image ~/.vz/images/base.imgFor advanced CI workflows, vz vm patch create also supports --operations <json> + --payload-dir <dir>.
# 1) Create a binary image delta from a signed bundle (runs bundle apply on a temp image copy)
sudo vz vm patch create-delta \
--bundle /tmp/patch-1.vzpatch \
--base-image ~/.vz/images/base.img \
--delta /tmp/patch-1.vzdelta
# 2) Apply the binary delta without sudo to produce a new bootable image
vz vm patch apply-delta \
--base-image ~/.vz/images/base.img \
--delta /tmp/patch-1.vzdelta \
--output-image ~/.vz/images/base-patched.img
# 3) Boot-test the patched image
vz vm run --image ~/.vz/images/base-patched.img --name delta-test --headlessinit, run, run -i, stop, status, logs
These are the shipped legacy lifecycle commands. They and the infrastructure
groups below are removed from the 0.4 public surface in favor of up, exec,
status, stop, and delete; advanced operations move to typed APIs.
pull, run, create, exec, images, prune, ps, stop, rm, logs
The former stack command family is retired on the 0.4 development line; it
returns legacy_command_removed and is not retained as a hidden alias.
vm init, vm run, vm exec, vm save, vm restore, vm list, vm stop, vm cache, vm provision, vm cleanup, vm self-sign, vm validate, vm base, vm patch
Runtime-mutating CLI surfaces (sandbox, image, file, lease, execution, checkpoint, build) use vz-runtimed over gRPC/UDS.
- Default socket path is derived from the state DB directory:
<state-db-parent>/.vz-runtime/runtimed.sock
- Endpoint override:
VZ_RUNTIME_DAEMON_SOCKET=/absolute/path/to/runtimed.sock
- Autostart policy:
VZ_RUNTIME_DAEMON_AUTOSTART=1(default) enables daemon cold-startVZ_RUNTIME_DAEMON_AUTOSTART=0disables autostart and fails fast when unreachable
- Transport selector:
VZ_CONTROL_PLANE_TRANSPORT=daemon-grpc(default)VZ_CONTROL_PLANE_TRANSPORT=api-httpis accepted; current CLI execution path uses a compatibility connector while full HTTP control-plane routing is tracked in beadvz-pip6
- Sandbox startup defaults (daemon policy):
VZ_SANDBOX_DEFAULT_BASE_IMAGE=<image-ref>VZ_SANDBOX_DEFAULT_MAIN_CONTAINER=<command-or-container-hint>VZ_SANDBOX_DISABLE_LEGACY_DEFAULT_BASE_IMAGE=1disables compatibility fallback (debian:bookworm)
- Retention policy defaults (daemon-owned GC):
- Untagged checkpoints: max
128retained, max age30days - Tagged checkpoints (
--tag): retained until explicit deletion - Receipts: max
20_000retained, max age14days
- Untagged checkpoints: max
vz-cli
|
+-- container commands --> vz-oci --> vz-runtime-contract
| |-> macOS backend (vz-oci-macos, VM-backed)
| '-- Linux backend (vz-linux-native)
'-- vm commands (macOS) -> vz (Virtualization.framework wrapper) + vz-guest-agent
cd crates
cargo build --workspace
cargo clippy --workspace -- -D warnings
cargo nextest run --workspaceRuntime API adapter local smoke test:
cd crates
cargo run -p vz-api -- \
--bind 127.0.0.1:8181 \
--state-store-path /tmp/vz-api-state.db \
--daemon-auto-spawn true \
--stack-baseline \
--capability fs_quick_checkpoint
# in another shell
curl -s http://127.0.0.1:8181/v1/capabilities
curl -s http://127.0.0.1:8181/openapi.jsonvz-api daemon lifecycle behavior can be tuned for local/dev/operator scenarios:
VZ_RUNTIME_DAEMON_AUTOSTART=1(default) enables cold-start ofvz-runtimedVZ_RUNTIME_DAEMON_AUTOSTART=0disables auto-start and returnsdaemon_unavailableif daemon is not already runningVZ_RUNTIME_DAEMON_SOCKET=/absolute/path/to/runtimed.sockoverrides daemon socket targetVZ_RUNTIME_DAEMON_RUNTIME_DIR=/absolute/path/to/.vz-runtimeoverrides runtime data directory used during daemon spawn
Sandbox-specific real VM integration validation (macOS ARM64):
./scripts/run-sandbox-vm-e2e.sh --suite sandboxFull VM lanes (runtime + stack + buildkit):
./scripts/run-sandbox-vm-e2e.sh --suite allSee docs/sandbox-vm-e2e.md for reproducible debug workflow and artifact paths.
Conformance and parity coverage: