Axiom Lean 4 Proof Verification
Axiom provides cloud-based Lean 4 proof verification through the Axle API. It compiles and checks Lean code against a full Mathlib environment without requiring a local Lean installation -- verification results come back in seconds rather than the minutes it takes to build locally.
Reference Files
Read these as needed based on the task:
- references/axiom-configuration.md -- Setup, authentication, environment selection. Read this first if the user hasn't configured Axiom yet.
- references/axiom-api-reference.md -- All 14 API endpoints with parameters and response formats. Read when you need exact parameter names or response fields.
- references/axiom-cli-reference.md -- CLI commands and options. Read for exact flags and usage details when working with local files.
- references/axiom-best-practices.md -- Workflow guidance, scope limitations, and tips. Read when planning a multi-step workflow or hitting unexpected behavior.
Workflow
Step 1: Select the Right Tool
Match the user's intent to the appropriate endpoint:
| User wants to... | Endpoint | Notes |
|---|
| Verify a proof is correct | | Checks candidate proof against a formal statement |
| Check if code compiles | | Quick syntax and type checking |
| Understand proof structure | | Splits file into self-contained theorem units |
| Rename declarations | | Automatic reference updates throughout |
| Convert theorem/lemma | | Switch between and keywords |
| Stub out proofs | | Replace proofs with for scaffolding |
| Combine files | | Intelligent deduplication across files |
| Remove no-op tactics/haves | | Tactics that don't change proof state, unused haves |
| Remove post-completion tactics | | Tactics after proof is done, replace sorry, fix unsafe tactics |
| Extract have statements | | Promote inline to standalone lemma |
| Stub have bodies | | Replace bodies with |
| Extract sorry placeholders | | Turn into lemma stubs |
| Test if statement is false | | Attempts counterexample via Plausible |
| Standardize formatting | | Clean up sections, namespaces, comments |
When unsure which tool to use:
- Start with to see if the code compiles at all
- Use to understand what's in the file
- Use first if the file uses / blocks (these can cause issues with other tools)
Step 2: Execute
When working with local files, prefer the
CLI -- it reads files directly from disk, has simpler syntax, and can write output to files with
. The CLI reads
from the environment automatically. Note: CLI commands use hyphens (e.g.,
), while the HTTP API uses underscores (
). All code is sent to
for compilation against a full Mathlib environment -- the CLI is not local verification.
When constructing Lean code dynamically (generating content in scripts, CI/CD pipelines, or building code strings programmatically), use the HTTP API via curl or the Python client (
). The API accepts content as JSON strings, which is better suited for generated or in-memory code.
Check code compiles:
bash
axle check file.lean --environment lean-4.28.0 --ignore-imports
Verify a proof:
bash
axle verify-proof formal_statement.lean proof.lean \
--environment lean-4.28.0 --ignore-imports
Repair broken proofs:
bash
axle repair-proofs file.lean --environment lean-4.28.0 --ignore-imports \
--repairs remove_extraneous_tactics,apply_terminal_tactics
Disprove a conjecture:
bash
axle disprove file.lean --environment lean-4.28.0 --ignore-imports
Normalize a file (flatten sections/namespaces):
bash
axle normalize file.lean -o normalized.lean --environment lean-4.28.0 --ignore-imports
Extract theorems:
bash
axle extract-theorems file.lean --environment lean-4.28.0 --ignore-imports
Simplify theorems:
bash
axle simplify-theorems file.lean --environment lean-4.28.0 --ignore-imports
Rename declarations:
bash
axle rename file.lean --declarations '{"old_name": "new_name"}' \
--environment lean-4.28.0 --ignore-imports
Stub proofs with sorry:
bash
axle theorem2sorry file.lean --environment lean-4.28.0 --ignore-imports
Write transformation output to a file (works with normalize, repair-proofs, simplify-theorems, rename, etc.):
bash
axle normalize file.lean -o output.lean -f --environment lean-4.28.0 --ignore-imports
API example (for dynamically constructed code):
bash
curl -s -X POST https://axle.axiommath.ai/api/v1/check \
-H "Authorization: Bearer $AXLE_API_KEY" \
-H "Content-Type: application/json" \
-d "$(jq -n \
--arg content "$LEAN_CODE" \
'{content: $content, environment: "lean-4.28.0", ignore_imports: true}')" \
| jq '{okay, failed_declarations, lean_errors: .lean_messages.errors, tool_errors: .tool_messages.errors}'
For the full CLI command reference, see references/axiom-cli-reference.md. For the full API parameter reference for all 14 endpoints, see references/axiom-api-reference.md.
Step 3: Interpret Results
Every response includes two types of messages -- understanding both is key to helping the user:
- : Direct Lean compiler output. Errors here mean the Lean code itself has problems (type mismatches, tactic failures, unknown identifiers).
- : Axle-specific diagnostics. Errors here mean the tool couldn't process the request (import mismatches, unsupported constructs, timeouts). The field often contains unsolved goals when a proof fails -- always check this for debugging context.
Severity levels:
- Errors: Result may be unusable
- Warnings: Suspicious but non-fatal
- Infos: Timing/debug output, unsolved goals
For : Returns
(boolean) and
(list). The
flag reflects
compilation success only --
if the code compiles without errors (warnings like
don't affect it).
is empty when
is
. The
endpoint does
not detect sorry usage or other verification-level issues -- it only checks that code compiles. Use
to validate that proofs are complete.
For : Returns
(boolean) and
(list). The
flag reflects
proof validity --
only if the code compiles
and passes all verification checks (no sorry, signatures match, no disallowed axioms). Note the distinction:
- Compilation errors (tactic failures, syntax errors, name collisions): is , is empty. The errors appear in .
- Verification failures (sorry usage, signature mismatch, disallowed axioms): is , and the offending names appear in with details in .
- Fully valid proof: is and is empty. This is the only state that means the proof is both compilable and complete.
For transformation tools (
,
,
, etc.): These do not return
or
. Check that
is empty and inspect the
field for the transformed result.
For : Check
(list of refuted names) and
(dict mapping each theorem name to a human-readable outcome string). If a counterexample is found, the name appears in
and the
entry contains the counterexample. If disprove fails (the theorem may be true),
is empty and the
entry describes why the negation could not be proven.
Import handling: Always use
(CLI) or
(API) unless you have a specific reason not to (e.g., testing that exact imports are correct). Without this flag, import mismatches return a
string instead of the standard response format, which breaks JSON parsing and hides the actual verification result. Code snippets, code from different Lean/Mathlib versions, and proof-logic checks all require this flag.
responses: Several error conditions return
{"user_error": "...", "info": {...}}
instead of the standard response format. This includes import mismatches (when
is false), unrecognized declaration names in
, and other request-level validation failures. Always check for a
field before parsing
/
.
Common Multi-Step Workflows
Verify and fix a proof:
- -- see if it compiles
- If errors: -- attempt automatic fix
- again -- verify the repair worked
- -- confirm it proves the intended statement
Analyze and clean a file:
- -- standardize formatting first (flatten sections/namespaces)
- -- understand the structure
- with
remove_extraneous_tactics
-- remove tactics after proof is already complete
- -- remove unused haves and no-op tactics
- -- verify nothing broke
Scaffold a proof development:
- Write formal statements
- -- stub out proofs with (use parameter to target specific theorems)
- Fill in proofs incrementally
- after each proof to verify progress
- -- track remaining obligations (generates lemma stubs inserted before each sorry'd theorem)
- for final verification
Test a conjecture:
- -- look for counterexamples first
- If no counterexample found, attempt the proof
- incrementally as you build the proof
- when complete
Common Pitfalls
- Custom project attributes and constructs. Files from Lean projects often define custom attributes (e.g.,
@[category research open, AMS 11]
) and helper constructs (e.g., ) via project-specific imports. When replaces those imports with standard Mathlib, these custom constructs become unresolvable and produce compilation errors. Before submitting, strip custom attributes and project-specific constructs using sed or similar: sed 's/@\[category [^]]*\]//' file.lean
removes blocks; replace with or remove it entirely. Note: triggers a misleading "Candidate uses banned 'open private' command" tool error because the parser misinterprets the word inside the attribute as the command -- this is a false positive that disappears once the attribute is stripped.
- is off in Mathlib environments. Always declare type variables explicitly (e.g., or ). Implicit variables like without declaring will fail.
- Mathlib name shadowing. If your theorem names match existing Mathlib declarations (e.g., , , ), you'll get "already declared" errors and all transformation tools will silently return unchanged content with zero stats. The error appears only in , not -- you must inspect to notice the problem. Use to give theorems unique names, or prefix with a namespace.
- cannot see through opaque definitions. The tactic works on linear arithmetic over and , but it treats user-defined functions as opaque. If you define
def my_double (n : Nat) := n + n
and try to prove with , it will fail because doesn't know what computes. Use (or ) before to expose the definition.
- vs for cleanup. These serve different purposes:
- with : removes tactics that are no-ops (don't change the proof state at all)
- with
remove_extraneous_tactics
: removes tactics that appear after the proof is already complete
- For cleaning up redundant tactics, you usually want first, then .
- Sections and namespaces. , , and other transformation tools may produce non-compilable output when sections/namespaces are present because extracted names won't be fully qualified. Always run first to flatten these constructs. Note that preserves the original indentation from inside flattened blocks -- the output may look oddly indented but still compiles correctly. Caveat: may not update all references inside theorem bodies when flattening namespaces (e.g., may not become ). Always the normalized output and fix any unresolved references manually.
- requires fully-qualified names. The parameter must use fully-qualified names including namespace prefixes. For example, if is inside , use
{"Foo.my_thm": "Foo.new_name"}
, not . Using an unqualified name returns a ("Source name not found").
- Non-theorem commands in . The tool warns about any non-theorem command it encounters with
"Unsupported command kind ..."
. This includes , , , , and other non-declaration commands. These warnings are informational -- the tool still correctly extracts all theorem declarations and includes dependencies (including bindings, statements, etc.) in each theorem's standalone block.
- Always check both message types. Transformation tools can "succeed" (return content with zero errors) while the underlying code has compilation errors visible only in . Always inspect even when is clean. This silent failure mode applies broadly: any compilation error (custom attributes, missing imports, syntax issues, name shadowing) causes transformation tools to return unchanged content with zero stats. The only signal is non-empty .
- The environments endpoint uses (no prefix), while all tool endpoints use .