How a memory works
Introduction
Section titled “Introduction”If you know the LLM Wiki idea, you already know the shape: a raw/ folder of documents nobody edits, a wiki/ folder of Markdown pages linked with [[links]], and a schema file that tells the agent how to write them. A graph memory follows the same shape, but stores each part in PostgreSQL so that every piece knows where it came from and who may see it.
This page explains that model. It covers graph memories; a collection stops at passages, and a personal memory holds short facts.
From LLM Wiki to Brain
Section titled “From LLM Wiki to Brain”| LLM Wiki | Brain | What it is |
|---|---|---|
A file in raw/ |
Source | A document, text or file you add. Never edited. |
| (nothing) | Passage | A piece of a source’s text, kept with where it came from. Search reads these. |
A .md page in wiki/ |
Page | An entity: a company, a person or a topic, with aliases. |
| A paragraph of a page | Section | One fact on a page, with its citations. The API and the web app call it a fact. |
A [[link]] |
Link | A reference from one page to another, tied to the sources that say it. |
| The schema file | Schema | Each graph memory says what it is about and which page types it keeps. |
A page is not one block of Markdown because the unit that matters is the fact. Each section knows:
- which sources it came from, with a locator for each;
- when it became true, and when it stopped being true;
- which section it replaced;
- whether a person wrote it, and whether it is locked.
So deleting a source retires only the sections that came solely from it, and a page keeps every fact that another source still supports.
Sources and versions
Section titled “Sources and versions”A source is the text you add, with a title and a media type. Its passages carry the labels. Brain stores a hash of the content, and the caller may also give an externalId, its own stable id for the document.
- The same
externalIdwith the same content changes nothing. - The same
externalIdwith new content creates the next version. The old version is superseded: lists and search show only the current one, and only what differs in the compiled pages changes. - Without an
externalId, a source is the same one when its title and content hash are both unchanged.
Deleting and erasing sources is described in the overview.
Passages
Section titled “Passages”A passage is a piece of a source’s text. The model never rewrites it: what you search and what a citation quotes is the text you added.
Reading the file
Section titled “Reading the file”| Type | How it is read |
|---|---|
| Plain text, Markdown, CSV | As it is. |
| HTML | Scripts and styles dropped, block tags become line breaks, entities decoded. |
| Text per page, so the page number survives. | |
| Anything else | Refused, with a message naming the types that work. |
A file with no text fails and the source is kept as failed. That includes a PDF made only of images: Brain does no OCR. By default the extractor also refuses a file with more than 2,000,000 characters of text.
Splitting it
Section titled “Splitting it”Text is cut into pieces of at most 800 characters, with no overlap. A cut falls at the last paragraph break in the window, then at the last sentence end, then at a space, and only where the piece would be at least 200 characters long; otherwise it cuts at 800.
Each passage carries a locator, and that is what a citation shows:
| Source | Cut by | Locator |
|---|---|---|
| Page, then size | p. 3 |
|
| Text with Markdown headings | Heading, then size | §2 |
| Anything else | Size | chars 0-780 |
A page has a type, a title and aliases. Today the types are company, person and topic.
- Aliases. A page keeps every name a source used for it. A name is matched without case, accents or a legal suffix such as
S.r.l., and close spellings are found by trigram similarity. No vectors are involved. - Links. A link from one page to another records which sources say it.
- Conflicts. When two sources disagree, the page records the claim and both versions instead of choosing.
- Revisions. A page change keeps what the page was before it.
- Merges. Merging two pages leaves the losing page pointing at the survivor (
merged_into). - Review. What Brain will not decide alone becomes an item for an admin: one item per document for the passages whose labels Brain wants confirmed, conflicts, empty pages, and possible duplicates, each naming the two pages involved. A pair an admin has judged to be different pages is remembered so it is not proposed again.
Curating a memory shows how an admin works through these.
Compiling a source
Section titled “Compiling a source”With a chat model configured, a new source in a graph memory is compiled into pages in two model calls:
- Extract. The model lists the companies, people and topics the source is about, at most 12 names.
- Compile. For each name Brain finds up to 5 candidate pages and shows the model only what the source’s audience can already read. The model answers with operations on sections, not whole pages: add a new section, update a candidate section into one that cites every source, or noop when a candidate already says it, which only gains the citation.
The result is applied in one transaction that reads the pages again first. If a person deleted a page while the model was running, what was said about it is dropped, not recreated. If the page was merged, its facts go to the surviving page.
The compile queue
Section titled “The compile queue”Compiles are queued in the database, not run inside the request, so they survive a restart. Per memory they run one at a time, in order. Brain’s own worker checks the queue every two seconds and works up to four memories at once. A worker elsewhere on the same database takes the same jobs: each claim has its own id and a lease, so a run that outlived its lease cannot finish the job under the run that took it over.
While a source waits or runs, its compile status is pending. A job that throws waits longer before each retry. After three attempts the status becomes failed and the source keeps its passages and search. A model call gives up after 90 seconds, so a stalled answer does not hold a memory’s queue. A request that adds a source and waits for its compile runs only jobs of its own memory and stops waiting after two minutes, leaving the source pending; the web app then re-reads the sources list every few seconds until the row settles. See the overview for the steps as an admin sees them.
Vectors are optional
Section titled “Vectors are optional”Pages, aliases and links never use vectors. Finding a candidate page is names, trigram similarity and full text.
Only passages can have an embedding:
- Passage search always runs full text on PostgreSQL (
tsvector). - When an embedder is configured and answers, semantic search is added on top of it. If the embedder fails, the query still runs as full text.
- A memory server uses one embedding model for all memories, and the size of the vector column is fixed when the schema is created if you configure it.
Embed it in a host has the configuration.
Faces: who sees what
Section titled “Faces: who sees what”Access is decided by labels on passages, and everything compiled from a passage is read through it. See Brain at a glance for the model.
- A passage is a piece of a source’s text. It carries labels, and a label belongs to a family, such as
Department. A source with labels you or a rule set gives them to its passages; otherwise Brain labels each passage by its content (Labels: who decides). - A viewer reads a passage when they hold any one of its labels. A passage with no label is read only by viewers who see everything.
- A fact is readable when the viewer can read every passage it cites. A page is visible when one of its facts is readable, and a link between pages when the viewer can read a fact that mentions the other page. A conflict cites the passages of both sides and is read by whoever can read them all.
- A role grants each family one of
none,some(a list of labels) orall. A member holds the labels their roles grant.
A fact a person wrote by hand has no passage, so it carries its own labels.
A document is listed for whoever can read at least one of its passages, and its text shows the other parts as restricted. Brain merges new content into an existing fact only when that fact has the same readers as the passages the new content cites, so no one gains access through a merge.
Personal memories
Section titled “Personal memories”A personal memory has no pages and no labels. It holds short facts: one standalone sentence each, written by an agent or by the person, readable only by that person. See the overview.
The tables
Section titled “The tables”Every table lives in one PostgreSQL schema. Only the columns that explain the model are shown.
access memories(id, kind, access, owner_id) ├─ members(memory_id, user_id, role, role_ids) ├─ families(id, memory_id, name) │ └─ labels(id, family_id, name) └─ roles(id, memory_id, name) └─ grants(role_id, family_id, mode, label_ids)
raw sources(id, memory_id, label_ids, content_hash, external_id, previous_version_id, superseded_by, compile_status) └─ passages(id, source_id, ordinal, text, locator, embedding, tsv)
wiki pages(id, memory_id, type, title, locked, merged_into) ├─ aliases(page_id, alias, norm, origin_source_id) ├─ sections(id, page_id, text, label_ids, origin, locked, │ valid_at, invalid_at, superseded_by) │ └─ citations(section_id, source_id, locator) ├─ links(page_id, to_page_id) │ └─ link_sources(link_id, source_id) ├─ conflicts(id, page_id, claim, a, b) │ └─ conflict_sources(conflict_id, source_id) ├─ revisions(page_id, at, reason, before) └─ pairs(page_a, page_b) pages judged to be different reviews(id, memory_id, type, subject, source_id, page_id, other_page_id)
personal facts(id, memory_id, text, pending, deleted_at, replaced_by)
work compile_jobs(id, memory_id, kind, source_id, attempts) connectors, connector_runs, rules labelling and ingestion audit(memory_id, action, summary, undo) tokens, token_grants access for agentssections has no foreign key to a source on purpose: deleting a source retires its sections instead of removing them, and only erasing a source deletes them.
Next steps
Section titled “Next steps”- Brain overview for the memory kinds and what runs without a model.
- Curating a memory to review, merge, split and lock pages.
- Embed it in a host to configure models and embeddings.
- Connectors to bring sources in on a schedule.
- HTTP API for every route.
- Use it from an agent and Run the standalone service.