Skip to content

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 competitor collection you'll filter by funding stage and sort by raised amount.
  • An invoice collection you'll filter by status and due date.
  • An incident collection 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