Schema layering
ESSE schemas are not a flat pile. They are built up in layers, each one constructed only from the layers beneath it. This is the single most useful thing to understand about the repository: once you know which layer a schema belongs to, you know roughly what it may contain, what may depend on it, and where to add something new.
The ontology map draws these layers literally — primitives sit at the centre and each ring outward is a layer further up the build-up.
The layers
| Layer | Schemas |
|---|---|
directory |
156 |
category |
152 |
entity-component |
107 |
system |
38 |
reusable |
31 |
primitive |
23 |
application-parsing |
17 |
entity |
11 |
reference |
10 |
abstract |
9 |
in-memory-entity |
7 |
definition |
4 |
core/primitive — the atoms
Custom primitive types that extend what JSON Schema gives you: scalar, array_of_3_numbers,
array_of_ids, slugified_entry, string. The defining property, and the reason they are their
own layer, is stated in the repository README: primitives are defined solely in terms of default
JSON Schema types and cannot be re-constructed from each other. They are the bottom of the stack
by construction.
If you find yourself wanting a primitive that is "like scalar but…", it is not a primitive.
core/abstract — unit-less mathematics
Structures with mathematical meaning but no physical interpretation: vector_3d, matrix_3x3,
coordinate_3d, 3d_grid, 2d_plot. An array_of_3_numbers is a primitive; a vector_3d is
that array understood as a vector. Nothing here carries units, because nothing here knows what it
is measuring.
Keeping this layer unit-less is what lets one 2d_plot definition serve a density of states, a
convergence trace and a phonon dispersion alike.
core/reusable — domain building blocks
The first layer that means something physically: energy, band_gap, atomic_orbital,
kpoint, categories, file_metadata. These combine primitives and abstracts and attach
meaning — an energy is a scalar with units, drawn from definitions/units.
This layer exists to stop the same block being redefined in a dozen property schemas. When you notice two schemas describing the same physical quantity, the answer is usually a reusable.
core/reference — provenance
How a record points at where it came from: literature, experiment, modeling, exabyte.
Provenance is deliberately separate from the data it describes, so the same property schema can
carry a computed value or a measured one without changing shape.
definitions — shared vocabularies
Enumerations and constants shared across the whole corpus: units, chemical_elements,
constants, material. definitions/units is the most-referenced schema in ESSE, which is the
intended outcome: units are defined once, and every quantity points at that definition rather than
restating a list of strings.
in_memory_entity and system — behaviour, not payload
These two layers do not describe materials science at all. They describe how an object behaves as
a record on a platform — that it has a name, that it has defaults, that it can be soft-removed,
shared, timestamped, referenced from elsewhere. They are mixed into entities with allOf, and
they are the subject of Behavioural mixins.
Keeping them out of the domain layers is what allows a consumer to take the science and leave the platform behind.
entity and entity-component — the nouns
The eleven root schemas (material, model, method, workflow, job, project, element,
context-provider, and the material variants) plus the components they are assembled from —
material/material_properties, workflow/unit/*, model/mixins/*, method/unit_method, and so
on. Entity anatomy covers these in detail.
category, directory and application-parsing — the catalogues
The largest layers by file count, and the least surprising: *_category schemas express the
CateCom taxonomies, *_directory schemas are the concrete catalogues of models, methods,
properties and software, and apse/* describes application file formats and parser outputs.
Categorization explains the split.
The hubs
Because each layer is built from the ones below it, the lower layers are referenced far more often than the upper ones. The most-referenced schemas in the corpus are exactly what the layering predicts:
A schema high in this table is one you should be careful changing: a great deal depends on it. The ontology map draws these larger than their neighbours for the same reason.
Why keep the layers separate at all?
It would be less typing to inline everything. Three things are bought by not doing so.
Change has a blast radius you can see. Adding a unit to definitions/units is a one-line
change that correctly reaches every quantity in the corpus. Inlined, it would be a hundred edits
and a guarantee that some were missed.
Generated code stays small. The pydantic models and TypeScript types mirror this structure, so a shared block is a shared type rather than a hundred structurally identical anonymous ones.
It documents intent. Where a schema sits says what it is for. A new contributor wondering where to put something can usually answer it by asking which layer it could be built from — and if the answer is "none of them", that is itself informative.