Docs / Under the hood

How it works

What Kuvo Box runs on your Mac, and how the docker command reaches the engine inside the VM.

Docker containers need a Linux kernel, and macOS doesn’t have one. Like every Docker app for the Mac, Kuvo Box runs Linux in a virtual machine. What’s different is how little sits around it.

The pieces

How Kuvo Box connects your Mac to the Linux VMThe docker command, the kuvo command and the Kuvo Box app all talk to ~/.kuvo/docker.sock on your Mac. Kuvo Box relays that socket over vsock to socat in the VM, which passes it to dockerd, which runs the containers. Ports published by containers come back through NAT and Kuvo Box's port bridge to localhost on your Mac. The /Users folder is shared into the VM at the same path with virtiofs.Your MacLinux VMAlpine · Virtualization frameworkdocker CLIkuvo CLIKuvo.app~/.kuvo/docker.sockvsocksocatdockerdcontainersNATport bridgelocalhost:8080/Usersvirtiofs/Users
Teal lines are what crosses between your Mac and the VM.

There are two processes on your Mac: Kuvo Box itself, and the virtual machine, which macOS runs in a separate process for it.

The virtual machine

Kuvo Box uses Apple’s Virtualization framework, the same one behind most modern Mac VM apps. There’s no QEMU and no bundled hypervisor.

  • Linux. Kuvo Box boots the official Alpine Linux kernel and installs Alpine onto a disk image on first launch. Alpine is small and boots quickly.
  • Docker. The engine is the docker package from Alpine’s repository: the real dockerd, containerd and runc, not a reimplementation.
  • Size. The VM gets half your CPU cores (at least two) and half your memory, up to 8 GB. The VM only takes memory from your Mac as it uses it.
  • Disk. A sparse 64 GB disk image holds Alpine, Docker, and all your images, containers and volumes. It only takes the space that’s in use. Deleting files inside a VM doesn’t shrink its disk on the Mac by itself, so whenever Docker deletes something, and every time the VM starts, Kuvo Box has Linux tell macOS which blocks are free (a TRIM), and macOS frees them.
  • Rosetta. If Rosetta is installed, Kuvo Box shares it with the VM and registers it for x86-64 binaries, so linux/amd64 images run without CPU emulation.

The boot scripts that run inside the VM are plain shell, kept short so they’re easy to read and audit. They live in GuestScripts.swift.

Reaching the engine

dockerd listens on its usual Unix socket inside the VM. A small relay (socat) exposes it on a vsock port, a direct channel between the VM and the Mac that doesn’t go over the network. Kuvo Box connects that channel to ~/.kuvo/docker.sock on your Mac.

The docker command, the kuvo command and the app itself all talk to that one socket, using Docker’s standard Engine API.

Ports

The VM has its own private network address behind NAT. When a container publishes a port, Kuvo Box sees it in the container list and opens the same port on 127.0.0.1, relaying each connection to the VM. When the container stops, the port closes again.

DNS

The VM, and the containers in it, look up names through your Mac, so they see the same DNS your Mac does. Some VPNs, firewalls and content filters block those lookups from the VM. When your Mac doesn’t answer but a public DNS server does, Kuvo Box adds Cloudflare (1.1.1.1) and Google (8.8.8.8) to the VM’s DNS servers, next to your Mac’s. It checks again on every start, and never does this while your Mac’s DNS answers.

Files

Two folders are shared into the VM with virtiofs:

  • /Users, mounted at the same path, so bind mounts like -v $PWD:/app work without translating paths.
  • Kuvo Box’s own folder, used to hand the VM its boot scripts and kernel modules, and for the VM to hand back its network address and Docker’s log.

Starting and stopping

When you open Kuvo Box, it boots the VM and waits until Docker answers on the socket. That usually takes about three seconds.

When you quit, Kuvo Box asks the VM to shut down cleanly: Docker stops its containers, the disk is synced, and the VM powers off. If it hasn’t finished within 15 seconds, Kuvo Box stops it.

The app

Kuvo Box is written in Swift with SwiftUI and AppKit. There’s no web view. It speaks HTTP to the Docker socket directly with Apple’s Network framework, and draws live graphs and animations with Core Animation, so they keep running without redrawing the rest of the window.

The program, including the kuvo command, is a single 2.5 MB binary. It has three dependencies: swift-argument-parser for the CLI, SwiftTerm for the terminal, and Sparkle for updates.

Updates

Kuvo Box uses Sparkle, the standard update framework for Mac apps outside the App Store. Each release on GitHub includes a small feed, appcast.xml, that names the new version and carries an EdDSA signature of its download. Kuvo Box checks the newest release’s feed once a day, and only installs an update whose signature matches the public key built into the app. Updates are also signed with a Developer ID and notarized by Apple, like the first download.

Sparkle is trimmed to what Kuvo Box needs: Apple silicon only, English only, and without the helper services that only sandboxed apps use. That brings it to under 1 MB.

Not Apple’s containerization

macOS 26 includes Apple’s own container framework, which runs each container in its own lightweight VM. Kuvo Box doesn’t use it. Kuvo Box runs one VM with the full Docker Engine, so Compose, networks, volumes, BuildKit and the rest of the Docker API work exactly as they do on Linux.

Updated Oct 13, 2026
esc