> ## Documentation Index
> Fetch the complete documentation index at: https://docs.brussle.com/llms.txt
> Use this file to discover all available pages before exploring further.

# What Brussle is

> Brussle is a database where a column can be an AI model's answer about a document, and that answer can read other documents and stay current when they change.

This page says what Brussle is, and the four problems that it solves for AI answers about your records. Read it before the other pages.

## A database for AI answers

Brussle is a database. In Brussle, a column can be the answer that an AI model gives about a document. We call this column a **judgment**. We call the AI model that makes its answers the **engine**.

An answer can read other documents. Brussle keeps each answer current when those documents change. Each answer records the question version and the engine version that made it. You can measure each answer against what actually happened.

You decide what to ask, what an answer means and what to do with it. Brussle keeps the answers correct as data: current, versioned, traceable and measurable.

## Four problems that an AI column cannot solve

You can already keep an AI answer in a column of your own database. A trigger runs when a record changes. A worker calls an AI model and writes the answer back. If the answer reads only its own record, this column is enough.

The column fails on four problems. Brussle exists to solve them.

### 1. The answer depends on other documents

Some questions about a record need other records. *Which open invoice does this payment settle?* needs the open invoices. *Did this contract section change in a way that matters?* needs the section as it was at the last check.

A trigger on one table does not know which records in other tables read the changed record. To answer such a question in your own database, you must build and run these parts:

* Code that fetches the related records for each question and cuts them to fit the AI model's context.
* Code that finds each record that a write affects. One write can affect many records.
* A queue and workers that call the AI model again for each affected record.
* A debounce, so that a burst of 100 writes does not cause 100 calls for one record.
* A limit on cost. A change to one product can affect thousands of order lines.
* A way to know which version of each related record an answer read.

Each new relation makes this code larger. In Brussle, a **relation** makes a judgment read other documents. Brussle does each of these parts for you:

* The judgment's [context recipe](/guides/context-recipes) says which related documents to read, how many, and which of their fields. Brussle fetches them and cuts the context to fit.
* Brussle finds the affected documents through the attribute that you already write.
* You can set a **debounce**, so that Brussle waits until changes settle. A **ceiling** makes sure that Brussle still judges a busy document.
* Some documents are read by many others, such as a product that thousands of order lines point at. For a change to such a document, a **re-judge scope** limits which documents Brussle judges again. A **rolling limit** caps how many documents Brussle judges again in this way in 30 days.
* Before Brussle creates a judgment that reads related documents, it shows an estimate of the monthly cost. Brussle creates the judgment only when you confirm.
* Each answer records the position in the namespace's log at which Brussle read the related documents.

A relation reads the documents that your ids connect, not similar text. See [relations](/concepts/relations) and, for the cost controls, [freshness policies](/guides/freshness-policies).

### 2. The answer must say whether it is current

A column holds the last value that a worker wrote. The column cannot tell you whether that value still agrees with the records that it read.

In Brussle, each answer has a **freshness**. An answer is `fresh` when it agrees with each document that it read, at their current revisions, and with the judgment's active version. If not, the answer says so, for example with `pending` or `stale`. A `stale` answer gives its cause in `stale_reason`. A query can send `answers: "fresh_only"` to leave out each document whose answer is not `fresh`. See [freshness](/concepts/freshness).

### 3. A change to the question or the engine must not mix old and new answers

When you change a prompt or an AI model, old answers and new answers mix in the column. Nothing records which answer came from which.

In Brussle, a judgment's definition has versions, like a schema:

* Each answer records its `judgment_version` and its `engine_version`. Queries can filter on both.
* After you activate a new version, an answer from an older version that asks differently reads `stale`, with the reason `older_version`. Thus, `answers: "fresh_only"` leaves it out.
* Activation judges nothing again. A [backfill](/concepts/judgments#backfill) judges those documents again, and shows its cost before you confirm it.
* The engine can change its behaviour. Each period of the same behaviour is an **epoch**. The `engine_version` of each answer names its epoch. A new epoch alone does not make an answer stale.

See [versions](/concepts/judgments#versions).

### 4. The number must be measurable against what happened

The engine says 0.8, and a column stores 0.8. Nothing tells you how often 0.8 comes true on your data.

In Brussle, you record **outcomes**. An outcome is what actually happened to a judged document. You post outcomes, or outcome rules make them from writes that you already send. Brussle keeps your outcomes beside the answers. The calibration report measures the answers against them.

From 100 outcomes, with at least 20 for each of two different values, Brussle fits a correction of the probabilities on your outcomes. Brussle uses the fit only when it does better than the raw numbers on outcomes that the fit did not use. See [calibration](/concepts/calibration).

## What you can rely on

You can rely on four things about each answer:

* The answer is the engine's answer to exactly the inputs that its [evaluation](/concepts/evaluations) (the permanent record of one judging) records.
* The answer is current with respect to those inputs, or it says that it is not.
* The answer records the question version and the engine version that made it.
* You can measure the answer's number against the outcomes that you record.

Brussle does not promise that an answer is correct, or that a judgment answers your real question. You measure that with your outcomes. See [what you can rely on](/behavior).

## When an answer reads one document

If an answer reads only its own document, use a column in your own database. A trigger and a direct call to an AI model are enough. Each answer then costs less than in Brussle. See [Brussle versus an AI column in your own database](/versus-ai-column).

## An example: a payment and its open invoices

You copy your records to Brussle with one write API. Brussle keeps each copy as a **document**. Payments and invoices are documents in one [namespace](/concepts/namespaces) (the container for one tenant's documents):

* A payment has `attributes.kind: payment` and `attributes.status: unmatched`.
* An open invoice has `attributes.kind: invoice` and `attributes.status: open`.
* Each payment and each invoice has a key in `attributes.block`, for example the counterparty and the currency.

```mermaid theme={"theme":{"light":"css-variables","dark":"css-variables"}}
flowchart LR
  p["payment pay_881<br/>block: acme-gbp"] -- "same block" --- k{{"block: acme-gbp"}}
  k --- i1["invoice inv_2041"]
  k --- i2["invoice inv_2043"]
  k --- i3["invoice inv_2051"]
  p -. "choice: settles" .-> i2
  p:::judged
  classDef judged stroke-width:3px
```

You define a `choice` judgment, `settles`, on unmatched payments: *Which of these open invoices does this payment settle?* Its relation reads the open invoices in the payment's block. Each invoice becomes one option. The answer is `none_of_the_above` when no invoice fits.

Then this happens:

1. A payment arrives. Brussle judges it with the open invoices of its block. The answer names one invoice or `none_of_the_above`, with a probability.
2. A new invoice arrives in the same block. The payment's answer becomes `pending`. Brussle judges the payment again.
3. Your team settles a payment. You write the match and the new status of the payment in one write. An outcome rule records the match as an outcome.
4. The calibration report measures the answers of `settles` against these outcomes.

You did not write code to find the payments that a new invoice affects, to judge them again, or to record which invoices each answer read. Whether the matches are good on your data is yours to measure. The [quickstart](/quickstart) does this example step by step. [Match one record to another](/guides/entity-matching) has the full definition.

## What a relation can read

A relation lets a judgment read more than the document that it judges. Each kind of relation fits a different kind of question:

| Question | What the judgment reads | Guide |
| - | - | - |
| Does an amendment conflict with this contract? | The documents that point at the contract: its amendments. | [Related documents](/guides/related-documents) |
| Does this order line need a review? | The document that the order line points at: its product. | [Referenced document](/guides/referenced-document) |
| Does this contract have a clause that needs a review? | The answers of other judgments on its clauses. | [Roll-ups](/guides/roll-ups) |
| Which open invoice does this payment settle? | The open invoices that have the same key as the payment, for example the same customer. | [Entity matching](/guides/entity-matching) |
| Did this contract section change in a way that matters? | The section as the judgment last saw it. | [Change detection](/guides/change-detection) |
| Is this the fifth report of the same outage? | The newest open tickets in the same queue. | [Queue context](/guides/queue-context) |
| Does one person operate these accounts? | The accounts that share a device, phone number, email or card. | [Linked accounts](/guides/linked-accounts) |
| Does this listing break a rule written on a category above it? | The categories above the listing in its tree. | [Hierarchy](/guides/hierarchy) |
| Does this post break the community's rules? | One document that holds the rulebook. | [Policy simulation](/guides/policy-simulation) |

You do not need to know your relations before you start. [Find your relations](/finding-relations) shows which of your attributes already point at other documents.

## How it fits together

* A **namespace** holds documents. Usually you have one namespace for each [tenant](/concepts/namespaces#tenants-and-environments) (one of your own customers) in each environment, for example production or staging. A relation reads only documents in the same namespace.
* A **document** is your copy of one record in Brussle. It has `attributes`, which queries can filter on, and a JSON `state`, which judgments read. An attribute can hold the `id` of a different document. This attribute is how documents point at each other.
* A **judgment** is a column that the engine fills in: a typed question (`bool`, `choice` or `score`) on a namespace. The judgment names one engine version. That engine version makes its answers. The definition of a judgment has versions.
* A **relation** is part of a judgment. It tells the judgment which other documents to read, and what to read from them. See [relations](/concepts/relations).
* An **answer** is the current result of one judgment for one document. It is a probability distribution, not free text. It also shows its freshness and its provenance, that is, the versions that made it. Queries can filter and sort on answers.
* An **evaluation** is the permanent record of one time that Brussle judged a document. It holds the exact text that the engine read, including the related documents, and a reference to each image that it read. Brussle keeps each evaluation.
* An **outcome** is what actually happened to a judged document. You post outcomes, or outcome rules make them from your writes. Brussle measures answers against your outcomes. It also calibrates the probabilities on them.

Start with the [quickstart](/quickstart). Before you build on Brussle, read [what you can rely on](/behavior) and the [tradeoffs](/tradeoffs).

## Where it fits

Brussle works next to the database that you already have. Your database stays the system of record. Brussle holds a copy of the records that your questions need.

Brussle judges in the background. An answer usually arrives a few seconds after the write that needs it. A burst of writes waits its turn. To read an answer that already exists takes a fraction of a second.

Thus, Brussle fits work that runs beside your product: matching and reconciliation, review queues, triage queues, moderation, and fraud and abuse review.

Brussle is not made to sit inside a user's request. If a page must wait for a new AI answer before it can respond, call an AI model directly. A request can read an answer that already exists. Only the wait for a new answer is slow. See [tradeoffs](/tradeoffs).

## The one thing to learn: what the engine sees

Each judgment has a [context recipe](/guides/context-recipes). The recipe lists what the engine reads to make an answer: fields of the document, and relations. The engine answers only from what the recipe shows.

The recipe controls two things:

* The cost of an answer.
* When Brussle judges a document again. A change to something that the recipe does not read does not cause a new judgment. This rule applies to related documents too.

Use this pattern for each judgment:

1. Ask a narrow question about one document.
2. Put the right related document beside it in the recipe, for example the open invoices of a payment, or a section as the judgment last saw it.
3. On a `bool` judgment, keep numbers, such as counts, as `features`, with `"render": false` in the relation's `aggregate`. The fit on your outcomes weighs them.

The engine reads text, and images if it reads images. It does not forecast. For a question about what will happen, the counts and the fit carry the number. The calibration report's `features_only` shows what the engine adds to your own numbers.

Start from a [starter judgment](/guides/starter-judgments), and change it as necessary. A starter judgment has a recipe for a common question. Several starters already read related documents, for example queue context, linked accounts and hierarchy.

## What else you get

* **A recipe that costs no more than it must.** When a judgment has enough outcomes, Brussle tests smaller versions of its recipe on your labelled outcomes. Brussle suggests a smaller recipe only when it costs less and the accuracy on your outcomes does not drop. See [let your outcomes tune the recipe](/guides/measure-improve-tune#let-your-outcomes-tune-the-recipe).
* **Answers that you can explain later.** Brussle keeps each [evaluation](/concepts/evaluations). An evaluation holds the exact context that the engine saw, the answer and the versions that made the answer.
* **Predictable cost.** Brussle does not judge a document again if its relevant content did not change. A [backfill](/concepts/judgments#backfill) (the first judging of the documents that already exist) shows its cost before you confirm it. [Budgets](/guides/freshness-policies#budgets) limit what each namespace can spend.
* **Many tenants.** With [template judgments](/guides/templates), you define a question one time for the namespaces of all your tenants. You can also set [budgets per tenant](/guides/multi-tenant-platforms#budgets-per-tenant).

## What you pay for

You pay for judging per judgment, by size class, times the weight of the [engine](/engines/index). If the context and the question of an answer fit in 2,000 tokens, the answer is one standard judgment. A larger answer counts as more than one judgment. The context includes the related documents that the recipe reads, and the [images](/guides/images) that the engine reads. On an engine with a weight above 1, each answer counts more: on gpt-6-luna, a standard answer counts as 2.5 judgments.

Brussle judges a document again only in two cases:

* What its judgment reads changes. This includes a change to a related document that the judgment reads.
* The interval of a `periodic` judgment ends. A `periodic` judgment judges each document again, whether or not the document changed.

Each answer costs more than a direct call to an AI model. To see what your own traffic costs, price it on the [pricing](/pricing) page.


## Related topics

- [What you can rely on](/behavior.md)
- [Brussle versus an AI column in your own database](/versus-ai-column.md)
- [Judge a ticket with its queue](/guides/queue-context.md)
- [Change a question or engine safely](/guides/change-a-judgment.md)
- [Pricing](/pricing.md)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.