Organization Ontology
Read and extend the memory vocabulary: the content types a memory can be classified as, and the relation types an edge between memories can carry.
Endpoints
Read the current vocabulary
import osfrom memorysync import MemorySyncClientclient = MemorySyncClient(api_key=os.environ["MEMORYSYNC_API_KEY"],base_url="https://api.memorysync.io",project_id=os.environ["MEMORYSYNC_PROJECT_ID"],end_user_id="usr_7f3a9c2e",)ontology = client.get_ontology()print(ontology.content_types)print(ontology.custom_relation_types)
{"content_types":["preference","fact","behavior","intent","temporal","relationship","skill","event","other"],"relation_types":["similar","derived_from","continuation","contradiction","summary_of","detail_of","caused_by","references","supports","extends"],"builtin_content_types":["preference","fact","behavior","intent","temporal","relationship","skill","event","other"],"builtin_relation_types":["similar","derived_from","continuation","contradiction","summary_of","detail_of","caused_by","references","supports","extends"],"custom_content_types":[],"custom_relation_types":[],"max_custom_types":32}
Add your own types
import osfrom memorysync import MemorySyncClientclient = MemorySyncClient(api_key=os.environ["MEMORYSYNC_API_KEY"],base_url="https://api.memorysync.io",project_id=os.environ["MEMORYSYNC_PROJECT_ID"],end_user_id="usr_7f3a9c2e",)ontology = client.update_ontology(content_types=["symptom", "dosage"],relation_types=["contraindicates"],)
Custom types appear after the built-ins in content_types and relation_types. Built-ins always come first.
Additive only, and why
Sending {"content_types": []} clears your custom content types and leaves all nine built-ins in force.
The two vocabularies are independent
Omit a field and that vocabulary is left untouched, so adding a content type cannot accidentally wipe your relation types. Sending neither field is a 422 — an empty request would silently do nothing while returning success.
Naming rules
| Rule | Contract |
|---|---|
| Characters | Lowercase letters, digits and underscores. |
| First character | Must be a letter. |
| Length | 1–32 characters. |
| Ceiling | 32 custom entries per vocabulary. |
| Duplicates | Listing the same name twice in one request is rejected. |
| Restating a built-in | Accepted and quietly ignored — it is already true, so nothing is stored. |
Names end up in JSON keys, log fields, metadata values and LLM prompts, which is why they are restricted to a plain identifier.
What a custom type changes
- The extractor is told about custom content types and may assign them.
- A
typesfilter on recall accepts them instead of silently discarding the name. - A custom relation type becomes valid on Create Relation; before you add it, that request is rejected with a
400listing the accepted values.
Errors and next action
A 400 names the offending entry: a malformed name, a duplicate, or more than 32 entries. A 400 also results when the caller has no resolvable organization — an ontology has nowhere to live without one, and returning success while writing nothing would be worse.