silo · for macos · apple silicon

Run dev tools.
Not risks.

Silo wraps every tool invocation in a fresh Apple Containerization micro-VM with its own Linux kernel. npm install can't exfiltrate your SSH keys. pip can't read your cloud credentials. And it feels native — ~600 ms warm start (rootfs cache hit).

$ brew install rchekalov/apps/silo
§01 / the problem

Your dev tools run a lot of code you never read.

A single npm install might execute thousands of postinstall scripts from hundreds of maintainers. Your machine trusts all of them by default. One malicious release — and you've shipped your life to a Discord webhook.

attack vector / 01

SSH keys

~/.ssh/id_ed25519, known_hosts, agent sockets — readable by any process you run. A four-line postinstall exfils every server you touch.

attack vector / 02

Cloud credentials

~/.aws/credentials, gcloud tokens, kubeconfig. Stolen credentials turn into crypto miners on your company's account by breakfast.

attack vector / 03

Browser cookies

Chrome and Safari cookie jars are just files. Session cookies let attackers skip your 2FA entirely — on GitHub, Gmail, banking, anything.

attack vector / 04

Slack & Discord tokens

Desktop chat apps keep tokens on disk in predictable paths. Impersonation in your company Slack is a ten-line script away.

attack vector / 05

Source code

Every private repo, every draft, every half-finished side project. Tarball ~/code to a remote host — done in seconds.

attack vector / 06

Your keychain

Once a malicious binary runs under your user, it can prompt for keychain access with your own app's name. You'll click yes. We all would.

attack vector / 07

AI agent blast radius

Claude Code, Cursor, and friends read your tree and run shell commands. A prompt-injected README is game over. Same access as you.

attack vector / 08

Other projects

Lateral movement doesn't need privilege escalation. Your dev laptop has every client's code on one disk, under one UID.

Python venvs, Node's nvm, and even pipx isolate dependencies — not permissions. Everything still runs as you, with your full filesystem, on your kernel.

§02 / how it works

One process → one micro‑VM. Real kernel boundary.

Built on Apple Containerization

macOS 26 shipped a native Containerization.framework that boots stripped-down Linux VMs in the low hundreds of milliseconds. Silo is a thin CLI on top of it: when you run a tool, it spins up a one-shot VM, mounts only the files you asked for, runs your command, streams output to your terminal, and evaporates.

Feels native, isn't

Silo installs shims for python, node, cargo, go, deno — so typing python app.py transparently runs inside a VM. No ceremony, no exec, no container runtime glued to your shell.

Explicit, not magic

Every non-default exposure — network egress, host files, forwarded ports — is an explicit key in silo.toml, checked in with the repo. Reviewed once, reused forever.

real terminal · silo init → silo build node npm install → silo npm start
§03 / commands

The CLI is small on purpose.

silo install <tool>[@ver]
Install a tool from the registry (python, node, rust, go, deno, psql, claude-code, and more). Pulls the image, adds shims, warms the rootfs cache.
silo run <tool> <args...>
Run any command inside a fresh micro-VM. Silo flags go before the tool name; everything after is the inner command. The cwd is mounted read-write; nothing else is. Also available as silo <tool> shorthand and via ~/.silo/bin shims.
silo shell <tool>
Drop into an interactive sandboxed shell — useful for scratch work and untrusted scripts.
silo init
Auto-detect tools from marker files (package.json, requirements.txt, Cargo.toml, go.mod) and generate a silo.toml.
silo build <tool> <cmd...>
Bake a persistent rootfs layer on top of the tool's image — e.g. silo build node npm install. Survives every future run.
silo add <packages|language>
Project-scoped rootfs additions baked into <projectRoot>/.silo/<tool>/. silo add kotlin appends JDK + Kotlin to claude-code via silo.toml overrides — no touch on the global install.
silo shim <tool> add <name>
Add or remove ~/.silo/bin shims so extra commands route through silo — yarn, pnpm, ipython, anything.
silo sync
Reconcile the environment to silo.toml: install missing tools, warm the rootfs cache. Safe to re-run.
silo cache report|gc|compress|clean
Inspect ~/.silo disk use, LRU-evict cold rootfs entries, zstd-compress stale ones, or wipe everything.
silo doctor
Check runtime readiness — kernel, initfs, bootstrap state, shim health.
silo current [tool]
Show installed tools and the effective tool definition after silo.toml overrides.
Full command reference →
§04 / how it compares

Silo vs. the tools you already use.

silo docker desktop devcontainers venv / nvm native
Malicious code exposure micro-VM per invocation × depends on workflow partial (workspace + mounts) × full $HOME, keys, creds × full $HOME, keys, creds
Kernel isolation real (new kernel) × shared linuxkit × shared linuxkit × none × none
Filesystem scoping cwd only, by default partial (volumes) partial (workspace mount) × full $HOME × full $HOME
Network deny-by-default per-project allowlist × bridge wide open × bridge wide open × same as host × same as host
Start latency ~600 ms warm / ~25 s first run 2–8 s + daemon 2–8 s + daemon instant instant
Memory overhead 2 GB / VM (default) 1–4 GB persistent 1–4 GB persistent none none
Transparent shims python/node/cargo/go × explicit docker run × explicit devcontainer partial (per-tool) n/a
Background daemon? none × required × required none none

Docker and devcontainers are container orchestration that happens to offer isolation. Silo is isolation that happens to use a container. Different goals; they coexist fine.

§05 / install

Three lines to sandboxed.

# 1. install silo (the user/tap/formula triple dodges homebrew-cask's silo)
$ brew install rchekalov/apps/silo

# 2. put silo shims on your PATH via shellenv (same convention as brew)
$ echo 'eval "$(silo shellenv)"' >> ~/.zshrc

# 3. install a tool (first run fetches a prebuilt kernel + initfs; ~30 sec once, seconds after)
$ silo install python

# python is now sandboxed:
$ python suspicious_script.py

# one silo install per tool you need:
$ silo install node         # adds npm, npx shims
$ silo install claude-code  # adds claude shim

# network is off by default. opt in per-tool via silo.toml:
$ silo init                 # auto-detects tools + writes an allowlist stub

Requires macOS 26+ on Apple Silicon. The Homebrew formula installs a codesigned binary with com.apple.security.virtualization entitlements — everything is handled for you. See the quickstart for silo.toml and opt-in network rules.

§06 / performance

Fast enough you'll forget it's there.

vm warm start
583ms
p50 on M2 Pro, rootfs cache hit. First run unpacks the image (~25 s).
shim overhead
12ms
per invocation, once the rootfs cache is warm.
idle memory
0mb
no daemon. VMs die when they exit.
per-vm memory
2gb
default VM allocation (raised from 512 MB in 0.5.0). Heavy tools bump further: claude-code 4 GB, jupyter 8 GB.
npm install time
+4%
vs. host. create-react-app baseline.
cargo build time
+2%
ripgrep release build, warm cache.

measured on M2 Pro · macOS 26.1 · silo 0.6.2 · your results will vary

§07 / faq

The questions you're about to ask.

Is this just Docker with a nicer CLI?

No. Docker orchestrates containers — namespaced processes sharing the host kernel. Silo uses Apple Containerization, which boots a real Linux VM per container with its own kernel. That's the difference between "shared kernel, fences between processes" and "separate kernel, hypervisor boundary." Different goals; they coexist fine.

Why only Apple Silicon?

Apple Containerization framework (macOS 26+) is the piece that makes sub-second VM starts possible on macOS. It needs Apple Silicon. A Docker backend for Linux users is on the roadmap — on Linux, native namespaces give you most of what Silo gives you on macOS.

Do I lose editor integration? LSPs?

No. silo lsp <tool> runs the language server (pyright, tsserver, rust-analyzer, gopls) inside the VM and proxies JSON-RPC over stdio with automatic path rewriting. silo ide vscode|zed|neovim generates editor configs that point at the proxied server. Autocomplete and go-to-definition work; code analysis stays isolated.

How do I give a project network access?

Add a silo.toml with an allowlist. The VM has no network by default. Flip hostAccess = true and list the domains each tool is allowed to reach — registry.npmjs.org, pypi.org, *.github.com, your private registry. Everything else is blocked by an in-VM HTTP proxy.

What about files outside my cwd?

They don't exist. The VM only mounts the directory walk-up finds the silo.toml in (or the cwd, if none). ~/.ssh, ~/.aws, other projects — none of it is visible. That's the whole point: a compromised package literally cannot open a file that isn't there.

Does `npm install` / `pip install` work out of the box?

Yes, for the standard registries. Since 0.6.0 the registry ships built-in allowlists: pip reaches pypi.org, npm reaches registry.npmjs.org, cargo reaches crates.io. Everything else is blocked — if your project needs a private registry or an extra CDN, add it to silo.toml. To allow open internet for a tool: set proxy.allow = ["*"] in its overrides block.

Can I use it in CI?

Silo is macOS-only today (Apple Silicon + macOS 26+), so CI works if your runners are macOS. A prebuilt-image workflow that ships ready-to-boot rootfs artifacts from GitHub Actions is planned — see docs/ci-prebuilt-images.md in the repo. For Linux CI, use a normal container.

What persists between runs?

Your project directory (mounted read-write), the rootfs cache (so warm starts are ~600 ms), and per-tool package caches (pip, npm, cargo). Everything else is ephemeral. If you want packages installed via pip or npm to survive, either keep them inside the project (venv, node_modules) or use silo build to bake them into the rootfs.

Is Silo free?

Yes. Apache 2.0. It's a personal project, not a product. The CLI wraps Apple's Containerization framework (also open-source) — there's no paid tier, no telemetry, no account.

§08 / changelog

What shipped, when.

0.6.2 May 15, 2026

Fix install proxy regression; uv + poetry cache mounts.

  • 0.6.0 introduced deny-by-default networking, but also broke silo install for any tool with a registry allowlist: the install-time proxy was cleared before RunSetup, so pyright, eslint, and similar postInstall commands saw a deny-all proxy and failed. Fixed in 0.6.2: BakeTool now preserves the registry's proxy and lets RunSetup union allow ∪ installAllow as designed.
  • Python tool gains two new cache mounts: ~/.cache/uv and ~/.cache/pypoetry. Poetry and uv users now get warm-cache behavior between runs (no re-download on every silo run).
  • Registry overlay extended to cache mounts: existing installs pick up new registry mounts (uv, poetry) without needing a silo install --force. Includes end-to-end integration tests for venv auto-activation, pyproject editable installs, pytest, poetry, and uv workflows.
0.6.0 May 15, 2026

Deny-by-default networking; pip install and npm install work out of the box.

  • Network policy is now deny-by-default. The registry ships built-in allowlists for every standard tool: pip install reaches pypi.org, npm install reaches registry.npmjs.org, cargo add reaches crates.io, and so on — without any [network] block in your silo.toml. To allow open internet: set proxy.allow = ["*"].
  • Network config merges as a list-union: silo config network allow node 'corp.registry.io' extends the npm allowlist rather than replacing it. Add proxy.deny to block individual hosts the registry allows.
  • Before 0.6.0, tools with hostAccess: true and no allowlist reached the open internet. Affected claude-code, playwright, cypress, psql, and jupyter at runtime. All are now proxy-gated with purpose-appropriate allowlists. Legacy projects that want open internet can opt in explicitly with proxy.allow = ["*"].
0.5.3 Apr 27, 2026

rootfs sync fix, venv auto-activation, shim shadowing detection.

  • silo build now runs sync inside the guest before snapshotting the rootfs — fixes 0-byte package directories after pip install.
  • Python projects with a .venv/ or venv/ in the workspace root auto-activate it on entry: VIRTUAL_ENV + PATH are set so pip and the interpreter resolve inside the venv, not the rootfs.
  • silo doctor and silo install warn when a shim in ~/.silo/bin/ is shadowed by an earlier PATH entry (homebrew, conda, asdf) so the shim is silently unreachable.
0.5.2 Apr 26, 2026

Pyenv-style pinning, TOML config, ssh-agent forwarding.

  • Sync-installed tools now fall through to the next instance on PATH (homebrew, pyenv, system) when invoked outside any project that claims them — silo install still claims globally. silo pin / silo unpin flip the flag; silo list / silo current surface it. (0.5.0)
  • Default VM memory raised from 512 MB to 2 GB — the old default was tight enough that npm install on real projects would OOM mid-postinstall. Per-tool overrides still apply.
  • Project bakes are now content-addressed under ~/.silo/baked/<sha>/ instead of scattered under each project tree. silo list / silo sync accurately surface project-pinned images and stop printing "rootfs up-to-date" when there is no project rootfs. (0.5.1)
  • .siloconf (YAML) is now silo.toml; auto-migration on first run, YAML accepted until 0.6. SSH-agent forwarding lands as a config option — forwards $SSH_AUTH_SOCK into the VM without exposing host private keys, so private git+ssh URLs work. (0.5.2)
  • Argv parsing went Docker-style: silo flags before the tool, inner command after — the old -- separator still works but is no longer required.
0.4.x Apr 21&ndash;23, 2026

Homebrew prebuilts, claude-code reliability, install UX polish.

  • Homebrew install in seconds, not minutes (0.4.17): prebuilt ad-hoc-codesigned tarball attached to each release — no Go or Swift toolchain pulled in, ~3.5 GB of transitive deps gone. Reproducible Swift TLS/HTTP stack via committed Package.resolved (0.4.10). Tap moved to rchekalov/apps; old path auto-redirects (0.4.19).
  • First silo install fetches a prebuilt vmlinux + initfs.ext4 from the GitHub release (~30 sec) instead of cross-compiling vminitd (~5 min); on failure (offline, bad checksum) drops to source-build fallback (0.4.4).
  • Claude Code actually installs and stays logged in: registry entries can declare postInstall:, baked into ~/.silo/builds/<tool>/rootfs.ext4 (0.4.12); CLAUDE_CONFIG_DIR + ANTHROPIC_CONFIG_DIR pinned so credentials persist across runs (0.4.13); cache mounts can mark themselves noGC so background GC doesn't silently drop OAuth state (0.4.14).
  • silo add <packages|language> records project-scoped postInstall overrides and bakes a per-project rootfs without mutating the global tool. Language shortcuts: silo add kotlin / java / ruby (0.4.15).
  • Install UX: atomic install — pull before write, no half-installed zombies in silo list (0.4.6); live byte-accurate progress during the OCI pull (0.4.8 / 0.4.9 / 0.4.11); real HTTP 401/429/5xx messages instead of RegistryClient.Error error 0 (0.4.9); Python 3.13/3.14, plus rejection of unknown versions (was silently rewriting 3.13 to the 900 MB debian variant) (0.4.7); broadened silo shellenv to fish/csh/tcsh/pwsh (0.4.5).
  • In-VM HTTP proxy now binds 0.0.0.0 so the guest can reach host.silo.internal — was silently 100% failing allowlisted requests with ECONNREFUSED (0.4.16).
0.4.0 Apr 18, 2026

CLI reshape, Go-only, disk reduction.

  • One verb per job: silo build absorbs setup/rebuild, silo sync absorbs pull/apply, status splits into doctor + current.
  • Rust implementation removed; Go is now the sole binary.
  • Disk reclaim: LRU + age-based rootfs GC, zstd cold-tier compression (~4× smaller), image deletion on uninstall.
  • Two-phase SIGINT handler; reaper for stale silo-* container dirs.
0.3.0 Mar 19, 2026

Project config.

  • .siloconf walk-up with project-overrides-global merge; per-tool env, network allowlists, port forwarding.
  • silo use / silo unuse for pyenv-style project pins.
  • silo init auto-detects tools from marker files.
0.2.0 Feb 27, 2026

Transparent shims.

  • Shell shims for python, node, cargo, rustc. Editor-friendly (LSPs work).
  • Kernel image split from binary — silo install fetches it on demand.
  • Fixed a deadlock when stdout was a pipe and the tool wrote > 64 KB.
0.1.0 Jan 30, 2026

Hello world.

  • Initial release. silo run works for Python, Node, and bash.
  • macOS 26+, Apple Silicon only.
§09 / how to use

Short reads to get real work done.