← → or Space · P presenter

$ silo claude


AI coding agents in isolated containers and lightweight VMs

github.com/leighmcculloch/silo

Agenda


The journey

How I got here — the problem, what I tried, and what worked

Demo break

See it in action

Features

How silo works, config, backends, and the bigger picture

// journey

AI agents need freedom


// journey

But we need control


Full access
Maximum capability
Restricted
Reduced utility

Give them access and accept the risk, or restrict them and lose the thing that makes them useful.

// journey

Permissions


"permissions": { "allow": [
  "Bash(git fetch:*)", "Bash(git diff:*)", "Bash(git log:*)",
  "Bash(git show:*)", "Bash(git branch:*)", "Bash(git add:*)",
  "Bash(git commit:*)", "Bash(git stash:*)", "Bash(git checkout:*)",
  "Bash(git rebase:*)", "Bash(git merge:*)", "Bash(git push:*)",
  "Bash(git pull:*)", "Bash(git clone:*)", "Bash(git remote:*)",
  "Bash(gh pr view:*)", "Bash(gh pr list:*)", "Bash(gh pr create:*)",
  "Bash(gh pr checkout:*)", "Bash(gh pr merge:*)", "Bash(gh api:*)",
  "Bash(gh issue view:*)", "Bash(gh issue list:*)", "Bash(gh issue create:*)",
  "Bash(gh run view:*)", "Bash(gh run list:*)", "Bash(gh run watch:*)",
  "Bash(cargo build:*)", "Bash(cargo test:*)", "Bash(cargo run:*)",
  "Bash(cargo clippy:*)", "Bash(cargo fmt:*)", "Bash(cargo check:*)",
  "Bash(go build:*)", "Bash(go test:*)", "Bash(go run:*)",
  "Bash(go vet:*)", "Bash(go mod:*)", "Bash(go install:*)",
  "Bash(npm install:*)", "Bash(npm test:*)", "Bash(npm run:*)",
  "Bash(npx:*)", "Bash(deno run:*)", "Bash(deno test:*)",
  "Bash(make:*)", "Bash(cmake:*)", "Bash(docker build:*)",
  "Bash(docker run:*)", "Bash(docker compose:*)", "Bash(kubectl:*)",
  "Read(~/.cargo/**)", "Read(~/.local/go/pkg/mod/**)",
  "Read(~/.rustup/**)", "Read(~/.npm/**)", "Read(~/.config/**)",
  "Write(~/Library/Caches/go-build/**)", "Write(~/.cargo/registry/**)",
  "Write(~/Library/Caches/Homebrew/**)", "Write(~/.npm/_cacache/**)"
]}

Felt thorough. But one permitted gh api call and an agent commented on a random GitHub discussion completely unrelated to my work.

// journey

The gh api incident

GitHub discussion the agent commented on The agent's unrelated comment
// journey

Sandboxing


  • OpenAI Codex CLI shipped sandbox mode first, then Claude Code added it
  • Experimented with macOS sandbox-exec and custom rules
  • Hard to get right — build caching broke, Go build cache errors, flaky tool behavior
  • Often falls back to the permissions list anyway — only a small edge
> /sandbox
// journey

Remote


// journey

Containers & VMs


Shell script + Docker

VS Code Dev Containers

Lima

UTM

silo

What is silo?


A CLI tool that runs AI coding agents in isolated containers and lightweight VMs — so they get full access without touching our machine.

// journey

Lots of little silos


My machine
silo
AI
silo
AI
silo
AI

The agent runs in yolo mode with full capability — but only inside an isolated container with access to our working directory.

Using silo


brew install --HEAD leighmcculloch/silo/silo

# or
go install github.com/leighmcculloch/silo@latest

# then
silo
// under the hood

How silo works


What happens when you run silo claude

// under the hood
$ silo claude
Resolve config
build:
Base image
Tool layer
post_build_hooks
↑ async: fetch latest version → rebuild in background
Stage mounts
run:
pre_run_hooks
claude
// under the hood

Mount mapping


Host
Container
~/Code/rs-soroban-sdk-feat-worktree/
~/Code/rs-soroban-sdk-feat-worktree/
~/Code/rs-soroban-sdk/
~/Code/rs-soroban-sdk/
~/.claude/
~/.claude/
~/.claude.json
~/.claude.json
~/.apikey_github_ro
~/.apikey_github_ro
// under the hood

Supported tools


Claude Code

Anthropic's CLI for Claude

silo claude

OpenCode

AI coding CLI

silo opencode

GitHub Copilot CLI

GitHub's Copilot in the terminal

silo copilot

// under the hood

Two isolation backends


Docker

  • Works on any platform
  • Containers share one Linux VM
  • Shared kernel
  • Shared Docker engine

Apple Container

  • macOS only
  • Each container = its own VM
  • VM isolation (own kernel)
  • Own Docker engine
experimenting

Fly.io

  • Remote
  • Each container = its own VM
  • VM isolation (own kernel)
  • Own Docker engine

Auto-detected: uses Apple Container if installed, falls back to Docker.

// under the hood

Pre-built dev environment


Base

Ubuntu 24.04, build-essential, pkg-config

Languages

Node.js, Go, Rust (latest stable)

Tools

git, GitHub CLI, Docker CE, jq, zsh

LSP

gopls, rust-analyzer

MCP Servers

github-mcp-server pre-installed

Git Identity

Auto-configured from our host

Identical Paths

Same filesystem layout as host

// under the hood

Seamless local ↔ silo



# Agent works on stuff unattended
silo claude

# Continue same session local
claude --continue

Continue the same session locally — with full access to API keys, GitHub tokens, and everything else on our machine.

// under the hood

Auto-updating agents



Content-addressed image caching

Images tagged by hash of Dockerfile + tool + build args. Only rebuilt when something changes.

// under the hood

What works for you?


Permission lists

Sandbox modes

Claude web / GitHub Coding Agent

Docker / VS Code Dev Containers

VMs

Vibe code your own!

Thanks

brew install --HEAD leighmcculloch/silo/silo

# or
go install github.com/leighmcculloch/silo@latest

# then
silo

github.com/leighmcculloch/silo

Apache 2.0 · macOS · Docker & Apple Containers