lungo

lungo · for coding agents

Let your agent set up lungo

Give this line to Claude Code, Codex, Cursor or any coding agent working in your project. It installs lungo for your system, then sets it up for your project's language.

Fetch https://machinefabric.com/lungo/agents.md and set up lungo in this project.

lungo compiles a Lean (Lake) project into a library for Rust, Go, Python, Swift, TypeScript (WebAssembly) or C. Theorems marked @[lungo_claim] ship with the package as proved claims.

Ask the user before sudo or editing files they did not ask about. If a step fails, stop and report the command and its output.

1. Detect

2. Lean

If elan --version fails, install elan:

curl https://elan.lean-lang.org/elan-init.sh -sSf | sh
curl -O --location https://elan.lean-lang.org/elan-init.ps1
powershell -ExecutionPolicy Bypass -f elan-init.ps1
del elan-init.ps1

Then, in a new shell:

elan toolchain install leanprover/lean4:v4.34.1

This is the only supported toolchain; the project’s lean-toolchain must name it exactly, or lungo fails with LNG0102.

3. The lungo command

Skip for Rust. Otherwise install it one of these ways, then check lungo --version:

System Install
macOS, Linux with Homebrew brew install machinefabric/tap/lungo
Debian, Ubuntu (amd64, arm64) apt, below
Fedora, RHEL (x86_64, aarch64) dnf, below
Windows PowerShell, below
any, with Rust 1.89+ cargo install lungo-cli
# apt
curl -fsSL https://release.machinefabric.com/packages/keys/repo-signing-prod.asc \
  | sudo gpg --dearmor -o /usr/share/keyrings/machinefabric.gpg
echo "deb [signed-by=/usr/share/keyrings/machinefabric.gpg] https://release.machinefabric.com/packages/apt stable main" \
  | sudo tee /etc/apt/sources.list.d/machinefabric.list
sudo apt update && sudo apt install lungo
# dnf
sudo tee /etc/yum.repos.d/machinefabric.repo >/dev/null <<'EOF'
[machinefabric]
name=MachineFabric
baseurl=https://release.machinefabric.com/packages/rpm/$basearch
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=https://release.machinefabric.com/packages/keys/repo-signing-prod.asc
EOF
sudo dnf install lungo
# Windows: latest release from the manifest, digest checked, added to the user's PATH
$manifest = Invoke-RestMethod https://release.machinefabric.com/lungo-cli/manifest
$version = $manifest.channels.release.latestVersion
$archive = $manifest.channels.release.versions.$version.platforms.'windows-x86_64'.installers[0]
Invoke-WebRequest $archive.path -OutFile $archive.name
if ((Get-FileHash $archive.name -Algorithm SHA256).Hash -ne $archive.sha256) { throw "the archive does not match the manifest's digest" }
$dir = "$env:LOCALAPPDATA\Programs\lungo-$version"
Expand-Archive $archive.name -DestinationPath $dir
[Environment]::SetEnvironmentVariable('Path', [Environment]::GetEnvironmentVariable('Path', 'User') + ";$dir\lungo", 'User')
$env:Path += ";$dir\lungo"

The same manifest (https://release.machinefabric.com/lungo-cli/manifest) lists a .tar.gz with its sha256 for darwin-arm64, darwin-x86_64, linux-x86_64 and linux-arm64; it holds lungo/lungo.

4. The Lake project

Put it in lean/. If one exists, check that lean-toolchain names the toolchain above and that lake-manifest.json exists; lungo setup installs the toolchain, fetches locked dependencies and prepares lungo’s worker. Otherwise create one:

mkdir lean
echo 'leanprover/lean4:v4.34.1' > lean/lean-toolchain
# lean/lakefile.toml
name = "geometry"
version = "0.1.0"
defaultTargets = ["Geometry"]

[[lean_lib]]
name = "Geometry"

Write the definitions in lean/Geometry.lean, inside namespace Geometry (ask the user what they should be). Then (cd lean && lake update) and commit lake-manifest.json. lungo never fetches dependencies: run lake update after adding one.

5. Rust

Needs Rust 1.89+.

cargo add lungo
cargo add --build lungo-build
// build.rs
fn main() -> lungo_build::Result<()> {
    lungo_build::compile_lean("lean")
}
// src/lib.rs: the module is named after the Lake package
pub mod geometry {
    lungo::include_lean!("geometry");
}

cargo build (the first takes minutes: lungo builds its Lean worker once). Lean structures become structs, functions plain functions, Nat is lungo::Nat.

6. Go, Python, Swift, TypeScript, C

# lungo.toml, at the project root; one table per language
project = "lean"

[go]          # or [python], [swift], [ts], [c]
out = "geometry"

Run lungo generate (prints generated go into geometry) and add .lungo/ to .gitignore. Without a lungo.toml: lungo generate --go_out=DIR (--python_out, --swift_out, --ts_out, --c_out).

<out> is the output directory. <name> is the Lake package’s name: lowercased in Go, Python and TypeScript, - as _ in C, UpperCamelCase as Swift’s module.

Language Needs Use
Go Go 1.22, cgo, a C compiler (MinGW-w64 GCC on Windows) go mod tidy; import <module>/<out>. Functions return (result, error); Nat is *big.Int.
Python Python 3.9, CMake, a C compiler pip install ./<out> into the venv; from <name> import …. Structures are frozen dataclasses; Nat is int.
Swift Swift 5.9, macOS (targets macOS, iOS, iOS simulator) .package(path: "<out>") in Package.swift; depend on the product <out>/Package.swift declares.
TypeScript Node.js 20, or a browser "<name>": "file:./<out>" in package.json, npm install; import { load } from "<name>", const lib = await load(). Nat is bigint. Don’t commit <out>/program.wasm; lungo generate --link makes it.
C CMake 3.20, a C11 compiler add_subdirectory(<out>), target_link_libraries(<target> PRIVATE <name>); header <out>/include/<name>.h. The first configure downloads lungo’s runtime; offline, lungo runtime fetch and configure with -D<NAME>_FETCH_LUNGO=OFF -DCMAKE_PREFIX_PATH=<runtime> (<NAME> is <name> in upper case, - as _: GEOMETRY_FETCH_LUNGO for geometry).

7. Verify

8. Claims (optional)

Add lungo’s Lean library at the tag of the lungo in use (lungo --version, or the lungo crate’s version):

# lean/lakefile.toml
[[require]]
name = "lungo"
git = "https://github.com/machinefabric/lungo-rs"
rev = "v<version>"
subDir = "lean"

(cd lean && lake update), then import Lungo and mark the theorem:

@[lungo_claim "lungo.law" subject area scale]
theorem area_scale (k : Nat) (r : Rect) : area (scale k r) = k * k * area r := by
  simp only [area, scale]
  rw [Nat.mul_mul_mul_comm]

lungo assurance reports each export’s claims, trust and assumptions. To fail the build when a claim is missing or unproved:

# lungo.toml
[assurance]
require-claims = ["Geometry.area", "Geometry.scale"]

In Rust: lungo_build::configure().require_claims("Geometry.area").compile_lean("lean").

Errors

Reference