Markdown for LLMs
Packages and cases
The source Markdown for this article. Copy it into your assistant or download it as a text file.
# 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 <package> → 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<tmp>/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/).