Getting started with Silo in three commands

Install silo from the Homebrew tap, add its shims to your PATH, and install your first sandboxed tool. Total setup time: one coffee's worth.

Silo ships as a Homebrew tap. The first install takes about five minutes — most of that is the one-time runtime bootstrap (kernel download, Swift toolchain, vminitd cross-compile). Everything after is seconds.

Prerequisites

The Homebrew formula installs a codesigned binary with com.apple.security.virtualization entitlements. (If you prefer to build from source, clone the repo and run make install — do not use raw go build, macOS will SIGKILL an unsigned binary.)

Install

brew install rchekalov/silo/silo

# Put silo shims on your PATH (same convention as `brew shellenv`)
echo 'eval "$(silo shellenv)"' >> ~/.zshrc
source ~/.zshrc

The three-part name (user/tap/formula) is intentional. There’s already a silo cask in homebrew/cask for an unrelated app; the fully-qualified form forces Homebrew to use our tap’s formula instead of the collision.

Verify:

silo --version
silo doctor

silo doctor reports runtime readiness. On a fresh machine it’ll say the kernel and initfs haven’t been fetched yet — that’s normal. They’ll be fetched by the first silo install.

Install your first tool

Pick a tool from the registry — Python is the gentlest:

silo install python

The first time you run this, Silo bootstraps the runtime: downloads a Kata Containers Linux kernel (~280 MB), installs Swift 6.3 via swiftly, cross-compiles vminitd for Linux, and produces an initfs.ext4 to boot the guest. All of this is cached at ~/.silo/ and reused forever after.

After bootstrap, it pulls the python:3.12-slim OCI image, unpacks it to an ext4 rootfs, and caches it. The next silo run python uses APFS clonefile to copy the cached rootfs in about a millisecond.

Run a command

Before the first example, the mental model in one sentence: every silo run is a fresh VM, and three things — and only three — persist across runs. Files you write into the mounted project directory (node_modules/, .venv/, build output). Registry-declared cache mounts (pip downloads, npm cache, cargo registry). And anything you bake into the rootfs with silo build. Everything else inside the VM vanishes when the command exits.

Because ~/.silo/bin/ is on your PATH, the shim for python transparently routes through Silo:

python --version
python -c 'import os; print(list(os.environ))'

That second command is the fun one: notice how much of your environment isn’t there. That’s the point.

To run explicitly without the shim:

silo run python -- script.py
silo shell python      # interactive shell inside the VM

Tool-shorthand also works — silo python script.py expands to silo run python -- script.py, and silo npm test resolves the npm shim and routes to the node tool.

Give it a project

Create a .siloconf in your project root to tell Silo what this project needs:

# .siloconf
passEnv:
  - GITHUB_TOKEN
overrides:
  python:
    network:
      hostAccess: true
      proxy:
        allow:
          - pypi.org
          - "*.pythonhosted.org"
    ports:
      - host: 8000
        guest: 8000

Or have Silo guess:

silo init

silo init scans for marker files (package.json, requirements.txt, Cargo.toml, etc.) and generates a .siloconf interactively.

Persist dependencies

A fresh VM per invocation means installed packages vanish at the end of each run. To persist them, use silo build:

silo build python -- pip install -r requirements.txt

That runs pip install inside the VM, captures the resulting filesystem as .silo/python/rootfs.ext4, and uses it as the starting point for future runs. Commit .siloconf, ignore .silo/, and your team gets reproducible builds.

Where to go next

Questions, issues, requests — open an issue on GitHub.

← all posts