Per-workspace development containers. Powered by Podman, Nix, and home-manager.
- Simple way to create and run personal workspace containers, set up via home-manager
- Full secured agent sandbox
- Reproducibility — builds may vary across machines or time
- Per-workspace isolation — each workspace gets its own container
- Nix + home-manager — shared
home.user.nixand per-workspace.silo/home.nix - Workspace mount — the host directory is mounted inside the container
- Persistence — persist package caches and other data across containers and rebuilds
- Port forwarding — expose container ports to the host
- Resource limits — control CPU, memory, and process limits per workspace
- Nested Podman — optional support for running containers inside the container
- VS Code support — generate a
.devcontainer.jsonwhich uses the workspace image
Requirements: Go 1.23+, Podman
# Build binary
go build .
# Run tests
go test ./...
# Install to $GOPATH/bin
go install .siloOn first run, silo initializes required files, builds the workspace image, starts the container, and connects to it. Subsequent runs skip steps that are already complete and connect directly.
# Edit .silo/home.nix
silo stop
silo build --rebuild
siloEvery workspace goes through a fixed chain of steps. Each step depends on the ones before it. Running silo triggers the full chain.
user init → init → build → volume setup → start → connect
| Step | Description | Idempotency | Calls |
|---|---|---|---|
| user init | Creates user config files under $XDG_CONFIG_HOME/silo/ |
Writes files only on first run | - |
| init | Creates .silo/silo.toml and .silo/home.nix |
Writes files only on first run | silo user init |
| build | Builds the workspace image | Skipped if image exists | silo init |
| volume setup | Creates directories on shared volume | Safe to re-run | - |
| start | Creates and starts the container | Skipped if container is already running | silo build, silo volume setup |
| connect | Opens an interactive shell inside the running container | - | - |
silo [--stop]
silo init [--podman|--no-podman]
silo build [--rebuild] [--no-cache]
silo start
silo volume setup
silo connect
silo stop
silo rm
silo status
silo user init
silo devcontainer [--update]
silo devcontainer connect
silo devcontainer stop
silo devcontainer status
silo help
Run the full lifecycle chain if needed, then connect to the container for the current workspace.
| Flag | Description |
|---|---|
--stop |
Stop and remove the container when the session exits |
Initialize workspace files. Creates .silo/silo.toml and .silo/home.nix.
| Flag | Description |
|---|---|
--podman |
Enable Podman inside the container |
--no-podman |
Disable Podman inside the container |
Build the workspace image if it does not exist yet.
| Flag | Description |
|---|---|
--rebuild |
Force rebuild even if image exists; aborts if container exists or is running |
--no-cache |
Disable build cache |
Creates and starts the container. If the container is already running, this command does nothing.
Creates directories on the persistence volume for paths configured in [persistence]. Runs a temporary container with the workspace image for the setup.
Connect to the container for the current workspace. Requires the container to exist and be running.
Stop and remove the running container.
Remove the workspace image. If the container exists and is stopped, it is removed first. Returns an error if the container is running.
Create user files under $XDG_CONFIG_HOME/silo/ if they do not exist:
home.user.nix- User-wide home-manager config baked into every workspace imagesilo.user.toml- User-wide silo configurationdevcontainer.user.json- Personal configuration merged into every generated.devcontainer.json
Print Running or Stopped for the workspace container.
Generates .silo/devcontainer.json and .devcontainer.json for VS Code in the current host directory. See VS Code devcontainer for details.
| Flag | Description |
|---|---|
--update |
Update existing .devcontainer.json |
Stop and remove the devcontainer.
Print Running or Stopped for the devcontainer.
Connect to the devcontainer for the current workspace. Requires the devcontainer to exist and be running.
Show the full command reference.
silo is configured via two TOML files. Both configs are merged at runtime.
- User config at
$XDG_CONFIG_HOME/silo/silo.user.toml - Workspace config at
.silo/silo.toml
If $XDG_CONFIG_HOME is not set, ~/.config/silo/ is used.
Configuration changes require restart of the container to become effective.
| Section | silo.user.toml |
.silo/silo.toml |
Description |
|---|---|---|---|
[general] |
user- |
-id |
Your username Workspace ID (8-char random) |
[features] |
- | podman |
Enable nested Podman inside the container |
[persistence] |
shared_pathsprivate_paths |
shared_pathsprivate_paths |
Paths persisted and shared across all containers Private paths to persist A trailing slash marks a directory |
[podman] |
create_args |
create_args |
Podman create arguments Default values are set on silo init |
[network] |
ports |
ports |
Port forwarding mappings (e.g. 8080:8080) |
[limits] |
- | cpusmemoryprocesses |
CPU limit Memory limit (MB) Process ID limit Zero or negative = unlimited |
[general].user- user config only[general].id- workspace config only; set once on first run[features].podman- workspace config only; set bysilo init --[no-]podmanon first run[persistence].shared_paths- user paths first, then workspace paths[persistence].private_paths- user paths first, then workspace paths[podman].create_args- user args first, then workspace args[network].ports- user ports first, then workspace ports
[general]
user = "alice"
[persistence]
shared_paths = [
"$HOME/.cache/uv/"
]
private_paths = [
"$HOME/.local/share/fish/fish_history"
]
[podman]
create_args = []
[network]
ports = [][general]
id = "ab3f9c12"
[features]
podman = false
[persistence]
shared_paths = []
private_paths = []
[podman]
create_args = [
"--cap-drop=ALL",
"--cap-add=NET_BIND_SERVICE",
"--security-opt",
"no-new-privileges"
]
[network]
ports = [ "8080:8080" ]
[limits]
cpus = 0
memory = 0
processes = 1024silo builds a workspace image using Podman. The image is based on Fedora, with Nix and home-manager installed.
Each image build generates a Nix flake in a temporary directory on the host. The flake wires together nixos-unstable, home-manager, home.user.nix, and .silo/home.nix.
When creating a container, silo passes several arguments to podman create:
- Name and hostname:
--name silo-<id>and--hostname silo-<id> - Workspace mount: The host directory is mounted at
/workspace/<id>/<dirname> - Persistence volume: The named volume
silois mounted at/silo/persistence - Limits args:
--cpus=N,--memory=Nm,--pids-limit=N(from[limits]config) - Network ports: Port forwarding mappings from
[network].ports - Create args: Additional args from
[podman].create_args
silo uses named Podman volumes with subpath mounts. Each configured path gets its own mount point directly inside the container, using the volume's subpath feature.
Shared paths: Persisted at shared/<path> on the volume. Shared across all workspaces. A trailing slash marks a directory; no trailing slash marks a file. $HOME is expanded inside the container.
Example: shared_paths = ["$HOME/.cache/uv/"] creates a volume mount with target=/home/alice/.cache/uv and subpath=shared/home/alice/.cache/uv.
Private paths: Persisted at <SILO_ID>/<path> on the volume. Local to each workspace.
Example: private_paths = ["/data"] in workspace abc12345 creates a volume mount with target=/data and subpath=abc12345/data.
When the Podman feature is enabled, Podman is installed and configured inside the container. This is implemented as home-manager module, which is part of the image and enabled via silo.podman.enable = true in .silo/home.nix
silo devcontainer generates .silo/devcontainer.json and .devcontainer.json. The latter is created by merging three sources in the following order:
- Personal defaults -
$XDG_CONFIG_HOME/silo/devcontainer.user.json - Project-specific -
.silo/devcontainer.json - Silo - Sets workspace image, username, container name, mounts, limits, forwarded ports and run args
Merge behavior:
- Objects merge recursively (key-by-key)
- Arrays concatenate
- Scalars override
Important:
- The devcontainer uses the workspace image, but is independent from the silo container
- The container is named
silo-<id>-dev - Creation is handled by VS Code/devcontainers, not by
silo.