@sponzey/devenv
v0.1.28
Published
Rust-based multi-language development runtime manager.
Maintainers
Readme
DevEnv
DevEnv is a Rust-based CLI for selecting, installing, and activating development runtimes and command-line tools per project.
The project takes inspiration from tools such as jenv, goenv, pyenv, asdf, and mise, while aiming for a broader, extensible provider model across many languages and tools. DevEnv is CLI-first and does not require a server, GUI, daemon, database, or cloud dependency.
The product version is defined by the root Cargo.toml:
Cargo.toml -> [workspace.package] -> versionCurrent Status
DevEnv is currently in an MVP stage. The core workflow is implemented, but providers do not all have the same maturity level.
Supported workflows:
- Register an existing runtime:
devenv add <tool> <path> - Remove a registered external runtime:
devenv remove <tool> <path> - Delete a DevEnv-owned install:
devenv uninstall <tool> <version> - List installed and registered runtimes:
devenv list <tool> - List remote versions:
devenv list-remote <tool> - Install a runtime:
devenv install <tool> <version> - Select a project version:
devenv local <tool> <version> - Select a global version:
devenv global <tool> <version> - Show the current selection:
devenv current - Run a command in an activated environment:
devenv exec -- <command> - Generate shims:
devenv shim rehash - Check local state:
devenv doctor
Provider status:
| Tool | Provider | Current support | | ------------ | -------------- | ---------------------------------------------------------------------------- | | Java | Temurin | Direct install metadata and local registration | | Go | Official | Direct install metadata, catalog metadata, local registration | | Node.js | Official | Direct install metadata, catalog metadata, local registration | | Python | CPython | Fixture-backed direct path and local registration; live provider is deferred | | Ruby | Local | Local registration only | | PHP | Local | Local registration only | | Rust | rustup | Delegated to rustup; DevEnv discovers/registers toolchains | | Flutter/Dart | Stable channel | Direct install metadata and local registration | | Terraform | HashiCorp | Direct install metadata, catalog path, single-binary install | | OpenTofu | OpenTofu | Direct install metadata, single-binary install |
DevEnv reads common project version files where implemented:
devenv.toml.tool-versions.java-version.go-version.node-version.nvmrc.python-version.ruby-version
More details are in docs/user-guide.md.
Quick Start From Source
Build and run locally:
cargo run --bin devenv -- --help
cargo run --bin devenv -- --versionRun tests:
cargo testBuild a release binary for the host target:
cargo build --release --bin devenvUse a built binary:
target/release/devenv --version
target/release/devenv doctorExample Usage
Register runtimes that already exist on the machine:
devenv add java /Library/Java/JavaVirtualMachines/temurin-17.jdk/Contents/Home
devenv add go /usr/local/go
devenv add node ~/.nvm/versions/node/v20.11.1
devenv add python ~/.pyenv/versions/3.12.2
devenv add rust ~/.rustup/toolchains/1.85.0-aarch64-apple-darwinSelect project versions:
devenv local java 17
devenv local go 1.22
devenv local node 20Run with DevEnv activation:
devenv current
devenv exec -- java -version
devenv exec -- go version
devenv exec -- node --versionFor direct commands such as java --version, activate shims once in the current shell:
eval "$(devenv activate zsh)"
eval "$(devenv activate bash)"
java --versiondevenv local and devenv global write version selections. They do not directly mutate the parent shell process. Direct commands such as go version change only after the DevEnv shim directory is active at the front of PATH.
This is the same model used by tools such as goenv, jenv, pyenv, and rbenv: local writes a project version file, and shell initialization makes shims read that file for each command.
For new terminal sessions, add the exact activation line printed by devenv local, devenv global, or devenv use to your shell profile:
devenv init bash --write
devenv init zsh --write
# Manual alternative:
devenv global java 21
# zsh: copy the printed "new sessions:" line into ~/.zshrc.
# bash: copy the printed "new sessions:" line into ~/.bashrc.Ubuntu/bash example:
devenv init bash --write
source ~/.bashrc
hash -r
type -a godevenv init <shell> previews the managed shell profile block without editing files. Add --write to update the profile. Existing DevEnv init blocks are replaced idempotently.
The first go entry should point to the DevEnv shim directory, usually ~/.local/share/devenv/shims/go on Linux. If a system Go path still appears first, move the DevEnv activation line below any existing Go PATH setup in ~/.bashrc.
This matters for npm installs because the npm entrypoint is a Node.js wrapper. The generated line uses the native DevEnv binary path so DevEnv shims can safely manage node, npm, and other commands.
After activation, devenv local, devenv global, and devenv use selections are picked up by the shims for subsequent tool commands in that shell.
If no DevEnv version is selected for a shimmed command, DevEnv falls back to the next matching command on PATH.
Refresh remote metadata and install:
devenv list-remote go --refresh
devenv install go 1.22Metadata And Catalog
DevEnv separates metadata refresh from runtime artifact downloads.
metadata updateandlist-remote --refreshfetch small provider metadata.list-remote --offlinereads fixture overrides or the local metadata cache.installdownloads runtime artifacts only after metadata resolution.- checksum-bearing artifacts are verified before being promoted into the download cache.
The GitHub metadata catalog path is experimental. The catalog stores normalized metadata only. It must not store runtime archives.
Current catalog support includes:
- schema v1 documents and fixtures;
- manifest and payload checksum verification;
- Go catalog metadata path;
- Node catalog metadata path;
- Terraform/OpenTofu catalog shape validation;
- opt-in catalog smoke script.
Catalog usage is opt-in:
export DEVENV_ENABLE_CATALOG=1
export DEVENV_CATALOG_BASE_URL=file:///mirror/devenv-metadata/v1
devenv metadata verify-catalog go --catalog /mirror/devenv-metadata/v1 --source file
devenv metadata update go --source catalog
devenv list-remote go --offlineCatalog network smoke is not part of the default test loop:
scripts/catalog-smoke.sh --help
DEVENV_CATALOG_SMOKE=1 DEVENV_CATALOG_SMOKE_BASE_URL=file:///mirror/devenv-metadata/v1 scripts/catalog-smoke.shDistribution
Distribution currently uses GitHub release artifacts and npm.
Release Version
The product version is controlled only by:
Cargo.toml -> [workspace.package] -> versionDo not maintain a separate Rust, npm, or documentation version.
Prepare a version bump:
scripts/release-version.sh <version>The script updates Cargo.toml, refreshes Cargo.lock, runs verification, creates a Release <version> commit, and creates an annotated v<version> tag. It does not push commits or tags.
Push explicitly after review:
git push origin HEAD --tagsGitHub Release Artifacts
The release workflow builds these targets:
aarch64-apple-darwinx86_64-apple-darwinx86_64-unknown-linux-muslaarch64-unknown-linux-muslx86_64-pc-windows-msvc
Artifacts are named:
devenv-<version>-<target>.tar.gz
devenv-<version>-<target>.tar.gz.sha256
SHA256SUMSEach package contains:
devenvordevenv.exeUSER_GUIDE.md
Linux release artifacts use musl targets so npm installs do not depend on the glibc version available on the user's distribution.
Package smoke executes the binary only when the package target matches the build host. Cross-compiled artifacts such as aarch64-unknown-linux-musl are unpacked and checked, but not executed by default.
Build a local package for the host target:
DEVENV_BUILD_GIT_SHA="$(git rev-parse --short=12 HEAD)" scripts/package-release.shBuild an explicit target:
DEVENV_BUILD_GIT_SHA="$(git rev-parse --short=12 HEAD)" \
DEVENV_RELEASE_TARGET=aarch64-apple-darwin \
scripts/package-release.shnpm
The public npm package name is:
@sponzey/devenvThe npm package is generated from the Cargo workspace version. Do not hand-edit an npm package version.
Generate and smoke-test the package:
scripts/npm-smoke.shPublish after the matching GitHub release artifacts are available:
scripts/package-npm.sh
npm login --registry=https://registry.npmjs.org/
npm publish target/npm/@sponzey/devenv --access public --registry=https://registry.npmjs.org/The release workflow publishes through npm Trusted Publishing, not a long-lived NPM_TOKEN. Configure npm with GitHub Actions as a trusted publisher for package @sponzey/devenv, repository Sponzey-com/DevEnv, workflow filename release.yml, and allowed action npm publish.
Use the official npm registry for account creation and publishing. CNPM, npmmirror, and other mirrors are not valid places to create or publish the public @sponzey/devenv package.
The release workflow only attempts npm publish when repository variable NPM_PUBLISH_ENABLED is set to true. Leave it unset while bootstrapping the npm scope so GitHub Release artifacts can still be published.
For the first publish, make sure the npm sponzey organization or user scope exists and that the publishing account has permission to create @sponzey/devenv. If npm returns E404 during PUT https://registry.npmjs.org/@sponzey%2fdevenv, the package or scope is not accessible to the publisher. Bootstrap the package once with an authorized npm account using 2FA or a granular access token with Bypass 2FA, then enable Trusted Publishing for subsequent releases.
The package installs a small Node.js shim and downloads the matching prebuilt GitHub release artifact during postinstall. It verifies the .tar.gz.sha256 checksum before installing the local devenv binary.
User-facing install/update:
npm install -g @sponzey/devenv@latestIf npm returns 404 Not Found, the package name has not been published yet or the requested version is not available in the public registry.
Development Standards
The project is developed around:
- Clean Architecture
- Tidy First
- TDD
Core policy should stay independent from shell, filesystem, network, package registry, archive format, and platform-specific details. New languages and tools should be added through stable contracts, adapters, and tests rather than hard-coded behavior in the CLI layer.
Documentation
- User guide:
docs/user-guide.md - Distribution guide:
docs/distribution.md - Catalog schema:
docs/catalog/schema-v1.md - Catalog repository workflow:
docs/catalog/repository-workflow.md - Architecture decisions:
docs/adr/
License
MIT. See LICENSE.
