Schemas as documents
The schema for document type task is itself a document: sys:schema:task,
of type sys:schema. It is created and updated through the same API as user
data, synced to clients like user data, and validated like user data — against
a meta-schema.
What a schema describes
Section titled “What a schema describes”A schema document declares the shape of a document type’s data:
- Field types — objects, arrays, records, strings, numbers, booleans,
enums, and
unknownfor escape hatches. - References — fields that point at other documents (or at records within the same document), with integrity rules for what happens when the target disappears. See References & integrity.
- Migrations — an append-only log of schema evolutions (rename, remove, remap). A document written under an old schema version is brought forward on its next read and the migrated data is persisted back — the full story is on Schema evolution.
Documents whose type has no schema are freeform: they sync and patch like any other document, just without validation.
Why schemas want to be documents
Section titled “Why schemas want to be documents”One API. Evolving the data model is a document write, not a deploy. The same subscription machinery that gives you live user data gives you live schema changes.
Agents can model. An AI agent that decides it needs a new document type writes a schema document and starts using it — no out-of-band tooling.
One timeline, not two. When schemas live only in source code, a stored document’s meaning is split across two histories — the repository’s and the data’s — and correlating them means mapping deploy times onto document versions. Remove a field from a code-only schema and that removal is recorded nowhere except a commit. As documents, schemas have their history in the same event log as the data they govern: introspecting a document as it was at any point in time means looking in exactly one place. The same property is what makes the data portable — a folder’s history carries its own interpretation with it.
Schemas version like data. Sequence numbers, event history, and guarded writes apply to schema changes exactly as they do to data changes.
Where the schema truth lives
Section titled “Where the schema truth lives”Schemas being documents doesn’t mean giving up TypeScript. There are three ways to source them, and they compose:
Authored in TypeScript. A schema can be defined in code, and the document data types are inferred from the schema literal — compile-time validation and typed reads/writes with no code-generation step. The defined value is a plain schema document’s data; the types are phantom.
Upserted at startup. The host application writes its TypeScript-defined
schemas into the sys:schema:* documents when a folder boots — a no-op when
nothing changed. Rolling out a schema change in code becomes a document
update in each folder, still subject to the server’s append-only
migration rules. This is what makes
TypeScript authoring compatible with the one-timeline argument above: the
upsert turns every code change back into document history, so even when git
is where schemas are written, the schema documents remain where their
history lives — the repository never becomes a second timeline you’d have
to consult.
Document-driven only. Types created at runtime — by a user, or by an agent — exist purely as schema documents, with no TypeScript counterpart.
Whatever the source, the server’s write path always validates against the
schema documents — the TypeScript definitions are never a second,
shadow truth. Clients then choose per app: bundle the static TypeScript
schemas (typed, instant optimistic validation, no waiting for schemas to
sync) or, with dynamic schemas enabled, subscribe to sys:schema:* and
validate against whatever the folder currently declares — required when
document types are born at runtime.