avm is a Rust-native, monorepo-based tooling layer for local command aliases, project-level runtime selection, and plugin-driven command discovery.
It solves three practical problems:
- command drift across projects
- manual setup of project-specific runtime versions
- repetitive shell configuration for ad hoc aliases
- project and global alias resolution from
.avm.json - directory-aware execution with local-first precedence
- runtime environment injection via
PATHand explicitenvvalues - Node package-script discovery from
package.json(npm/yarn/pnpm/bun) - shim-based command interception (for
node,npm, and future tool shims) - a plugin system with pluggable providers
- fallback behavior: if a managed version is not installed, avm uses the host/system command and warns
For positioning versus popular alternatives, see Comparison with asdf and vfox.
| Capability | avm (this project) | asdf | vfox |
|---|---|---|---|
| Runtime model | Native Rust binary | Ruby/plugin ecosystem with Bash integrations | Rust shell-hook engine with plugin runtime |
| Tool interception | PATH shims in ~/.avm/shims |
Shim generation + dispatch by plugin hooks | Shell hook updates PATH dynamically |
| Plugin ecosystem | Provider-first + optional adapter layer | Bash-style plugins | Lua-style plugins |
| Node support strategy | Merged Node provider (package.json + version resolver) |
External Node plugin scripts | Provider-based Node integrations |
| Fallback if requested node version missing | Uses system node with warning | Typically triggers plugin install flow | Typically triggers plugin install flow |
| Configuration default | .avm.json with local/global + legacy compatibility |
.tool-versions |
.tool-versions |
| Security / isolation | Rust host + plugin runtime boundary (WASM/exec adapters) | Shell scripts (higher host access) | In-process plugin runtime (less isolated than strict sandbox) |
avm init
avm add dev "pnpm run dev"
avm tool use node 20.11.1
avm run deveval "$(avm shell-init)"This enables direct execution via shims. For example, if node is managed in .avm.json, node will resolve through avm-managed versions before falling back.
{
"aliases": {
"dev": "pnpm run dev",
"release": "npm run release $1"
},
"env": {
"NODE_ENV": "development",
"API_URL": "https://api.local"
},
"tools": {
"node": "20.11.1"
}
}avm also reads legacy flat-map .avm.json files and migrates them into the structured object form on read.
Precedence rules:
- local
.avm.jsonoverrides global~/.avm.json - alias suggestions respect override ordering
- environment is merged with local values overriding global values
- tool version lookup is local first, then global
avm initinitializes.avm.jsonin the current directoryavm add [--global] <alias> <command>adds an aliasavm remove [--global] <alias>removes an aliasavm listshows merged aliases, env, tools, and plugin aliasesavm which <alias-or-tool>prints the origin and resolved valueavm run <alias> [args...]executes resolved commandavm envprints shell-safeexportlinesavm resolve <alias> [args...]prints the expanded shell commandavm tool use [--global] <tool> <version>sets tool versionavm tool install <tool> <version>is reserved for provider installers; the current Node baseline does not auto-installavm tool uninstall <tool> <version>removes an installed managed Node directory when presentavm tool listprints configured and installed toolsavm plugin add|list|remove|updatemanages external providersavm shims install|remove|pathcontrols shim lifecycleavm shell-initprints shell bootstrap scriptavm versionprints current CLI version
This repository is organized as a Rust workspace:
crates/avm-cli- Clap-based binary entrypoint and command routing
crates/avm-core- config parsing, alias/tool/env resolution, and shared types
crates/avm-shims- shim generation and shim execution hooks
crates/avm-plugin-api- host/plugin contract interfaces and manifest/schema model
crates/avm-plugin-node- merged Node provider
- Node version management and package-script alias discovery
crates/avm-runtime- plugin runtime and external plugin execution abstraction
Architecture docs:
Agent and LLM docs:
Use any option supported in your environment:
brew install avmnpm install -g @prajanova/avmcargo install --path .Run the full Rust and scenario suite in an isolated container:
docker/tests/run-docker-tests.shRun only Rust tests locally:
cargo test --workspaceRun one scenario:
docker/tests/run-docker-tests.sh 01
docker/tests/run-docker-tests.sh 01-basic-alias.sh
docker/tests/run-docker-tests.sh docker/tests/scenarios/01-basic-alias.shScenario files:
docker/tests/scenarios/01-basic-alias.shdocker/tests/scenarios/02-local-global-precedence.shdocker/tests/scenarios/03-shim-fallback.shdocker/tests/scenarios/04-node-package-scripts.sh
The Node provider currently powers:
- project
package.jsonalias extraction - tool version selection for
node - manager fallback to an existing system installation when managed version is missing
The architecture is plugin-first, so additional providers can be added without changing the CLI flow.
- Keep all runtime logic in Rust crates.
- Prefer explicit, typed errors (
thiserror/anyhow) over panics in runtime paths. - Follow workspace standards in AGENTS.md.
- Use shim execution as the default integration model for plain command resolution.
MIT