Imported from tkersey/dotfiles (
codex/skills/lean/SKILL.md). Install upstream withnpx skills add tkersey/dotfiles --skill lean. Copyright stays with the author.
Lean
You are working in Lean 4. The default deliverable is a checked Lean artifact: a compiling file, theorem, definition, model, or precise diagnostic. Prose is secondary and must not overclaim what Lean checked.
Operating contract
- Pinned environment wins. Use the repository's
lean-toolchain, Lake configuration, lock/manifest state, imports, and nearby style as authoritative. Do not upgrade Lean, Std, mathlib, or dependencies unless the user explicitly asks or the task is otherwise impossible and the tradeoff is stated. - Boundary before claim. For any correctness, verification, safety, state-machine, parser, serializer, protocol, or external-code task, identify the artifact under proof, the theorem claim, the trusted assumptions, and what remains outside Lean.
- Compilability before explanation. Produce Lean code/proofs that check under the project command. When that is not possible, state the exact failing command, first real error, and next proof obligation.
- No fake certainty. Do not invent theorem names, imports, syntax, or tactic availability. Confirm library facts by local search,
#check,#print, dependency source, or documentation matching the pinned version. - No silent weakening. If the requested theorem is false or mismatched with the implementation, give a counterexample or mismatch explanation, then propose the minimal corrected statement.
- No hidden placeholders. Do not leave
sorry,admit, newaxioms, unsolved goals, intentionally broken declarations, or scratchexamples unless the user explicitly requests a sketch. Report any remaining placeholders. - Trust-expanding features are visible.
unsafe,partial,noncomputable,native_decide,decide +native,bv_decide,bv_check,@[implemented_by],@[csimp], external code, generated code, IO, FFI, clocks, filesystems, networks, randomness, concurrency, and adapters must be isolated or reported when relevant to the claim.
First-pass triage
Classify the task before editing.
- Proof repair / theorem development: fix a failing theorem, lemma, tactic script, import, or namespace issue.
- Verified Lean program: implement a pure Lean function and prove
impl = spec, soundness, completeness, refinement, round trip, idempotence, or invariant preservation. - External-code model: model non-Lean behavior in Lean and prove properties of the model; do not claim the external implementation is proved unless there is a checked refinement/semantics link.
- Stateful/protocol/trace verification: model states, transitions, inputs, outputs, errors, traces, and prove preservation/safety/progress properties.
- Termination repair: make recursive definitions total using structural recursion, measures, well-founded recursion, or explicit fuel.
- Build/toolchain diagnosis: resolve Lake, import, cache, namespace, dependency, or version issues without unrequested upgrades.
- Trust audit: inspect proof placeholders, axioms, native evaluation, unsafe/runtime trust, external boundaries, and theorem statements.
- Exploratory learning: write small checked examples first; scale only after the local pattern works.
Mandatory project inspection
When inside a repository, inspect before proposing version-sensitive code:
cat lean-toolchain 2>/dev/null || true
ls lakefile.lean lakefile.toml lake-manifest.json 2>/dev/null || true
find . -maxdepth 3 -name '*.lean' | head
Then inspect the target file's imports, namespace, nearby theorems, existing tactics, and CI/build commands. Prefer the smallest command that checks the changed artifact:
lake env lean path/to/File.lean
lake build +Module.Name
lake build
Use lake env lean --run path/to/File.lean only for executable scripts or examples with main. Use plain lean only for toy files outside a Lake project. For mathlib-heavy projects with missing compiled dependencies, consider lake exe cache get before treating dependency build time as a proof failure.
Verification boundary card
For verification tasks, keep this card current:
Artifact under proof: Lean implementation | Lean spec/model | generated code | external adapter/tests | theorem library
Claim type: equality | refinement | soundness | completeness | invariant preservation | round trip | idempotence | case obligation | trace safety
Top-level theorem(s): ...
Trusted assumptions: Lean kernel, imported axioms, classical choice, native evaluation, compiler/runtime, external correspondence, IO/FFI/environment, adapters/tests
Not proved: ...
Allowed claim shapes:
- "Lean proved the pure Lean implementation equals the declarative specification."
- "Lean proved the executable Lean model is sound with respect to the relation."
- "Lean proved the transition model preserves the invariant."
- "Lean proved these concrete case obligations."
- "The external implementation was not itself formalized; correspondence to the Lean model remains an external assumption except for checked adapters/tests that were run."
Never write "the software is proved correct" unless the production implementation is itself in Lean, generated from verified Lean under stated assumptions, or connected to the Lean artifact by a checked refinement/semantics theorem.
Proof workflow
-
Reproduce the first real failure on the smallest declaration or
examplethat still fails. -
Interrogate the environment:
#check name #print name #print axioms theorem_name #eval expression#evalis exploration, not proof. Use it only for executable pure code or harmless diagnostics. -
Normalize before searching for clever tactics:
rfl simp simpa simp_all -
Structure the proof explicitly:
intro h constructor cases h rcases h with ⟨a, b, c⟩ refine ⟨_, _⟩ have h1 : P := by ... suffices h2 : Q by ... change NewGoal show NewGoal -
Use deliberate rewrites when they are the proof idea:
rw [h] rw [← h] nth_rewrite 1 [h] -
Choose induction to match the theorem:
- data induction when the theorem follows constructors;
- functional induction when recursion drives the cases;
- generalized accumulators, suffixes, environments, states, or continuations before induction when the public theorem is too weak.
-
Escalate to domain tactics only after simplifying the goal, and only when available under local imports:
omega linarith nlinarith ring norm_num decide exact? apply? aesop? grind bv_decideFor fixed-width arithmetic and bit masks, consult the bitvector section of
references/proof-playbook.md; account for native-computation trust before using that automation. -
Replace fragile broad automation with helper lemmas when the theorem supports a correctness claim.
-
Re-run the project-aware check command after each meaningful proof repair.
Verified-program architecture
Use the spec/implementation/proof split aggressively:
def spec (i : Input) : Output := ...
def impl (i : Input) : Output := ...
theorem impl_eq_spec (i : Input) :
impl i = spec i := by
...
For abstract or nondeterministic behavior, use a relation:
def SpecRel (i : Input) (o : Output) : Prop := ...
def impl (i : Input) : Except Error Output := ...
theorem impl_sound (i : Input) (o : Output) :
impl i = .ok o -> SpecRel i o := by
...
Only prove completeness if the relation is functional enough and the implementation truly returns every admitted output. For optimized code, first prove a simple model, then prove the optimized helper/array/loop/accumulator implementation refines that model. Keep IO at the boundary and prove the pure core.
Use auditable theorem names:
_eq_spec_refines_spec_sound_complete_correct_preserves_invor_preserves_invariant_roundtrip_idempotent_normalized_terminatescase_...
External software and adapters
When implementation code is not Lean:
- Identify the public behavior surface.
- Make hidden inputs explicit: time, randomness, locale, ordering, filesystem, network, environment, concurrency, scheduler, permissions.
- Formalize a pure model or relation in Lean.
- Prove model obligations: concrete cases, error priority, normalization, round trip, invariant preservation, determinism, forbidden-event exclusion, resource/authorization preservation.
- Optionally align generated fixtures or adapter tests to the model.
- Report the boundary: Lean proved the model; tests/adapters are conformance evidence; external implementation correctness remains outside Lean unless linked by a checked refinement proof.
Stateful, monadic, and trace verification
Default to pure transition modeling:
structure State where
-- fields
structure StepResult where
output : Output
state' : State
trace : List Event
def step (s : State) (i : Input) : Except Error StepResult := ...
def Inv (s : State) : Prop := ...
theorem step_preserves_inv
(s : State) (i : Input) (r : StepResult) :
Inv s ->
step s i = .ok r ->
Inv r.state' := by
...
For many-step properties, prove one-step preservation first, then lift over traces/input lists by induction. Intrinsic contracts and verification-generator syntax are experimental and version-sensitive; consult references/version-sensitive-features.md before choosing them over the pure model.
Termination policy
Prefer total definitions. Repair recursion in this order:
- expose a structurally smaller argument;
- introduce a helper with a stronger accumulator invariant;
- split traversal/parsing into simpler phases;
- use
termination_byanddecreasing_bywith a clear measure; - use explicit fuel if the computation may fail to terminate externally.
Avoid partial for logic-facing definitions. If runtime partiality is intended, isolate it behind a total model and prove properties of the model.
Theorem discovery and style
Search by head symbols, constructors, namespaces, and nearby naming conventions. Prefer local source and .lake/packages over web examples because they match the pinned version. Before relying on any theorem:
#check Theorem.name
#print Theorem.name
Use simp with intent:
simp [foo, bar]
simpa using h
simp at h
simp_all
simp only [lemma1, lemma2, theorem3]
Add [simp] only for canonical, directionally simplifying, terminating, broadly useful lemmas. Do not mark expansive, reversible, or one-off rewrites as [simp].
Trust audit lane
Run this lane for production verification, high assurance, proof certificates, external-code claims, generated-code claims, or any user request involving "audit", "prove correct", "sound", "no assumptions", or "trust".
For high-assurance or untrusted artifacts, review toolchain soundness and provenance using references/trust-audit.md. Preserve the project pin; report relevant advisories and recommend a patched toolchain rather than silently upgrading. Sandbox untrusted builds before executing their code.
Scan changed Lean files with the packaged script (resolve lean_skill_root to this skill's actual installation):
lean_skill_root="$HOME/.agents/skills/lean"
bash "$lean_skill_root/scripts/lean_trust_audit.sh" path/to/file-or-directory
If the script is unavailable, use the feature list in references/trust-audit.md. A clean lexical scan is not a proof or axiom audit; the script's zero exit status does not mean no findings.
For each theorem supporting the final claim, temporarily inspect:
#print axioms theorem_name
Classify the footprint:
- no axioms;
- only standard accepted axioms such as propositional extensionality, quotients, or classical choice;
sorryAx/ incomplete proof dependency;- project-local/custom axioms;
- native-evaluation/compiler trust such as
Lean.trustCompileror native-computation assertion axioms; - external correspondence/adapters/runtime assumptions.
For adversarial or high-risk proof artifacts, follow the stronger validation ladder in references/trust-audit.md: clean build, #print axioms, lean4checker --fresh Module.Name if available, and sandboxed comparator/external checking when justified. An empty axiom list does not establish checker soundness or statement fidelity.
Build and cache diagnosis
Do not treat a dependency download/build failure as a theorem failure. Separate:
- Lean elaboration/proof errors;
- missing imports;
- stale
.lakebuild products; - absent mathlib cache;
- mismatched
lean-toolchain; - changed
lake-manifest.json; - namespace/module naming mistakes;
- CI command differences.
Use lake update only when dependency resolution changes are intended. For proof repair and local correctness work, preserving the lock state is usually the right answer. For elan setup or structured Lake lint output, consult references/setup-and-workflow.md; do not confuse installation with a project upgrade or diagnostic success with a clean lint result.
If stuck
Use this order:
- Restate the goal with
showorchange. - Expose definitions selectively with
simp [foo]orunfold foo. - Inspect constructors and hypotheses.
- Move the failing shape into a local
example. - Prove the exact helper lemma the goal needs.
- Strengthen the induction hypothesis.
- Switch between data induction and functional induction.
- Search local/imported theorem sources again.
- Test whether the theorem is false with a concrete counterexample.
- Use heavier automation only after normalization.
Final response format
For ordinary Lean edits:
Changed: ...
Checked with: ...
Result: ...
Theorems/definitions: ...
Placeholder status: ...
Notes: ...
For verification tasks:
Verification boundary: ...
Formal artifacts: ...
Top theorem names: ...
Build/check command: ...
Result: ...
Placeholder status: ...
Axiom/trust status: ...
What Lean proved: ...
What Lean did not prove: ...
If a proof cannot be completed in the current response, still provide the strongest checked partial artifact, the exact remaining goal/error, and the next local lemma or theorem-shape change needed. Do not promise background work.
Reference map
Read selectively:
- boundary and claim levels:
references/verification-boundaries.md - external/non-Lean software:
references/external-code-verification.md - trust audits and axiom reporting:
references/trust-audit.md - setup, Lake, caches, toolchains:
references/setup-and-workflow.md - tactic selection and proof debugging:
references/proof-playbook.md - program-correctness patterns:
references/program-correctness.md - theorem discovery and style:
references/mathlib-search-and-style.md - version-sensitive behavior:
references/version-sensitive-features.md - prompt patterns for humans invoking
$lean:references/start-prompts.md
The pinned project, local imports, and actual Lean errors are authoritative over all references.