Lemma Engine
A pure, declarative language for business rules.
Lemma Engine is the Rust crate behind the Lemma language. It lets you parse, validate, and evaluate Lemma docs from your own applications while keeping the same natural, auditable semantics that the CLI exposes.
Status
Lemma is pre-1.0. The language and APIs are stable for most use cases, but breaking changes may occur between minor versions. Pin your dependency version and review the changelog before upgrading.
Why Lemma?
- Readable by business stakeholders – rules look like the policies people already write
- Deterministic and auditable – opt in to a full explanation tree with
explain: true - Type-aware – dates, percentages, units, and automatic conversions are first-class
- Composable – specs extend and reference each other without boilerplate
- Multi-platform – use the engine from Rust, power the CLI/HTTP server, ship via WebAssembly, or embed on the JVM
Quick start
Add the crate:
[]
= "0.9.0"
Minimal example
use ;
use HashMap;
use Arc;
let mut engine = new;
engine.load?;
let now = now;
let response = engine.run?;
for in &response.results
Providing values at runtime
use ;
use HashMap;
use Arc;
let mut engine = new;
engine.load?;
let now = now;
let response = engine.run?;
Discovering required data
Engine::show is static: data used by the spec's rules, plus local rule result types and temporal window. Types, prefilled literals, and -> suggest hints live on Show.data. For overlay-aware requirements on a partial run, call run and inspect each rule's missing_data:
let response = engine.run?;
for in &response.results
Bound inputs (caller overlay, spec prefilled literals, or data vetoes) are omitted from missing_data. Suggestions on Show.data do not bind until supplied in run's data map.
Loading registry dependencies
use ;
use fs;
use Arc;
let mut engine = new;
// After fetching from your registry:
engine.load?;
let workspace_text = read_to_string?;
engine.load?;
Embedded units stdlib
Engine::new() loads the embedded repo lemma / spec units standard library internally via SourceType::Dependency("lemma"). It always appears in Engine::list. Formatted source: engine.source(Some("lemma"), None, None)?.
Public load rejects SourceType::Dependency("lemma") — that id is reserved for the embedded stdlib.
Public Engine API
| Method | Purpose |
|---|---|
new() / with_limits() |
Construct engine (stdlib pre-loaded) |
load(sources) |
Load (SourceType, text) pairs; provenance from SourceType alone |
list() |
All loaded repositories (ResolvedRepository[]: name, effective_from, effective_to per row) |
show(repository, spec, effective) |
Interface + temporal window (Show; no Lemma text) |
source(repository, spec?, effective) |
Formatted Lemma source (repo-wide when spec omitted) |
run(repository, spec, effective, data, rules, explain) |
Evaluate; each RuleResult may include missing_data; explanation when explain is true (schema) |
remove(repository, spec, effective) |
Remove a temporal spec slice |
limits() |
Resource limits |
Free function: lemma::resolve_effective.
Consumer API tiers
Tier 1 — always available (all targets, registry feature optional): consumer verbs (Engine, load, list, show, source, run, remove), wire types (Show, Response, DataPath, ListedSpec, ResolvedRepository, DateTimeValue, TimezoneValue, Explanation, Cause, ExplanationNode, OperationResult — explanation JSON uses "type" + "name"; see explanation.v1.json), language surface for tooling (parse, ParseResult, Lexer, TokenKind, DataValue, SpecRef, Span, Source, format_source, format_specs, format_parse_result, type_detail_lines), limit constants (MAX_*_NAME_LENGTH). Language-surface exports are intentional for CLI/LSP/tests — not a minimal “verbs only” crate.
Tier 2 — registry feature: Registry, LemmaBase, RegistryBundle, RegistryError*, Context, LemmaRepository, LemmaSpec, LemmaSpecSet, and native resolve_registry_references.
Tier 3 — native only (not(wasm32)): lemma::deps for filesystem dependency cache paths.
EffectiveDate is planning-internal and not exported. Language-surface Span and Source are exported (parse/AST). LSP and CLI use DateTimeValue and SpecRef::resolved_instant at temporal boundaries.
Features
- Rich type system – percentages, mass, length, duration, temperature, pressure, power, energy, frequency, and data sizes
- Automatic unit conversions – convert between units inside expressions without extra code
- Page composition – extend specs, bind data, and reuse rules across modules
- Audit trail – with
explain: true, each rule result carries a structured explanation (seedocumentation/schemas/explanation.v1.json) - JavaScript / TypeScript –
npm install @lemmabase/lemma-enginefor browser, Node, and edge runtimes - Java / Kotlin –
com.lemmabase:lemma-engineon Maven Central (BigDecimal-first JNI binding)
Constraint-style inversion (what inputs would yield a given outcome?) is planned; it is not documented as a supported API yet.
Installation options
As a library
CLI tool
HTTP server
JavaScript / TypeScript
import from '@lemmabase/lemma-engine';
const engine = await ;
Build: node build.js (from engine/packages/npm/). See packages/npm/README.md.
Maven (Java / Kotlin)
com.lemmabase
lemma-engine
0.9.0
Build/test: cargo build -p lemma_jni then ./mvnw test under engine/packages/maven/. See packages/maven/README.md.
Documentation
- Learn guide: https://github.com/lemma/lemma/blob/main/documentation/learn/readme.md
- API documentation: https://docs.rs/lemma-engine
- Examples: https://github.com/lemma/lemma/tree/main/documentation/examples
- CLI usage: https://github.com/lemma/lemma/blob/main/documentation/reference/cli.md
Use cases
- Compensation plans and employment contracts
- Pricing, shipping, and discount policies
- Tax and finance calculations
- Insurance eligibility and premium rules
- Compliance and validation logic
- SLA and service-level calculations
Contributing
Contributions are very welcome!
License
Apache 2.0