# How it works

What Kuvo 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 runs Linux in a virtual machine. What's different is how little sits around it.

## The pieces

```text
  your Mac                                        Linux VM (Alpine)
 ┌──────────────────────────────────┐            ┌──────────────────────┐
 │ docker CLI ─┐                    │            │                      │
 │ kuvo CLI ───┼─▶ ~/.kuvo/docker.sock ── vsock ──▶ socat ─▶ dockerd    │
 │ Kuvo.app ───┘                    │            │            │         │
 │                                  │            │        containers    │
 │ localhost:8080 ◀── port bridge ──┼── NAT ─────┼────────────┘         │
 │ /Users ──────────────────────────┼─ virtiofs ─▶ /Users               │
 └──────────────────────────────────┘            └──────────────────────┘
```

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

## The virtual machine

Kuvo uses Apple's [Virtualization framework](https://developer.apple.com/documentation/virtualization), the same one behind most modern Mac VM apps. There's no QEMU and no bundled hypervisor.

- **Linux.** Kuvo 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.
- **Rosetta.** If Rosetta is installed, Kuvo 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`](https://github.com/serhatandic/kuvo/blob/main/Sources/Kuvo/Engine/GuestScripts.swift).

## Reaching the engine

`dockerd` listens on its usual Unix socket inside the VM. A small relay (`socat`) exposes it on a [vsock](https://man7.org/linux/man-pages/man7/vsock.7.html) port, a direct channel between the VM and the Mac that doesn't go over the network. Kuvo 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 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.

## 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'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, it boots the VM and waits until Docker answers on the socket. That usually takes about three seconds.

When you quit, Kuvo 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 stops it.

## The app

Kuvo 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 two dependencies: [swift-argument-parser](https://github.com/apple/swift-argument-parser) and [SwiftTerm](https://github.com/migueldeicaza/SwiftTerm).

## Not Apple's containerization

macOS 26 includes Apple's own container framework, which runs each container in its own lightweight VM. Kuvo doesn't use it. Kuvo 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.