The law, held in common.
Quick start · Features · Screenshots · How it works · Docs · Governance · Roadmap
MIT OR Apache-2.0 · Rust 1.85+ · SQLite + FTS5 · TypeScript UI · offline-first · no accounts, no billing, ever
Search across the corpus. Every judgment carries its court, neutral citation, provenance class and inbound-citation weight. All screenshots use the demo corpus — there is no bundled corpus yet (full tour).
| Free, forever No accounts, no telemetry, no billing, no hosted service. Universities, firms and individuals run nodes. Nobody bills anybody. |
Verifiable by recomputation Judgment ids are BLAKE3 of canonical text. The citation graph comes from a pinned extractor anyone can re-run and compare byte for byte, given the same region profiles. |
No single publisher Releases need k-of-n signatures from independent organisations. A threshold below 2 is refused in code — including for us. |
Molao (Sotho and Tswana for law) is a free, decentralized commons of case law: a corpus of judgments, a citation graph over them, and a single binary that serves both. It is not a product and not a business. There is no hosted service to sign up for, no subscription, and no plan to add one.
A node is one executable over one SQLite file. It works fully offline, makes no outbound requests of its own, and needs nothing from anyone to keep serving the law. Judgments are identified by the hash of their canonical text, so two nodes that have never exchanged a packet agree on what a judgment is, and a release is signed by a quorum of independent organisations rather than published by one operator who could be pressured, bought, or breached.
Molao is infrastructure any jurisdiction can stand up for its own corpus — an LII, a law faculty, a bar council, a ministry of justice. It is the model the LII network (AustLII, CanLII, BAILII, SAFLII, NZLII, the AfricanLII members) has run for decades under the Free Access to Law Movement, and Molao is joining that tradition rather than inventing it. What it adds is content-addressed identity, threshold-signed releases, and a citator whose mechanical layer can be checked by anyone.
No jurisdiction is hardcoded. Court codes, court names, hierarchy tiers and
law-report series ship as region profiles — data a node loads, never an
assumption baked into the parser. A generic profile makes Molao usable
anywhere on day one, and South Africa (ZA) is the first fully-populated
profile, never a special case.
This works because the free-access-to-law world already converged on one citation convention:
| Jurisdiction | Neutral citation | Published by |
|---|---|---|
| United Kingdom | [2020] UKSC 1 |
BAILII |
| Australia | [2020] HCA 1 |
AustLII |
| New Zealand | [2020] NZSC 1 |
NZLII |
| South Africa | [1995] ZACC 3 |
SAFLII |
Same grammar, different court codes — which is exactly why the codes belong in data. A profile is a TOML file naming the courts (code, name, tier, seat) and the law-report series, and a node loads a directory of them at start-up:
molao --profiles ./profiles regions # what this node resolves, and from where
molao --profiles ./profiles ingest judgments.jsonlA loaded profile takes precedence over the compiled-in profile of the same
code, and the compiled-in set is the fallback for everything not supplied — so
correcting one court code is a file, not a rebuild, and a jurisdiction nobody
has compiled in works the same way. Fourteen profiles ship as both:
profiles/*.toml and constants in molao_core::region, held equal by a test.
docs/COURTS.md. Nothing about that
changes for Kenya, Nigeria, or any of the roughly sixteen AfricanLII member
jurisdictions — the citation grammar is already shared continent-wide; only
the court registry differs, and that is data, not code.
What a profile does not carry: the tier authority weights (Apex 1.00 …
Lower 0.10) are constants in molao-core, shared across every jurisdiction,
and there is no per-profile override. Nor does a profile select citation
styles — every profile is parsed with the same grammar, and a jurisdiction that
uses fewer forms simply matches fewer of them.
Note
Status: 0.1.0, early — decentralisation-ready, not decentralisation-running.
The trust model is real, and it is built and tested today: hash-identified
judgments, threshold-signed releases, a citation graph verifiable by
recomputation, and a node that runs standalone and fully offline. Region
profiles load from TOML at run time (molao --profiles <DIR>), with the
fourteen compiled-in profiles as the fallback — ZA populated, GENERIC
anywhere, though GENERIC finds only neutral citations and case numbers
because reported citations need an enumerated report-series list.
What is not live yet: peer-to-peer distribution and a public corpus.
There is no bundled corpus — a node starts empty, and molao demo seeds
a synthetic one. No public signed release exists yet. Three crates carry
the machinery: molao-ingest (a robots-respecting, collectively-built
corpus — witnesses fetch and sign independently; corroboration, not upload
trust), molao-dist (content-addressed releases, a torrent export, and
an iroh transport behind a feature flag), and molao-index (a local
vector+keyword search cache, rebuildable and unsigned, never part of a
release). All three are now wired into the node — molao release publish/sign/fetch/torrent package and move a release, and molao verify
checks one in eight steps, including re-running the pinned extractor over
the stored text. But none of it has carried real data: no release has
been published, neither transport has moved one, and nothing has run against
a real jurisdiction. Treatment attestations are built but unused — the
signature check, ingest, conflict display, reader-side trust policy and
molao attest all exist and are tested, and nobody has ever attested
anything; there is no gossip, no authoring path and no UI for them.
Semantic search over a release is deliberately excluded
(why) —
a local rebuildable cache is not the same thing and does not reopen that
question. Full status in ROADMAP.md.
| ⚖️ For reading the law | 🔗 For trusting it |
|---|---|
|
|
Honest about the hard parts
- The citator is the real prize, and its interpretive half is not built. A corpus that does not know case A was overruled by case B will hand a lawyer dead authority. Mechanical citation edges are deterministic and verifiable, and those exist. Treatment labels (followed / distinguished / overruled) are interpretation, and are modelled as signed attestations that may conflict, showing disagreement rather than resolving it. That machinery is now built and tested — signatures checked on ingest and again on every read, conflicts displayed and never resolved — but nobody has attested anything, and there is no UI for it. Check currency yourself.
- "No central server" is achievable; "no central authority" is not. Somebody must attest that a hash is the real judgment. So the trust root is a quorum plus a public append-only log, not one operator. That is a large improvement over one database with one administrator, and it is not trustlessness. GOVERNANCE.md
- Federations decay when the person running the node leaves. Hence a
zero-maintenance single binary with no external database and nothing to
rotate, plus network health exposed publicly on
/api/status. docs/RUNNING-A-NODE.md - Sourcing is an ethical position, not a technical one. Courts and gazettes directly, a polite robots-respecting crawl where that is all a court publishes, licensed bulk data from Laws.Africa / AfricanLII, and SAFLII treated as a citation-resolution target rather than a scrape target. No single upload is trusted either way: the corpus is built collectively, and a document counts only once independent witnesses corroborate it. docs/SOURCES.md
- Decentralised in trust; not yet in distribution. The parts that are
built are the parts that matter most: content-addressed identity,
threshold signatures, a recomputable graph, offline nodes. The part that
is not yet live is moving a release peer-to-peer and having a public
corpus to move.
molao-dist(content-addressed packaging, a torrent export, a filesystem transport, and an iroh adapter behind--features iroh) is reached frommolao release publish/sign/fetch/torrent, andmolao release fetchwrites nothing if verification fails. But no release has ever moved through it — there is none to move, and nothing has been seeded. It does not by itself create a public corpus either. docs/DISTRIBUTION.md
The web UI running against the demo corpus — synthetic judgments with a real citation graph between them. There is no bundled corpus yet. Full tour in docs/SCREENSHOTS.md.
Molao runs by itself. It has no dependency on any hosted service or on a network.
Rust 1.85 or newer, and Node 20 or newer for the web UI. Nothing else — SQLite
is bundled by rusqlite, so there is no database to install and no connection
string to configure.
git clone https://github.com/vul-os/molao
cd molao
cargo build --workspace
cargo test --workspaceThe tests are the fastest way to see what the project guarantees: that canonicalisation is idempotent, that tampering with a judgment breaks its id, that one signer cannot reach a quorum by signing repeatedly, and that ordinary prose extracts no citations.
npm ci
npm run build
cargo run -p molao-nodeThe node binds 127.0.0.1 and serves the HTTP API plus the
embedded UI.
The node crate and UI are in progress. The API contract is specified and the core crates are complete, but the server is still being written. Run
cargo run -p molao-node -- --helpto see what your clone actually offers.
A node starts empty. Molao ships no bundled corpus, and no public signed
release exists. molao demo seeds a small synthetic corpus so you can see
search, judgments, citations and the graph working — it is part of the same
in-progress work as the server above.
To ingest real documents, read docs/SOURCES.md first. The sourcing rules are a deliberate ethical position.
A July 2026 sweep of the free-access-to-law world found the honest shape of the
problem: the LII aggregators mostly forbid AI use. Most publish a
robots.txt Content-Signal: ai-input=no, or block AI crawlers, or say so in
their terms. Molao honours that — its crawler reads the signal and, by default,
will not ingest a source that declines AI input into the corpus (which feeds a
RAG index). It never disguises itself to get around a control: it always
identifies as molao-node, always obeys robots.txt, and there is no
browser-spoofing option. See docs/CONTENT-SIGNALS.md.
So the corpus comes from courts and official publishers directly, or under
licence — the honest inversion of where you'd instinctively start. The full
per-jurisdiction map is docs/SOURCE-MAP.md; molao sources
prints the crawler's live registry. In brief:
| Status | Jurisdictions |
|---|---|
| 🟢 Usable now | New Zealand, Kenya, Ghana, Scotland, Northern Ireland, South Africa (Constitutional Court direct — SA judgments are public domain by statute) |
| 🟡 A free paperwork step away | England & UK Supreme Court (National Archives API, Akoma Ntoso), Ireland, Australia, federal Canada |
| 🟡 Via a Laws.Africa licence | Most of Africa, as bulk |
| 🔵 Preliminary | EU (EUR-Lex/CJEU), France, Netherlands, Germany |
| 🔴 Off-limits by their policy | BAILII, AustLII, NZLII, CanLII, SAFLII |
This is where an open-source community moves faster than any one team. The
code adapters (a court-direct parser for New Zealand, Ghana, the SA
Constitutional Court, EUR-Lex) are pick-up tasks behind one trait; a new
jurisdiction's court codes are a TOML region profile;
and the biggest unlocks are licence applications a person files — drafted and
ready in paperwork/. See the contribution list in
docs/SOURCE-MAP.md.
Both core crates work standalone, with no node and no network. If all you want
is a citation parser for your jurisdiction, molao-cite plus a region profile is that:
use molao_cite::{extract, Pinpoint};
let refs = extract("as held in S v Makwanyane [1995] ZACC 3 at para 87");
assert_eq!(refs[0].citation.key(), "neutral:1995:ZACC:3");
assert_eq!(refs[0].pinpoint, Some(Pinpoint::Paragraph { from: 87, to: None }));Sources are fetched by independent witnesses who sign the bytes they saw. A builder canonicalises the text, extracts citations with a pinned extractor, and produces a manifest. A quorum of independent organisations signs it. A node verifies the quorum and the chain, then serves the corpus locally — offline, forever, with nothing to phone home to.
flowchart TB
subgraph sources["Sources"]
courts["Courts & gazettes<br/>(direct — canonical)"]
la["Laws.Africa / AfricanLII<br/>(Akoma Ntoso, licensed)"]
end
subgraph witnesses["Independent witnesses"]
w["Witness A · B · C<br/>sign (doc_id, url, fetched_at, raw_hash)"]
end
subgraph build["Reproducible build"]
canon["canonicalise()<br/>DocId = BLAKE3(text)"]
cite["molao-cite extract()<br/>pinned EXTRACTOR_VERSION"]
man["Manifest<br/>corpus_root · graph_root · previous"]
end
subgraph quorum["Attestation — k-of-n, k ≥ 2"]
sig["Independent signers<br/>(universities, law societies, LIIs)"]
log["Public append-only log<br/><em>designed, not built</em>"]
end
subgraph node["A node — one binary, one SQLite file"]
ver["verify: quorum + chain"]
db[("SQLite + FTS5")]
api["axum HTTP API"]
ui["Embedded web UI"]
end
courts --> w
la --> w
w -->|"k-of-n corroboration"| canon
canon --> cite --> man --> sig
man -.-> log
sig -->|"SignedRelease"| ver
ver --> db --> api --> ui
Two absences are deliberate. There is no server a node must reach to function: a node with a corpus on disk needs no peers and no internet. And there is no embedding or vector index anywhere, because float inference is not reproducible across hardware — so a contributed index could never be verified — and a poisoned index is worse than a poisoned document, since the text stays correct while retrieval quietly steers.
Between nodes there is no hub. Every node holds a full copy. A release is a
content-addressed file set plus a signed manifest, so it can travel over
iroh, as a torrent export, or as a plain HTTP mirror — verified identically
regardless of which one carried it. The packaging, the torrent export and the
transports live in molao-dist
(docs/DISTRIBUTION.md), which nothing depends on yet;
today a plain file host, mirrored by hand, is still the only transport actually
moving bytes, because there is no public corpus yet to move. P2P will never be
required to read the law — a node with a corpus on disk needs no peers at
all.
There is nothing to configure to read the law. No config file is required, no database to point at, no credentials, no account, and no service endpoint.
| What | Default | Note |
|---|---|---|
| Bind address | 127.0.0.1 |
Serving a network is a deliberate flag, not an accident |
| Region profiles | the fourteen compiled in | --profiles <DIR> loads your own; they shadow the compiled-in profile of the same code, and the rest stay as the fallback |
| Storage | one SQLite file | Bundled; no external database |
| Network calls | none | A node makes no outbound requests of its own |
| Telemetry | none | There is no code to disable |
Node roles, what each costs to run, and the practical guidance are in docs/RUNNING-A-NODE.md.
| Document | What it covers |
|---|---|
| GETTING-STARTED.md | Clean clone to a running node, and what does not work yet |
| ARCHITECTURE.md | The binding contract: layers, identity, canonicalisation, storage, non-negotiables |
| CITATIONS.md | The citation grammar the parser implements — neutral, reported, historical, case numbers, pinpoints, keys; and which parts are profile-driven |
| COURTS.md | The region-profile contract, the shared tier model, and how to add a jurisdiction |
| RELEASES.md | Threshold signing, manifest chaining, content-addressed packaging, and how to verify a release yourself |
| DISTRIBUTION.md | How a release travels: content-addressed packaging, iroh, torrent export, HTTP mirror, and verification on receipt — the molao-dist crate, reached from molao release |
| RAG.md | The local, rebuildable, unsigned search cache: what it indexes, why it is never part of a release, and how to build one |
| PROVENANCE.md | Witnesses, corroboration, and the Corroborated / Single / Manual classes — the model that lets a corpus be built collectively |
| THREAT-MODEL.md | Poisoning, split view, why embeddings are excluded, why a rebuildable RAG cache doesn't reopen that, distribution over untrusted transports, and what is not protected |
| SOURCES.md | How to source responsibly in any jurisdiction: direct, robots-respecting crawl, licensed bulk, and why an LII that declines bulk supply is not scraped |
| SOURCE-MAP.md | The live per-jurisdiction map: what is usable now, what needs an adapter, what needs a licence — and how to help |
| CONTENT-SIGNALS.md | How the crawler reads Content-Signal and AI-crawler blocks, and the three layers (identity, robots, signal) — which are absolute and which is a policy |
| RUNNING-A-NODE.md | The four roles — Mirror, Witness, Builder, Attestor — and what each costs |
| API.md | The node's read-only HTTP API, endpoint by endpoint |
| SCREENSHOTS.md | The screenshot set and how to regenerate it |
| FAQ.md | Straight answers, including the ones that are "not yet" |
Also: GOVERNANCE.md (the signer set, what a signature does and does not attest, and the open questions on takedown and data protection), ROADMAP.md (phases, with what is done, in progress, designed-not-built, and deliberately excluded), CONTRIBUTING.md, CODE_OF_CONDUCT.md, SECURITY.md, CHANGELOG.md, and CITATION.cff if you need to cite this in research or teaching.
If you want to help: the highest-leverage tasks are laid out in
SOURCE-MAP.md — verify a
court-direct host, write an adapter, add a region profile (a TOML file, no
code), or file one of the licence requests drafted in
paperwork/. Issue templates exist for each. And if your
institution might hold a signing key, that is the one thing the project cannot
do for itself — threshold < 2 is refused in code, so Molao cannot publish
anything until two independent organisations say yes.
# Rust workspace
cargo build --workspace
cargo test --workspace
cargo clippy --all-targets -- -D warnings
cargo fmt --all -- --check
# Web UI
npm ci
npm run build
npm run typecheck
npm run lintCI runs exactly these (.github/workflows/ci.yml).
Every crate is #![forbid(unsafe_code)]. Determinism in molao-cite is a hard
contract, not a preference: no hash-map iteration order in output, no locale, no
clock, and any change to extraction behaviour bumps EXTRACTOR_VERSION —
including adding a court or a law-report series. Read
docs/ARCHITECTURE.md before changing anything
structural; it is the contract.
Contributions welcome, and some of the most useful ones involve no code: citation-parser test cases from real judgments that are mis-parsed, court and series registry corrections, running a node, and the institutional work of assembling a genuinely independent signer set. See CONTRIBUTING.md.
The mark in brand/ is the source of truth. Every icon this repo
ships — favicon, PWA and app icons, the mark in the README and on the site — is
rendered from brand/logo.svg rather than redrawn, so there is one approved
drawing and no second copy to drift.
Copy it outward, never edit a derived copy, and never edit brand/ to match
something downstream.
MIT OR Apache-2.0 — © Molao contributors. Source and issues at github.com/vul-os/molao. The judgments themselves are not anyone's to license — they are public documents, the work of the courts.
![]()
vulos — open by design



