Skip to main content
Glama

Precedent

Case law for your codebase. Decision records are immutable, so later decisions quietly overrule parts of earlier ones while the old header still says Accepted. Precedent reads that prose once, builds the citation graph in Relate, and tells you — and your coding agent — which clauses are still good law.

▶ Try it in your browser  ·  Demo video (1:33)  ·  Method  ·  Evaluation  ·  Agent integration

The Precedent explorer: ADR-0116 is declared Accepted, but seven of its ten clauses were taken out of force by three later decisions

Everything in that screenshot is answered by Relate compiled to WebAssembly, running in the browser tab — no server.

Use case

Teams (and agents) increasingly steer software with decision records: ADRs, RFCs, specs. The records are write-once, so a change of mind is a new record that says, in a sentence somewhere inside it, "§4 is superseded". Nothing updates the old one. A reader — human or LLM — who opens the original acts on dead clauses.

We ran Precedent on the real, public decision log of Relate itself — 533 ADRs in relatedb/relate:

decisions partly or wholly superseded by a later decision

115 (21.6 %)

…of which the header still says Accepted or Proposed

111

flat full-text searches whose top‑5 contain at least one such decision

74.5 % of 533 queries

tasks where a model, given those documents, builds on an already‑overruled clause (24 tasks × 3 runs, Claude Sonnet 5.5)

63.9 % → 4.2 % once preflight is in its context; a generic "be careful" note changes nothing (66.7 %) — details and limits

ADR-0116 — Fixed namespaces…

declared Accepted; §1, §4–5, §7–10 are out of force (ADR‑0229, ADR‑0276, ADR‑0307); §2–3, §6 still stand

Which relationships matter? treatments — "A supersedes §4 of B", "C reverses A", "D withdraws part of E" — and the citations and code paths around them. That is a graph, and "is this still good law?" is a question about walking it.

Related MCP server: ratchet-mcp

What Precedent does

Standing

Per clause, not per document: in force, partly superseded, out of force, contested. Computed with grounded argumentation semantics, so "A overruled B, then C overruled A" resolves correctly (B is good law again).

Evidence on every edge

Each treatment keeps the exact sentence it came from, the rule that fired and a confidence — a human can check any claim in one click.

Preflight for agents

preflight(task, paths) returns the decisions an agent must respect, with stale clauses flagged and the controlling decision pulled in, inside a token budget. Served over MCP.

A guard for agent‑written decisions

propose_decision writes the draft into the graph inside a Relate transaction, recomputes standing on the uncommitted state, and reports which decisions change, who relies on what you are overruling, and errors that each carry a fix — then commits or rolls back. A dry run is a what‑if.

Overlap finder

find_overlaps(draft) — before an agent writes a decision, it points at the clauses the draft would overrule (declare them) and at ground that is already out of force (cite the replacement). A ranking, not a ruling: the agent writes the language, the graph checks the claim. Measured on 55 real overrulings in the evaluation.

Header patches

precedent fix-status turns each stale "Accepted" into a reviewable one‑line diff, in the corpus's own wording (Superseded in part by ADR‑0229 (§1, §4–5)). On the real corpus: 111 stale headers → 0, no verdict changes (verified).

cite‑check

Stale statuses, reliance on superseded clauses, ghost file paths, near‑duplicate decisions, temporal impossibilities. CI‑friendly (--fail-on-warn).

Browser explorer

The same graph in your tab, queried with Cypher — try it.

precedent status ADR-0116

Try it

No install — open the explorer: search any decision to see which clauses still hold and who overruled the rest, browse all 533, or see the whole network. The Query tab runs your own Cypher on the same graph.

CLI (Python ≥ 3.10; uv recommended). The store is already in the repo — nothing to build, no keys, no network:

git clone https://github.com/ZNLong2203/precedent && cd precedent
uv sync
uv run precedent demo                       # 20-second tour
uv run precedent status ADR-0116            # clause-level standing + the quoted evidence
uv run precedent preflight "add support for creating and switching between multiple databases"
uv run precedent overlaps "Allow creating and dropping databases instead of three fixed namespaces"   # before you write a decision
uv run precedent fix-status --limit 5       # which headers still say Accepted, and what they should say (--diff for a patch)
uv run precedent cite-check                 # 300+ structural findings, grouped
uv run precedent propose examples/proposal-multi-tenant.json    # what-if: dry run of a draft ADR

Inspect the raw Relate store with the stock relate CLI (read-only, so git stays clean):

curl -sSfL https://relatedb.ai/install.sh | bash
relate -d data/relate-adr.rl --read-only "MATCH (d:Decision) WHERE d.status = 'accepted' AND d.standing = 'partial'
  RETURN d.id, d.title, d.out_clauses ORDER BY size(d.out_clauses) DESC LIMIT 10"
relate serve --database data/relate-adr.rl --read-only --bolt 7687 --http 7474 --mcp 7475 --auth none   # Bolt: the official Neo4j driver connects (examples/bolt_driver.py)

With your coding agent — the repo ships a project‑scoped .mcp.json and a Claude Code skill. Open the repo in Claude Code, approve the precedent server, and ask: "Add support for multiple databases to Relate — what do I have to respect?" → what the agent sees.

precedent propose: a draft ADR is rejected because two live decisions rely on what it overrules

How it uses Relate

  • Mode: single file (data/relate-adr.rl, 17 MB, committed).

  • Why this mode:

    • Not :memory: — judges must be able to open the graph, and the standing it holds is the product.

    • Not a directory — one file is the unit of sharing, of git history, and of forking: a .rl bundle copy is a complete, writable fork of the graph, which is how the guard simulates a draft against a read‑only store without touching it.

    • The stock relate CLI and relate serve (Bolt/HTTP/MCP) open the committed file as‑is, and the official Neo4j Python driver queries it over Bolt (examples/bolt_driver.py, tested with driver 6.4.1).

  • What the graph models — decisions as cases, clauses as holdings, treatments as how later cases treat them:

graph LR
  D((Decision)) -- HAS_CLAUSE --> C((Clause))
  D -- "CITES {section, clauses, evidence}" --> E((Decision))
  D -- "SUPERSEDES · REVERSES · WITHDRAWS<br/>AMENDS · REINSTATES · AFFIRMS<br/>{scope, clauses, evidence, rule, confidence, effective}" --> E
  D -- "REFERS_TO {section}" --> P((CodePath))
  D -- "SIMILAR {score, cited}" --> E

533 Decision, 1 591 Clause, 697 CodePath nodes; 3 741 CITES, 362 treatment edges, 2 548 SIMILAR. standing, out_clauses and controlled_by are derived by standing.py and written back, so plain Cypher answers "what is still good law?".

Relate capability

Where Precedent uses it

Embedded Python library (relate-db)

the whole app runs in‑process — no server to start (graph.py)

Single‑file .rl store, constraints, persisted indexes

graph.build; unique Decision.id, Clause.key, CodePath.path

Full‑text (BM25) + vector index / SEARCH

hybrid retrieval: decisions + clauses + 96‑d offline LSA vectors fused with RRF (api.search); "More like this" in the browser uses the stored vector as the query

Cypher: quantified paths, shortestPath, list predicates

explain, cite‑check, the Ask Relate examples

Explicit transactions + rollback, read‑your‑writes

guard.propose: write the draft, recompute standing on uncommitted state, commit or roll back

Whole store is one file → cheap fork

what‑if on a read‑only store (guard.scratch_copy)

read_only=True, many readers / one writer

CLI and MCP open read‑only; the lock error is explained (StoreLocked)

WebAssembly build (@relate/relate-wasm)

the explorer: every query runs in the tab

MCP

our intent‑level server (mcp_server.py, in‑process Relate) on top of Relate's own read_cypher/write_cypher (relate serve --mcp)

Bolt / HTTP via relate serve

the official Neo4j driver connects (example); Neo4j Browser is documented by Relate as compatible, but we have not tried it

Setup and run

Prerequisites: Python 3.10+, uv (or pip install -e .). Optional: the relate CLI and Node (only to re‑vendor the WASM bundle).

uv sync --extra dev          # install
uv run pytest                # 72 tests, a few seconds (real Relate store, real MCP calls, 31 real ADRs)
uv run precedent --help

To build a store for your own decision records (NNNN-title.md, ADR style):

uv run precedent index /path/to/repo --adr-dir docs/adr --out my.rl --name my/repo
uv run precedent cite-check --store my.rl
uv run precedent mcp --store my.rl            # serve the tools to an agent (stdio)

Reproduce the committed store and every number in the docs from the pinned upstream commit: make data eval (clones relatedb/relate at 1ebb65e).

Where the data lives

Path

What

data/relate-adr.rl

the persistent Relate store (single file; relate info -d data/relate-adr.rl)

data/relate-adr.lsa.npz

the LSA basis used to embed queries for the vector index

data/gold/

all 178 negative treatments with an audit label (how)

docs/data/graph.json

the browser export of the same store

tests/fixtures/relate-adr/

31 real ADRs used for regression tests

How well does it work?

Full numbers and caveats in docs/evaluation.md. Headlines:

  • Precision of the 178 negative treatments (every one read against its evidence): 176 correct, 1 plausible, 1 wrong — but the rules were tuned on this audit; held‑out precision is unmeasured.

  • Agent behaviour (24 tasks, 3 runs each, a model with no tools): relied on an overruled clause in 46 of 72 runs with the documents alone, 48 of 72 with a generic warning, 3 of 72 with preflight. The tasks were chosen where such a clause exists, only what the model says it relies on was scored, and the one residual miss is a decision preflight did not surface — see §8.

  • Recall of explicit overruling statements ≈ 91–97 % on a held‑out sample (statements phrased without any trigger word are invisible to that estimate).

  • 0 of 184 dated treatments are temporally impossible (actor older than target).

  • Latency on the real graph: status 0.35 ms, hybrid search / preflight ≈ 45 ms (p50).

Limitations (honest list)

  • Rule‑based extraction tuned on one corpus (Relate's ADRs, written in a very regular style). Other styles will extract less; the evidence‑on‑every‑edge design makes errors cheap to spot. No LLM is used at runtime.

  • Clause granularity needs numbered clauses in ## Decision; otherwise supersession is tracked as "a part of it".

  • Relate is single‑process and keeps the graph in RAM: one writer at a time (readers are fine), working set must fit in memory — a non‑issue for decision records.

  • The corpus never contains an overruling that is itself fully overruled, so the restoration path of the standing engine is covered by unit tests, not by the demo data.

  • The browser explorer is a sandbox copy; edits there never leave the tab.

Where models are involved

The shipped product makes no model calls. Two places involve a model: the gold audit labels were produced by an AI assistant rather than a human (see data/gold/README.md), and the evaluation calls one: scripts/agent_eval.py run feeds prompts to Claude Sonnet 5.5 through the claude CLI as the model under test (prompts, raw answers and per-call metadata are committed in data/agent-eval/).

License and attribution

Apache‑2.0 (LICENSE). The decision records analysed are © Neo4j, Inc. and contributors, Apache‑2.0, from relatedb/relate; see NOTICE. Vendored: @relate/relate-wasm (Apache‑2.0), force-graph (MIT). Relate and Neo4j are trademarks of Neo4j, Inc.; this project is not endorsed by Neo4j.

Available Tools

9 tools
cite_checkC
Read-onlyIdempotent

Structural findings: stale statuses, reliance on superseded clauses, ghost paths, near-duplicates...

Inputs: limit, categories. Returns: object

decision_statusB
Read-onlyIdempotent

Is this decision still good law? Clause-level standing, who treated it and the quoted evidence, who relies on it.

Inputs: decision (required). Returns: object

find_overlapsA
Read-onlyIdempotent

Before you write a decision: which existing clauses does your draft overlap? Paste the draft text (and/or the files it touches). Flags clauses that still bind (declare them in treats if you change them) and clauses already out of force (cite their replacement instead). A ranking, not a ruling - then verify with propose_decision.

Inputs: draft, limit, paths. Returns: object

graph_schemaA
Read-onlyIdempotent

The graph model and example Cypher for query_graph.

Inputs: no named parameters. Returns: object

preflightB
Read-onlyIdempotent

Which decisions must you respect before doing task / touching paths? Returns good-law-aware cards: live clauses are binding; stale clauses name the decision that replaced them.

Inputs: task, limit, paths, budget_tokens. Returns: object

propose_decisionA

Review a draft decision against the graph before it lands (dry run unless commit=true). treats: [{target:'ADR-0116', kind:'SUPERSEDES'|'REVERSES'|'WITHDRAWS'|'AMENDS', clauses:[1,4], reason:'...'}]. cites: [{target:'ADR-0276', clauses:[1]}]. Returns errors (each with a fix), warnings, which decisions change standing, who relies on what you overrule, and the ADR markdown to save.

Inputs: title (required), body, cites, commit, +4 more. Returns: object

query_graphB
Read-onlyIdempotent

Run a READ-ONLY Cypher query. Rows are capped; a capped result says so in truncated.

Inputs: cypher (required), max_rows, parameters. Returns: object

search_decisionsB
Read-onlyIdempotent

Hybrid search (BM25 + clause BM25 + vector) over decisions; each hit carries its standing.

Inputs: query (required), limit. Returns: object

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    A3.5/5.0

    Scored across 9 tools

    Disambiguation4/5

    Each tool has a distinct role: preflight (pre-work obligations), find_overlaps (pre-authoring overlap check), decision_status (single-decision standing), cite_check (corpus-wide structural audit), search/explain/query for retrieval, and propose_decision for writes. The closest pair is preflight vs. find_overlaps, which both surface binding clauses, but their descriptions clearly separate 'before doing a task' from 'before writing a decision'. decision_status and cite_check also overlap mildly on staleness reporting, though at different granularities.

    Naming Consistency4/5

    All names are lower snake_case, which is consistent. Most are verb_noun (search_decisions, explain_link, cite_check, find_overlaps, propose_decision, query_graph), but decision_status and graph_schema are noun_noun and 'preflight' is a bare noun with no verb, so the pattern is not fully uniform. Still readable and predictable enough.

    Tool Count5/5

    Nine tools is well within the ideal range for a decision-graph server. Each tool maps to a recognizable workflow step (orient, search, inspect status, audit, draft, propose), and graph_schema is a small but justified companion to query_graph. No obvious redundancy or padding.

    Completeness4/5

    The surface covers the full decision lifecycle: search, standing checks, citation tracing, structural auditing, drafting, and committing via propose_decision. Minor gaps remain, such as no explicit get_decision for fetching a full decision body by ID (workable via search or query_graph) and no listing/timeline operation. Agents can work around these through the Cypher escape hatch, so no dead ends.

    Maintenance

    ActivityMaintained
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      Not graded
      quality
      C
      maintenance
      Provides a decision memory layer for codebases, enabling AI agents to search, retrieve, and record business decisions with metadata filters and full-text search.
      1
      MIT
    • A
      license
      Not graded
      quality
      B
      maintenance
      Enables AI agents to read and update a repository's decision ledger, check which files a decision governs, find stale files after a decision reversal, and record or reverse decisions over MCP.
      20 npm
      Apache 2.0
    • A
      license
      Not graded
      quality
      B
      maintenance
      Enables coding agents to locally record decisions with constraints, evidence, and answers; search validated precedents; and explicitly supersede prior calls while keeping linked history. Also provides tools for expanding records, reviewing active context, checking coverage and status, and finding duplicates or stale decisions without network access.
      301 npm
      MIT