Your first .nomos program, in 15 minutes.
By the end of this page you will have installed Nomos, encoded a real legal rule, bound facts to it, run the query, and read the proof tree. No prior logic-programming experience required.
Install.
Nomos needs Node ≥ 20. Python is optional (Eyecite for US-citation resolution).
git clone https://github.com/sboghossian/nomos
cd nomos
npm install
npm run build
That's it. The nomos CLI is now available via
npx nomos.
Write a tiny program.
Create a new file hello.nomos:
// hello.nomos — a 6-line rule about California minimum wage.
rule minimum_wage_applies @ US-CA from 2023-01-01 {
requires worker.age >= 14
requires worker.hours_per_week > 0
authority: ca_labor_code.section("1182.12")
}
query minimum_wage_applies as of 2026-04-18
Then hello.input.json next to it with the facts:
{
"worker": { "age": 17, "hours_per_week": 20 }
}
A rule has a name, a jurisdiction
(@ US-CA), a validity date
(from 2023-01-01), a list of requires
predicates, and one or more authority: citations. The
query asks "does this rule apply as of this date?"
Run it.
npx nomos run hello.nomos You'll see three sections:
─── VERDICT ────────────────────────────────
value TRUE
winning rule minimum_wage_applies
authorities
ca_labor_code.section("1182.12")
─── PROOF ──────────────────────────────────
✓ minimum_wage_applies
✓ worker.age >= 14 → true
✓ worker.hours_per_week > 0 → true
The rule fires because both requires are satisfied. You can also
run nomos parse hello.nomos to see the AST,
nomos check hello.nomos for diagnostics only, or
nomos resolve hello.nomos to resolve the US citation
through Eyecite.
Read the proof tree.
Change worker.age to 12 in the JSON and
re-run. The proof tree now shows which requirement failed:
─── VERDICT ────────────────────────────────
value FALSE
winning rule —
─── PROOF ──────────────────────────────────
✗ minimum_wage_applies
✗ worker.age >= 14 → 12 ← the actual value
✓ worker.hours_per_week > 0 → true
The failing requirement prints the computed value (12)
so you can see exactly why the rule didn't fire. Every verdict is
auditable end-to-end.
Add a defeater.
Real law has exceptions. Here's an exemption for casual babysitters that overrides the base rule:
rule babysitter_exemption @ US-CA priority 100
defeats minimum_wage_applies
when worker.role == "babysitter"
{
authority: ca_labor_code.section("1182.4(a)")
}
With priority 100 (higher than the default 0),
this rule beats minimum_wage_applies whenever
worker.role == "babysitter". Nomos records the tiebreak
in the proof tree with a human-readable reason.
Defeasibility is the point. Rules contradict; Nomos resolves the contest and tells you how.
Extract facts from prose (optional).
So far your facts were a hand-written JSON file. Nomos can also extract them from contracts or statutes via LLM:
type Worker {
age: Int
role: String
hours_per_week: Int
}
fact worker: Worker = extract<Worker>(contract_text)
using llm("claude-sonnet-4-5")
verified_by human if confidence < 0.95
With an OPENROUTER_API_KEY in .env:
npx nomos run hello.nomos --with-llm
The compiler derives a JSON schema from the Worker type,
calls OpenRouter, and binds the extracted value. If the model's
self-rated confidence falls below 0.95, Nomos flags it
for human review instead of trusting the extraction blindly.
Prefer not to run it locally? The browser playground has an LLM toggle that calls a hosted proxy — no key required.
Where to go next.
- ▸ Open the playground and flip between three scenarios of a French non-compete clause.
- ▸ Read the thesis — why Nomos exists and what claims it makes.
- ▸ Skim the prior-art survey — Catala, OpenFisca, Blawx, Kowalski, etc.
- ▸ See honest CUAD benchmark numbers for
extract<T>. - ▸ Look at the architecture page to see every compiler stage linked to its source file.
- ▸ Browse the GitHub repo — issues and discussions welcome.
Nomos is v0. Breaking changes expected. Not legal advice.