You write rules. An LLM pulls facts out of contracts. When two rules contradict each other (a consumer law against a labour law, say), Nomos picks a winner and shows its work, citations and all.
No install, no signup. Edit the code in your browser.
Employee · fair terms
—
winning rule: —
νόμος /ˈnomos/
Law, custom, rule — whichever binding norm a community happens to treat as authority. The word is old enough that Plato and Aristotle were already arguing about what it meant, and legal philosophers like H. L. A. Hart were still at it in the last century. I picked it because the English word "law" is already overloaded.
Law is computation. Logic programming made that literal in the 1970s and then stalled for fifty years, because getting a contract into a computer meant paying a paralegal to retype it into Prolog.
LLMs fixed that part. They also introduced a new problem: you can't put a chatbot on the witness stand. So Nomos only uses the LLM at the edge, to read prose. The reasoning itself stays deterministic, so when the verdict is wrong you can point to the rule that's wrong.
None of this is invented. The citation parser is Eyecite. The evaluation dataset is from the Atticus Project. The idea of default logic for legal rules comes from Sarah Lawsky and the Catala team. I'm mostly soldering other people's work together and adding a couple of new primitives on top.
Five stages, one non-deterministic link in the middle. The packets moving along the arrows are the typed values actually crossing each boundary. Click any box on /architecture to jump to its source file.
A French non-compete, evaluated under the post-2016 labour code, with a consumer-protection rule that defeats it when the employee happens to be acting as a consumer. The LLM pulls the clause data out of the PDF; the rule engine takes it from there.
// A French non-compete clause, reasoned about as of 2026-04-18.
type Party {
name: String
role: "seller" | "buyer" | "employee" | "employer" | "consumer"
}
type NonCompete {
duration: Duration
scope: Geography
compensation_pct: Float
}
rule non_compete_enforceable @ FR from 2016-08-10 {
requires clause.duration <= 24.months
requires clause.scope is reasonable
requires clause.compensation_pct >= 0.30
authority: code_du_travail.art(L1121-1)
∧ cass_soc(2002-07-10, "00-45135")
}
rule consumer_protection_override @ FR priority 100
defeats non_compete_enforceable
when party.role == "consumer" {
authority: code_conso.art(L212-1)
}
// LLM bridge — typed, verified, auditable.
fact parties: List<Party> = extract<Party>(contract.pdf)
using llm(claude-opus-4-7)
verified_by human if confidence < 0.95
fact clause: NonCompete = extract<NonCompete>(contract.pdf, section: "non-compete")
using llm(claude-opus-4-7)
query non_compete_enforceable(clause, parties[0]) as of 2026-04-18
false. Not enforceable. The consumer-protection
rule wins on priority (100 vs 0) and defeats the labour rule.
A tree: L212-1 defeated L1121-1, which would otherwise have
been satisfied by Cass. soc. 2002-07-10 · no. 00-45135. Every fact gets
a citation.
Other projects have pieces of this. Catala has the cleanest account of legislative exceptions I've seen. OpenFisca is running actual tax code at national scale. LangGraph is fine at agent plumbing. I don't know of anything that puts all four below in one place.
extract<T> using llm(...) verified_by human if confidence < X
is a language primitive. You get a typed value back or the compiler
complains. If the model isn't confident enough, the extraction
goes to a human queue instead of silently being wrong.
A rule declares @ FR from 2016-08-10. A query runs
as of 2015-01-01. The compiler won't apply the rule to
the fact. I had to get this right first because French law changed
in 2016 and every other one of my demos was wrong until I did.
Law has rules for when rules contradict each other. Nomos ships those rules: priority first, then whichever is more specific, then whichever came later. When two rules fire, the proof tree tells you which won and on what ground.
Every output is reproducible. If you disagree with a verdict, you can trace it to the requirement that passed, the fact that triggered it, the statute behind the rule. Nothing is a black box. This is the part a compliance officer actually needs.
Most of Nomos isn't Nomos. It's Chevrotain parsing tokens into an AST, Eyecite resolving US citations, OpenRouter calling the LLMs, with a few hundred lines of glue between them. I credit everything and link upstream.
This field is older than I am. Every project below taught me something. A few of their authors are still active, and I'd like to hear from them at some point.
Inria's research project. Default logic as a first-class feature, mirroring how legislation actually structures exceptions. The closest modern academic ancestor.
Cleanest account of legislative exceptions I've seen.
Tax and benefit law as typed Python. Deployed at national scale in France, UK, New Zealand, Tunisia, Senegal.
Proof that rules-as-code actually runs in production.
Visual rules-as-code over s(CASP), with natural-language explanations for every answer. Built for lawyers, not engineers.
Explanation-first UX Nomos should borrow.
Controlled natural language that compiles to Prolog. Kowalski's framing of law-as-logic.
A plausible future frontend for Nomos.
The foundational encoding — an entire statute, in Prolog, forty years ago. CodeX Prize 2021.
The logic was never the hard part.
XML interchange format for legal rules. Not a programming language, but a shared vocabulary for rule/exception/defeasibility.
Possible interop target.
I had six free weekends and wanted to see if this idea held up. It mostly does. It's open, Apache-2.0, no company attached. If you try it and something breaks, tell me.