Project ontology
The project ontology is a single project's own vocabulary of node and relationship types, layered over the platform schema that every project shares. It is what lets your project describe things the platform did not anticipate, in your organization's words rather than generic ones.
It is the only one of a project's four stores that describes the shape of another store rather than holding content of its own: it says what kinds of thing may exist in the context graph. If you are still deciding whether what you have is a type at all, read where your data goes first.
The one you edit is this one
create-ontology is the only tool that writes a vocabulary, and it
writes the project ontology. There is no tool, no route and no surface that creates, edits or
deletes the platform schema. So the answer to "which one am I editing by default" is: this one,
always, on every call you can make.
What that leaves is the reverse problem — choosing a name the platform already owns. That is the mistake worth reading about, and it is on the platform schema page.
How a change happens depends on the project mode
This is the fact most worth carrying away, because the two modes behave differently enough that advice written for one is wrong for the other. See project mode for which one a project is in and how that is changed.
Simple mode: the vocabulary organizes itself
In Simple mode the ontology extends itself as data arrives. Saving a node with a label that has
never been used registers that label; there is no separate declaration step. Calling
create-ontology in Simple mode has the same character: the types you declare are ensured
immediately, there is no staging step, and re-declaring a label that already exists extends it
rather than colliding with it. The mode argument is ignored here, and there is no budget.
The one thing to watch is that a Simple-mode commit reports what the project ontology actually
holds afterwards rather than echoing what you sent. A result of status: "committed" means the
labels are present. Any other status is telling you something, and the
platform schema page explains the one you are most likely to see.
Advanced mode: propose, then commit
In Advanced mode a vocabulary change is governed, and it happens in two steps.
- Propose. Call with
mode: "proposal". The declared types are validated and staged, and you get back a proposal identifier and the staged shape. Nothing in the live vocabulary has changed yet, so you can see what the change would do before it takes effect. - Commit. Call with
mode: "commit". The change is validated again, checked against the live vocabulary, and merged in. A commit is a change to the meaning of everything already stored in the context graph, so policy may hold it for an approval before it lands — see policy and approvals.
Advanced mode is also where save-context is unavailable: direct data writes are refused, and the
governed flow above is the way in.
What a proposal must satisfy
The same validation runs in both modes, so these rules apply wherever you are.
- Labels are identifiers, not sentences. A label starts with a letter and continues with
letters, digits or underscores. The convention across the platform is PascalCase —
PurchaseOrder, notpurchase_order. - Every node type has a category, one of
person,interaction,context,otherordata. Thedatacategory is reserved for the platform's own catalog types and is not the one you want for your own entities. - A declared primary key must be a declared property. Naming a key that is not in the type's property list is refused, with the offending type named.
- Property names within a type must be unique, and a property with an empty name is refused.
- Relationship endpoints must resolve. Both ends of a relationship must name a type you are declaring in this same call or one that is already live. A relationship to a type that does not exist yet is refused rather than creating the type implicitly.
- Cardinality, if given, is one of
1:1,1:N,N:1orN:M. The verbose spellings —ONE_TO_MANYand its relatives — are accepted and normalized, so either form works.
Every one of these refusals names the index and label of the type that caused it, so the message tells you which of a batch of twenty was the problem.
The edit budget
Each project has a ceiling on how many vocabulary commits it may make. Each successful commit
consumes one. When the budget is exhausted, a commit is refused with ontology edit budget exhausted for project, and the refusal happens before anything is written.
The budget exists because the project ontology describes the shape every node in the context graph is checked against. A vocabulary that can be rewritten without limit is a store whose historical data can quietly stop meaning what it meant when it was written, and a bounded number of deliberate changes is cheaper to reason about than an unbounded number of casual ones.
Two practical points. The budget counts commits, not types — one commit declaring twelve node types costs the same as one declaring one, so batching a coherent change into a single commit is the frugal way to spend it. And the ceiling is a deployment setting: the platform ships with a default of 50 commits per project, an operator can raise or lower it, and a negative value means unlimited. Check your own deployment rather than assuming the default.
Proposals do not consume the budget. Only commits do, which is another reason to propose first and look at the staged shape before spending an edit on it.
Two other refusals worth recognizing
A label that already exists. In Advanced mode, declaring a node type whose label is already
live is refused with label collision with committed ontology, naming the label. That is a
deliberate difference from Simple mode, where re-declaring extends. If you meant to add properties
to an existing type, you are not fighting a bug — you are being told the change is not the one you
described.
A name the platform owns. This is the one that reads like a fault and is not, and it takes three
forms depending on the call you made. Declaring a node type whose label is one of the platform's
data-estate catalog types — Table, Column, Dashboard and their relatives — is refused during
validation in both modes with node[0] label "Table" is reserved for the platform data-estate catalog. Saving data under one of the platform's own managed labels, such as User or Project,
is refused by save-context with "User" is a platform-managed type and cannot be written through save-context. And in Simple mode a name the storage service owns produces no error at all: the call
returns HTTP 200 with status: "partially_committed" and the label listed under missing_labels,
which is the one you are most likely to mistake for success.
None of the three means the platform schema can be edited once you find the right call. There is no such call — see platform schema for why, and for what to do instead.