Kernel
The kernel module gives Python direct access to Lean 4’s type-checker,
elaborator, and tactic engine. It wraps ~30 @[python] functions from
LeanPy.Kernel into two classes: Kernel (the environment facade)
and GoalState (an opaque proof state handle).
Setup
Any Lean project that imports LeanPy.Kernel automatically has the
kernel surface available. On the Python side:
from lean_py import LeanLibrary
from lean_py.kernel import Kernel
lib = LeanLibrary.from_lake("path/to/lean", "MyLib", build=True)
k = Kernel(lib)
Loading an environment
Before any queries, load one or more Lean modules:
>>> k.init_search("")
>>> k.load(["Init"])
>>> k.is_loaded()
True
>>> k.decl_count()
8947
init_search sets the search path (empty string uses the default
toolchain path). load imports one or more modules — pass
["Init", "Mathlib.Tactic.Omega"] to get multiple.
Querying declarations
Once loaded, the full Lean environment is queryable:
>>> k.decl_exists("Nat.succ")
True
>>> k.decl_type("Nat.succ")
'Nat → Nat'
>>> k.module_of("Nat.succ")
'Init.Prelude'
>>> k.search("add_comm")
['Nat.add_comm', 'Int.add_comm', ...]
catalog() returns all declaration names. all_decls() returns them
including internal names. decl_value retrieves the definition body.
Elaboration
The kernel can elaborate, reduce, and decide:
>>> k.infer_type("Nat.succ Nat.zero")
'Nat'
>>> k.whnf("(fun x => x + 1) 4")
'5'
>>> k.decide("1 + 1 = 2")
'true'
expr_echo returns both the elaborated expression and its type:
>>> expr, ty = k.expr_echo("(1 : Int) + 1")
>>> expr
'@HAdd.hAdd Int Int Int (@instHAdd Int Int.instAdd) ...'
>>> ty
'Int'
This is useful for discovering the fully-elaborated form of Lean
expressions — for instance, the exact instance names needed when building
Lean.Expr trees programmatically.
Creating goals and running tactics
This is the heart of the kernel facade. Create a goal from a type string, then apply tactics step by step:
>>> state = k.goal_create("∀ n : Nat, n + 0 = n")
>>> state.n_goals()
1
>>> state.is_solved()
False
>>> print(state.pretty())
⊢ ∀ (n : Nat), n + 0 = n
Apply a tactic:
>>> result = state.try_tactic("intro n")
>>> result.ok
True
>>> result.status
'success'
>>> print(result.state.pretty())
n : Nat
⊢ n + 0 = n
Close the proof:
>>> result2 = result.state.try_tactic("simp")
>>> result2.state.is_solved()
True
Failed tactics return result.ok == False with diagnostic messages:
>>> bad = state.try_tactic("exact rfl")
>>> bad.ok
False
>>> bad.messages
['type mismatch...']
Prograde tactics
Beyond try_tactic, structured proof construction is available:
result = state.try_have("h", "n = n") # have h : n = n := ?
result = state.try_let("x", "Nat") # let x : Nat := ?
result = state.try_define("x", "42") # let x := 42
result = state.try_draft("Nat.add_zero n") # may leave sorry subgoals
Conv and calc modes
Enter conversion or calculation mode, then exit when done:
conv_state = state.conv_enter().state
# ... apply conv tactics ...
final_state = conv_state.fragment_exit().state
Goal state lifecycle
Goal states support serialisation, branching, and merging:
# Pickle to disk and restore later
state.pickle("/tmp/goal.bin")
restored = k.goal_unpickle("/tmp/goal.bin")
# Branch: apply different tactics to the same state
branch_a = state.try_tactic("intro n").state
branch_b = state.try_tactic("intros").state
# Continue: merge a branch back
merged = state.continue_with(branch_a)
# Resume with specific goal names
resumed = state.resume(["_uniq.42"])
Environment serialisation
The entire Lean environment can be saved and restored:
k.env_pickle("/tmp/env.bin")
k.env_unpickle("/tmp/env.bin")
Frontend processing
Process raw Lean source code against the current environment:
>>> k.process("def myFn : Nat := 42\\n")
>>> state, msg = k.collect_sorrys("def f : Nat := sorry\\n")
>>> state.pretty()
'⊢ Nat'
collect_sorrys extracts all sorry placeholders as goals — useful
for AI-driven proof completion.
API reference
- class lean_py.kernel.Kernel(lib: Any) None[source]
Bases:
objectThe kernel facade.
Wraps a
LeanLibrarywhose Lean source has importedLeanPy.Kerneland exposed the standard@[python]surface.Example:
from lean_py import LeanLibrary from lean_py.kernel import Kernel lib = LeanLibrary.from_lake("path/to/project", "MyLib") k = Kernel(lib) k.init_search("") k.load(["Init"]) s = k.goal_create("∀ n : Nat, n + 0 = n") print(s.pretty())
- decide(src: str) str[source]
Returns
"true"/"false"/"<undecided>"/"<elab: ...>"etc.- Return type:
- goal_create(type_str: str) GoalState[source]
Create a new goal state from a type expression string. Raises
LeanErroron parse / elaboration failure.- Return type:
- goal_unpickle(path: str) GoalState[source]
Load a goal state previously serialised with
GoalState.pickle().- Return type:
- find_source_path(module_name: str) str[source]
Locate the
.leansource file formodule_name.- Return type:
- class lean_py.kernel.GoalState(kernel: Kernel, handle: Any) None[source]
Bases:
objectOpaque handle to a Lean
GoalState. Methods dispatch back into the underlying Lean library.- try_have(binder_name: str, type_str: str) TacticResult[source]
Equivalent to
have <binder_name> : <type_str> := ?.- Return type:
- try_let(binder_name: str, type_str: str) TacticResult[source]
Equivalent to
let <binder_name> : <type_str> := ?.- Return type:
- try_define(binder_name: str, expr_str: str) TacticResult[source]
Equivalent to
let <binder_name> := <expr_str>.- Return type:
- try_draft(expr_str: str) TacticResult[source]
Substitute the goal with an expression that may contain sorrys, leaving the sorrys as fresh subgoals.
- Return type:
- pickle(path: str) None[source]
Serialise the goal state to disk via Lean’s
saveModuleData. Round-trips withKernel.goal_unpickle(). Raises on error.- Return type:
- replay(src: GoalState, src_prime: GoalState) GoalState[source]
Merge differential
src → src_primeontoself(the dst).- Return type:
- class lean_py.kernel.TacticResult(status: str, messages: list[str], state: GoalState | None) None[source]
Bases:
objectResult of running a tactic.
- status
one of
"success","failure","parseError","invalidAction".
- messages
zero or more diagnostic / error messages.
- state
the new
GoalStateifstatus == "success", elseNone.