View the leaderboard → · Submit a solution →
This repository is a comparator-based Lean benchmark for formal mathematics.
Benchmark authors write trusted problem statements once in shared Lean modules, and the
tooling generates one comparator workspace per problem under generated/.
A submission is scored entirely by comparator results: a problem counts as solved iff comparator accepts the submitted solution.
The main user-facing entrypoint is:
lake exe lean-eval --helpUse this path if you are adding or editing benchmark problems.
lake exe cache get
cache_env="$(bash scripts/fetch_dependency_caches.sh --restore .)" && eval "$cache_env"
lake buildThe second line downloads the oleans of Tau Ceti, which some problems import, instead of compiling it, and fails if any would have to be compiled. This requires lean-eval to pin exactly the Lean toolchain and Mathlib revision of the pinned Tau Ceti commit, which the script checks.
Put the statement in one of the shared modules under LeanEval/ and mark it with
@[eval_problem].
@[eval_problem]
theorem my_new_problem : ... := by
sorryCurrent source modules live in topic folders such as:
LeanEval/NumberTheory/LeanEval/Topology/LeanEval/ComplexAnalysis/LeanEval/EasyProblems.lean
Each tagged declaration must be listed by exactly one file under
manifests/problems/. One file per problem,
named <id>.toml, with top-level keys (no [[problem]] wrapper). The
filename stem must match the id field. The holes array names every
@[eval_problem]-tagged declaration in the module that the problem
owns; for the common single-theorem case it has one element.
# manifests/problems/my_new_problem.toml
id = "my_new_problem"
title = "My new problem"
group = "formalization-evaluation"
status = "draft"
visible = true
statement_revision = 1
tags = []
module = "LeanEval.SomeModule"
holes = ["my_new_problem"]
submitter = "Your Name"
notes = "Optional notes."
source = "Optional citation or URL."
informal_solution = "Optional proof sketch or reference."The required fields are:
id(must equal the filename stem)titlegroupstatusvisiblestatement_revisiontagsmoduleholessubmitter
The one-file-per-problem layout means two PRs adding distinct problems never conflict on the manifest.
See Catalog metadata for lifecycle history, the tag registry, append-only named sets, and the deterministic v1 evidence tool.
The manifest is the only entry point CI has into LeanEval/, so a module
no manifest names is never built. validate-manifest therefore rejects any
.lean file under LeanEval/ that is neither named by some module field
nor imported (directly or transitively) by a module that is, and rejects any
file in manifests/problems/ that is not a .toml.
A problem may bundle several defs, instances and theorems — list
them all in holes. Comparator then asks the participant to fill every
listed declaration in their Submission.lean. Two conventions:
- Name every instance. The generator addresses holes by their
declaration name, and Lean's auto-generated names for anonymous
instances (e.g.instTopologicalSpaceJacobian) are not stable. Useinstance instAddCommGroup : ... := sorryrather thaninstance : ... := sorry. - Use
holeseven for one declaration. There is notheorem = "..."shorthand; a singleton hole is justholes = ["my_thm"].
See LeanEval/Sandbox/DefHoleExample.lean
and LeanEval/Sandbox/InstanceHoleExample.lean
for the smallest working examples, or
LeanEval/Geometry/JacobianChallenge.lean
for a realistic multi-hole problem.
lake exe lean-eval validate-manifest
lake exe lean-eval check-problem-buildvalidate-manifest checks that @[eval_problem] declarations and manifest entries
match, and that no module under LeanEval/ escapes the manifest's reach.
check-problem-build builds the problem modules so warning-producing Lean changes
do not slip through. Both catch the most common mistakes before a CI roundtrip;
on a clean checkout, validating the full problem inventory can take some time.
That's it — push your branch and open a PR. CI regenerates the comparator workspaces
under generated/ and verifies they build, so you do not need to commit anything
under generated/ yourself. Once the PR merges, a separate workflow regenerates
generated/ on main and pushes the result.
If CI fails with a generation or build error, you'll need to fix the source. The fastest local equivalent is:
lake exe lean-eval generate --problem my_new_problem
lake exe lean-eval check-generated-builds --problem my_new_problemUse this path if you want to prove benchmark problems without touching the trusted benchmark files.
Generated workspaces live under generated/, one directory per problem. The current
catalog is summarized in generated/index.json.
Examples:
generated/two_plus_two/generated/list_append_singleton_length/generated/cyclotomic_integer_house_le_two/
Copy a clean starter workspace:
lake exe lean-eval start-problem two_plus_twoThat creates workspaces/two_plus_two/ by default. You can also pass a destination:
lake exe lean-eval start-problem two_plus_two /tmp/two_plus_twocd workspaces/two_plus_two
lake updateSolver-owned files are:
Submission.leanSubmission/Helpers.lean- any additional Lean files you add under
Submission/
Trusted files you should not edit in the normal solver workflow are:
Challenge.leanSolution.leanconfig.jsonlakefile.toml
Challenge.lean contains the benchmark statement. Solution.lean is the fixed bridge
that tells comparator to check your theorem from the Submission namespace.
Solutions may import LeanPool.* modules from Lean Pool
in Submission.lean or Submission/ helpers. The pinned dependency is included in
all generated workspaces via solution-dependencies.json. Problem statements and
their local helpers may not import it; workspace generation rejects these imports.
Comparator and nanoda checks apply as usual.
lake testThe pinned Lean toolchain includes Lake comparator, leanexport, the Lean
checker, and NanoDa. The trusted test driver always requires both Lean and NanoDa.
The only additional verifier dependency is bubblewrap on Linux with user namespaces.
Install bubblewrap 0.12.0 using the same checksum-verified installer as CI (requires Meson, Ninja, libcap development headers, curl, and a C compiler):
# Run from the lean-eval repository root, outside a problem workspace.
export COMPARATOR_BWRAP="$(bash scripts/install_bwrap.sh "$PWD/.tools/bubblewrap")"On Ubuntu 24.04 the installer loads an executable-specific AppArmor profile using
sudo when user namespaces are restricted. On a system where bubblewrap 0.12.0
is already configured, put bwrap on PATH or set COMPARATOR_BWRAP to its
absolute path.
Check the installation against the starter problem:
lake exe lean-eval check-comparator-installationRun lake test in a problem workspace to invoke the toolchain's
lake comparator. It pins the exporter and checker to the same Lean release,
avoiding separate exporter builds and incompatible olean formats. When changing
toolchains, refresh the dependency caches and remove stale workspace build outputs.
The trusted driver uses Lake's LAKE and LEAN_SYSROOT settings and removes
workspace/cache directories from executable and library search paths before
starting comparator. LEAN_PATH remains available for module imports.
Install bubblewrap and the toolchain outside submission-writable directories.
The old COMPARATOR_BIN, COMPARATOR_LANDRUN, COMPARATOR_LEAN4EXPORT,
and COMPARATOR_NANODA overrides are no longer used.
Root scoring makes the trusted shared package cache visible read-only inside Lake's sandboxes. Direct local workspaces can keep their own dependencies; no cache wrapper is needed for that layout.
From the repo root:
lake exe lean-eval run-eval
lake exe lean-eval run-eval --jsonThe scorer prefers workspaces/<problem-id>/ when present and falls back to
generated/<problem-id>/ otherwise.
For current instructions to submit a solution, start at the stable page:
That page is the primary authenticated submission path from
2026-09-02T06:57:10Z. The application itself is at
https://lean-eval-submission-server.lean-eval.workers.dev/; this change of
origin is expected.
Submission issue
intake
remains available as a fallback through at least 2026-09-30T06:57:10Z, four
weeks after the overlap began. Conditional on stable operation, adequate
adoption, no unresolved severity-high incident, and a reconciled final corpus,
that is the planned retirement time. This notice was issued at
2026-09-02T23:06:35Z, more than two weeks in advance. Retirement will be
postponed if any gate is not satisfied.
Scheduled release is recommended for authenticated intake, while submitters may keep accepted source private instead. Once selected, scheduled release cannot be changed back to private. Accepted source is published under the Apache License 2.0 exactly two UTC calendar months after acceptance. A submitter who initially chooses private source may later change that choice once to scheduled release.
The service takes a problem ID and resolves its group and current statement revision from the protected LeanEval catalog; clients do not supply those canonical fields. Formalization problems must be visible and active. Software-verification problems may be visible and draft or active. Public source repositories must use scheduled publication; withholding is available only for private repositories.
Before acceptance, the submitter explicitly authorizes private fetch, archive, build, and execution of the exact commit, indefinite encrypted retention even after rejection or failure, and public display of the result and submitted metadata. Do not submit secrets. Every new request is archived with a fresh per-submission key envelope before evaluation, and the service evaluates only the selected problem. Exact resubmissions by the same owner return the original submission, and each owner may have at most four active submissions.
This repository (leanprover/lean-eval) holds only the problem set and the
comparator/sandbox integration.
Participants may use Mathlib freely.
If a proof needs helper code that is not already in Mathlib, that code must be included
inside the submission workspace itself. Multi-file submissions are allowed through
Submission.lean and extra local modules under Submission/.
For benchmark-repo submissions (a PR that edits a generated/ workspace in place),
validate changed paths with:
lake exe lean-eval validate-submission --file generated/two_plus_two/Solution.leanThe current validator accepts:
- modifications to
generated/<problem-id>/Solution.leanandgenerated/<problem-id>/Submission.lean - additions, modifications, deletions, renames, or copies of
.leanfiles undergenerated/<problem-id>/Submission/ - additions (only) of markdown files anywhere inside
generated/<problem-id>/, other than the generatedREADME.md - additions (only) of a top-level
generated/<problem-id>/LICENCEorgenerated/<problem-id>/LICENSEfile
In practice, solvers should normally work in Submission.lean and Submission/.
LeanEval/: trusted authored problem statementsmanifests/problems/: one TOML file per problem, named<id>.tomlmanifests/tags.toml: stable tag registrymanifests/sets/: versioned and optionally frozen named problem setsgenerated/: generated comparator workspacesscripts/: generation, validation, and scoring helpersPLAN.md: deferred design and roadmap notes
bash scripts/fetch_dependency_caches.sh --restore . restores imported TauCeti
modules without permitting compilation. Downloads have bounded retries and
timeouts and use temporary files to keep interrupted transfers out of the
artifact cache. Cache-only restoration is retried once; if it still fails, the
script prints verbose diagnostics before stopping. Verify the pinned versions
and published cache when outputs are missing. The exported cache settings keep
the download wrapper active for subsequent trusted builds.
For a local health pass over the repository:
lake exe lean-eval validate-manifest
lake exe lean-eval check-problem-build
lake exe lean-eval generate --check
lake exe lean-eval check-generated-builds
lake exe lean-eval run-evalThere is also an end-to-end workflow self-check:
lake exe lean-eval check-eval-workflow