Silo v0.5.0 release notes
Pyenv-style shim fall-through. Tools added via `silo use` no longer shadow your homebrew binaries everywhere — only inside projects that claim them.
Silo v0.5.0 changes how ~/.silo/bin/<tool> shims behave for tools you added via silo use + silo sync. They now fall through to the next instance on PATH (homebrew, pyenv, system) when invoked outside a project that claims them. silo install-installed tools still claim their command everywhere, exactly as before.
The problem
Before v0.5.0, every shim in ~/.silo/bin/ was effectively a global claim. If you ran silo use node@22 in one project and let silo sync install it, ~/.silo/bin/npm would shadow your /opt/homebrew/bin/npm system-wide. That made silo feel invasive for users who only wanted per-project version pinning, not a global toolchain takeover.
The user-facing complaint was a one-liner: “I have homebrew npm. I added silo node to one project. Now which npm says silo for every project on this machine.”
The mechanism
v0.5.0 distinguishes two install paths via a new flag, pinnedGlobally, in ~/.silo/config.yaml:
silo install <tool>— the explicit “silo owns this command everywhere” gesture — setspinnedGlobally: true.silo use <tool>@<v>followed bysilo sync— the project-scoped pin — leaves itfalse.
When a ~/.silo/bin/<tool> shim is invoked, silo run walks .siloconf up from the cwd, then checks the global pin, then falls through:
[A] If the merged .siloconf claims this tool → silo dispatches into the VM
[B] Else if pinnedGlobally is true → silo dispatches into the VM
[C] Otherwise → strip ~/.silo/bin/ from PATH,
exec next instance (homebrew/pyenv/system)
This matches pyenv’s model: which python always shows pyenv’s shim, but the actual interpreter that runs depends on cwd.
Two-projects example
# ~/work/proj-a/.siloconf
tools: [node]
overrides:
node: { image: docker.io/library/node:22-slim }
# ~/work/proj-b/.siloconf
tools: [node]
overrides:
node: { image: docker.io/library/node:18-slim }
cd ~/work/proj-a && node --version # → v22.x (silo, branch [A])
cd ~/work/proj-b && node --version # → v18.x (silo, branch [A])
cd ~ && node --version # → homebrew node (branch [C])
which node # → ~/.silo/bin/node (always)
New commands
silo pin <tool>— flip a sync-installed tool to globally pinned. Same end state as if you’d originally runsilo install.silo unpin <tool>— the inverse. Drops the global claim so the shim falls through outside projects that list the tool.
silo list gained a PINNED column. silo current now shows [project] / [pinned] / [fall-through] per tool so it’s obvious which dispatch branch will fire from your current cwd.
Migration
Existing installs predate the flag. On first load of ~/.silo/config.yaml after upgrading, every entry defaults to pinnedGlobally: true. Behavior is unchanged for tools you’ve already installed — you keep the global claim until you explicitly run silo unpin.
The schema bumped from version: 1 to version: 2. The migration is in-place and idempotent; no manual action needed.
When you’d use each path
- You want silo to handle this tool anywhere on the machine. Use
silo install <tool>. Same as today. - You want this version of this tool only inside this project, with homebrew/pyenv/system handling everything else. Use
silo use <tool>@<v>followed bysilo sync. New default in v0.5.0. - You changed your mind about a tool’s scope. Use
silo pin/silo unpin— no reinstall needed.
Why not project-local PATH
The earlier idea was per-project <root>/.silo/bin/ directories with a chpwd shell hook that swapped them on/off PATH. That works but adds shell magic, breaks in non-interactive shells, and depends on shell-specific hook plumbing.
Pyenv-style fall-through has zero shell magic. One PATH entry, one dispatch decision in silo run, works in any environment that puts ~/.silo/bin/ on PATH — including IDE terminals, CI runners, and bash -c subshells.
Compatibility
silo installsemantics unchanged.- Existing shims keep working;
silo install --force <tool>regenerates the shim with the new template if you want it sooner. New installs /silo syncwrite the new template directly. - The
_SILO_SHIM_DISPATCH=1env marker baked into the shim distinguishes PATH-shim invocations from explicitsilo run/silo <tool>shorthand. The latter never falls through — if you typedsilo, you get silo or an error.
Upgrade with brew upgrade silo (Homebrew tap) or rebuild from source. silo --version should report 0.5.0.