# Cheat sheet The whole language on one page. Every `law` block below belongs to one package: put them together in `parking.law` and it compiles; the scenarios at the end run against it. Each section links to the page that explains the construct in depth.
Open this package in the playground → — edit the rules and the scenarios of this page and run them in your browser.
## Package header ```law language "law.core" version "0.2"; package demo.parking version "0.1.0"; namespace "urn:law:demo:parking"; ``` Three lines open every package: the language version, the package name and version, and the namespace that makes every name globally unique. ## Vocabulary ```law entity Applicant; entity Office; enum Zone { central; outer; } relation resident(a: Applicant) kind institutional; relation vehicle_registered(a: Applicant) kind institutional; relation permit_eligible(a: Applicant) kind institutional; relation permit_suspended(a: Applicant) kind institutional; relation outstanding_fines(a: Applicant) kind institutional; relation disability_badge(a: Applicant) kind institutional; relation fraud_flag(a: Applicant) kind institutional; relation household_member(a: Applicant, m: Applicant) kind empirical; relation large_household(a: Applicant) kind institutional; relation lives_in(a: Applicant, z: Zone) kind empirical; relation application_filed(a: Applicant, on: Date) kind empirical { key(a); } relation decision_due(a: Applicant, due: Date) kind institutional; relation decision_notified(a: Applicant) kind empirical; relation resells_permit(a: Applicant) kind empirical; relation revocation_notice(o: Office, a: Applicant) kind empirical; relation permit_revoked(a: Applicant) kind institutional; relation permit_office(o: Office) kind institutional; ``` | Form | Meaning | |---|---| | `entity Name;` | a kind of thing the norm talks about | | `enum Name { a; b; }` | a closed list of values | | `relation name(x: Type, …) kind …;` | a statement that can be true, false, both or unknown | | `kind institutional` | true because a rule or an authority says so | | `kind empirical` | true because it happened; comes from evidence | | `{ key(a); }` | at most one record per key: a second value is a conflict | ## Values ```law const MONTHLY_RATE: Money = 10 EUR; const LARGE_HOUSEHOLD: Integer = 4; function permit_fee(months: Integer) -> Money = months * MONTHLY_RATE; ``` Constants and pure functions. Money carries its currency (`10 EUR`), percentages are written `25 percent`, dates `@2026-03-01`, periods `30 calendar_day`. ## Rules ```law rule PermitEligibility defeasible { for a: Applicant; when resident(a) and vehicle_registered(a); then permit_eligible(a); unless permit_suspended(a); } ``` | Strength | When to use it | |---|---| | `strict` | no exception is possible; `unless` on it is an error (`LDC-E4110`) | | `defeasible` | the general rule that exceptions may defeat | | `defeater` | an exception that withdraws a conclusion without asserting the opposite | `for` binds variables, `when` is the condition, `then` the conclusion, `unless` a proviso that blocks this rule only. A conclusion `not p(x)` is a refusal: it supports the opposite. See [Your first rule](/language/first-rule/) and [Exceptions and priorities](/language/exceptions-and-priorities/). ## Exceptions and priority ```law rule FinesRefusal defeasible { for a: Applicant; when outstanding_fines(a); then not permit_eligible(a); } rule BadgeEligibility defeasible { for a: Applicant; when disability_badge(a); then permit_eligible(a); } priority RefusalOverEligibility { prefer FinesRefusal over PermitEligibility; reason lex_specialis; } rule FraudBlocksBadge defeater { for a: Applicant; when fraud_flag(a); defeat permit_eligible(a); } ``` | You want | Write | |---|---| | an exception inside one rule | `unless …;` | | a refusal | a rule with `then not p(x);` | | one rule to beat another | `priority … { prefer A over B; reason …; }` | | to cancel support without refusing | a `defeater` rule with `defeat p(x);` | Two rules with opposite conclusions and no priority give `BOTH`: the conflict is reported, not silently resolved. ## Definitions, negation, aggregates ```law definition central_resident(a: Applicant) exact { when resident(a) and lives_in(a, central); } rule LargeHousehold strict { for a: Applicant; when resident(a) and count(collect m: Applicant where household_member(a, m)) >= LARGE_HOUSEHOLD; then large_household(a); } ``` | In a condition | Means | |---|---| | `p(x)` | `p(x)` is established | | `not p(x)` | the opposite of `p(x)` is established | | `not_known(p(x))` | nothing establishes `p(x)` | | `count(collect m: T where …)` | how many values satisfy the condition | | `sum(collect all v: Money, m: T where …)` | the total of the values | `definition` names a concept ("who counts as …"); the explanation then says "by definition". Missing and refuted facts are different answers — see [Missing and conflicting facts](/language/missing-and-conflicting/). ## Closed lists ```law relation applicant_on_file(a: Applicant) kind institutional; closure ResidentsRegister { predicate resident; domain applicant_on_file; snapshot "urn:snapshot:demo-parking-residents:2026"; complete_as_of @2026-01-01T00:00:00Z; derive_explicit_negative true; } ``` By default silence proves nothing: a missing record gives `NEITHER`. A `closure` says the register is complete for a domain at a moment, so inside that domain a missing record becomes a denial (`FALSE_ONLY`); outside it, silence stays silence. ## Time and deadlines ```law deadline policy CALENDAR_DAYS { start_count next_day; include_end true; roll no_roll; } rule DecisionDeadline strict { for a: Applicant; for on: Date; when application_filed(a, on); then decision_due(a, add_calendar_period(on, 30 calendar_day)); } ``` | Form | Meaning | |---|---| | `add_calendar_period(d, 30 calendar_day)` | calendar arithmetic; needs a deadline policy in the case | | `add_business_days(d, n)` | working days; also needs the official calendar | | `effective [@2026-01-01, infinity);` | inside a rule: when the rule is in force | | `deadline policy … { … }` | how to count: start, end, rolling over holidays | Without a policy the deadline is not guessed: the answer is `MISSING_POLICY`. See [Sources and legal time](/language/sources-and-legal-time/). ## Sources and editions ```law source PARKING_RULES { kind municipal_act; jurisdiction NORTHBRIDGE; number "2026-1"; label en official "Northbridge Residential Parking Rules"; } edition PARKING_RULES_2026 of PARKING_RULES { language en; officiality official; adopted @2025-12-01; in_force [@2026-01-01, infinity); materialization_status PINNED_OFFICIAL_BYTES; } publication PARKING_RULES_2026_TEXT of PARKING_RULES_2026 { media_type "text/plain; charset=utf-8"; uri "urn:demo:parking:rules:2026"; retrieved_at @2026-01-05T09:00:00Z; content_hash "sha256:9060e85e1fd30cd22b8a9f618afb8aabd15ae356b23b47f86ab1689b6aacb660"; local_path "sources/parking-rules-2026.txt"; } fragment PARKING_RULES_2026_ART2 in PARKING_RULES_2026 { kind article; locator "article/2"; label en official "Article 2. Eligibility"; text en official """A residential parking permit is issued to an applicant who is a resident of Northbridge and has a vehicle registered at their address. """; content_hash "sha256:e309c8a75c1eab992dd0ad66ff477f9111bf99651e167ce1de6a651129a758be"; } relation eligibility_notice(a: Applicant) kind institutional; @source(PARKING_RULES_2026_ART2) rule EligibilityNotice defeasible { effective [@2026-01-01, infinity); for a: Applicant; when permit_eligible(a); then eligibility_notice(a); } ``` | Form | Meaning | |---|---| | `source` | the act itself: kind, jurisdiction, number | | `edition … of …` | one version of the act, with its dates in force | | `publication … of …` | the official bytes of an edition, pinned by hash | | `fragment … in …` | an article or clause, with its text and hash | | `@source(FRAGMENT)` | anchors a rule to the text it formalizes | | `effective [from, to);` | when the rule applies; outside it the rule does not fire | The answer cites the fragment, and the hash proves which text was used. See [Sources and legal time](/language/sources-and-legal-time/). ## Duties, prohibitions, powers ```law rule DecisionDuty strict { for a: Applicant; for o: Office; for on, due: Date; when application_filed(a, on) and decision_due(a, due) and permit_office(o); then duty NotifyDecision { bearer o; beneficiary a; goal achievement { condition decision_notified(a); window [on, due]; } }; } rule NoResale strict { for a: Applicant; for o: Office; when permit_eligible(a) and permit_office(o); then prohibition NoPermitResale { bearer a; beneficiary o; action resells_permit(a); window [@2026-01-01, @2026-12-31]; }; } rule RevocationPower strict { for a: Applicant; for o: Office; when permit_office(o) and permit_eligible(a); then power RevokePermit { holder o; over a; exercise revocation_notice(o, a); valid_when (resells_permit(a)); effect create(permit_revoked(a)); }; } ``` | Position | Says | Key fields | |---|---|---| | `duty` | the bearer must bring something about | `bearer`, `beneficiary`, `goal`, `window` | | `prohibition` | the bearer must not do something | `bearer`, `action`, `window` | | `power` | the holder can change the legal situation | `holder`, `over`, `exercise`, `valid_when`, `effect` | The engine reports each position's state: `ACTIVE`, `FULFILLED`, `VIOLATED` and others, with the facts behind it. ## Packages and imports ```law pub relation permit_holder(a: Applicant) kind institutional; ``` Only declarations marked `pub` are visible to other packages. A package that uses another one names it in `law.toml` and imports it; foreign names are written with the package prefix. These lines are not part of this page's package: ```toml [dependencies] "demo.parking" = "0.1.0" ``` ```law import demo.parking version "0.1.0"; rule ResidentDiscount strict { for a: demo.parking::Applicant; when demo.parking::permit_holder(a); then discount(a); } ``` `law add demo.parking@0.1.0` writes the dependency and the lock for you. Referring to a name that is not `pub` fails with `LDC-E1105`. ## Asking questions Questions are asked in a scenario (`.lawtest`) or with `law ask`. | Question | Form | Answer | |---|---|---| | is it true? | `evaluate truth(p(x));` | a truth status | | who? | `evaluate collect a: Applicant where p(a);` | a list | | how much? | `evaluate permit_fee(3);` | a value | | when? | `evaluate truth(decision_due(x, @2026-04-02));` | a truth status for the date | | who owes what? | `evaluate positions();` | positions and their states | ## Four answers | Status | Means | |---|---| | `TRUE_ONLY` | established, nothing against | | `FALSE_ONLY` | refuted, nothing for | | `BOTH` | grounds on both sides: a conflict the package does not resolve | | `NEITHER` | not established, not refuted: something is missing | Next to the truth status every answer carries an `evaluation_status`: `COMPUTED` when the engine had everything it needed, or a reason such as `MISSING_POLICY` when it did not. ## Scenarios ```law test "the general rule" { given { context { legal_time @2026-03-01; decision_time @2026-03-01T09:00:00Z; knowledge_time @2026-03-01T09:00:00Z; timezone "UTC"; } assert resident(entity_ref("urn:demo:parking:ann")) { id "resident-ann"; origin case_input; } assert vehicle_registered(entity_ref("urn:demo:parking:ann")) { id "vehicle_registered-ann"; origin case_input; } } evaluate truth(permit_eligible(entity_ref("urn:demo:parking:ann"))); expect truth_status == TRUE_ONLY; expect applied(PermitEligibility); } ``` | Part | Holds | |---|---| | `context { … }` | legal time, decision time, knowledge time, timezone, deadline policy | | `assert p(x) { id "…"; origin case_input; }` | one fact with its identity and origin | | `assert not p(x) { … }` | a stated denial | | `evaluate …;` | the question | | `expect …;` | `truth_status ==`, `evaluation_status ==`, `applied(Rule)`, `value ==`, `collected(…)`, `position(Name, STATE)` | More in [Testing a package](/language/testing-a-package/). ## Commands ```bash law init my-package law engine check parking.law law engine test tests/scenarios.lawtest --program parking.law law engine fmt parking.law law ask my-case --query 'evaluate truth(permit_eligible(entity_ref("urn:demo:parking:ann")));' --query-id q1 law explain LDC-E4110 law codegen demo.parking --target ts --out gen --name parking --version 0.1.0 ``` | Command | Does | |---|---| | `law init` | a new package or case | | `law engine check` | compile and report diagnostics | | `law engine test` | run scenarios against the package | | `law engine fmt` | format the source | | `law ask` | ask a question of a case; the answer comes with its proof and hashes | | `law explain LDC-E…` | what a diagnostic means and how to fix it | | `law codegen` | a TypeScript, Python or Go module of the package, no engine needed | ## Common errors Each row is checked: the page is changed as described, and the compiler must report exactly this code. | Code | Cause | Fix | |---|---|---| | `LDC-E0201` | a missing `;` or rule strength | end declarations and clauses with `;`; specify the rule strength | | `LDC-E0203` | a keyword used as a name (`entity rule;`) | pick another name | | `LDC-E1201` | the same name declared twice | rename one of them | | `LDC-E1305` | a duty without `bearer` | name who owes the duty | | `LDC-E1308` (warning) | `defeat` in a non-defeater rule | make the rule a `defeater` | | `LDC-E1330` | a name in the conclusion that nothing binds | bind it with `for` and use it in `when` | | `LDC-E2101` | an unknown type | declare it with `entity`, `enum` or `type` | | `LDC-E2102` | a relation that is not declared | declare it, or fix the spelling | | `LDC-E2103` | wrong number of arguments | match the declaration | | `LDC-E4101` | a variable bound only under `not` | bind it by a positive condition first | | `LDC-E4108` | a priority names a rule that does not exist | fix the rule name | | `LDC-E4110` | `unless` on a `strict` rule | make the rule `defeasible` | `law explain LDC-E…` prints the full card for any code. ## Types | Type | What it holds | |---|---| | `Algebraic` | An exact algebraic real number: a minimal polynomial plus the index of its real root. | | `Boolean` | A two-valued data type: `true` or `false`. | | `Bounds` | A closed rational interval bundled with the derivation that produced it. | | `Currency` | The currency of a `Money` amount — the code in a literal such as `1000000 KZT`. | | `Date` | A calendar date, written as `@2008-03-01`. | | `Decimal` | An exact decimal number, written as a literal such as `0.20`. | | `Duration` | A physical duration in seconds and nanoseconds. | | `Instant` | A point on the time axis, written with an offset: `@2026-03-31T18:00:00+05:00`. | | `Integer` | A whole number. | | `Jurisdiction` | The type of a jurisdictional binding: a code that names a legal order. | | `LanguageTag` | A BCP-47 language tag such as `kk-KZ`. | | `List` | An ordered collection that allows duplicates. | | `Magnitude` | A value whose dimension is computed from the unit registry, with product, quotient and conversion. | | `Money` | An amount in a named currency, written as a literal such as `1000000 KZT`. | | `Number` | The single exact numeric domain of 0.4 programs: every numeric spelling is one value, carried as an irreducible fraction. | | `Option` | An optional value: there is no `null`, absence is `Option