AusLaw MCP
# jurisd
**Source-grounded Australian & New Zealand legal research, on your own machine.**
jurisd is an open, local-first research and drafting workbench for AU/NZ law. It
gives you, or the AI assistant you already use, fast answers from legislation and
case law where **every claim traces back to the primary source**. It runs locally
by default, so confidential and privileged work never has to leave your machine.
```mermaid
flowchart LR
q["Query: a case name<br/>or cases citing X"]
q --> route{"In a local module"}
route -->|"yes, offline"| local["Local recall:<br/>provision lookup,<br/>semantic search,<br/>citation graph"]
route -->|no| live{"AustLII reachable"}
live -->|"Cloudflare-blocked"| exa["Exa discovery<br/>or direct citation URL"]
live -->|yes| fetch
exa --> fetch["Fetch AustLII document<br/>HTML or PDF"]
local --> src["Primary source obtained"]
fetch --> src
src --> aglc4["Format AGLC4 citation"]
aglc4 --> trace["Trace cited-by and<br/>citing cases<br/>via the citation graph"]
trace --> out["Result:<br/>case text, AGLC4 citation,<br/>and citing cases,<br/>each linked to its source"]
```
Guiding principle: **no source span, no trusted legal claim.** Vector recall is
recall, not authority; a model's output is a candidate until you can see its
source and check it.
> _Previously published as `auslaw-mcp`._
**Status:** v0.5.0, pre-1.0. The surface that ships today is a CLI, a TUI search
shell, and a set of tools the AI assistant you already run can call, across live
research, citation and bibliography work, and local data modules. The longer arc
is in [Where this is heading](#where-this-is-heading).
## Why jurisd is different
- **Traceable, not hallucinated.** Every result links to its primary source (an
`austlii.edu.au` URL, the provision text, an AGLC4 citation). You verify it; you
do not take its word.
- **Local-first and private.** Recall, provision lookup, and the citation graph
work offline over installed corpora. Your matter stays on your machine.
- **Australian-law-native.** All AU/NZ jurisdictions, jurisdiction-aware search,
AGLC4 citation formatting.
- **Degrades visibly, never silently.** A missing key, dependency, or module
disables only the feature that needs it and says so. With no key and no network,
local-module recall still answers.
## Who it's for
- The **practitioner** who just wants to ask a question and get an answer they can
stand behind in front of a client or a court.
- The **researcher or student** who needs to trace authority, not just read a
summary.
- The **terminal-native power user** who wants scriptable, composable legal tools.
- The **builder** wiring AU/NZ legal research into their own AI agent.
## How jurisd answers
jurisd has three answer sources, tried in precedence order:
1. **Local data modules** (offline, no network, no key). Installed parquet bundles
holding legislation and decisions with provision-level structure, citation
edges, and chunk embeddings. This is the local-first core: deterministic
provision lookup, an Act containment tree, an offline citation graph, and local
semantic search.
2. **Live research over AustLII.** Natural-language case and legislation search,
full-text fetch (HTML and PDF), and AGLC4 formatting. AustLII's own search sits
behind a Cloudflare challenge, so discovery is recovered through Exa-backed
search (and direct citation URLs); the documents returned are AustLII primary
sources throughout. See [Tools](#tools) for the detail.
3. **OALC fallback.** An Open Australian Legal Corpus layer that backs the live
layer when a direct fetch is blocked.
## Quick start
### Run with npx (no clone)
```bash
npx -y jurisd
```
`npx` installs the package from its built distribution and launches the server
over stdio in one step. Before the npm registry package is published, use
`npx -y github:russellbrenner/jurisd`.
### Install the CLI persistently from NPM or directly from GitHub
#### npm published package
```bash
npm install -g jurisd
jurisd --help
```
#### npm install via git directly, including your own fork
```bash
npm install -g https://github.com/russellbrenner/jurisd/archive/refs/heads/main.tar.gz
jurisd --help
```
**NB:** Bare git installs such as `npm install -g github:russellbrenner/jurisd` depend
on npm's `install-links` setting and can leave a broken global bin on hosts where
`install-links=false`.
### Register with Your Coding Agent
```bash
claude mcp add jurisd -- npx -y github:russellbrenner/jurisd
```
Or add it to your client config directly:
```json
{
"mcpServers": {
"jurisd": {
"command": "npx",
"args": ["-y", "github:russellbrenner/jurisd"]
}
}
}
```
Using a different agent? [docs/HARNESS-SETUP.md](docs/HARNESS-SETUP.md) has
copy-paste configs for Cursor, Windsurf, VS Code, Cline, Continue, Codex CLI,
Zed, Gemini CLI, and more.
All environment variables are **optional** — with none set, the live AustLII
layer and the local-module recall layer both work. See
[docs/INSTALL.md](docs/INSTALL.md) for the local-clone path, every config option,
and the offline/baseline guarantee.
### Claude Code skill
A bundled [Claude Code skill](skills/jurisd-research/SKILL.md) teaches the agent
expert jurisd usage from day 0 — which of the 12 tools to reach for, the
local-first/live-fallback rule, AGLC4 citation workflows, and a
[worked research session](skills/jurisd-research/examples/research-session.md).
Install it by copying the skill folder into your skills directory:
```bash
cp -r skills/jurisd-research ~/.claude/skills/
```
(or your plugin's skills path). The skill activates automatically on legal-research
and AGLC4 prompts once the `jurisd` MCP server is registered.
## Tools
12 tools in three groups. Operation variants are selected via a
`mode` / `op` / `action` / `by` discriminator on the relevant tool.
### Live research (AustLII)
| Tool | What it does |
| --------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
| `search_cases` | Natural-language case-law search across all AU/NZ jurisdictions; authority ranking; title/phrase/boolean methods; pagination. |
| `search_legislation` | Search AU/NZ legislation with the same method/jurisdiction/sort controls. |
| `fetch_document_text` | Fetch full text from an AustLII URL (HTML, PDF). |
> **AustLII sits behind Cloudflare.** AustLII now serves a JavaScript
> managed-challenge that automated clients — including TLS-impersonating ones —
> cannot clear, so `search_cases` / `search_legislation` cannot query AustLII
> directly. Configure a **fallback source**; results are still AustLII primary
> sources (`austlii.edu.au` URLs) recovered through another channel.
>
> | Fallback | Env var | Cost | You gain | You lose |
> | ------------------- | ------------- | -------------- | ---------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
> | **Direct citation** | none | Free | Queries containing a neutral citation such as `[2018] HCA 9` resolve directly to the canonical AustLII case URL. | Citation-only. It is not general natural-language search. |
> | **Exa** | `EXA_API_KEY` | Paid/free tier | Search discovery returns canonical AustLII case/legislation URLs, even for obscure cases. | Discovery only (URL + citation); full text is fetched separately. |
> | **none** | - | - | - | Search returns a degraded result whose warning names the env vars; document fetch still falls back to the local OALC corpus when available. |
>
> Resolution order: direct citation URL when present, then Exa, then a degraded
> result. The document source remains AustLII throughout.
When AustLII search is Cloudflare-blocked, the tools degrade gracefully rather
than failing: `search_cases` returns any Exa results it can find
plus a `warning`, `sources`, and `degraded: true`, and reports incomplete
configured coverage (for example `exa: "not_configured"`) instead of hiding
that source status. `search_legislation` returns an empty degraded result with
the same machine-readable status instead of failing the tool call. CLI search
commands exit 4 for degraded source coverage.
### Citation + bibliography (AGLC4)
| Tool | What it does |
| ------------------ | -------------------------------------------------------------------------------------------------------------------- |
| `format_citation` | Format an AGLC4 citation. `mode`: `full` (default), `short`, `ibid`, `subsequent`, `pinpoint`. |
| `resolve_citation` | Resolve a citation to its source. `mode`: `auto` (default), `validate` (AustLII existence check), `search`. Falls back to the direct citation URL and Exa when AustLII is Cloudflare-blocked; `validate` reports `status` (`found`, `not_found`, `blocked`, `unreachable`, `invalid`) so a challenge is never mistaken for "not found". |
| `cite` | Write to the local citation cache. `action`: `add` (default) or `refresh_source` (conditional-HEAD freshness check). |
| `bibliography` | Read the local citation cache (no network). `op`: `get`, `list` (default), `export` (`.bib`), `cited_by`. |
### Local data modules (offline recall)
These five tools serve installed offline data modules. They require the optional
`@duckdb/node-api` dependency and at least one installed module;
`semantic_search_local` additionally needs `@huggingface/transformers`. Every
answer carries `metadata.source = "local_module"` with the module name, version,
and snapshot date (plus a staleness advisory when the snapshot is old).
| Tool | What it does |
| ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `get_provision` | Deterministic provision lookup (e.g. `s 18` of an Act). No embedding, no ranking; typed not-found so the router can fall through. |
| `get_act_structure` | Containment tree of an Act (Act → Part → Division → section/schedule/clause) over `act_provision` edges, closed-world. |
| `find_citing` | Documents in installed modules that cite a target, with each citation's provenance span. |
| `semantic_search_local` | Vector recall: the query is embedded locally (bge-small, offline, no key) and ranked by cosine over chunk embeddings, with optional facet pre-filters. |
| `list_data_modules` | Introspect installed modules: coverage, doc/chunk counts, embedding descriptor, load status, snapshot date and staleness. |
Full parameter tables for every tool are in
[docs/AGENT-GUIDE.md](docs/AGENT-GUIDE.md).
## CLI foundation and compatibility
jurisd keeps the MCP server as the compatibility surface while the CLI is being
reorganised around task-oriented command contracts.
- CLI guide: [docs/CLI.md](docs/CLI.md)
- MCP compatibility reference: [docs/MCP-COMPATIBILITY.md](docs/MCP-COMPATIBILITY.md)
- Security and authority model: [docs/SECURITY-AUTHORITY.md](docs/SECURITY-AUTHORITY.md)
Existing flat CLI commands remain available during the foundation work.
## Data modules
A **data module** is a self-describing parquet bundle (documents, chunks, edges,
unmatched citations, plus a `manifest.json`) published as a Hugging Face dataset.
Everything needed to load and query a module — schema version, coverage,
embedding descriptor, file hashes, and licence posture — is in its manifest. No
out-of-band config.
> **Status: first module published.** `legislation-cth` is available from
> `workingmem/legislation-cth` on Hugging Face. It provides Commonwealth primary
> and secondary legislation, 32,143 documents, 857,262 chunks, citation edges,
> unmatched citations, and local bge-small embeddings. Running
> `jurisd fetch-module legislation-cth` downloads the manifest and parquet files
> from Hugging Face, verifies every file against the manifest sha256 values, and
> installs the module atomically.
Modules are queried in place: DuckDB scans the parquet on disk and never
materialises a whole table into memory, so a host can install many modules
(Commonwealth legislation + per-state + decisions) and stay flat in RSS.
### Installing modules
Modules are **operator-installed via the CLI** (kept off the tool surface so an
LLM never triggers a large download mid-conversation):
```bash
jurisd fetch-module <name> [--modules-dir DIR] # download + sha256-verify + atomic install
jurisd verify-module <name> [--modules-dir DIR] # re-verify installed files against the manifest
jurisd list-modules [--modules-dir DIR] # list installed modules (incl. refused)
```
The default install root is `~/.jurisd/modules/` (override with
`JURISD_MODULES_DIR` or `--modules-dir`). `fetch-module` validates the manifest
and checks the schema version **before** downloading any parquet, sha256-verifies
every file against the manifest, installs atomically (temp-then-rename, so a
half-written module never appears), and prints the licence attribution lines at
install time.
Advanced operators can pass `--manifest-url URL` to install from an explicitly
trusted manifest. The sha256 checks prove downloaded files match that manifest;
they do not prove the manifest's provenance or protect against a malicious or
compromised manifest source.
### Baseline vs domain-specialised variants
A module's identity is `(name, module_version)`. The `module_version` handle
distinguishes a module's **variant** — a **baseline** module is the standard
build (deterministic structure, citation edges, bge-small embeddings); a
**domain-specialised** variant is a build tuned for a particular corpus or task.
Use `list_data_modules` to see the variant, coverage, and embedding descriptor of
each installed module, and pin a specific one with the `module` argument on any
recall tool.
### BYOK provider adapter
`semantic_search_local` has two optional enhancement slots that operate **over
the locally-retrieved top-k results** — they never replace local recall, they
refine it:
- **rerank** — reorder the local top-k by a stronger relevance model.
- **extractive-QA** — return the best answer span within a retrieved chunk.
Both are expressed through one vendor-neutral `DomainAdapter` interface. The
distinction is **capability presence**, framed as **baseline vs
domain-specialised** with a **provider-interpolated display label**:
- **Baseline** (always present): pure local cosine order. No network, no key.
- **Domain-specialised** (slot): selected only if a provider is configured **and
reachable** via a BYOK key. With `ISAACUS_API_KEY` set and the endpoint
reachable, the capability probe reports
`domain_adapter: { label: "Isaacus-enhanced", canRerank: true, canExtractiveQA: true }`
and responses carry `metadata.enhancement = "Isaacus-enhanced"`.
If the key is unset, or set-but-unreachable, the adapter degrades to baseline and
the tool still returns local cosine results — reported by the probe, never thrown
into a tool result.
## Quality
jurisd's local data layer is built and scored honestly against a gold set. The
`jurisd-data` gold-set evaluation measures the local enricher (segments, defined
terms, citation crossrefs) against 90 Open Australian Legal Corpus / Kanon ILDGS
documents, under two parallel metrics:
- **strict** — the conservative audit metric: every typed prediction unmatched
within its type is a false positive.
- **aligned** — the decision metric: a strict false positive whose span
co-locates an _untyped_ gold sub-span at IoU ≥ 0.9 is credited as a granularity
agreement (a vocabulary disagreement with the silver standard, not an extraction
error) rather than penalised.
The current baseline **does not yet pass all four gate thresholds** (segment F1,
citation precision, citation recall, defined-term F1). Headline segment F1 is
0.44 strict / 0.64 aligned against a 0.85 gate. The report localises every gap
to a specific rule (the residual segment gap is genuine over-segmentation, chiefly
an endnotes-boundary flood; citation precision is internal-ref over-firing on
structural lines). The published module exposes the resulting data artefacts;
evaluation reports remain part of the module publishing workflow until a public
report location is available.
## Where this is heading
The sections above describe what ships today. The longer arc for jurisd is a
secure, local-first workbench for high-trust legal work, built so serious
reasoning can happen on your own machine with every act provable and nothing
leaving without your say-so. Planned directions (design intent, not yet built):
- **A sandboxed local agent runtime.** Run a research and drafting agent over your
own sources inside an isolated, encrypted workspace, so sensitive and privileged
material cannot leak.
- **Tamper-evident provenance.** An auditable record of every step, and an
Evidence Pack you can hand a reviewer to verify process and sources (not legal
correctness).
- **A first-class desktop app and TUI.** Matter view, source and provenance pane,
review queue, and a drafting canvas, for both terminal-native researchers and
practitioners who just want a clean interface.
- **An SDK and plugin base,** with connectors for the tools you already use (Word,
Obsidian, Zotero).
- **Source-anchored drafting.** Work-product where every assertion carries its
citation, gated by human review.
Nothing in this list is claimed as built. See [ROADMAP.md](docs/ROADMAP.md) for
the sequenced workstreams and review gates.
## Licensing
- **Code:** Apache-2.0 (see [LICENSE](LICENSE)). Third-party dependency licences are
catalogued in [LICENSE-THIRD-PARTY.md](LICENSE-THIRD-PARTY.md).
- **Module data:** licensed **per source**, declared in each module's
`manifest.json` `licence` block, and surfaced at `fetch-module` install time.
The aggregate is CC-BY-4.0 (Open Australian Legal Corpus), but redistribution is
decided per source, not in aggregate:
- **AustLII-sourced rows are excluded from published modules by default** — the
AustLII Terms of Service is restrictive, and re-importing it is exactly what
the live transport layer routes around. They remain available **recipe-only**
(rebuild locally).
- **VIC** and **NT** legislation are **not redistributable** (Government Printer
/ Crown copyright, no open licence) — **recipe-only**.
- Commonwealth (FRL), NSW, QLD, SA, TAS, WA legislation and HCA/FCA/NSW
case-law sources are redistributable under the CC-BY-4.0 aggregate, subject to
per-source confirmation before each module publishes.
Each published module carries its own `licence` block in `manifest.json`,
surfaced at `fetch-module` install time.
## Documentation
| Document | Description |
| -------------------------------------------------------- | -------------------------------------------------------------------------- |
| [INSTALL.md](docs/INSTALL.md) | Day-0 install paths, Claude Code config, env vars, module flow |
| [HARNESS-SETUP.md](docs/HARNESS-SETUP.md) | Copy-paste MCP config for every popular coding agent (CC, Cursor, Zed, …) |
| [CLI.md](docs/CLI.md) | CLI command shape, compatibility aliases, output rules, exit codes |
| [MCP-COMPATIBILITY.md](docs/MCP-COMPATIBILITY.md) | Compatibility reference for the current MCP tool surface |
| [SECURITY-AUTHORITY.md](docs/SECURITY-AUTHORITY.md) | Command authority, side-effect classes, terminal safety, credential rules |
| [jurisd-research skill](skills/jurisd-research/SKILL.md) | Claude Code skill: tool decision guidance, AGLC4 workflows, worked example |
| [AGENT-GUIDE.md](docs/AGENT-GUIDE.md) | Agent-facing usage guide with full tool catalog and examples |
| [ARCHITECTURE.md](docs/ARCHITECTURE.md) | System architecture, deployment topology, CI/CD |
| [DOCKER.md](docs/DOCKER.md) | Docker deployment guide |
| [ROADMAP.md](docs/ROADMAP.md) | Forward-looking project roadmap and review gates |
## Jurisdictions
| Code | Jurisdiction |
| --------- | ------------------------------ |
| `cth` | Commonwealth of Australia |
| `federal` | Federal courts (alias for cth) |
| `vic` | Victoria |
| `nsw` | New South Wales |
| `qld` | Queensland |
| `sa` | South Australia |
| `wa` | Western Australia |
| `tas` | Tasmania |
| `nt` | Northern Territory |
| `act` | Australian Capital Territory |
| `nz` | New Zealand |
| `other` | All jurisdictions (no filter) |
## Example queries for AI assistants
Once connected, ask natural-language questions:
- "Find the High Court decision in Mabo v Queensland (No 2) and explain native title."
- "Search for recent NSW cases about defamation on social media."
- "What does section 18 of the Australian Consumer Law say?" (answered offline if the module is installed)
- "Find cases that cite Mabo v Queensland (No 2)."
- "Format `Mabo v Queensland (No 2) [1992] HCA 23 (1992) 175 CLR 1` per AGLC4 at [64]."
- "Compare how Victoria and NSW courts have treated non-compete clauses."
## Development
```bash
git clone https://github.com/russellbrenner/jurisd.git
cd jurisd
npm install
npm run dev # hot reload
npm run build # TypeScript compile
npm start # run the built server
npm test # unit + integration + perf (integration hits live services)
npm run lint # ESLint (flat config)
```
### Docker
```bash
./build.sh # build the image
docker-compose up # run locally
```
See [docs/DOCKER.md](docs/DOCKER.md) for details.
### Kubernetes (k3s)
```bash
./build.sh
# import the image to k3s nodes (see k8s/README.md)
./deploy-k8s.sh
```
See [k8s/README.md](k8s/README.md).
## Contributing
See [CONTRIBUTING.md](CONTRIBUTING.md) and [SECURITY.md](SECURITY.md) for
responsible disclosure.
**Key principles:**
- Primary sources only (no journal articles)
- Citation accuracy is paramount
- Degrade visibly, never silently
- All unit tests must pass before committing
## Disclaimer
**This tool is for legal research purposes only and does not constitute legal
advice.**
- Search results may not be comprehensive and should not be relied upon as a
complete statement of the law.
- Source databases may not include all decisions or the most recent updates.
- Always verify citations and check for subsequent treatment of cases.
- Legal advice should be sought from a qualified legal practitioner for any
specific legal matter.
- The authors and contributors accept no liability for any loss or damage arising
from use of this tool.
## License
Apache-2.0
TDQS
Scored across 12 tools
Tools fall into clear groups—searching, fetching text, citation formatting/resolution, cache read/write, and local module lookup—so most are easy to distinguish. A few pairs (fetch_document_text vs get_provision, and the online searches vs semantic_search_local) could be confused at a glance, but their descriptions make the offline/online and document/provision boundaries clear.
Most tools follow a predictable verb_noun pattern like search_legislation, resolve_citation, get_act_structure. Deviations like 'cite' and 'bibliography' are single words rather than verb_noun, and semantic_search_local reverses the expected order, but the naming remains readable and mostly consistent.
Twelve tools is well within the ideal range and appropriate for a legal research server covering online search, document fetching, citation management, and offline analysis. Each tool addresses a distinct part of the workflow without obvious redundancy.
The toolset covers the core legal research lifecycle: search, retrieve, format/resolve citations, cache citations, and query local data modules. Minor gaps exist (e.g., no explicit citation deletion or update tool, no direct document download by ID), but agents can complete typical workflows.