Hyperion AI / Products

Apex

A formal verification framework that turns what you meant into something Lean 4 can check — and tells you plainly when it can’t.

an English description of intent a test suite the source itself
theorem clamp_in_bounds (x lo hi : ℝ) (h : lo ≤ hi) :
  lo ≤ clamp x lo hi ∧ clamp x lo hi ≤ hi checked by the Lean 4 kernel, or reported as a gap
§1

What it is

Apex is developed at Hyperion AI and released as open source.

Apex is a formal verification framework for Python, written in Python, with Lean 4 as its proof engine. It reads what you have — prose specifications, docstrings, a test suite, the function body — unifies those into a single formal specification, generates Lean 4 theorem statements from it, and attempts to prove them automatically.

Where a proof succeeds, you have a mathematical guarantee that holds for every input, not a sample of them. Where a proof does not succeed, Apex produces a gap report: a specific, readable account of which obligation was not discharged and what would be needed to discharge it.

Both outcomes are the product. The framework is designed on the assumption that the second one happens more often, and that it is still worth having.

§2

The problem it addresses

Code is now generated faster than it can be read. A model produces a function in two seconds; a careful review of that function takes minutes, and reviewers do not scale with generation. The usual answer is more tests, but tests are sampling. A test suite tells you the function behaved on the inputs someone thought to write down. It says nothing about the inputs nobody thought of — which, for machine-written code, are exactly the ones that matter, because the author had no intuition to encode in the first place.

Formal verification answers the universal question rather than the sampled one. Its historical problem is not power but access: writing Lean by hand requires a skill that most working engineers do not have and cannot justify acquiring for a single module.

AI-generated code changes the cost–benefit of formal methods. The remaining barrier is not the prover; it is the on-ramp.

Apex sits on that gap. The insight is that language models are unreliable at deciding whether something is true, but useful at proposing a formal statement of what someone meant. That proposal is then handed to a system that is very good at deciding truth and has no opinions at all.

Lean 4 is the sole trust anchor.

Nothing a language model produces is believed. It is only ever a candidate, submitted to a kernel that accepts or rejects it on its own terms.

§3

Inputs, and why there are three

Most verification tools ask you to write a specification first. Apex assumes you already wrote one, three times over, in three incomplete forms:

English intent
Docstrings, comments, an issue description, a paragraph you type at the prompt. Rich in intent, weak in precision, and often the only place a precondition is ever recorded.
The test suite
Precise but partial. Each test is a concrete point on a curve nobody drew. Useful for pinning down edge-case intent and for catching a specification that contradicts observed behaviour.
The source
Total but silent about purpose. It says exactly what happens and nothing about what should. It also supplies the types, the control flow, and the definitions Lean will need.

Unification is where the interesting work happens. Three partial views of the same intent will disagree, and the disagreements are informative: a docstring that promises something the tests never check, a test that asserts behaviour the prose forbids. Apex surfaces those conflicts rather than silently picking one.

§4

The pipeline

English intent docstrings, prose Test suite concrete behaviour Source types, control flow 1 Ingest Parse each source into a common intermediate form. 2 Unify Reconcile the three views into one specification. Contradictions are recorded, not resolved silently. 3 Translate Emit Lean 4 definitions and theorem statements. The function is modelled; the claims become obligations. 4 Prove Automation searches; the kernel decides. The only stage whose verdict is trusted. 5 Report Discharged obligations, plus a gap report. Machine-readable and human-readable. Stages 1–3 propose. Stage 4 judges. Stage 5 explains.
Figure 1. The five stages. Everything above the black band is a proposal about what you meant; only the black band produces a verdict about whether it holds.
§5

The trust model

This is the design decision the whole framework rests on. Everything else is negotiable.

The architecture draws one hard line. On one side sits every component that guesses: the model that reads your prose, the heuristics that reconcile a test suite with a docstring, the tactic search that hunts for a proof. On the other side sits the Lean 4 kernel, which does not guess.

Artifacts cross that line in one direction only, and they cross as candidates. A proposed proof term is either accepted by the kernel or it is not, and no amount of model confidence changes the answer. This means a hallucinated proof is not a silent failure — it is a rejected term, which is a normal, visible, reportable event.

Proposal zone — nothing here is trusted Specification unification prose + tests + source → one spec Lean translation spec → theorem statements Tactic & proof search automation, retries, lemma lookup may be wrong at any time candidate proof term Lean 4 kernel small, fixed, independently auditable type-checks the term against the statement the only trust anchor Trusted base Accepted obligation discharged Rejected feeds the gap report the trust boundary
Figure 2. Correctness never depends on a model being right. It depends only on the kernel, which is small enough to audit and does not change between runs.
§6

Three outcomes, all of them useful

Each obligation Apex generates terminates in one of three states. A tool that only reports the first one would be nearly useless in practice, because on real code the first one is not the common case.

Obligation Proved ∎ Holds for every input satisfying the stated preconditions. Ship it. Gap Not proved, not refuted. Something is missing: an assumption, a lemma. Read the report. Refuted A concrete input breaks the claim. Handed back as a test. Fix the code, or the spec. A gap is a result. It is not an error, and it is not a failure of the run.
Figure 3. The middle branch is the one most tools hide behind a stack trace. Apex treats it as a first-class output with its own format and its own quality bar.
§7

The gap report

A gap report that says “proof failed” is worthless. The design constraint is that every gap must name something the reader can act on.

When automation cannot discharge an obligation, the interesting question is why not, and there are only a few honest answers: a precondition was never stated, a supporting lemma is absent, the specification is stronger than the code, or the search simply ran out of budget. Apex distinguishes these and says which one it hit.

In practice the most valuable gaps are unstated preconditions. They are the assumptions a human author held in their head and never wrote down — and, for generated code, assumptions nobody ever held at all.

Gap — unstated precondition

clamp_in_bounds : lo ≤ clamp x lo hi ∧ clamp x lo hi ≤ hi

Not provable as stated. When hi < lo, the function returns lo, which violates the upper bound.

The docstring says the bounds are “a valid range” but never constrains their order. No test exercises hi < lo. The source does not check it.

Suggested: add the hypothesis lo ≤ hi to the specification, or raise on invalid input in the source. Either resolves the obligation; they are different products.

That last line is the point. Apex does not decide which fix is correct, because the two fixes mean different things to whoever uses the function. It makes the choice visible and forces it to be made deliberately.

§8

A worked example

The input — an ordinary pure function with an ordinary docstring:

def clamp(x: float, lo: float, hi: float) -> float:
    """Constrain x to the range [lo, hi].

    Values below lo become lo; values above hi become hi;
    values already in range are returned unchanged.
    """
    if x < lo:
        return lo
    if x > hi:
        return hi
    return x

Two obligations fall out of that docstring. The first is a bounds claim, the second an identity claim — and the prose states both, in the two halves of its second sentence:

def clamp (x lo hi : ℝ) : ℝ :=
  if x < lo then lo else if x > hi then hi else x

theorem clamp_in_bounds (x lo hi : ℝ) (h : lo ≤ hi) :
    lo ≤ clamp x lo hi ∧ clamp x lo hi ≤ hi

theorem clamp_id_in_range (x lo hi : ℝ) (h₁ : lo ≤ x) (h₂ : x ≤ hi) :
    clamp x lo hi = x

The generated Lean 4 model and its two obligations. The hypothesis h : lo ≤ hi is the gap from §7, promoted into the statement.

The second theorem proves without difficulty. The first does not, until that hypothesis is added — and finding that hypothesis, rather than proving the theorem, is the work Apex actually saved.

§9

Surfaces

Illustrative usage. The command grammar is not fixed here.

Apex is delivered two ways, aimed at two different moments.

Command line

For running against a file or a package, in a terminal or in CI. The exit status distinguishes proved, gapped, and refuted, so a pipeline can decide what to do with each.

$ apex verify src/geometry.py --function clamp

  clamp_id_in_range      proved
  clamp_in_bounds        gap — unstated precondition (lo ≤ hi)

  1 proved, 1 gap, 0 refuted

MCP server

For the moment the code is written. Exposed over the Model Context Protocol, Apex becomes a tool a coding agent can call on its own output — so a model that has just generated a function can ask for a proof before proposing it, and receive a gap report it can act on. This is the closing of the loop the framework is named for: generation and verification in the same turn, with the verification half not trusting the generation half.

§10

Scope

The MVP is deliberately narrow. Pure Python functions only — no side effects, no mutation, no I/O, no global state. This is not a limitation to be apologised for; it is the region where automatic translation to Lean is tractable and where the proofs mean something clean.

In the MVPDeliberately out
Pure Python functionsEffectful code, mutation, I/O
Lean 4 as the only proof engineAlternative or additional solvers
CLI and MCPVS Code extension — a later phase
PythonJavaScript — a later phase
Gap reports as a primary outputSilent failure of any kind

JavaScript support and editor integration are both deferred to post-talk phases. Widening the language surface before the core translation and reporting are trustworthy would produce a tool that is broad and useless.