Structured vs. unstructured memory¶
Hadron memory is unstructured by default, structured on opt-in — one substrate. Every node is still a node in the same graph; opting a memory into a schema doesn't move your data into a different store or a different API. It layers typed columns, constraints, and structured queries on top of the same nodes you already have.
This page is the mental model. For the exact contract see Structured storage and queries; for step-by-step recipes see the how-tos linked at the bottom.
The one-substrate idea¶
A plain Hadron memory is a pile of nodes you retrieve by meaning and
text — keyword search, vector search, tags, loc hierarchy. That's the
right default for knowledge: articles, notes, extracted facts, chat records.
You don't declare columns up front, and nothing is rejected for failing to
fit a shape.
Some corpora aren't prose — they're records of the same kind of thing: competitors, invoices, incidents, contacts. For those you want what a database gives you: a declared shape, a way to say "only the rows in this collection", exact predicates over fields, and ordering by a value. Hadron lets you opt a memory into exactly that, per collection, without leaving the graph.
The database analogy¶
The design hangs on a direct mapping to a relational/document store. If you know SQL, you already know the model:
| Database concept | Hadron | Notes |
|---|---|---|
| Row | Node | One record. |
| Table / collection | Node.objectType |
A discriminator: competitor, insight, invoice. Orthogonal to nodeType. |
| Typed columns | Memory.schema |
Per-objectType field definitions (type, required, enum values). |
| Join | Typed edge (Edge.type) |
Nodes are related through edges, as before. |
WHERE |
where predicate |
Recursive and/or/not tree over properties/data. |
ORDER BY |
sortProperty |
Order by a JSON-path value. |
VALIDATE CONSTRAINT |
hadron_validate conformance |
An on-demand audit for rows that pre-date or bypassed the schema. |
The vocabulary lines up on purpose: a field's declared type in the schema
is its query cast in where and sortProperty (text, number,
datetime, boolean, plus enum in the schema). Declare a field as
number and it's queryable and sortable as a number — no separate mapping to
keep in sync.
objectType vs. nodeType¶
The two are orthogonal, and mixing them up is the common early mistake.
nodeType(info,abstract,record,system,reference) is about a node's role in retrieval — is it knowledge, a summary, a high-volume record, agent scaffolding? See Node types.objectType(competitor,insight, …) is about which domain collection the node belongs to — the "table" it's a row in.
A node can be both: a record-type node with objectType: competitor is a
high-volume factual record that also happens to be a row in the competitor
collection. A node with no objectType is an ordinary, uncollected node —
the default.
Schema-on-write, never retroactive¶
When a memory has a schema, every write of a collection member is validated:
objectType must name a declared collection, required fields must be
present, and each present field's value must be coercible to its declared
type (a strict collection additionally rejects undeclared property keys). A
violation is rejected at write time (BAD_USER_INPUT).
Crucially, the schema is not retroactive. Adding or tightening a schema
never invalidates nodes that already exist — it only governs writes from that
point on. Rows written before the schema existed, or through a path outside
the write seam, are caught by the conformance audit (hadron_validate),
which reports non-conforming nodes without mutating anything. This keeps
"turn on a schema" a safe, non-destructive operation.
When to reach for a schema¶
Reach for a schema when the memory holds many instances of the same shape and you'll want to query or order them by field values:
- A
competitorcollection you'll filter by funding stage and sort by raised amount. - An
invoicecollection you'll filter by status and due date. - An
incidentcollection you'll filter by severity and time window.
Stay unstructured when the memory is prose you retrieve by meaning — articles, guides, design write-ups, chat history. Keyword and vector search are the right tools there, and a schema would just be ceremony. See Understanding memory for the retrieval-first model that remains the default.
You don't have to choose once for a whole memory: a schema declares
collections, and nodes without an objectType coexist untouched alongside
them. A memory can be mostly unstructured knowledge with one or two typed
collections living in it.
What's next¶
- Structured storage and queries — the
exact contract: schema shape,
wheregrammar,sortProperty, and the surface matrix. - Give a memory a structured schema — declare collections and typed fields.
- Query nodes by their properties —
the
wherepredicate end to end. - Build a market-research agent with structured memory — the whole model in one worked example.