Korely

Use cases Legal assistant

A legal agent that keeps every matter in its own folder

Per-matter scoping so Deal A stays out of Deal B, deal terms that know what is true now and what used to be, and an EU-hosted audit trail. Reachable from any framework over the REST API or SDK.

On this page

The idea

Think about a great paralegal who has been at the firm for ten years. You hand her a new matter and she does not start from zero. She already knows that this client always wants the indemnity cap at twelve months of fees, that the partner hates passive voice in recitals, and that on the last deal we conceded the non-compete down to eighteen months.

But here is the part that makes her great. When she is working on the Acme deal she is thinking only about Acme. She does not accidentally drop a Beemark clause into an Acme contract just because she read it last week. She keeps each matter in its own folder in her head.

That is exactly the memory you want to give your agent, and it is the part that is genuinely hard to build. Korely is that per-matter notebook, scoped so nothing crosses over.

How you build it

Six steps, and the last one is the piece you skip

  1. Pick your stack

    You already have Claude Code or Cursor to write the agent, and your favorite framework to run the loop. The agent reads the matter file, drafts a clause, flags a risk. That part is the easy part and you can stand it up in an afternoon.

  2. Decide what is worth remembering on every matter

    Deal terms the client agreed to, the precedent clauses you reused, the partner drafting preferences, the positions you conceded last round, the counterparty habits. Each of these is a small durable fact, not a whole document.

  3. Scope every memory to a single matter

    This is the rule you cannot get wrong. The Acme agent must read Acme facts and only Acme facts. One leak of Deal A confidential terms into Deal B is not a bug, it is a malpractice problem. So you give each matter its own user_id and you isolate the store so nothing crosses over.

  4. Make the facts time-aware

    A negotiation moves. The cap was twelve months on Tuesday, the client agreed to twenty four on Thursday. The agent has to answer from what is true now, while still being able to show what it used to be, because in legal the history is the audit trail.

  5. Handle contradictions on the way in, not on the way out

    When the new position lands, the old one has to be marked superseded automatically, with both versions kept. Otherwise your agent will happily cite a term the client walked away from three rounds ago. Pair that with retrieval that finds the right clause by meaning, plus typed facts you can look up by entity with get_facts(entity=...) when the agent needs the related limitation of liability and the survival provision.

  6. Skip the hard part with Korely

    Now the honest part. Steps three through five are a bi-temporal graph-RAG memory layer, and building that yourself is months of work, a Postgres schema you will get wrong twice, a contradiction resolver, and a retrieval pipeline you have to tune. With Korely you skip all of it. You call one add to store a fact scoped to a matter id, one get_context to read back the facts true now, and the per-matter scoping, the time-awareness, the contradiction handling, and the graph are already done. You keep building the lawyer-smart part. We keep the memory honest, for 19 euro a month + VAT after the free tier.

The shape of the fix

Write per matter, read back only what is true now

Round 1, the Acme deal

The agent records a deal term

  • Client agrees: indemnity cap = 12 months
  • Scoped to matter "acme-2026"

Korely memory

Acme matter, under its own id

  • cap = 12 months (superseded)
  • cap = 24 months (current)

Round 4, drafting

The agent reads it back

  • get_context(..., user_id="matter-acme-2026")
  • Reads the Acme facts true now first
Each matter sits under its own id. The Acme agent passes the Acme id and reads Acme facts, and it answers from the cap that is true now, not the one the client walked away from.

How Korely fits

Korely saves you from building a bi-temporal graph-RAG memory store with per-matter scoping. That means the typed fact layer (this client wants the cap at twelve months), the two time axes, so a fact knows both when it was true in the negotiation and when you recorded it, the two-stage contradiction resolver that retires the superseded position the moment a new one arrives, the entity graph that links a clause to its related provisions, and the vector retrieval (pgvector plus a lookup of the typed facts) that finds the right precedent by meaning.

It matters specifically here because legal work is adversarial and auditable. You cannot ship an agent that quotes a walked-back term, and you absolutely cannot ship one that recalls Deal A confidential terms while drafting Deal B. The store is Postgres only and EU-hosted, and the Self-hosted plan puts the same engine on your own infrastructure when privileged client data cannot leave it.

And it is fast where it counts. Reads run no generative model, so the memory lookup is a database query in the drafting loop, not another model turn. The context block stays under a token budget you set, 800 tokens by default, however long the matter runs. And every fact carries two times: when it was true, and when Korely learned it, so you can show what the agent knew on the day it drafted a clause.

Show me the code

A minimal write-then-read, scoped to one matter

legal_assistant.pypython

# ── The agent learns a deal term on the Acme matter ────────────
from korely_memory import Korely

korely = Korely(api_key="kor_live_...")

# Client agrees the indemnity cap. Scope it to this matter only.
korely.add(
    "Client agreed indemnity cap at 12 months of fees. "
    "Partner wants no passive voice in recitals.",
    user_id="matter-acme-2026",
)

# ── Round 4: the agent drafts the indemnification section ──────
context = korely.get_context(
    "indemnity cap and drafting preferences",
    user_id="matter-acme-2026",
)
# context.context → the Acme facts true now first, never a Beemark term.

# The agent prepends this to its prompt before drafting.
# The Beemark matter lives behind its own user_id: a read that
# passes this id never returns it.

The same memory is reachable from any agent, Claude Code, Continue, n8n, LangGraph, or a plain HTTP client. A different user_id per matter keeps each client's facts apart: reads pass that id, and a new term can only supersede facts of the same matter. agent_id separates reads only, so two matters written under one user_id (or none) can still close each other's facts.

When the term moves

The agent drafts from what is true now, and can still show the timeline

It is round four of the Acme acquisition. Early on, the client agreed to an indemnity cap of twelve months of fees. Two weeks later, after the disclosure schedules came back ugly, they pushed it to twenty four. Your associate asks the agent to draft the indemnification section.

A plain agent that just retrieves the most semantically similar paragraph might grab the twelve-month line, because it appears more often in the thread. The agent built on Korely answers from what is true now. The twelve-month fact was marked superseded the instant the twenty four-month position landed, so the draft comes back with twenty four months, and the agent can still show the partner the timeline of how the cap moved if anyone asks why.

Same scene, different matter. The moment the agent switches to the Beemark file and passes the Beemark id, the Acme cap is not in scope, so it does not bleed one client terms into another contract.

timeline.pypython

korely.add(
    "Indemnity cap = 12 months of fees.",
    user_id="matter-acme-2026",
    timestamp="2026-02-04",
)

# Two weeks later the client pushes the cap up
korely.add(
    "Indemnity cap = 24 months of fees.",
    user_id="matter-acme-2026",
    timestamp="2026-02-18",
)

ctx = korely.get_context("indemnity cap", user_id="matter-acme-2026")
# once extraction has run, ctx.context lists under Known facts what is true now: 24 months. The 12-month fact is closed.

# The full audit trail, with when each fact started and stopped being true:
korely.get_facts(user_id="matter-acme-2026", include_invalidated=True)
# each Fact has valid_from and invalid_at

Frequently asked

How do you guarantee one client's terms never leak into another client's contract?

You give every matter its own user_id when you write, and you pass the same id on every read, so the Acme agent reads Acme facts only. A read that leaves the id out spans every matter in the project. For a hard wall, hand the drafting agent a key confined to the matter's user_id (create_key(..., users=[...])), or keep each client in its own project.

My client agreed to a term, then changed it mid-negotiation. Which version does the agent use?

The current one. Facts in Korely are time-aware. When the new position lands, the old one is marked superseded automatically and the agent answers from what is true now. The old version is not deleted though, it is kept in the timeline, so if a partner asks why the cap moved you can show the full history. In legal that audit trail is a feature, not clutter.

Is this safe enough for privileged client data?

The store is Postgres only and hosted in the EU, in Helsinki. For privileged material that must stay on your own infrastructure, the Self-hosted plan runs the same engine on your servers, with the model provider you choose. On the hosted tiers you write and read over a REST API or the Python and Node SDK, nothing to host yourself, and you can list a matter memory page by page or erase it with one call. The text of each write, with the matter's identifier, up to ten of that matter's earlier memories, the earlier facts it is compared with, and the phrase of any relation that matter has not used before, with a value, goes to the model of your project's region to extract facts, the Gemini API by default or Scaleway in Paris if you choose the EU region, and no generative model sits in the read path reading your facts.

Will the memory lookup slow down my drafting agent?

No. There is no generative model on the read path: it is a straight vector search and fact lookup. The context block comes back under a token budget you set, 800 tokens by default, however long the matter history grows.

Do I have to build the retrieval and the graph myself?

No, that is the whole point. You bring Claude Code or Cursor to build the lawyer-smart part of the agent. Korely is the memory layer underneath: the bi-temporal facts, the contradiction handling, the per-matter scoping, the entity graph, and the vector search are already built and tuned. You call add to store a fact and get_context to read back what is true now. The hard infrastructure is done.

What does it cost to start?

There is a free tier so you can wire up a matter, write a few deal terms, and see the per-matter scoping and the time-awareness work end to end before you pay anything. Paid plans start at 19 euro a month + VAT when you need more. You can build the whole proof of concept on the free tier first.

Every matter already known, no two clients ever mixed up

If your agent should walk into every matter already knowing the deal, the precedent, and the partner style, start free and move to 19 euro + VAT a month when you are ready.

See pricing and start free

Looking for a different shape? See the other nine use cases →

Back to top ↑