Blog / How-to guides

An ontology you never write: the classes and relations your memory builds as you store

12 October 2026 · Semurg · 4 min read · Markdown

Verified: every command below ran on a fresh node of r11.78.20261012.bc0d94f (how)

knowledge-graphontologymemoryagents

Most knowledge graphs ask for a schema first: the kinds of thing you will store, and how they may connect. Semurg does not. Each memory builds its ontology from what you store: every entity type you send becomes a class, and every relationship type becomes a relation. One call reads it back, so the next agent, or the next session of the same one, can reuse what is already there instead of inventing a near-duplicate.

Store a few facts

bash
export SEMURG_API_TOKEN=<your token>
curl -sS http://localhost:4000/v1/memory/remember \
  -H "Authorization: Bearer $SEMURG_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"scope": "ontology-intro", "source": "onboarding notes",
       "facts": {"entities": [{"name": "Priya Raman", "type": "Person"},
                              {"name": "Tom Okafor", "type": "Person"},
                              {"name": "Northwind Retail", "type": "Company"}],
                 "relations": [{"source": "Priya Raman", "target": "Northwind Retail", "type": "WORKS_AT"},
                               {"source": "Tom Okafor", "target": "Northwind Retail", "type": "WORKS_AT"}]}}'

Expected: the facts are stored

No schema came first. person and company are now classes in this memory (class names are kept in lower case, so letter case never splits a class), and WORKS_AT is a relation.

Read the ontology

The status call, given a scope, returns that memory's ontology beside the usual status:

bash
export SEMURG_API_TOKEN=<your token>
curl -sS "http://localhost:4000/v1/memory/status?scope=ontology-intro" \
  -H "Authorization: Bearer $SEMURG_API_TOKEN"

Expected: the ontology lists the classes person and company, and the relation WORKS_AT among its spellings

What the reply holds, under ontology:

  • types and relation_types: how many classes and relations this memory has.
  • top_classes: the biggest classes, up to 50, each with its member count. members_bound says what the count is: exact (the live members; forgetting one lowers it by one) or upper (a very large class, where the number is an upper bound). Read the bound before you rely on the count.
  • relations: the relations in use, up to 50, each with a lower-case name and its spellings, the exact names it was stored under.
  • merge: whether classes are merged automatically; it says off by default.
  • classes_shown and relations_shown: how many of each the lists carry, so a capped list says it is capped.
  • coherence: whether the ontology holds together (below).

How often a relation is used is not counted yet: each relation's count says not_counted, never a made-up zero.

Reuse it, spelled exactly

A class matches letter case aside: Person and person are one class. A relation is listed the same way, works_at and WORKS_AT under one name, but each spelling is kept as its own relationship record. So the same fact stored once as works_at and once as WORKS_AT is stored twice, and the reply lists both spellings under the one relation so you can see it happened. Before an agent invents a class or a relation, it reads the ontology and reuses what is there, spelled exactly as listed.

Does it hold together?

Because the ontology grows as you store, it can drift: a class nothing uses, a chain of aliases, a loop. coherence reports it in one of three states: coherent; incoherent, with each problem named; or could_not_judge, with the reason. It never answers an empty list that would read as "no problems" when the check did not run.

What it does not do yet

  • Count how often each relation is used: count says not_counted.
  • Merge two classes that mean the same thing under different names, such as Company and Organisation: merge says off, and reuse is up to the writer, which is why the agent block asks for it.

Next

How these commands were checked

Our test farm ran each of the 3 command blocks marked runnable, exactly as written, with the answer checked against the expectation printed under it, against a fresh node of the published release r11.78.20261012.bc0d94f. A post is published only when every one of them passed there.

Related