# Packages and cases One session, two folders: a canon package holds the rules, a case package holds the situation. The canon below is a parcel tariff — up to 2 kg the fee is 500, above that 500 plus 150 for every kilogram over 2. Every terminal ran; every file is shown as written. ## A canon package `law init` with the package template creates `law.toml` and `source.law`: ```text title="Terminal" $ law init parcel-tariff --name demo.parcel_tariff --template package parcel-tariff: law.toml, source.law ``` The rules go into `source.law`: ```law title="parcel-tariff/source.law" language "law.core" version "0.2"; package demo.parcel_tariff version "0.1.0"; namespace "urn:law:demo:parcel_tariff"; pub entity Shipment { label en unofficial "Shipment"; } pub relation weight_kg(s: Shipment, kg: Decimal) kind empirical { label en unofficial "weight of the shipment, kg"; } pub relation fee(s: Shipment, amount: Decimal) kind institutional { label en unofficial "postage under the tariff"; } rule BaseFee(s: Shipment, kg: Decimal) strict { label en official "up to and including 2 kg: base fee 500"; when weight_kg(s, kg); when kg <= 2.0; then fee(s, 500.0); } rule HeavyFee(s: Shipment, kg: Decimal) strict { label en official "over 2 kg: 500 plus 150 for each kilogram above 2"; when weight_kg(s, kg); when kg > 2.0; then fee(s, 500.0 + (kg - 2.0) * 150.0); } ``` Expectations are written from the tariff text before the run: 5 kg goes to 500 + 3 × 150 = 950; exactly 2 kg stays at 500. `tests/tariff.lawtest`: ```law title="parcel-tariff/tests/tariff.lawtest" language "law.core" version "0.2"; package demo.parcel_tariff version "0.1.0"; namespace "urn:law:demo:parcel_tariff"; test "urn:query:demo-parcel-tariff-t01-heavy" { given { context { legal_time @2026-09-25; decision_time @2026-09-25T00:00:00Z; knowledge_time @2026-09-25T00:00:00Z; timezone "UTC"; } assert "w": weight_kg(entity_ref("urn:case:box-1"), 5.0) { origin case_input; } } evaluate truth(fee(entity_ref("urn:case:box-1"), 950.0)); expect truth_status == TRUE_ONLY; expect evaluation_status == COMPUTED; } test "urn:query:demo-parcel-tariff-t02-base" { given { context { legal_time @2026-09-25; decision_time @2026-09-25T00:00:00Z; knowledge_time @2026-09-25T00:00:00Z; timezone "UTC"; } assert "w": weight_kg(entity_ref("urn:case:box-2"), 2.0) { origin case_input; } } evaluate truth(fee(entity_ref("urn:case:box-2"), 500.0)); expect truth_status == TRUE_ONLY; expect evaluation_status == COMPUTED; } ``` And `law.toml` gains the suite stanza: ```toml title="parcel-tariff/law.toml.append.toml" [[tests]] family = "parcel_tariff" suites = ["tests/tariff.lawtest"] world = ["demo.parcel_tariff"] ``` ## Check, fix, test The first draft carries a typo: line 23 of `source.law` calls the relation `weight_kgs`. The static check reports it with a line, a column and a stable code: ```text title="Terminal" $ law engine check . ./source.law:23:10: error LDC-E2102: predicate "weight_kgs" is not declared as a relation in this file (exit 1) ``` The code [LDC-E2102](/diagnostics/LDC-E2102/) names the fault — a predicate with no declaration — so an editor can react to the code rather than the wording. With the name corrected the check passes: ```text title="Terminal" $ law engine check . check OK: . ``` `law engine lock` writes `law.lock`: ```text title="Terminal" $ law engine lock . --write written ./law.lock ``` And `law test` runs the declared scenarios: ```text title="Terminal" $ law test law test demo.parcel_tariff: world demo.parcel_tariff ok [parcel_tariff] tests/tariff.lawtest / urn:query:demo-parcel-tariff-t01-heavy ok [parcel_tariff] tests/tariff.lawtest / urn:query:demo-parcel-tariff-t02-base total: 2 checked, 2 passed, 0 failed, 0 not run; code 0 ``` ## A case under it `law pack` puts the canon into one portable file: ```text title="Terminal" $ law pack --out ../tariff.arxo demo.parcel_tariff → ../tariff.arxo: 6 files, 5 objects (12 KiB → 7 KiB after dedup → 6 KiB in the archive) containerHash sha256:829566fe4347…; capabilities: execute, rebuild, test ``` A case package holds your situation; the canon arrives as a pinned dependency. A second folder, a second init: ```text title="Terminal" $ cd .. && law init my-case my-case: case package my_case, law.core language 0.2 created: law.toml, package.law, main.lawcase, law.lock case Main declared in main.lawcase and registered in law.toml; set the time axis by explicit input next: law add → law install → law ask ``` `law add` pins the packed canon with no network: ```text title="Terminal" $ cd my-case && law add ../tariff.arxo demo.parcel_tariff@0.1.0 ← ../tariff.arxo (containerHash sha256:829566fe4347…), registries: file file ← /private/my-case/.law/arxo-registry-77540/file (--registry) + demo.parcel_tariff 0.1.0 exports (3): Shipment, fee, weight_kg changed: .law/transport.json changed: deps/demo.parcel_tariff.lawir.json changed: law.lock changed: law.toml changed: package.law ``` The case file sets the date axis and asserts one fact — a 5 kg shipment: ```law title="my-case/main.lawcase" language "law.core" version "0.2"; package my_case version "0.1.0"; namespace "urn:law:my_case"; case Main { context { legal_time @2026-10-01; knowledge_time @2026-10-01T12:00:00Z; decision_time @2026-10-01T12:00:00Z; timezone "UTC"; } assert demo.parcel_tariff::weight_kg(entity_ref("urn:case:box-1"), 5.0) { origin case_input; } } ``` The question asks the fee for that shipment: ```text title="my-case/query.txt" evaluate truth(demo.parcel_tariff::fee(entity_ref("urn:case:box-1"), 950.0)); ``` `law ask` saves the request with the full evaluation document; piped through `jq` the summary reads as a status with the result hash: ```text title="Terminal" $ law ask --query "$Q" --query-id fee --format brief --out runs/fee | jq -r '.results[0].status, .resultHash' TRUE_ONLY sha256:0290d550984a… ``` `law eval` recomputes the saved run and reaches the same hash: ```text title="Terminal" $ law eval runs/fee | jq -r .resultHash sha256:0290d550984a… ``` ## Where next - To write rules of your own: the [Language](/language/) topic, from a first rule to a package. - To read the saved document field by field: [How to read an answer](/guide/reading-an-answer/) and the [Decision protocol](/protocols/decision-protocol/). - To see what a question sends: the [Fact protocol](/protocols/fact-protocol/). - When the check fails on another code: [Diagnostics](/diagnostics/).