Linguo

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).
Install
Four ways in, pick one:
# Homebrew (macOS/Linux)
&&
# curl install script (macOS/Linux, glibc or musl)
|
# native packages: deb, rpm, and a Windows MSI on the releases page
# from source
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=0.9.0 (or sh install.sh 0.9.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.
The tap's formula is updated automatically by the release pipeline (each
release also attaches the generated linguo.rb, kept at
packaging/homebrew/linguo.rb).
Then add the shell hook to your rc file so pinned runtimes activate
automatically when you cd into a project:
On Windows (PowerShell), add this to your $PROFILE instead:
linguo activate powershell | Out-String | Invoke-Expression
Optionally, 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
[]
= true
Usage
Every language gets the same runtime commands:
# Upgrades: newest release within the pin by default, or bump the pin itself
# rewriting whichever file held the pin
And, 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):
&&
&&
Monorepos 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:
Terraform and OpenTofu share one command (linguo tf works too); OpenTofu
versions are spelled opentofu@<version> and resolve the tofu binary:
Rust additionally understands rustup-style channels, components, and targets;
a project's rust-toolchain.toml components/targets arrays are honored
automatically at install time:
Zig 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.
Version pins
Pins live in linguo.toml, resolved from the nearest one up the directory
tree, then the global config (~/.linguo/config.toml):
[]
= "3.12"
= "24"
= "1.96"
= "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.
Roadmap
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.
Contributing
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.