The Python SDK, completely
The MCP server lets an AI assistant use Lemma. This page is for when you want to use Lemma directly in your own Python code — in a script, a Jupyter notebook, or an automated test. It does the same checks, just called straight from Python instead of through an AI.
Everything here reads the same cards and runs the same checker as the MCP server — there’s no second, different copy of the logic.
flowchart TD
subgraph SDK["the artano-lemma library"]
CA[browse the cards]
VA[validate a card]
EN[check a formula]
TL[the eight tool functions]
CL[talk to a running server]
end
Cards[(cards)] --> CA
CA --> VA --> EN
classDef c fill:#1e3a5f,stroke:#4a90d9,color:#fff;
class EN c;
Install it
In a terminal:
pip install artano-lemma(If you’re working inside the project’s own code, use pip install -e ./sdk-py
instead, which installs your local copy.)
If you want the engine to prove limit and conservation claims rather than record them, add the optional extra:
pip install "artano-lemma[symbolic]"The lemma command
Installing the library also gives you a small command you can type in the
terminal, called lemma, with seven sub-commands:
| Type this | And it… |
|---|---|
lemma verify <card> … | checks a finished result against what the card declares |
lemma crosscheck <card|file> | checks a proposed card, from the corpus or a draft |
lemma list | lists the cards |
lemma show arrhenius-rate-law | prints one card in full |
lemma paths | shows where the cards and template live on disk |
lemma authors <card> | shows who a card credits |
lemma serve | runs Lemma as a tool server (the Python version) |
Try lemma list first — it’s the quickest way to see what’s in the library.
Browse the cards from code
The most common thing: load the cards into your program and look around. Each line below is explained in the comment after it:
from artano_lemma import load_cards, find_card, filter_cards, domains
cards = load_cards() # load every cardprint(len(cards), "cards across", len(domains(cards)), "subjects")# -> 40 cards across 22 subjects
chem = filter_cards(domain_prefix="chemistry", cards=cards) # only chemistryone = find_card("arrhenius-rate-law", cards) # one specific cardprint(one.name, "·", one.formulaTeX) # its title and formulaload_cards() hands you the cards as Python objects you can read. filter_cards
narrows by kind or subject; find_card grabs one by its id (or returns nothing
if it doesn’t exist). This whole snippet is the runnable file
examples/browse_cards.py.
Check that a card is well-formed
This is the same “does it fit the template?” check from the Cards page, but in Python:
from artano_lemma import is_valid_card_payload, parse_card, CardValidationError
is_valid_card_payload(my_card) # -> True or Falsetry: parse_card(my_card) # turns it into an object, or complainsexcept CardValidationError as e: for problem in e.issues: # each problem, in plain text print(problem.path, problem.message)A broken card lists every problem (e.g. 'formulaTeX' is a required property).
Runnable version:
examples/validate_card.py.
Check a formula (the cross-checker)
This runs the same verification the engine page describes:
from artano_lemma import load_cards, parse_card, run_hypothesis_checks
corpus = load_cards()card = parse_card({ "kind": "hypothesis", "id": "candidate-ke", "version": "0.1.0", "name": "Kinetic energy", "proposal": "E = half m v squared", "proposedFormulaTeX": "E", "origin": "llm", "references": ["..."], "checks": {"dimensional": { "lhsLabel": "E", "lhsDims": {"M":1,"L":2,"T":-2}, "rhsLabel": "half m v^2", "rhsDims": {"M":1,"L":2,"T":-2}, "expr": "(1/2)*m*v**2", "symbols": {"m":{"M":1}, "v":{"L":1,"T":-1}}, }},})result = run_hypothesis_checks(card, corpus=corpus)print(result.overall.severity) # -> NONE (i.e. green / looks correct)You can also use just the units-working-out part on its own:
from artano_lemma import derive_dims, stringify_dimsprint(stringify_dims(derive_dims("(1/2)*m*v**2", {"m":{"M":1}, "v":{"L":1,"T":-1}})))# -> L^2·T^-2·M (i.e. energy)The tool functions
The corpus and verification tools the AI assistant uses are also ordinary Python functions — handy if you want their nicely-formatted text directly:
from artano_lemma import ( cards_list, cards_get, ops_get, # browse hypothesis_crosscheck, # check a proposed card usce_check, series_check, # check a finished run convergence_check, agreement_check,)
cards_list(corpus=corpus) # the catalogue, as textcards_get("arrhenius-rate-law", corpus=corpus) # one card, as textops_get("slurm-marenostrum5-gpp-compute", corpus=corpus) # a template, as texthypothesis_crosscheck(id="free-fall-with-linear-drag") # a verdict on a proposalusce_check(id="ideal-gas-law", output={"gasConstant_J_per_molK": 8.3145})series_check(id="density-of-states", series={"epsilon": [-1, 0, 1], "g": [0.0, 1.2, 0.4]})convergence_check(id="runge-kutta-4", refinement=[[0.1, 1e-7], [0.05, 6.25e-9]])agreement_check(id="cross-method-reproducibility", outputs={"a": {"latticeConstant_A": 5.470}, "b": {"latticeConstant_A": 5.475}})These are the same eight tools the Python MCP server (lemma serve)
exposes, and they render byte-identical text to the Node server’s. That
matters because the two servers are drop-in alternatives — you pick one by
changing a single command in your assistant’s config, and a verdict that read
differently depending on which you installed would make that choice visible when
it should be invisible.
Runnable version:
examples/use_mcp_tools.py.
The search tool, rag_lookup, is the one exception — it needs Postgres and an
embedding model, so it lives only in the Node MCP
server.
Talk to a running server from Python
If you’d rather drive a running Lemma server from Python (instead of doing the work in-process), the library can act as a client too:
from artano_lemma import connect_lemma_stdioWhat’s ready, and what isn’t
Browsing cards, the lemma command, validating cards, the formula cross-checker,
the tool functions, and the client are all ready today. So is USCE’s
validation-envelope check — run_usce_checks(output, card) range-checks a
finished output against the card’s declared bounds — and the cross-method
comparison, run_agreement_checks(outputs, card), which asks whether two
independent methods agree rather than whether one run is in range.
Two things worth knowing that are not on by default:
run_usce_checks(output, card, require_checks=True)turns “nothing was checked” into a finding instead of a clean pass. Useful in CI.run_hypothesis_checks(card, corpus=cards, symbolic=True)actually proves limit and conservation claims instead of recording them. Needspip install "artano-lemma[symbolic]", and it is Python-only — see symbolic verification.
USCE’s deeper time-series checks (causality, asymptotic decay) are on the roadmap.
Next
- Putting it together — use this to make a real AI more correct.
- The MCP server — the same powers, for an AI assistant.