Skip to content

BoxingOctopusCreative/linguo

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

59 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Linguo

Linguo Logo

Release CI crates.io License: MPL-2.0

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

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 / fish

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
[settings]
auto-install = true

Usage

Every 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 directory

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):

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 declares

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:

linguo sync                       # fresh clone -> every member runnable

Terraform 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 plan

Rust 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-unknown

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):

[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.

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 tool semantics, 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.

About

multi-language runtime manager/bootstrapper

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages