Toolchains

This is the exhaustive reference for the tools Lattice knows about out of the box: every built-in task driver, and every engine it can version-check without help. The models behind these tables are Driver detection (how a workspace’s task driver gets picked) and Engines and provisioning (how a version constraint gets satisfied). Read those for the why; this page is the lookup.

The built-in driver table

Each driver is a DriverSpec: a fingerprint that identifies it in a workspace directory, a Role, the command that prints its version, and the shell template it invokes a task with (crates/lattice-workspace/src/lib.rs:70-288). A driver’s role decides how it competes: different roles in the same workspace compose into a stack (a node runtime plus a pnpm package manager); two drivers with the same role conflict until you disambiguate. A pure Runtime — node, python, ruby, java below — never drives a workspace by itself; on its own it still halts as an ambiguous/undetected driver, the same as no evidence at all. See Driver detection for the full evidence ladder and the composition/conflict rule.

{task} below is the literal placeholder each driver substitutes the task name into.

JavaScript and TypeScript

Tool Role Fingerprint Version command Invoke template
node Runtime .nvmrc node --version node {task}
deno Task Runner deno.json, deno.jsonc, deno.lock deno --version deno task {task}
bun Package Manager bun.lockb, bun.lock bun --version bun run {task}
pnpm Package Manager pnpm-lock.yaml pnpm --version pnpm run {task}
yarn Package Manager yarn.lock yarn --version yarn {task}
npm Package Manager package-lock.json npm --version npm run {task}

Rust

Tool Role Fingerprint Version command Invoke template
cargo Build Tool Cargo.lock, rust-toolchain.toml, rust-toolchain cargo --version cargo {task}

Go

Tool Role Fingerprint Version command Invoke template
go Build Tool go.sum go version go {task}

Python

Tool Role Fingerprint Version command Invoke template
uv Package Manager uv.lock uv --version uv run {task}
poetry Package Manager poetry.lock poetry --version poetry run {task}
pdm Package Manager pdm.lock pdm --version pdm run {task}
pipenv Package Manager Pipfile.lock pipenv --version pipenv run {task}
python Runtime .python-version python --version python -m {task}

Ruby

Tool Role Fingerprint Version command Invoke template
bundler Package Manager Gemfile.lock bundle --version bundle exec {task}
rake Task Runner Rakefile rake --version rake {task}
ruby Runtime .ruby-version ruby --version ruby {task}

The JVM (Java, Gradle, Maven)

Tool Role Fingerprint Version command Invoke template
gradle Build Tool gradlew gradle --version ./gradlew {task}
maven Build Tool mvnw mvn --version ./mvnw {task}
java Runtime .java-version java -version java {task}

.NET

Tool Role Fingerprint Version command Invoke template
dotnet Build Tool global.json dotnet --version dotnet {task}

Swift and Objective-C

Tool Role Fingerprint Version command Invoke template
pod Package Manager Podfile, Podfile.lock pod --version pod {task}
swift Build Tool Package.resolved swift --version swift {task}

PHP

Tool Role Fingerprint Version command Invoke template
composer Package Manager composer.lock composer --version composer {task}

Elixir

Tool Role Fingerprint Version command Invoke template
mix Task Runner mix.lock mix --version mix {task}

Dart and Flutter

Tool Role Fingerprint Version command Invoke template
dart Package Manager pubspec.lock dart --version dart pub {task}

Haskell

Tool Role Fingerprint Version command Invoke template
stack Build Tool stack.yaml.lock stack --version stack {task}
cabal Build Tool cabal.project.freeze cabal --version cabal {task}

Generic task runners

These aren’t tied to one language — any of them can sit above a language-specific driver in a workspace (see Driver detection on composition).

Tool Role Fingerprint Version command Invoke template
just Task Runner justfile, .justfile just --version just {task}
task Task Runner Taskfile.yml, Taskfile.yaml task --version task {task}
turbo Task Runner turbo.json turbo --version turbo run {task}
nx Task Runner nx.json nx --version nx run {task}

That is the complete DRIVERS table: 31 drivers across 13 language and ecosystem groups (crates/lattice-workspace/src/lib.rs:70-288).

Well-known engines

An engines entry can be a bare version-constraint string only if Lattice already has a built-in rule for checking that tool’s version — the WELL_KNOWN_ENGINES list (crates/lattice-config/src/lib.rs:13-16). A string naming anything else is rejected by lattice.json validation. Every name below is accepted in the short string form:

{ "engines": { "node": ">=20.0.0" } }
Engine Version rule (command Lattice runs)
node node --version
deno deno --version
bun bun --version
pnpm pnpm --version
yarn yarn --version
npm npm --version
rust rustc --version
cargo cargo --version
go go version
python python --version
python3 python --version
ruby ruby --version
bundler bundle --version
java java -version
gradle gradle --version
maven mvn --version
dotnet dotnet --version

(crates/lattice-workspace/src/toolchain.rs:35-70, builtin_version_cmd.) rust has no entry in the driver table above — cargo is the task driver for a Rust workspace, but rust is a separate, valid engine name for pinning the rustc toolchain version itself.

A bare string is shorthand for a version-only constraint — no installCmd means validate-only: Lattice runs the version command above against whatever is already on PATH and fails if it doesn’t satisfy the constraint. It never installs anything for a well-known engine unless you add an explicit installCmd in the object form.

Declaring a tool Lattice doesn’t know

Any other tool name needs the object form, with an explicit versionCmd — skip it and lattice.json validation rejects the config with the exact fix (crates/lattice-config/src/lib.rs:304-316):

engine 'alpes' in root uses the string (version-only) form, but 'alpes' is not
a well-known engine Lattice can version-check on its own. Use the object form
with an explicit `versionCmd`, e.g. "alpes": { "version": ">=1.0.0", "versionCmd":
"alpes --version" }

A working example, validating a tool already on PATH without installing it:

{
  "engines": {
    "alpes": {
      "version": ">=2.6.7",
      "versionCmd": "alpes --version"
    }
  }
}

Add installCmd (and optionally bin, which defaults to bin) to move this from validate-only to provisioned — Lattice installs it into .lattice/toolchains/alpes/ and pins the result instead of trusting PATH:

{
  "engines": {
    "alpes": {
      "version": ">=2.6.7",
      "versionCmd": "alpes --version",
      "installCmd": "curl -fsSL https://alpes.example/install.sh | sh -s -- --dir $LATTICE_TOOLCHAIN_DIR",
      "bin": "bin"
    }
  }
}

The full mechanics of that gradient — what $LATTICE_TOOLCHAIN_DIR receives, how a pin is reused across runs, and what gets prepended to a task’s PATH — are on the Engines and provisioning page.