Generic version manager
Ruby Shell
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Failed to load latest commit information.
shell-proxy @ 679312d


A generic version manager.

Frustrated with the fragmentation of the *vm/*env ecosystem, I set out to write a framework for emitting targeted, pure shell codebases.

My goals were:

  • Extensibility
  • Code reuse
  • Ease of development, by abstracting away all the fiddly bits in writing posix code

Should I use _vm?

Do you want to manage more than one type of thing? If the answer is yes, then probably.

_vm's architecture means that bugs are more difficult to introduce, and easier to fix permantly, in the same way the Rails makes it easier to write lots of webapps with minimal code, _vm makes it possible to generate lots of version managers with minimal code.

_vm vs rvm/chruby/pythonbrew/virtualenv

_vm is pretty much entirely a drop in replacement for chruby (while the DSL is novel, the implementation is pretty much directly derived from chruby)

By virtue of it's hands off nature, it can play very well with other ecosystems. For example symlinking virtualenvs or homebrew builds into your root directory will Just Work.


_vm uses the environment variable __name_LIST (ie, __php_LIST) to find versions. in my .zshrc I have:


Then simply source the relevant shell file:

source _php
source _ruby

If you don't want to pull in the ruby dependencies, you can fetch the current versions from${language}, ie

Which will always include the latest release.


The _vm generation process is aware of ZSH's existance. ZSH wants to use _foo as a completion function for foo, as such _vm spits out functions called ,foo. Builds are linked below:

ZSH builds also include tab completion.


_vm ships with a shell helper called brew! that will setup an ephemeral _vm helper in the current shell. It currently depends on some zsh specifics.

You use it like:

# Somewhere in your init files:
source ../path/to/_vm/contrib/

# Then in your shell
prompt% brew! go
# Assuming you've set _VM_USE_ZSH
prompt% ,go
prompt% ,go 1.2.1
prompt% which go

Contrib Modules

There are examples, as well as optional modules you may want, included in the repo, for example requiring the prompt.rb in contrib will give you access to

include Contrib::Prompt

to give you a function suitable for including current version in your prompt, eg

_ruby prompt # "system" or "2.0.0-p195" etc

Current Status

It's at the point where the framework mostly works. There are also a few really useful plugins for other languages.

A really quick tour:

xenia % ,rust system
xenia % ,ruby system
xenia % echo $DYLD_LIBRARY_PATH

xenia % ,rust 0.11.0-2eb3ab1
xenia % echo $DYLD_LIBRARY_PATH
xenia % ,ruby 2.0.0
xenia % echo $GEM_PATH
xenia % ,gem::add ~/code/some-dev-gem
xenia % echo $GEM_PATH
xenia % which nmap
xenia % brew! nmap
xenia % ,nmap
xenia % ,nmap 6.46
xenia % which nmap
xenia %

You'll notice that I'm using the prefix ,. You can either set this directly in your managers, or the ZSH contrib module will use , by default.


Requires shell-proxy which is basically only used by _vm, so it's submoduled in for convenience to make development more straightforward.

Currently you can either build it on the fly, or fetch prebuilt scripts (for example if your system doesn't have ruby)

# I'm using my RVM rubies with _vm
# In zsh, I'd love to know how to do this in bash:
emulate sh -c "`ruby _ruby`"

# Or if you don't want to be on the bleeding edge
mkdir -p ~/.vm
ruby _ruby > ~/.vm/_ruby
# in ${SHELL}rc
source ~/.vm/_ruby

# in a posix compatible sh

eval "`ruby _ruby`"

If you want to rebuild _vm at runtime, you should install shell-proxy as a submodule, which _vm checks for before doing a (very expensive) rubygems lookup.

Other platforms

I would love to know how to make this work with other languages/platforms.

I basically just need to know what environment variables the language expects to see (and a link to a convenient way to get/build the binaries would be nice). Feel free to open an issue


  • @mpapis: For the original skype call that lead me down this train of thought.
  • @postmodern: For chruby, from which most of the core was directly derived.