Resources
Schema-defined data types and the records that fill them.
A resource is a data type, like customer or ticket. A resource type is its shape; a
record is one instance of that type. You create a type by describing it to the
assistant — "track customers with a name and an email" — and from then on you get
validated storage and a full interface for its records.
You never have to write the shape yourself. The rest of this page describes what the assistant builds on your behalf and how it behaves, so you know what is possible to ask for. To do it, see Define a resource type.
Two halves: schema and data
Under the hood a type is a JSON Schema the assistant writes into the
soul at resources/{name}/schema.yml; the records live in the
datastore. TulipFarm reads each schema and materializes a table for it — this is called
reconciliation. A type the assistant creates is reconciled immediately, ready to hold
records with no restart.
The schema it writes is plain JSON Schema in YAML — for the customer example, this:
type: object
properties:
name:
type: string
email:
type: string
format: email
required:
- nameEvery write is validated against the schema before it is stored.
Identifiers
Each record has a system id that is a UUID — stable, internal, and used for linking.
Human-friendly identifiers like TICK-123 are a separate field, produced by the
x-id-strategy extension and never the primary id:
properties:
ref:
type: string
"x-id-strategy":
field: ref
prefix: "TICK-"
sequence: trueRelationships with x-links
A field can declare that it points at another resource using x-links. On write,
TulipFarm verifies the target record exists; a link to a missing record is rejected.
This catches the common case of an agent inventing a customerId that was never real.
Deletes are soft and do not cascade. If you delete a record that others link to, the referencing records remain — their link simply no longer resolves to a live record, and the UI surfaces it as unresolved rather than blocking the delete.
Computed and normalized fields
Beyond identifiers and links, schemas support declarative transforms applied before a write:
x-normalize— clean a value into canonical form. Supported strategies:trim,lowercase,uppercase,slugify,phone-e164,email-normalize.x-computed— derive a field's value from others. Supported strategies:sha256,uuid,sequence.
These cover the common before-write cases without code. For arbitrary logic, a resource
type can include a hooks.ts file executed in an isolated sandbox (isolated-vm). You
ask for these in plain language too — "auto-number tickets as TICK-1", "lowercase the
email" — and the assistant wires up the right extension.
You create resource types by asking the assistant — see
Define a resource type. You can also edit
schema.yml in the soul by hand if you prefer; that is the power-user path. Either way,
Work with records covers managing data once a type
exists.