Solitary

Core concepts

The pieces that make up a solitary cell.

Cell

A cell is the unit of isolation and lifecycle. It has a definition, a Lima VM, a persistent disk, and a container. Cells are meant to be disposable: destroy one when its state is no longer useful, then create a clean one from the same definition.

VM

The VM is the boundary. It is the part that separates a cell from the host kernel. On macOS and Linux, solitary uses Lima to create and manage it.

Container

The container is the toolset, not the security boundary. Change image: or build: and bring the cell up again to replace the container while retaining the cell's disk.

Host

The host is the operator and the display. It starts machines, forwards selected ports, stores secrets, and performs explicit file transfers. It does not mount your repository into a cell.

Persistence

The cell's home directory lives on the VM disk. It survives a stopped machine and a replaced container. rm destroys the VM and its disk; the cell definition and host-held secrets remain available for a fresh up.

Changing a cell

A cell is edited by editing cell.yaml and running up again. What that costs depends on which of the three layers the setting belongs to:

LayerSettingsApplied by
Containerimage, build, command, secrets, gitup — the container is replaced
Machinevm, ports, networkThe next boot: down then up
Diskwhat vm.provision did, and everything the cell has done sincerm then up — the disk goes with it

up says which one it is: it replaces a container without being asked, warns when a running machine is holding settings that changed, and applies them itself when the machine is stopped.

Removing a setting is applied like adding one. A machine that was restricted or tunnelled has its resolver, firewall and tunnel taken back out at the next boot, so the guest matches the definition in both directions — the machine is not left enforcing an allow list nothing describes any more.

vm.provision is the exception, and the reason the third row exists. The script runs in the machine and changes its disk; the disk survives every change short of rm. A new script runs at the next start, but nothing undoes what the old one did, so a machine built by the current script alone is a machine created again from scratch. Both up and the dashboard say so when the script changes.

How it works

up renders an embedded Lima template into a machine definition, creates the machine, and starts one rootless podman container inside it. Both are driven by shelling out — limactl on the host, podman through limactl shell in the machine — so there is nothing to install beyond Lima.

The container runs with --network host. The machine is the boundary, so there is no reason to put a second one between the container and the machine it lives in; ports reach the host through Lima's forwarding.

A container's identity is recorded in two labels: the image as written in cell.yaml, and a digest of the environment it was started with. up compares both and replaces the container when either has moved, which is why changing a secret or an image needs no separate command.

Authority

A cell receives authority in named pieces:

  • secrets controls which environment variables enter the container.
  • ports controls which listening ports are reachable from the host.
  • network.allow controls which destinations the cell can reach.
  • image or build determines which code is trusted inside the cell.

A cell also has no browser and no launcher configured. Anything that would normally authenticate by opening one is authenticated on the host instead, and the resulting credential is passed in under secrets.

The configuration should make those decisions reviewable before the cell runs. Because values are separated from names, the definition can be committed and shared as a reusable workflow without sharing credentials, and taken with solitary clone.

On this page