ν Nomos
Experimental Side project · built in public github.com/sboghossian/nomos
v0.1.0 · first public release Apache-2.0 TypeScript

A programming language for legal reasoning.

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.

Live · non_compete_enforceable
running
Scenario

Employee · fair terms

Verdict

winning rule:

Proof chain
  •  
Noun · Greek

νόμος /ˈ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.

§ 01 — Thesis

The premise.

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.

§ 02 — Pipeline

How a rule becomes a verdict.

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.

.nomos SOURCE rules + facts + query Parse LEX + CST → AST @nomos/core Check SYMBOL TABLE refs + diagnostics Fact resolver extract<T> · LLM typed + confidence ASYNC Evaluator RULE ENGINE priority → specialis Verdict + PROOF TREE authorities · facts · why THE COMPILER PIPELINE source → parse → check → resolve facts → evaluate → verdict human-written deterministic one LLM call per extract<T> deterministic again auditable output
Probabilistic at the edges (the fact resolver). Deterministic in the middle (parse, check, evaluate). Every arrow you see carries a typed value.
§ 03 — Language

A sketch.

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.

contract.nomos ● ready
// 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

The verdict.

false. Not enforceable. The consumer-protection rule wins on priority (100 vs 0) and defeats the labour rule.

The proof.

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.

§ 04 — Pillars

The four things I think matter.

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.

Pillar 1

Typed LLM bridges.

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.

Pillar 2

Time and jurisdiction, typed.

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.

Pillar 3

Defeasibility, by design.

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.

Pillar 4

Provenance, always.

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.

§ 05 — Stack

A thin layer.

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.

§ 06 — Prior art

Who came before.

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.

Code the law. Audit the reasoning.

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.