Linguo is a cross-platform, multi-language runtime, package, and project manager: think
uv, but for Python, Node.js, Ruby, PHP, Rust, Go, Zig, and Terraform/OpenTofu.
One binary manages runtime versions, per-project pins, and project workflows for every language, with the same command shape everywhere:
linguo <language> <command>
| Language | Runtime source | Project layer |
|---|---|---|
| Python | python-build-standalone | pyproject.toml + pip-backed .venv |
| Node.js | nodejs.org/dist | package.json via npm |
| Ruby | rv-ruby relocatable builds; RubyInstaller on Windows | Gemfile via bundler (shared per-toolchain gems) |
| Rust | static.rust-lang.org dist channels | Cargo.toml via cargo |
| Go | go.dev/dl | go.mod via the go tool |
| Zig | ziglang.org (static, musl-friendly) | build.zig.zon via the zig tool |
| PHP | static-php-cli builds (static); windows.php.net on Windows | composer.json via bundled Composer |
| Terraform / OpenTofu | releases.hashicorp.com / get.opentofu.org | runtime-only (providers stay terraform's job) |
Every download is sha256-verified against its upstream's published checksums.
Toolchains live under ~/.linguo/toolchains/<language>/<version> (override
with $LINGUO_ROOT).
Prebuilt binaries for macOS (arm64/x86_64), Linux (x64/arm64, glibc and fully static musl), and Windows (x64) are on the releases page. On musl systems (Alpine and friends), Python, Ruby, Rust, and Terraform/OpenTofu work natively; Node.js and Go publish no official musl builds, so linguo points you at the distro package instead. On Windows, Ruby comes from RubyInstaller archives (without the MSYS2 devkit, so gems with C extensions need a separate toolchain).
Pick your channel:
# Homebrew (macOS/Linux)
brew tap boxingoctopuscreative/tap && brew install linguo
# curl install script (macOS/Linux, glibc or musl)
curl -fsSL https://raw.githubusercontent.com/BoxingOctopusCreative/linguo/main/install.sh | sh
# crates.io
cargo install linguo
# native packages: deb, rpm, and a Windows MSI on the releases page
# Ubuntu PPA (rolling out; live once the first PPA build publishes)
sudo add-apt-repository ppa:boxingoctopuscreative/ppa && sudo apt install linguo
# Chocolatey (rolling out; live once the first submission clears moderation)
choco install linguo
# from a checkout
cargo install --path .The curl script detects your platform, downloads the latest release tarball,
verifies its checksum, and installs the binary to ~/.local/bin. Override
the destination with LINGUO_INSTALL_DIR, or pin a version with
LINGUO_VERSION=1.2.0 (or sh install.sh 1.2.0).
In CI or anywhere GitHub API rate limits bite, set GITHUB_TOKEN (or
LINGUO_GITHUB_TOKEN): linguo and the install script authenticate their
api.github.com queries with it, and never send it anywhere else.
Every channel is fed automatically by the release pipeline: the tap formula
(also attached to each release as linguo.rb), crates.io, the PPA (source
packages that Launchpad builds for noble and resolute), and the Chocolatey
package (which installs the release MSI).
Then add the shell hook to your rc file so pinned runtimes activate
automatically when you cd into a project:
eval "$(linguo activate zsh)" # or bash / fishOn Windows (PowerShell), add this to your $PROFILE instead:
linguo activate powershell | Out-String | Invoke-ExpressionOptionally, let the hook install unsatisfied pins on the spot (cd into a fresh clone and the pinned toolchains just appear). It's off by default and gated on the machine-level config (a cloned repo can't trigger downloads by itself), and failed attempts back off for 5 minutes so an unreachable upstream never stalls your prompt:
# ~/.linguo/config.toml
[settings]
auto-install = trueEvery language gets the same runtime commands:
linguo <lang> install [version] # sensible default: latest / latest LTS / latest stable
linguo <lang> list # installed; --available for what's downloadable
linguo <lang> use 3.12 # pin for this directory (writes linguo.toml)
linguo <lang> use 3.12 --global # default for everything else
linguo <lang> uninstall 3.12.4
linguo <lang> which [command] # path a command resolves to
linguo <lang> run -- <command> # run with the pinned toolchain on PATH
linguo status # cross-language overview (alias: linguo list)
# Upgrades: newest release within the pin by default, or bump the pin itself
linguo node upgrade # pin "22" -> installs the newest 22.x
linguo node upgrade --latest # bumps the pin (22 -> 24) and installs it,
# rewriting whichever file held the pin
linguo node upgrade --prune # also uninstall the superseded toolchains
linguo upgrade # all languages pinned in this directoryAnd, where the language has a project/package layer, the uv-style project commands (each drives the ecosystem's native tool, whether pip, npm, bundler, cargo, or go, rather than reimplementing it):
linguo python init # pyproject.toml + linguo.toml pin + .venv
linguo python add "requests>=2.31"
linguo node add typescript && linguo node run -- tsc --version
linguo ruby add rails
linguo php add monolog/monolog # composer, bundled with every php toolchain
linguo rust add serde && linguo rust run -- cargo build
linguo go add rsc.io/quote
linguo <lang> remove <pkg>
linguo <lang> sync # install everything the manifest declaresMonorepos sync in one shot: linguo sync at the top level finds every member
project (or honors [workspace] members = ["services/*", "web"] in the root
linguo.toml, globs allowed), installs any missing pinned toolchains, and runs
each member's dependency sync. Directories holding .tf files count as
toolchain-only members:
linguo sync # fresh clone -> every member runnableTerraform and OpenTofu share one command (linguo tf works too); OpenTofu
versions are spelled opentofu@<version> and resolve the tofu binary:
linguo tf install opentofu@1.12
linguo tf use opentofu@1.12 # writes terraform = "opentofu@1.12"
linguo tf run -- tofu planRust additionally understands rustup-style channels, components, and targets;
a project's rust-toolchain.toml components/targets arrays are honored
automatically at install time:
linguo rust install nightly # today's; nightly-2026-07-01 for a date
linguo rust use nightly # activates the newest installed nightly
linguo rust component add rust-analyzer rust-src
linguo rust target add wasm32-unknown-unknownZig projects work the same way (linguo zig init/sync/run/which); add
wraps zig fetch --save, which takes archive URLs or paths rather than
registry names.
Pins live in linguo.toml, resolved from the nearest one up the directory
tree, then the global config (~/.linguo/config.toml):
[runtimes]
python = "3.12"
node = "24"
rust = "1.96"
terraform = "opentofu@1.12"Requests can be a major (24), minor (3.12), or exact (1.96.1) version;
the highest installed match wins. Rust pins may also be channels: stable,
nightly, beta, or dated builds like nightly-2026-07-01. Bare channel
pins resolve to the newest installed build of that kind, so activation
stays offline and deterministic; linguo rust upgrade is what moves them
forward.
Existing projects work without a linguo.toml: when none covers a language,
linguo honors the ecosystem's own pin file (.python-version, .nvmrc /
.node-version, .ruby-version, go.mod's toolchain/go directives,
rust-toolchain(.toml), .zigversion, build.zig.zon's
minimum_zig_version, and .php-version), as long as it holds a plain version (or, for
rust, a channel; node aliases like lts/* are still ignored). Precedence:
project linguo.toml, then the ecosystem pin file, then the global config.
Next up, in release order:
- 1.3.0 Java and JDK-based languages: JDK management plus Kotlin, Groovy, and Scala.
Then, under consideration:
- Unit-testing framework support for the managed languages (pairs with developer tool management below).
- Windows arm64 binaries: the backends already map the targets; needs a release lane and CI coverage.
- Developer tool management: install linters, formatters, and test
runners through linguo (
linguo python tool install ruff,linguo node tool install eslint,linguo go tool install golangci-lint, ...), each in its own isolated environment with its executables on PATH. That's pipx /uv toolsemantics, but for every managed language. Tools would pin and upgrade like runtimes do, so a repo can declare its lint stack the same way it declares its toolchains.
cargo test runs the unit suite; CI additionally runs end-to-end smoke
tests (real toolchain installs and project flows) on Linux, on musl inside
an Alpine container, and on Windows for every push, and builds the deb, rpm,
and MSI packages so packaging can't rot between releases. Releases are cut
from the Actions tab via the Release workflow, which bumps the version, tags,
builds binaries for all seven platform lanes, packages deb/rpm/MSI, publishes
with notes generated from commit messages, and pushes the regenerated
Homebrew formula to the tap.
