Concepts
Eight primitives, in the order you'll encounter them. Read this once and you'll know how every endpoint composes.
Project
A project is the isolation boundary. Every API key authenticates exactly one project; every memory, entity, thread, and graph lives inside one. Cross-project reads are impossible — there's no API for it. You'll typically run one project per app (or per app + per environment, e.g. billing-bot-prod and billing-bot-staging).
Projects are created from the dashboard. The bootstrap step also creates one default group graph so the first POST /memory/add call works without any extra setup.
org (acme)
└── project (billing-bot)
├── default group graph ← created on bootstrap
├── user graphs (per end-user)
└── named group graphs (your call)Graph
A graph is a named container of memories, entities, and edges. There are two kinds, indicated by the kind enum:
USER— one per end-user, auto-created onPOST /v1/usersor the first ingest that targets a user.GROUP— shared knowledge that's not tied to one user. Company policies, product docs, the support team's playbook.
Search composes additively across graphs — one call can scope to one user's graph plus the policies group graph. See /v1/memory/search.
User
Users are first-class. You bring your own externalId (Clerk id, Auth0 sub, your DB primary key — anything unique inside the project). Creating a user atomically materializes their user graph; deleting a user cascades the graph plus every thread, message, memory, and entity reference.
POST /v1/users
curl -X POST "$MEMOS_URL/v1/users" \
-H "Authorization: Bearer $MEMOS_KEY" \
-H "Content-Type: application/json" \
-d '{ "externalId": "user_clerk_abc123", "email": "[email protected]" }'Thread
A thread is a conversation session for one user. Append messages with POST /v1/threads/:id/messages; user-role messages auto-ingest into the user's graph through the same extraction pipeline as raw text. Assistant, system, and tool messages are stored for replay but not treated as facts about the user.
Memory
A memory is a single typed fact, addressable by id, with full provenance back to its source chunk and ingestion job. Every memory carries a type drawn from the built-in ontology:
FACT— stable claim about the world ("Alice works at Acme")EVENT— something that happened at a point in timePREFERENCE— what the subject likes or wantsDECISION— a choice made by the subjectSTATE— current observable statusRELATIONSHIP— connection between two entitiesBELIEF— opinion or expressed viewSKILL— ability or competenceGOAL— explicit intent or objective
Memories carry a confidence score, a validity window (validFrom / validUntil), an isActive flag, and a supersededBy pointer for conflict surfacing.
Episode
An episode is a cross-session summary — "the last 14 days of Alice's billing conversations" — generated periodically by the summarization worker. Episodes let the agent recall the gist of past activity without re-ingesting every message. They surface in GET /v1/users/:id/context automatically when the user has enough thread volume.
Entity + relation
Extraction also auto-builds a knowledge graph alongside the memory list. Each entity has a canonical name, a type (PERSON, ORGANIZATION, LOCATION, …), and a list of aliases. Relations are predicate-typed edges between entities — WORKS_AT,MEMBER_OF, LOCATED_IN, plus anything your ontology adds. The dashboard's Graph view renders this directly; the API exposes it atGET /v1/memory/entity-graph.
text: "Alice works at Acme on the billing team"
memories: Alice WORKS_AT Acme (FACT)
Alice MEMBER_OF billing-team (FACT)
entities: Alice (PERSON)
Acme (ORGANIZATION)
billing-team (TEAM)
edges: Alice --WORKS_AT--> Acme
Alice --MEMBER_OF--> billing-teamSupersession + conflicts
When a new memory contradicts an existing one, MemHQ doesn't delete the old row — it marks it superseded (isActive = false, supersededBy = newId) and writes a CONTRADICTS edge linking the two. The dashboard surfaces every CONTRADICTS edge on the Conflicts page so an operator can resolve disagreements. Audit history is a property of the storage layer, not a separate log.
Ontology + backfill
Beyond the built-in memory types, projects on Scale and Enterprise can define custom entity types and predicates — SubscriptionPlan, ESCALATED_TO, anything domain-specific. Changes don't strand old data: POST /v1/ontologies/:id/backfill rewrites every existing memory in the project against the new ontology version. See /docs/api/ontology.
Audit chain
Every write (memory create, supersession, ACL grant, ontology bump) appends a row to the audit log with a SHA-256 hash chained to the previous row. The chain is verifiable end-to-end via POST /v1/audit/verify — if anyone tampers with history, the verify call surfaces it.
One model to keep in your head