Brainby arc-labs/docs
Concept

Memory types

The five typed-graph kinds Brain extracts — fact, preference, event, entity, relation — and how each is derived, stored, and mutated.

A stored memory is the text you encoded plus its embedding. On top of memories, the asynchronous extractor derives a typed graph: entities (the nouns), statements typed as Fact, Preference, or Event (typed claims about an entity), and relations (edges between two entities). Those five kinds are the vocabulary the graph retriever and the read router reason over. They are extracted after the write acks — see Write pipeline.

The three statement kinds are not three storage schemas — they are three contracts on one statements table. The kind column changes the mutation policy, default validity semantics, and query intent, not the layout.

fact

A stable claim about the world or an entity: "Priya is the engineering manager," "the staging cluster runs in eu-west-1." Facts are durable and, in principle, third-party verifiable.

The extractor emits a Fact when it lifts a stable assertion that isn't a first-person preference and isn't pinned to a moment. Facts are append-only: a new Fact with the same (subject, predicate) but a different object is stored as a contradiction alongside the old one, not a silent overwrite. The planner surfaces the conflict and returns the higher-confidence (or more recent, at equal confidence) one; the contradicted Fact stays in the audit trail. Surfacing contradictions is a feature.

Statement { kind: Fact, subject: Priya, predicate: role, object: "engineering manager", confidence: 0.92 }

preference

A revisable belief or choice: "Priya prefers async meetings," "always reply in markdown," "use metric units." Preferences are self-reported, not verifiable against the world.

The extractor emits a Preference when it detects preference language tied to a subject. Preferences are versioned via supersession: a new Preference for the same (subject, predicate) supersedes the old one — the old row's superseded_by points at the new one, "current preference" queries return only the new one, and history queries return the chain.

fact
preference
subject
Any entity
Usually a person or agent
truth-type
Verifiable in principle
Self-reported, not verifiable
on new evidence
Both stored; conflict surfaced
New supersedes old
example
"Berlin is the capital of Germany"
"I prefer markdown over plain text"

event

A discrete occurrence at a moment: "Priya scheduled a planning session on Tuesday," "shipped v0.3.0 on April 12." The defining field is event_at — when it happened — distinct from extracted_at, when the statement was derived.

The extractor emits an Event when it lifts an occurrence with a temporal anchor. Events are immutable: they never supersede each other — that's the point. A similar Event is stored as a second, independent Event; a correction is recorded as a new Event (or a corrective Fact), never a modification. The read path's recency boost leans on event_at for time-anchored cues.

entity

A canonical noun — a stable identity for a real-world referent (Person, Organization, Project, Place, Concept, …). An entity carries a UUIDv7 EntityId, a canonical_name, an alias list, a schema-declared entity_type_id, and typed attributes. Two mentions of "Priya" and "Priya Patel" resolve to one entity if the resolver decides they're the same person.

Entities are the graph's scaffolding: a statement's subject and a relation's endpoints are EntityIds. They aren't returned as recall answers — they back the identity dictionary the graph retriever joins on. See Entities for the full lifecycle (resolution, merge, unmerge).

relation

A directed edge between two entities — (subject, predicate, object) where both ends are entities. Relations encode "Priya works_at Arc Labs," "Acme acquired Beta Inc," "Bob reports_to Priya." A Fact's object may be a literal value ("role = manager"); a relation's object must resolve to an entity.

Fact:     subject=Priya, predicate=role,     object="engineer"        (object is a value)
Relation: subject=Priya, predicate=works_at, object=Entity(Arc Labs)  (object is an entity)

The extractor emits a Relation when it lifts a predicate connecting two named entities. The graph retriever traverses relations from an anchor entity, weighting edges by confidence so weakly-evidenced edges contribute less.

event
entity
lifetime
Point-in-time, immutable
Durable noun, evolves over time
returned as a recall answer
Yes (as a supporting statement)
No (graph scaffolding)
key field
event_at
canonical_name + type
example
"Shipped v0.3.0 on April 12"
"Arc Labs (Organization)"

Why exactly these five

Users mentally categorize knowledge as fact vs preference vs event, and each maps to a different mutation contract — a Fact is append-only, a Preference supersedes, an Event is immutable. Collapsing them into one type with a "mutability" flag would hide the distinction the read router needs. Brain resists a sixth kind: an "observation" is an Event with predicate=observed; a "goal" is a Preference with predicate=wants; a "hypothesis" is a low-confidence Fact. Entity and relation aren't statement kinds at all — they're the nodes and edges the statements hang on.

Why the write only takes text

You don't classify anything at write time. encode takes text (plus optional context and event time); the extractor assigns the kind asynchronously from the content. That keeps the write path LLM-free on the ack barrier and lets the same raw memory be re-examined as the entity dictionary grows.

Was this page helpful?

On this page