This document describes leanport v0.1.1 and the leanport.toml schema it
reads. Everything here is exercised by scripts/e2e.sh.
leanport <command> [flags]
Run leanport help for the command list. Command flags follow the standard Go
flag package, so they must appear before positional arguments:
leanport new --package authz Authz.
| Flag | Description |
|---|---|
-C, --dir <path> |
Run as if LeanPort was started in <path>. Applies before the command. |
-h, --help |
Show help. |
--version |
Print version and exit. |
There is no global --verbose in v0.1.1; external commands are echoed when they
matter (for example → lake build …).
Set up LeanPort in an existing Go project. Refuses to overwrite existing files
unless --force is given.
| Flag | Default | Description |
|---|---|---|
--env <nix|local> |
nix |
nix also writes flake.nix and .envrc; local assumes elan/Go/cc are installed. |
--lean <vX.Y.Z|stable> |
v4.29.1 |
Lean toolchain written to lean/lean-toolchain. The default is pinned deliberately; stable floats. |
--targets <list> |
linux/amd64 |
Comma-separated goos/goarch pairs. |
--ci <github|none> |
github |
github writes .github/workflows/verify.yml. |
--name <name> |
directory name | Project name used in leanport.toml and the Lake package. |
--go-module <path> |
from go.mod |
Go module path recorded in leanport.toml. |
--force |
false |
Overwrite conflicting files. |
Writes: lean/lean-toolchain, lean/lakefile.toml, leanport.toml,
AGENTS.md, and (per flags) flake.nix, .envrc,
.github/workflows/verify.yml. It also appends .leanport/, .lake/,
.elan/ and .direnv/ to .gitignore if they are missing; generated Go
packages are intentionally not ignored.
Re-running init on a configured project fails unless --force is given.
--force refreshes the scaffold but preserves existing [[binding]] entries
and any [[lean_lib]] blocks, so it does not delete modules.
Scaffold one verified module inside an existing LeanPort project.
Writes:
lean/LeanPort/<Module>/Policy.lean # spec + implementation
lean/LeanPort/<Module>/Proofs.lean # theorems, with one worked example
lean/LeanPort/<Module>/Boundary.lean # scalar boundary + @[export]
lean/LeanPort/<Module>/SPEC.md # human/agent specification
and appends a [[lean_lib]] block to lean/lakefile.toml plus a [[binding]]
entry to leanport.toml. The scaffolded binding is
bool, uint8 -> bool; edit Boundary.lean and the binding together.
Running new again appends another module; it does not overwrite existing
files. After adding or changing a module, run leanport check and
leanport build (and leanport docs for a refreshed SPEC.md).
| Flag | Description |
|---|---|
--package <name> |
Generated Go package name. Defaults to the lower-cased module name. |
--export <symbol> |
C symbol for the @[export] declaration. Defaults to leanport_<module>_<go-name>. |
--go-name <Name> |
Generated Go function name. Defaults to Decide. |
Runs lake build for each binding's Policy, Proofs and Boundary targets,
then:
- rejects
sorryandadmitin Lean code underlean/, reporting file and line. Line and block comments are stripped first, so documentation may mention the words; - verifies every
[[binding]]'sexportappears in the generated C.
Exit 0 on success, 1 on any failure.
The full pipeline. Equivalent to check, then:
- locate generated C under
lean/.lake/build/ir/**/*.c; - compile each translation unit with
ccand the flags fromleanc --print-cflags; - subtract symbols defined elsewhere in the project, then inspect the remaining undefined symbols;
- choose a boundary mode (see below) and generate one glue file per binding in
.leanport/build/; - compile the glue; in runtime-linked mode merge it with the module objects and
the Lean runtime (
libc++, GMP, libuv) into one relocatable object; - archive
native/<goos>_<goarch>/lib<Module>.a; - generate
<pkg>.go,<pkg>_cgo.go,artifact.goandMANIFEST.json; - run
go build ./...to prove the result links (--verify, default on).
| Flag | Default | Description |
|---|---|---|
--target <goos/goarch> |
host | Build only this target. Must match the host in v0.1.1. |
--verify |
true |
Run go build ./... after generating (--verify=false to skip). |
--clean |
false |
Remove .leanport/ build intermediates first. |
--runtime <auto|none|linked> |
auto |
Force a boundary mode. none fails if the binding needs boxed types. |
Boundary modes:
none— runtime-free. Scalars only. The archive contains the module objects and a glue object with fail-closed stubs for dead-path runtime symbols. Measured 12–28 KB.linked— runtime-linked. SupportsStringandByteArrayin addition to scalars. The Lean runtime is merged into the archive. Measured ~29 MB.auto— chooseslinkedif any argument/result isstring/bytes, or if a live Lean runtime symbol remains after linking the project's own objects; otherwisenone.
--clean does not delete generated Go packages or archives; it only clears
intermediate objects.
Writes/refreshes lean/LeanPort/<Module>/SPEC.md for every module, listing all
of its exports. It is idempotent and never edits Policy.lean or Proofs.lean.
AGENTS.md is written once by leanport init; docs does not modify it.
Prints paths and versions for go, cc, lean, lake, nix, the
CGO_ENABLED setting, and — inside a project — the config, toolchain and Lean
prefix. Exits 1 if a required tool (go, cc, lean, lake) is missing or
cgo is disabled.
Prints leanport <version> (commit <sha>, built <date>). Release binaries are
built with these values injected by -ldflags.
schema = 1
[project]
name = "docsvc" # informational
lean_dir = "lean" # location of the Lean project
go_module = "example.com/docsvc" # read from go.mod on init
package_dir = "internal/verified" # generated bindings go here
targets = ["linux/amd64"] # default build targets
[lean]
toolchain = "4.29.1" # mirrors lean/lean-toolchain
[[binding]]
package = "authz" # generated Go package name
module = "Authz" # Lean module under LeanPort/
export = "leanport_authz_authorize" # C symbol produced by @[export]
go_name = "Authorize" # Go function name
args = ["bool", "bool", "bool", "action:Action"]
result = "bool"
# "auto" (default) chooses none/linked; force with "none" or "linked".
runtime = "auto"
# Named code tables become Go constant blocks.
actions = { Create = 0, Read = 1, Update = 2, Delete = 3, ViewAudit = 4 }actions is an inline table so it stays attached to its [[binding]] entry.
LeanPort's writer emits the equivalent [binding.actions] sub-table; both forms
parse.
The generator in v0.1.1 supports the following tokens:
| Token | Lean | Go | Mode | Generator |
|---|---|---|---|---|
bool |
Bool |
bool |
runtime-free | yes |
uint8/16/32/64 |
UInt8/16/32/64 |
uint8/16/32/64 |
runtime-free | yes |
int8/16/32/64 |
Int8/16/32/64 |
int8/16/32/64 |
runtime-free | yes |
usize |
USize |
uint |
runtime-free | yes |
float |
Float |
float64 |
runtime-free | yes |
float32 |
Float32 |
float32 |
runtime-free | yes |
rune |
Char |
rune |
runtime-free | yes |
string |
String |
string |
runtime-linked | yes |
bytes |
ByteArray |
[]byte |
runtime-linked | yes |
action:<Enum> |
UInt8 code |
<Enum> |
runtime-free | yes |
| sealed record | record | struct |
either | planned |
array:<T> / list:<T> |
Array/List |
[]T |
linked | planned |
option:<T> |
Option |
(T, bool) |
linked | planned |
except:<E>:<T> |
Except |
(T, error) |
linked | planned |
Records, arrays, Option and Except have been validated at the ABI level (see
architecture.md); the code generator does not emit them
yet. Unknown tokens fail leanport build with a type error, never with silently
wrong code.
| Code | Meaning |
|---|---|
0 |
Success. |
1 |
Check/build failure, link failure, or missing toolchain. |
2 |
Usage error (unknown command, bad flag, malformed config type). |
| Variable | Purpose |
|---|---|
LEANPORT_CC |
Override the C compiler used for module and glue objects. |
CGO_ENABLED |
Must not be 0; generated bindings are cgo packages. |